⛏️ index : haiku.git

/*
 * Copyright 2004-2009, Marcus Overhagen. All rights reserved.
 * Distributed under the terms of the MIT License.
 */
#include "util.h"

#include <KernelExport.h>
#include <OS.h>
#include <vm/vm.h>
#include <string.h>


#define TRACE(a...) dprintf("ahci: " a)
#define ERROR(a...) dprintf("ahci: " a)


static inline uint32
round_to_pagesize(uint32 size)
{
	return (size + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1);
}


area_id
alloc_mem(void **virt, phys_addr_t *phy, size_t size, uint32 protection,
	const char *name)
{
	physical_entry pe;
	void * virtadr;
	area_id areaid;
	status_t rv;

	TRACE("allocating %ld bytes for %s\n", size, name);

	size = round_to_pagesize(size);
	areaid = create_area(name, &virtadr, B_ANY_KERNEL_ADDRESS, size,
		B_CONTIGUOUS, protection);
	if (areaid < B_OK) {
		ERROR("couldn't allocate area %s\n", name);
		return B_ERROR;
	}
	rv = get_memory_map(virtadr, size, &pe, 1);
	if (rv < B_OK) {
		delete_area(areaid);
		ERROR("couldn't get mapping for %s\n", name);
		return B_ERROR;
	}
	if (virt)
		*virt = virtadr;
	if (phy)
		*phy = pe.address;
	TRACE("area = %" B_PRId32 ", size = %ld, virt = %p, phy = %#" B_PRIxPHYSADDR "\n",
		areaid, size, virtadr, pe.address);
	return areaid;
}


area_id
map_mem(void **virt, phys_addr_t phy, size_t size, uint32 protection,
	const char *name)
{
	uint32 offset;
	phys_addr_t phyadr;
	void *mapadr;
	area_id area;

	TRACE("mapping physical address %#" B_PRIxPHYSADDR " with %" B_PRIuSIZE
		" bytes for %s\n", phy, size, name);

	offset = phy & (B_PAGE_SIZE - 1);
	phyadr = phy - offset;
	size = round_to_pagesize(size + offset);
	area = map_physical_memory(name, phyadr, size,
		B_ANY_KERNEL_BLOCK_ADDRESS, protection, &mapadr);
	if (area < B_OK) {
		ERROR("mapping '%s' failed, error 0x%" B_PRIx32 " (%s)\n", name,
			area, strerror(area));
		return area;
	}

	*virt = (char *)mapadr + offset;

	TRACE("physical = %#" B_PRIxPHYSADDR ", virtual = %p, offset = %"
		B_PRId32 ", phyadr = %#" B_PRIxPHYSADDR ", mapadr = %p, size = %"
		B_PRIuSIZE ", area = 0x%08" B_PRIx32 "\n", phy, *virt, offset, phyadr,
		mapadr, size, area);

	return area;
}


status_t
sg_memcpy(const physical_entry *sgTable, int sgCount, const void *data,
	size_t dataSize)
{
	if (sgTable == NULL || data == NULL) {
		if (dataSize == 0)
			return B_OK;
		return B_ERROR;
	}
	int i;
	for (i = 0; i < sgCount && dataSize > 0; i++) {
		size_t size = min_c(dataSize, sgTable[i].size);

		TRACE("sg_memcpy phyAddr %#" B_PRIxPHYSADDR ", size %lu\n",
			sgTable[i].address, size);

		vm_memcpy_to_physical(sgTable[i].address, data, size, false);

		data = (char *)data + size;
		dataSize -= size;
	}
	if (dataSize != 0)
		return B_ERROR;
	return B_OK;
}


void
swap_words(void *data, size_t size)
{
	uint16 *word = (uint16*)data;
	size_t count = size / 2;
	while (count--) {
		*word = (*word << 8) | (*word >> 8);
		word++;
	}
}