first and last commit

This commit is contained in:
Chris Nutter committed 2023-07-08 13:03:17 -07:00
commit 1bf4efd552
2612 files changed
+636500

No files matched your search

+541
View File
@@ -0,0 +1,541 @@
/*
* Copyright (C) 2006-2014 Apple Computer, Inc. All rights reserved.
*
* This document is the property of Apple Computer, Inc.
* It is considered confidential and proprietary.
*
* This document may not be reproduced or transmitted in any form,
* in whole or in part, without the express written permission of
* Apple Computer, Inc.
*/
#include <sys.h>
#include <stdlib.h>
#include <string.h>
#include <debug.h>
#include <lib/blockdev.h>
#ifndef HOST_TEST
#include <lib/mib.h>
#endif
#include <lib/libiboot.h>
#include <limits.h>
static struct blockdev *bdev_list = NULL;
#define BLOCKSIZE_MOD(dev, val) ((val) & ((1<<((dev)->block_shift)) - 1))
#define BLOCK_FROM_OFF(dev, off) ((off) >> (dev)->block_shift)
#define BLOCK_TO_OFF(dev, block) ((block) << (dev)->block_shift)
#define ALIGNMENT_MOD(dev, val) ((val) & ((1<<((dev)->alignment_shift)) - 1))
static size_t get_cpu_cache_line_size(void)
{
#ifndef HOST_TEST
return mib_get_size(kMIBPlatformCacheLineSize);
#elif defined CPU_CACHELINE_SIZE
return CPU_CACHELINE_SIZE;
#else
#error "Cache line size is not defined"
#endif
}
struct blockdev *lookup_blockdev(const char *name)
{
struct blockdev *dev;
for (dev = bdev_list; dev; dev = dev->next) {
if (strcmp(dev->name, name) == 0)
return dev;
}
return NULL;
}
struct blockdev *first_blockdev(void)
{
return bdev_list;
}
struct blockdev *next_blockdev(struct blockdev *dev)
{
return dev->next;
}
int register_blockdev(struct blockdev *dev)
{
ASSERT(dev != NULL);
ASSERT(dev->block_size > 0);
dprintf(DEBUG_INFO, "register_blockdev: dev %p '%s'\n", dev, dev->name);
dev->next = bdev_list;
bdev_list = dev;
return 0;
}
static void *get_bounce_buf(struct blockdev *dev)
{
void *result;
uint32_t align = __max(dev->alignment, (uint32_t)get_cpu_cache_line_size());
uint32_t size = __max(dev->alignment, dev->block_size);
posix_memalign(&result, align, size);
return result;
}
/* a reasonable default bytewise read routine in case the block device does not
* choose to override the read_hook. deblocks the device by reading from the read_block hook.
*/
static int blockdev_read_hook(struct blockdev *dev, void *ptr, off_t offset, uint64_t len)
{
int err;
size_t bytes_read;
block_addr block;
size_t buf_offset;
char *buf = NULL;
/* trim the read len */
RELEASE_ASSERT(offset >= 0);
if ((uint64_t)offset >= dev->total_len)
return 0;
if ((offset + len) > dev->total_len)
len = dev->total_len - offset;
buf_offset = 0;
bytes_read = 0;
block = BLOCK_FROM_OFF(dev, offset);
// dprintf(DEBUG_INFO, "read: ptr %p, buf_offset %d, bytes_read %zd, block %u, len %d, offset %lld\n", ptr, buf_offset, bytes_read, block, len, offset);
/* read in partial first block */
if (BLOCKSIZE_MOD(dev, offset) != 0 || ALIGNMENT_MOD(dev, (uintptr_t)ptr) != 0) {
size_t block_off = BLOCKSIZE_MOD(dev, offset);
size_t toread = __min(len, dev->block_size - block_off);
buf = get_bounce_buf(dev);
err = blockdev_read_block(dev, buf, block, 1);
if (err <= 0)
goto done;
/* copy the partial data */
memcpy(ptr, buf + block_off, toread);
block++;
offset += toread;
buf_offset += toread;
bytes_read += toread;
len -= toread;
}
// dprintf(DEBUG_INFO, "read2: ptr %p, buf_offset %d, bytes_read %zd, block %u, len %d, offset %lld, blockshift %d\n", ptr, buf_offset, bytes_read, block, len, offset, dev->block_shift);
ASSERT(len == 0 || BLOCKSIZE_MOD(dev, offset) == 0);
/* handle multiple middle blocks */
while (len >= dev->block_size) {
size_t blocks_to_read;
size_t alignment_offset;
blocks_to_read = BLOCK_FROM_OFF(dev, len);
/* If the buffer we're writing to isn't aligned, shorten the read by a block and
bounce through an aligned address higher up in the buffer. This relies on the block
size being >= the alignment, which is enforced by blockdev_set_buffer_alignment.
For reads of just one block, go through the bounce buffer */
alignment_offset = ALIGNMENT_MOD(dev, (uintptr_t)ptr + buf_offset);
if (alignment_offset != 0) {
if (blocks_to_read > 1) {
uint8_t *dest;
dest = (uint8_t *)ptr + buf_offset + dev->alignment - alignment_offset;
err = blockdev_read_block(dev, dest, block, blocks_to_read - 1);
if (err > 0)
memmove((uint8_t *)ptr + buf_offset, dest, BLOCK_TO_OFF(dev, err));
} else {
if (!buf)
buf = get_bounce_buf(dev);
err = blockdev_read_block(dev, buf, block, 1);
if (err > 0)
memmove((uint8_t *)ptr + buf_offset, buf, BLOCK_TO_OFF(dev, 1));
}
} else {
err = blockdev_read_block(dev, (uint8_t *)ptr + buf_offset, block, blocks_to_read);
}
if (err <= 0)
goto done;
/* account for blocks read */
block += err;
buf_offset += BLOCK_TO_OFF(dev, err);
bytes_read += BLOCK_TO_OFF(dev, err);
len -= BLOCK_TO_OFF(dev, err);
}
// dprintf(DEBUG_INFO, "read3: ptr %p, buf_offset %d, bytes_read %zd, block %ud, len %d, offset %lld\n", ptr, buf_offset, bytes_read, block, len, offset);
/* handle partial last block */
if (len > 0) {
ASSERT(len < dev->block_size);
if (!buf)
buf = get_bounce_buf(dev);
err = blockdev_read_block(dev, buf, block, 1);
if (err <= 0)
goto done;
memcpy((uint8_t *)ptr + buf_offset, buf, len);
bytes_read += len;
}
done:
if (NULL != buf)
free(buf);
return bytes_read;
}
static int blockdev_read_block_hook(struct blockdev *dev, void *ptr, block_addr block, uint32_t count)
{
dprintf(DEBUG_CRITICAL, "no reasonable default block read routine\n");
return -1;
}
static int blockdev_write_hook(struct blockdev *dev, const void *ptr, off_t offset, uint64_t len)
{
int err;
size_t bytes_written;
block_addr block;
size_t buf_offset;
char *buf = NULL;
const void *src;
/* trim the write len */
RELEASE_ASSERT(offset >= 0);
if ((uint64_t)offset >= dev->total_len)
return 0;
if ((offset + len) > dev->total_len)
len = dev->total_len - offset;
buf_offset = 0;
bytes_written = 0;
block = BLOCK_FROM_OFF(dev, offset);
// dprintf(DEBUG_INFO, "write: ptr %p, buf_offset %d, bytes_written %zd, block %u, len %d, offset %lld\n", ptr, buf_offset, bytes_written, block, len, offset);
/* write partial first block */
if (BLOCKSIZE_MOD(dev, offset) != 0 || ALIGNMENT_MOD(dev, offset) != 0) {
size_t block_off = BLOCKSIZE_MOD(dev, offset);
size_t towrite = __min(len, dev->block_size - block_off);
buf = get_bounce_buf(dev);
/* read in a buffer */
err = blockdev_read_block(dev, buf, block, 1);
if (err <= 0)
goto done;
/* copy the partial data */
memcpy(buf + block_off, ptr, towrite);
/* write it back out */
err = blockdev_write_block(dev, buf, block, 1);
if (err <= 0)
goto done;
block++;
offset += towrite;
buf_offset += towrite;
bytes_written += towrite;
len -= towrite;
}
// dprintf(DEBUG_INFO, "write2: ptr %p, buf_offset %d, bytes_written %zd, block %u, len %d, offset %lld, blockshift %d\n", ptr, buf_offset, bytes_written, block, len, offset, dev->block_shift);
ASSERT(len == 0 || BLOCKSIZE_MOD(dev, offset) == 0);
/* handle multiple middle blocks */
while (len >= dev->block_size) {
size_t blocks_to_write;
size_t alignment_offset;
/* If the buffer we're reading from isn't aligned, bounce buffer each block. iBoot
doesn't care about write performance for big writes, so it's ok for this to be slow */
alignment_offset = ALIGNMENT_MOD(dev, (uintptr_t)ptr + buf_offset);
if (alignment_offset != 0) {
if (!buf)
buf = get_bounce_buf(dev);
blocks_to_write = 1;
memcpy(buf, (const uint8_t *)ptr + buf_offset, BLOCK_TO_OFF(dev, blocks_to_write));
src = buf;
} else {
blocks_to_write = BLOCK_FROM_OFF(dev, len);
src = (const uint8_t *)ptr + buf_offset;
}
err = blockdev_write_block(dev, src, block, blocks_to_write);
if (err <= 0)
goto done;
/* account for write */
block += err;
buf_offset += BLOCK_TO_OFF(dev, err);
bytes_written += BLOCK_TO_OFF(dev, err);
len -= BLOCK_TO_OFF(dev, err);
}
// dprintf(DEBUG_INFO, "write3: ptr %p, buf_offset %d, bytes_written %zd, block %ud, len %d, offset %lld\n", ptr, buf_offset, bytes_written, block, len, offset);
/* handle partial last block */
if (len > 0) {
ASSERT(len < dev->block_size);
if (!buf)
buf = get_bounce_buf(dev);
err = blockdev_read_block(dev, buf, block, 1);
if (err <= 0)
goto done;
memcpy(buf, (uint8_t *)ptr + buf_offset, len);
err = blockdev_write_block(dev, buf, block, 1);
if (err <= 0)
goto done;
bytes_written += len;
}
done:
if (NULL != buf)
free(buf);
return bytes_written;
}
static int blockdev_write_block_hook(struct blockdev *dev, const void *ptr, block_addr block, uint32_t count)
{
dprintf(DEBUG_CRITICAL, "no reasonable default block write routine\n");
return -1;
}
static int blockdev_erase_hook(struct blockdev *dev, off_t offset, uint64_t len)
{
dprintf(DEBUG_CRITICAL, "no reasonable default erase routine\n");
return -1;
}
/* compare memory with a range of the block device */
int blockdev_compare(struct blockdev *dev, const void *_ptr, off_t bdev_offset, uint64_t len)
{
int result;
int err;
uint32_t i;
uint8_t *buf;
const uint8_t *ptr = (const uint8_t *)_ptr;
posix_memalign((void **)&buf, get_cpu_cache_line_size(), dev->block_size);
result = 0;
while (len > 0) {
size_t toread = __min(dev->block_size, len);
err = blockdev_read(dev, buf, bdev_offset, toread);
if (err <= 0) {
dprintf(DEBUG_CRITICAL, "bdev_compare: error reading from device at offset %lld\n", bdev_offset);
result = -1;
goto out;
}
if ((uint32_t)err < toread) {
dprintf(DEBUG_CRITICAL, "bdev_compare: short read from device at offset %lld (read %d)\n", bdev_offset, err);
result = -1;
goto out;
}
for (i=0; i < toread; i++) {
if (buf[i] != *ptr) {
dprintf(DEBUG_CRITICAL, "difference at offset %lld: dev 0x%02x mem 0x%02x\n", bdev_offset + i, buf[i], *ptr);
result++;
}
ptr++;
}
len -= toread;
bdev_offset += toread;
}
out:
free(buf);
return result;
}
/* write to the bdev safely, avoiding the protected region */
int blockdev_write_protected(struct blockdev *dev, const void *ptr, off_t offset, uint64_t len)
{
size_t overlap;
off_t protect_start, protect_end;
uint64_t total_length;
int err;
off_t bytes_written = 0;
// printf("write_protected: ptr %p offset 0x%llx length 0x%x\n", ptr, offset, len);
protect_start = dev->protect_start;
protect_end = dev->protect_end;
total_length = (uint64_t)offset + len;
// Test for negative offset and overlap
RELEASE_ASSERT(offset >= 0);
RELEASE_ASSERT(total_length >= len);
/* write the portion before the protected region */
if (offset < protect_start) {
ASSERT(protect_start >= 0);
if ((offset + len) > (size_t)protect_start) {
overlap = (offset + len) - protect_start;
} else {
overlap = 0;
}
// printf("BDEV: writing first part: 0x%llx/0x%x\n", offset, len - overlap);
err = dev->write_hook(dev, ptr, offset, len - overlap);
if (err < 0)
return err;
bytes_written += err;
}
/* and write the portion after */
RELEASE_ASSERT(protect_end >= 0);
if ((offset + len) > (size_t)protect_end) {
if (offset < protect_end) {
overlap = protect_end - offset;
} else {
overlap = 0;
}
// printf("BDEV: writing second part: 0x%llx/0x%x\n", offset + overlap, len - overlap);
err = dev->write_hook(dev, (char *)ptr + overlap, offset + overlap, len - overlap);
if (err < 0)
return err;
bytes_written += err;
}
return bytes_written;
}
int blockdev_write_block_protected(struct blockdev *dev, const void *ptr, block_addr block, uint32_t count)
{
size_t overlap;
size_t protect_start, protect_end;
int err;
uint32_t total_count;
// printf("write_block_protected: ptr %p block 0x%x count 0x%x\n", ptr, block, count);
protect_start = dev->protect_start >> dev->block_shift;
protect_end = dev->protect_end >> dev->block_shift;
total_count = block + count;
// Test for overlap
RELEASE_ASSERT(total_count >= block);
/* write the portion before the protected region */
if (block < protect_start) {
if ((block + count) > protect_start) {
overlap = (block + count) - protect_start;
} else {
overlap = 0;
}
// printf("BDEV: writing first part: 0x%x/0x%x\n", block, count - overlap);
err = dev->write_block_hook(dev, ptr, block, count - overlap);
if (err < 0) /* error */
return(-1);
if ((uint32_t)err < (count - overlap)) /* short write */
return(err);
}
/* and write the portion after */
if ((block + count) > protect_end) {
if (block < protect_end) {
overlap = protect_end - block;
} else {
overlap = 0;
}
// printf("BDEV: writing second part: 0x%x/0x%x\n", block + overlap, count - overlap);
err = dev->write_block_hook(dev, (char *)ptr + (overlap << dev->block_shift), block + overlap, count - overlap);
if (err < 0) /* error */
return(-1);
if ((uint32_t)err < (count - overlap)) /* short write XXX does not handle both ends
* overhanging */
return(err);
}
return(count);
}
/* set the protected region */
int blockdev_set_protection(struct blockdev *dev, off_t offset, uint64_t length)
{
if (dev->protect_end == dev->protect_start) {
dev->protect_start = offset;
dev->protect_end = offset + length;
dprintf(DEBUG_INFO, "BDEV: protecting 0x%llx-0x%llx\n", dev->protect_start, dev->protect_end);
return(0);
}
return(-1);
}
/* set the required buffer alignment for read and write buffers */
void blockdev_set_buffer_alignment(struct blockdev *dev, uint32_t alignment)
{
ASSERT(dev != NULL);
ASSERT(is_pow2(alignment));
/* Standard hooks don't support an alignment requirement bigger than the block size.
Drivers that need this can just make their blocksize equal to the alignment and
break the alignment-sized blocks into their intrinsic blocksize in their read block hook */
ASSERT(alignment <= dev->block_size);
/* can't change the alignment after first setting it */
ASSERT(dev->alignment == 1 && dev->alignment_shift == 0);
dev->alignment = alignment;
dev->alignment_shift = log2_int(dev->alignment);
}
/*
* set up the shared part of the block device structure, and set the default read hooks
* that provide a lot of the base functionality. The specific block device implementation should
* customize the structure further
*/
int construct_blockdev(struct blockdev *dev, const char *name, uint64_t len, uint32_t block_size)
{
ASSERT(dev != NULL);
ASSERT(is_pow2(block_size));
ASSERT(strlen(name) < sizeof(dev->name));
strlcpy(dev->name, name, sizeof(dev->name));
dev->flags = 0;
dev->block_size = block_size;
dev->block_shift = log2_int(dev->block_size);
dev->block_count = len >> dev->block_shift;
dev->total_len = len;
dev->alignment = 1;
dev->alignment_shift = 0;
ASSERT((len >> dev->block_shift) < UINT_MAX);
dev->read_hook = &blockdev_read_hook;
dev->read_block_hook = &blockdev_read_block_hook;
dev->write_hook = &blockdev_write_hook;
dev->write_block_hook = &blockdev_write_block_hook;
dev->erase_hook = &blockdev_erase_hook;
dev->protect_start = 0;
dev->protect_end = 0;
return 0;
}
+260
View File
@@ -0,0 +1,260 @@
/*
* Copyright (C) 2007-2011, 2013-2016 Apple Inc. All rights reserved.
* Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
*
* This document is the property of Apple Inc.
* It is considered confidential and proprietary.
*
* This document may not be reproduced or transmitted in any form,
* in whole or in part, without the express written permission of
* Apple Inc.
*/
#include <debug.h>
#include <lib/blockdev.h>
#include <lib/env.h>
#include <lib/mib.h>
#include <sys/menu.h>
#include <drivers/usb/usb_debug.h>
#define USB_TRANSFER_BLOCKS (1000)
static int do_slurp (struct blockdev *dev, char *filename, const size_t block_offset) {
int err = 0;
off_t lba;
off_t end;
size_t buf_offset;
const size_t buf_size = dev->block_size * USB_TRANSFER_BLOCKS;
uint8_t * read_buf;
uint8_t * base_buf;
uintptr_t buf_physical;
end = dev->total_len >> dev->block_shift;
base_buf = malloc(buf_size);
if (NULL == base_buf) {
printf ("malloc failed\n");
return -1;
}
buf_physical = mem_static_map_physical((uintptr_t)base_buf);
printf("slurping lba %zu to %llu\n", block_offset, end);
buf_offset = 0;
lba = block_offset;
while (lba < end) {
read_buf = base_buf + buf_offset;
*(UInt32*)read_buf = 0xa5a5a5a5; /* poison buffer */
err = blockdev_read(dev, read_buf, lba << dev->block_shift, dev->block_size);
if (err < 0){
printf("blockdev_read returns %d on lba %llu\n\n", err, lba);
// don't stop slurping
}
buf_offset += dev->block_size;
++lba;
if (buf_offset == buf_size) {
/*
* This issues writes over the USB pipe for USB_TRANSFER_BLOCKS ' worth of
* device blocks. This could be (4096) * 1000 or (8192) * 1000 depending
* on device block size.
*/
err = usb_send_data_to_file(filename, buf_offset, buf_physical, 0);
if (err) {
printf("USB transfer error %d\n", err);
goto out;
}
buf_offset = 0;
printf("Completed to block offset %llu\r", lba);
}
}
/* Send over the remainder of blocks.. */
if (buf_offset > 0) {
err = usb_send_data_to_file(filename, buf_offset, buf_physical, 0);
if (err) {
printf("USB transfer error %d\n", err);
goto out;
}
}
out:
printf("Completed to block offset %llu with code %d\n", lba, err);
free(base_buf);
return err;
}
int do_blockdev(int argc, struct cmd_arg *args)
{
if (!security_allow_modes(kSecurityModeDebugCmd)) {
printf("Permission Denied\n");
return -1;
}
if (argc < 2) {
printf("not enough arguments\n");
usage:
printf("usage:\n");
printf("%s list\n", args[0].str);
printf("%s read <dev> <offset> <len> [<address>]\n", args[0].str);
printf("%s scan <dev> <lba> <num>\n", args[0].str);
printf("%s slurp <dev> <file> \n", args[0].str);
printf("%s write <dev> <offset> [<len>] [<address>]\n", args[0].str);
printf("%s memcmp <dev> <offset> [<len>] [<address>]\n", args[0].str);
printf("%s erase <dev> <offset> <len>\n", args[0].str);
return -1;
}
if (!strcmp(args[1].str, "list")) {
struct blockdev *dev;
printf("block device list:\n");
for (dev = first_blockdev(); dev; dev = next_blockdev(dev)) {
printf("\tdevice '%s': size %lld, block_size %d\n", dev->name, dev->total_len, dev->block_size);
}
} else if (!strcmp(args[1].str, "read") || !strcmp(args[1].str, "write") || !strcmp(args[1].str, "memcmp")) {
if (argc < 4) {
printf("not enough arguments.\n");
goto usage;
}
off_t offset = args[3].u;
size_t len;
addr_t addr;
int err;
struct blockdev *dev;
if (argc >= 5) {
len = args[4].u;
} else {
len = env_get_uint("filesize", 0);
if (len == 0) {
printf("filesize variable invalid or not set, aborting\n");
return -1;
}
}
if (argc >= 6) {
addr = args[5].u;
} else {
addr = env_get_uint("loadaddr", mib_get_addr(kMIBTargetDefaultLoadAddress));
}
if (!security_allow_memory((void *)addr, len)) {
printf("Permission Denied\n");
return -1;
}
dev = lookup_blockdev(args[2].str);
if (!dev) {
printf("couldn't find block device '%s'\n", args[2].str);
return -1;
}
if (!strcmp(args[1].str, "read")) {
printf("reading %zu bytes from device '%s' to address 0x%llx\n", len, args[2].str, (uint64_t)addr);
err = blockdev_read(dev, (void *)addr, offset, len);
printf("blockdev_read returns %d\n", err);
} else if (!strcmp(args[1].str, "write")) {
printf("writing %zu bytes to device '%s' from address 0x%llx\n", len, args[2].str, (uint64_t)addr);
err = blockdev_write(dev, (void *)addr, offset, len);
printf("blockdev_write returns %d\n", err);
} else {
printf("comparing %zu bytes from device '%s' to address 0x%llx\n", len, args[2].str, (uint64_t)addr);
err = blockdev_compare(dev, (void *)addr, offset, len);
printf("blockdev_compare returns %d\n", err);
}
} else if (!strcmp(args[1].str, "erase")) {
if (argc < 5) {
printf("not enough arguments.\n");
goto usage;
}
off_t offset = args[3].u;
size_t len = args[4].u;
int err;
struct blockdev *dev;
dev = lookup_blockdev(args[2].str);
if (!dev) {
printf("couldn't find block device '%s'\n", args[2].str);
return -1;
}
err = blockdev_erase(dev, offset, len);
printf("blockdev_erase returns %d\n", err);
} else if (!strcmp(args[1].str, "scan")) {
if (argc < 5) {
printf("not enough arguments.\n");
goto usage;
}
off_t lba = (off_t)args[3].u;
size_t len = args[4].u;
int err;
struct blockdev *dev;
off_t end;
uint8_t *buffer;
dev = lookup_blockdev(args[2].str);
if (!dev) {
printf("couldn't find block device '%s'\n", args[2].str);
return -1;
}
if (!len || ((off_t)(lba + len) > (off_t)(dev->total_len >> dev->block_shift))){
end = dev->total_len >> dev->block_shift;
}else{
end = lba + len;
}
buffer = malloc(dev->block_size);
printf("scanning lba %llu to %llu\n", lba, end);
while (lba < end)
{
*buffer = 0xa5;
err = blockdev_read(dev, buffer, lba << dev->block_shift, dev->block_size);
if (err < 0){
printf("blockdev_read returns %d on lba %llu\n", err, lba);
free(buffer);
return 1;
}
if (lba % 1000 == 0)
printf("lba %zu\r", (size_t)lba);
++lba;
}
free(buffer);
printf("blockdev scan completed with no errors\n");
}
else if (!strcmp(args[1].str, "slurp")) {
/* Is it a slurp? */
if (argc < 3) {
/* bdev slurp device filename */
printf("slurp invalid arguments \n");
goto usage;
}
struct blockdev *dev;
size_t block_offset;
dev = lookup_blockdev(args[2].str);
block_offset = 0;
if (!dev) {
printf("could not find blk dev ' %s ' \n", args[2].str);
goto usage;
}
return do_slurp (dev, args[3].str, block_offset);
}
else {
printf("unrecognized subcommand.\n");
goto usage;
}
return 0;
}
+31
View File
@@ -0,0 +1,31 @@
# Copyright (C) 2014 Apple Inc. All rights reserved.
#
# This document is the property of Apple Inc.
# It is considered confidential and proprietary.
#
# This document may not be reproduced or transmitted in any form,
# in whole or in part, without the express written permission of
# Apple Inc.
#
LIBBLOCKDEV_DIR := $(GET_LOCAL_DIR)
LIBBLOCKDEV_BUILD := $(call TOLIBDIR,$(LIBBLOCKDEV_DIR)/LIBBLOCKDEV.a)
COMMONLIBS += LIBBLOCKDEV
# Only process the remainder of the makefile if we are building libraries
#
ifeq ($(MAKEPHASE),libraries)
LIBBLOCKDEV_OBJS := \
$(LIBBLOCKDEV_DIR)/blockdev.o \
$(LIBBLOCKDEV_DIR)/subdev.o \
$(LIBBLOCKDEV_DIR)/mem_blockdev.o \
$(LIBBLOCKDEV_DIR)/debug.o
LIBBLOCKDEV_OBJS := $(call TOLIBOBJDIR,$(LIBBLOCKDEV_OBJS))
ALL_DEPS += $(LIBBLOCKDEV_OBJS:%o=%d)
$(LIBBLOCKDEV_BUILD): $(LIBBLOCKDEV_OBJS)
endif
+77
View File
@@ -0,0 +1,77 @@
/*
* Copyright (C) 2006-2011 Apple Computer, Inc. All rights reserved.
*
* This document is the property of Apple Computer, Inc.
* It is considered confidential and proprietary.
*
* This document may not be reproduced or transmitted in any form,
* in whole or in part, without the express written permission of
* Apple Computer, Inc.
*/
#include <debug.h>
#include <sys.h>
#include <string.h>
#include <lib/blockdev.h>
#include <stdlib.h>
struct mem_blockdev {
struct blockdev bdev;
/* local data */
void *ptr;
};
static int mem_blockdev_read_block(struct blockdev *bdev, void *ptr, block_addr block, uint32_t count)
{
struct mem_blockdev *mdev = (struct mem_blockdev *)bdev;
// no overflow
RELEASE_ASSERT(block + count >= block);
if (block >= mdev->bdev.block_count)
return 0;
if ((block + count) > mdev->bdev.block_count)
count = mdev->bdev.block_count - block;
dprintf(DEBUG_SPEW, "mem_blockdev_read: dev %p, ptr %p, block %d, count %d\n", bdev, ptr, block, count);
memcpy(ptr, (uint8_t *)mdev->ptr + (block << mdev->bdev.block_shift), count << mdev->bdev.block_shift);
return count;
}
static int mem_blockdev_read(struct blockdev *bdev, void *ptr, off_t offset, uint64_t len)
{
struct mem_blockdev *mdev = (struct mem_blockdev *)bdev;
RELEASE_ASSERT(offset >= 0);
// no overflow
RELEASE_ASSERT((uint64_t)offset + len >= (uint64_t)offset);
if ((uint64_t)offset >= mdev->bdev.total_len)
return 0;
if ((offset + len) > mdev->bdev.total_len)
len = mdev->bdev.total_len - offset;
dprintf(DEBUG_SPEW, "mem_blockdev_read: dev %p, ptr %p, off %lld, len %llu\n", bdev, ptr, offset, len);
memcpy(ptr, (uint8_t *)mdev->ptr + offset, len);
return len;
}
struct blockdev *create_mem_blockdev(const char *name, void *ptr, uint64_t len, uint32_t block_size)
{
struct mem_blockdev *mdev;
mdev = malloc(sizeof(struct mem_blockdev));
construct_blockdev(&mdev->bdev, name, len, block_size);
mdev->ptr = ptr;
mdev->bdev.read_hook = &mem_blockdev_read;
mdev->bdev.read_block_hook = &mem_blockdev_read_block;
return &mdev->bdev;
}
+13
View File
@@ -0,0 +1,13 @@
# Copyright (C) 2007, 2009-2014 Apple Inc. All rights reserved.
# Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
#
# This document is the property of Apple, Inc.
# It is considered confidential and proprietary.
#
# This document may not be reproduced or transmitted in any form,
# in whole or in part, without the express written permission of
# Apple Inc.
#
OPTIONS += WITH_BLOCKDEV=1
LIBRARY_MODULES += lib/blockdev
+92
View File
@@ -0,0 +1,92 @@
/*
* Copyright (C) 2006-2011 Apple Computer, Inc. All rights reserved.
*
* This document is the property of Apple Computer, Inc.
* It is considered confidential and proprietary.
*
* This document may not be reproduced or transmitted in any form,
* in whole or in part, without the express written permission of
* Apple Computer, Inc.
*/
#include <debug.h>
#include <lib/blockdev.h>
#include <stdlib.h>
struct subdev_blockdev {
struct blockdev bdev;
/* local data */
struct blockdev *parent_dev;
off_t offset;
};
static int subdev_blockdev_read(struct blockdev *bdev, void *ptr, off_t offset, uint64_t len)
{
struct subdev_blockdev *sdev = (struct subdev_blockdev *)bdev;
RELEASE_ASSERT(offset >= 0);
if ((uint64_t)offset >= sdev->bdev.total_len)
return 0;
if ((offset + len) > sdev->bdev.total_len)
len = sdev->bdev.total_len - offset;
return blockdev_read(sdev->parent_dev, ptr, offset + sdev->offset, len);
}
static int subdev_blockdev_read_block(struct blockdev *bdev, void *ptr, block_addr block, uint32_t count)
{
struct subdev_blockdev *sdev = (struct subdev_blockdev *)bdev;
/* since our blocks might not be aligned on parent block boundaries, just punch through to the
* arbitrary alignment read handler and let it deal with it
*/
return subdev_blockdev_read(bdev, ptr, block << sdev->bdev.block_shift, count << sdev->bdev.block_shift);
}
static int subdev_blockdev_write(struct blockdev *bdev, const void *ptr, off_t offset, uint64_t len)
{
struct subdev_blockdev *sdev = (struct subdev_blockdev *)bdev;
RELEASE_ASSERT(offset >= 0);
if ((uint64_t)offset >= sdev->bdev.total_len)
return 0;
if ((offset + len) > sdev->bdev.total_len)
len = sdev->bdev.total_len - offset;
return blockdev_write(sdev->parent_dev, ptr, offset + sdev->offset, len);
}
static int subdev_blockdev_write_block(struct blockdev *bdev, const void *ptr, block_addr block, uint32_t count)
{
struct subdev_blockdev *sdev = (struct subdev_blockdev *)bdev;
/* since our blocks might not be aligned on parent block boundaries, just punch through to the
* arbitrary alignment write handler and let it deal with it
*/
return subdev_blockdev_write(bdev, ptr, block << sdev->bdev.block_shift, count << sdev->bdev.block_shift);
}
struct blockdev *create_subdev_blockdev(const char *name, struct blockdev *parent, off_t off, uint64_t len, uint32_t block_size)
{
struct subdev_blockdev *dev;
ASSERT(parent);
dprintf(DEBUG_SPEW, "create_subdev: name '%s' parent '%s' off 0x%llx len 0x%llx bsize 0x%x\n",
name, parent->name, off, len, block_size);
dev = malloc(sizeof(struct subdev_blockdev));
construct_blockdev(&dev->bdev, name, len, block_size);
blockdev_set_buffer_alignment(&dev->bdev, parent->alignment);
dev->parent_dev = parent;
dev->offset = off;
dev->bdev.read_hook = &subdev_blockdev_read;
dev->bdev.read_block_hook = &subdev_blockdev_read_block;
dev->bdev.write_hook = &subdev_blockdev_write;
dev->bdev.write_block_hook = &subdev_blockdev_write_block;
return (struct blockdev *)dev;
}
+470
View File
@@ -0,0 +1,470 @@
#include <unittest.h>
#include <lib/blockdev.h>
#include <string.h>
#include <stdlib.h>
struct mock_blockdev {
struct blockdev bdev;
/* local data */
void *ptr;
};
static int mock_blockdev_read_block(struct blockdev *bdev, void *ptr, block_addr block, uint32_t count)
{
struct mock_blockdev *mdev = (struct mock_blockdev *)bdev;
// no overflow
TEST_ASSERT_GTE(block + count, block);
// buffer must be properly aligned
TEST_ASSERT_EQ((uintptr_t)ptr & (bdev->alignment - 1), 0);
if (block >= mdev->bdev.block_count)
return 0;
if ((block + count) > mdev->bdev.block_count)
count = mdev->bdev.block_count - block;
memcpy(ptr, (uint8_t *)mdev->ptr + (block << mdev->bdev.block_shift), count << mdev->bdev.block_shift);
return count;
}
static int mock_blockdev_write_block(struct blockdev *bdev, const void *ptr, block_addr block, uint32_t count)
{
struct mock_blockdev *mdev = (struct mock_blockdev *)bdev;
// no overflow
TEST_ASSERT_GTE(block + count, block);
// buffer must be properly aligned
TEST_ASSERT_EQ((uintptr_t)ptr & (bdev->alignment - 1), 0);
if (block >= mdev->bdev.block_count)
return 0;
if ((block + count) > mdev->bdev.block_count)
count = mdev->bdev.block_count - block;
memcpy(mdev->ptr + (block << mdev->bdev.block_shift), ptr, count << mdev->bdev.block_shift);
return count;
}
struct blockdev *create_mock_blockdev(const char *name, void *ptr, uint64_t len, uint32_t block_size)
{
struct mock_blockdev *mdev;
mdev = malloc(sizeof(struct mock_blockdev));
construct_blockdev(&mdev->bdev, name, len, block_size);
mdev->ptr = ptr;
mdev->bdev.read_block_hook = &mock_blockdev_read_block;
mdev->bdev.write_block_hook = &mock_blockdev_write_block;
return &mdev->bdev;
}
static void do_blockdev_read_tests(struct blockdev *bdev, uint8_t *backing, size_t backing_size, uint32_t block_size)
{
uint8_t *readback;
uint8_t *zeroes;
int result;
readback = malloc(backing_size + 1);
TEST_ASSERT_NOT_NULL(readback);
zeroes = malloc(backing_size);
TEST_ASSERT_NOT_NULL(zeroes);
memset(zeroes, 0, backing_size);
// Reading entire buffer should work
memset(readback, 0, backing_size);
result = blockdev_read(bdev, readback, 0, backing_size);
TEST_ASSERT_EQ(result, backing_size);
TEST_ASSERT_MEM_EQ(backing, readback, backing_size);
// Reading entire buffer unaligned should work
memset(readback + 1, 0, backing_size);
result = blockdev_read(bdev, readback + 1, 0, backing_size);
TEST_ASSERT_EQ(result, backing_size);
TEST_ASSERT_MEM_EQ(backing, readback + 1, backing_size);
// Reading past the end results in a short read
memset(readback, 0, backing_size);
result = blockdev_read(bdev, readback, backing_size / 2, backing_size);
TEST_ASSERT_EQ(result, backing_size / 2);
// first half of buffer should have result of read
TEST_ASSERT_MEM_EQ(readback, backing + backing_size / 2, backing_size / 2);
// second half should be untouched
TEST_ASSERT_MEM_EQ(readback + backing_size / 2, zeroes, backing_size / 2);
// Reading totally past the end results in no read
memset(readback, 0, backing_size);
result = blockdev_read(bdev, readback, backing_size + 2, backing_size);
TEST_ASSERT_EQ(result, 0);
// buffer should be totally untouched
TEST_ASSERT_MEM_EQ(readback, zeroes, backing_size);
// Reads that are weird size should work
uint32_t read_sizes[] = {1, 2, 3, 13, 127, 129, 1023, 1025, 4094, 4097, block_size, block_size - 1, block_size - 2, backing_size - 2, backing_size - 1};
for (uint32_t i = 0; i < sizeof(read_sizes) / sizeof(read_sizes[0]); i++) {
uint32_t read_size = read_sizes[i];
if (read_size == 0 || read_size >= backing_size)
continue;
uint32_t read_offsets[] = {0, 1, 2, 3, 13, 127, 129, 1023, 1025, 4094, 4097, block_size, block_size - 1, block_size - 2, backing_size - 2, backing_size - 1};
for (uint32_t j = 0; j < sizeof(read_offsets) / sizeof(read_offsets[0]); j++) {
uint32_t read_offset = read_offsets[j];
if (read_offset >= backing_size || read_offset + read_size >= backing_size)
continue;
tprintf(TEST_INFO, "doing offset=%u size=%u\n", read_offset, read_size);
// make sure the read succeeds
memset(readback + 1, 0, backing_size);
result = blockdev_read(bdev, readback, read_offset, read_size);
TEST_ASSERT_EQ(result, read_size);
TEST_ASSERT_MEM_EQ(readback, backing + read_offset, read_size);
TEST_ASSERT_MEM_EQ(readback + read_size, zeroes, backing_size - read_size);
// make sure read succeeds with alignment forced off
memset(readback + 1, 0, backing_size);
result = blockdev_read(bdev, readback + 1, read_offset, read_size);
TEST_ASSERT_EQ(result, read_size);
TEST_ASSERT_MEM_EQ(readback + 1, backing + read_offset, read_size);
TEST_ASSERT_MEM_EQ(readback + 1 + read_size, zeroes, backing_size - read_size);
}
}
free(readback);
free(zeroes);
}
static void do_blockdev_read_block_tests(struct blockdev *bdev, uint8_t *backing, size_t backing_size, uint32_t block_size)
{
uint8_t *readback;
uint8_t *filler;
int result;
uint32_t blocks = backing_size / block_size;
readback = malloc(backing_size);
TEST_ASSERT_NOT_NULL(readback);
filler = malloc(backing_size + 1);
TEST_ASSERT_NOT_NULL(filler);
memset(filler, 0xee, backing_size);
// Reading entire buffer should work
memcpy(readback, filler, backing_size);
result = blockdev_read_block(bdev, readback, 0, blocks);
TEST_ASSERT_EQ(result, blocks);
TEST_ASSERT_MEM_EQ(backing, readback, backing_size);
// Reading past the end results in a short read
memcpy(readback, filler, backing_size);
result = blockdev_read_block(bdev, readback, blocks / 2, blocks);
TEST_ASSERT_EQ(result, blocks / 2);
// first half of buffer should have result of read
TEST_ASSERT_MEM_EQ(readback, backing + backing_size / 2, backing_size / 2);
// second half should be untouched
TEST_ASSERT_MEM_EQ(readback + backing_size / 2, filler, backing_size / 2);
// Reading totally past the end results in no read
memcpy(readback, filler, backing_size);
result = blockdev_read_block(bdev, readback, blocks + 2, blocks);
TEST_ASSERT_EQ(result, 0);
// buffer should be totally untouched
TEST_ASSERT_MEM_EQ(readback, filler, backing_size);
free(readback);
free(filler);
}
void test_mem_blockdev(uintptr_t param)
{
struct blockdev *bdev;
uint8_t *backing;
size_t backing_size = 8192;
uint32_t block_size = param;
backing = malloc(backing_size);
TEST_ASSERT_NOT_NULL(backing);
for (uint32_t i = 0; i < backing_size / sizeof(uint32_t); i++) {
uint32_t val = i + 0xaabbccdd;
memcpy(backing + i * sizeof(uint32_t), &val, sizeof(uint32_t));
}
bdev = create_mem_blockdev("dev", backing, backing_size, block_size);
do_blockdev_read_tests(bdev, backing, backing_size, block_size);
do_blockdev_read_block_tests(bdev, backing, backing_size, block_size);
// make sure backing wasn't touched during all the tests
for (unsigned i = 0; i < backing_size / sizeof(uint32_t); i++) {
uint32_t val;
memcpy(&val, backing + i * sizeof(uint32_t), sizeof(uint32_t));
TEST_ASSERT_EQ(val, i + 0xaabbccdd);
}
free(backing);
}
void test_blockdev_read_block(uintptr_t param)
{
struct blockdev *bdev;
uint8_t *backing;
size_t backing_size = 8192;
uint32_t block_size = param;
backing = malloc(backing_size);
TEST_ASSERT_NOT_NULL(backing);
for (uint32_t i = 0; i < backing_size / sizeof(uint32_t); i++) {
uint32_t val = i + 0xaabbccdd;
memcpy(backing + i * sizeof(uint32_t), &val, sizeof(uint32_t));
}
bdev = create_mock_blockdev("dev1", backing, backing_size, block_size);
do_blockdev_read_block_tests(bdev, backing, backing_size, block_size);
// make sure backing wasn't touched during all the tests
for (unsigned i = 0; i < backing_size / sizeof(uint32_t); i++) {
uint32_t val;
memcpy(&val, backing + i * sizeof(uint32_t), sizeof(uint32_t));
TEST_ASSERT_EQ(val, i + 0xaabbccdd);
}
free(backing);
}
void test_blockdev_read(uintptr_t param)
{
struct blockdev *bdev;
uint8_t *backing;
size_t backing_size = 8192;
uint32_t block_size = param;
backing = malloc(backing_size);
TEST_ASSERT_NOT_NULL(backing);
for (uint32_t i = 0; i < backing_size / sizeof(uint32_t); i++) {
uint32_t val = i + 0xaabbccdd;
memcpy(backing + i * sizeof(uint32_t), &val, sizeof(uint32_t));
}
bdev = create_mock_blockdev("dev1", backing, backing_size, block_size);
do_blockdev_read_tests(bdev, backing, backing_size, block_size);
// make sure backing wasn't touched during all the tests
for (unsigned i = 0; i < backing_size / sizeof(uint32_t); i++) {
uint32_t val;
memcpy(&val, backing + i * sizeof(uint32_t), sizeof(uint32_t));
TEST_ASSERT_EQ(val, i + 0xaabbccdd);
}
free(backing);
}
void test_blockdev_set_buffer_alignment_read(uintptr_t param)
{
struct blockdev *bdev;
uint8_t *backing;
size_t backing_size = 8192;
uint32_t block_size = param;
backing = malloc(backing_size);
TEST_ASSERT_NOT_NULL(backing);
for (uint32_t i = 0; i < backing_size / sizeof(uint32_t); i++) {
uint32_t val = i + 0xaabbccdd;
memcpy(backing + i * sizeof(uint32_t), &val, sizeof(uint32_t));
}
bdev = create_mock_blockdev("dev1", backing, backing_size, block_size);
blockdev_set_buffer_alignment(bdev, block_size);
do_blockdev_read_tests(bdev, backing, backing_size, block_size);
if (block_size > 2) {
bdev = create_mock_blockdev("dev2", backing, backing_size, block_size);
blockdev_set_buffer_alignment(bdev, block_size / 2);
do_blockdev_read_tests(bdev, backing, backing_size, block_size);
}
// make sure backing wasn't touched during all the tests
for (unsigned i = 0; i < backing_size / sizeof(uint32_t); i++) {
uint32_t val;
memcpy(&val, backing + i * sizeof(uint32_t), sizeof(uint32_t));
TEST_ASSERT_EQ(val, i + 0xaabbccdd);
}
free(backing);
}
static void do_blockdev_write_tests(struct blockdev *bdev, uint8_t *backing, size_t backing_size, uint32_t block_size)
{
uint8_t *data;
uint8_t *filler;
int result;
// need some source data we can write to the blockdev with
// easily recognizable patterns
data = malloc(backing_size + sizeof(uint32_t));
TEST_ASSERT_NOT_NULL(data);
for (uint32_t i = 0; i < backing_size / sizeof(uint32_t) + 1; i++) {
uint32_t val = i + 0xaabbccdd;
memcpy(data + i * sizeof(uint32_t), &val, sizeof(uint32_t));
}
filler = malloc(backing_size);
TEST_ASSERT_NOT_NULL(filler);
memset(filler, 0xee, backing_size);
// Writing entire buffer should work
memcpy(backing, filler, backing_size);
result = blockdev_write(bdev, data, 0, backing_size);
TEST_ASSERT_EQ(result, backing_size);
TEST_ASSERT_MEM_EQ(backing, data, backing_size);
// Writing entire buffer unaligned should work
memcpy(backing, filler, backing_size);
result = blockdev_write(bdev, data + 1, 0, backing_size);
TEST_ASSERT_EQ(result, backing_size);
TEST_ASSERT_MEM_EQ(backing, data + 1, backing_size);
// Writing past the end results in a short write
memcpy(backing, filler, backing_size);
result = blockdev_write(bdev, data, backing_size / 2, backing_size);
TEST_ASSERT_EQ(result, backing_size / 2);
// first half of backing should be untouched
TEST_ASSERT_MEM_EQ(backing, filler, backing_size / 2);
// second half of buffer should have result of write
TEST_ASSERT_MEM_EQ(backing + backing_size / 2, data, backing_size / 2);
// Reading totally past the end results in no write
memcpy(backing, filler, backing_size);
result = blockdev_write(bdev, data, backing_size + 2, backing_size);
TEST_ASSERT_EQ(result, 0);
// buffer should be totally untouched
TEST_ASSERT_MEM_EQ(backing, filler, backing_size);
// weird size writes should work
uint32_t write_sizes[] = {1, 2, 3, 13, 127, 129, 1023, 1025, 4094, 4097, block_size, block_size - 1, block_size - 2, backing_size - 2, backing_size - 1};
for (uint32_t i = 0; i < sizeof(write_sizes) / sizeof(write_sizes[0]); i++) {
uint32_t write_size = write_sizes[i];
if (write_size == 0 || write_size >= backing_size)
continue;
uint32_t write_offsets[] = {0, 1, 2, 3, 13, 127, 129, 1023, 1025, 4094, 4097, block_size, block_size - 1, block_size - 2, backing_size - 2, backing_size - 1};
for (uint32_t j = 0; j < sizeof(write_offsets) / sizeof(write_offsets[0]); j++) {
uint32_t write_offset = write_offsets[j];
if (write_offset >= backing_size || write_offset + write_size >= backing_size)
continue;
tprintf(TEST_INFO, "doing offset=%u size=%u\n", write_offset, write_size);
memcpy(backing, filler, backing_size);
result = blockdev_write(bdev, data, write_offset, write_size);
TEST_ASSERT_EQ(result, write_size);
TEST_ASSERT_MEM_EQ(backing + write_offset, data, write_size);
// data before and after write should be untouched
TEST_ASSERT_MEM_EQ(backing, filler, write_offset);
TEST_ASSERT_MEM_EQ(backing + write_offset + write_size, filler, backing_size - write_size - write_offset);
}
}
free(data);
free(filler);
}
void test_blockdev_write(uintptr_t param)
{
struct blockdev *bdev;
uint8_t *backing;
size_t backing_size = 8192;
uint32_t block_size = param;
backing = malloc(backing_size);
bdev = create_mock_blockdev("dev1", backing, backing_size, block_size);
do_blockdev_write_tests(bdev, backing, backing_size, block_size);
if (block_size > 1) {
bdev = create_mock_blockdev("dev2", backing, backing_size, block_size);
blockdev_set_buffer_alignment(bdev, block_size);
do_blockdev_write_tests(bdev, backing, backing_size, block_size);
}
if (block_size > 2) {
bdev = create_mock_blockdev("dev3", backing, backing_size, block_size);
blockdev_set_buffer_alignment(bdev, block_size / 2);
do_blockdev_write_tests(bdev, backing, backing_size, block_size);
}
free(backing);
}
void test_register_blockdev(uintptr_t param)
{
static uint8_t backing;
struct blockdev *bdev0;
struct blockdev *bdev1;
uint32_t found = 0;
bdev0 = create_mock_blockdev("lookup-bdev0", &backing, 1, 1);
TEST_ASSERT_NOT_NULL(bdev0);
bdev1 = create_mock_blockdev("lookup-bdev1", &backing, 1, 1);
TEST_ASSERT_NOT_NULL(bdev1);
TEST_ASSERT_NULL(lookup_blockdev("lookup-bdev0"));
TEST_ASSERT_NULL(lookup_blockdev("lookup-bdev1"));
TEST_ASSERT_NULL(first_blockdev());
register_blockdev(bdev0);
TEST_ASSERT_PTR_EQ(lookup_blockdev("lookup-bdev0"), bdev0);
TEST_ASSERT_PTR_EQ(first_blockdev(), bdev0);
TEST_ASSERT_NULL(lookup_blockdev("lookup-bdev1"));
register_blockdev(bdev1);
TEST_ASSERT_PTR_EQ(lookup_blockdev("lookup-bdev0"), bdev0);
TEST_ASSERT_PTR_EQ(lookup_blockdev("lookup-bdev1"), bdev1);
for (struct blockdev *bdev = first_blockdev(); bdev != NULL; bdev = next_blockdev(bdev)) {
if (bdev == bdev0)
found |= 1;
if (bdev == bdev1)
found |= 2;
}
TEST_ASSERT_EQ(found, 3);
}
struct test_suite blockdev_suite = {
.name = "blockdev",
.test_cases = {
{ "register_blockdev", test_register_blockdev, 0, "" },
{ "mem_blockdev,1", test_mem_blockdev, 1, "" },
{ "mem_blockdev,2", test_mem_blockdev, 2, "" },
{ "mem_blockdev,4", test_mem_blockdev, 4, "" },
{ "mem_blockdev,1024", test_mem_blockdev, 1024, "" },
{ "blockdev_read_block,1", test_blockdev_read_block, 1, "" },
{ "blockdev_read_block,2", test_blockdev_read_block, 2, "" },
{ "blockdev_read_block,4", test_blockdev_read_block, 4, "" },
{ "blockdev_read_block,1024", test_blockdev_read_block, 1024, "" },
{ "blockdev_read_block,4096", test_blockdev_read_block, 4096, "" },
{ "blockdev_read,1", test_blockdev_read, 1, "" },
{ "blockdev_read,2", test_blockdev_read, 2, "" },
{ "blockdev_read,4", test_blockdev_read, 4, "" },
{ "blockdev_read,1024", test_blockdev_read, 1024, "" },
{ "blockdev_read,4096", test_blockdev_read, 4096, "" },
{ "blockdev_read,8192", test_blockdev_read, 8192, "" },
{ "blockdev_write,1", test_blockdev_write, 1, "" },
{ "blockdev_write,2", test_blockdev_write, 2, "" },
{ "blockdev_write,4", test_blockdev_write, 4, "" },
{ "blockdev_write,1024", test_blockdev_write, 1024, "" },
{ "blockdev_write,4096", test_blockdev_write, 4096, "" },
{ "blockdev_write,8192", test_blockdev_write, 8192, "" },
{ "blockdev_set_buffer_alignment_read,2", test_blockdev_set_buffer_alignment_read, 2, "" },
{ "blockdev_set_buffer_alignment_read,8", test_blockdev_set_buffer_alignment_read, 8, "" },
{ "blockdev_set_buffer_alignment_read,1024", test_blockdev_set_buffer_alignment_read, 1024, "" },
{ "blockdev_set_buffer_alignment_read,4096", test_blockdev_set_buffer_alignment_read, 4096, "" },
TEST_CASE_LAST
}
};
TEST_SUITE(blockdev_suite);
+27
View File
@@ -0,0 +1,27 @@
# Copyright (C) 2014 Apple Inc. All rights reserved.
#
# This document is the property of Apple Inc.
# It is considered confidential and proprietary.
#
# This document may not be reproduced or transmitted in any form,
# in whole or in part, without the express written permission of
# Apple Inc.
#
LOCAL_DIR := $(GET_LOCAL_DIR)
TEST_NAME := blockdev
TEST_OBJS := \
lib/libc/log2.o \
$(LOCAL_DIR)/blockdev.o \
$(LOCAL_DIR)/mem_blockdev.o \
$(LOCAL_DIR)/subdev.o
TEST_SUPPORT_OBJS := \
tests/unittest-main.o \
$(LOCAL_DIR)/tests.o
TEST_CFLAGS := \
-DCPU_CACHELINE_SIZE=32 \
-DHOST_TEST=1