/* 
 * Copyright 2011 Stefan Lankes, Chair for Operating Systems,
 *                               RWTH Aachen University
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * This file is part of MetalSVM.
 */

#include <metalsvm/stdlib.h>
#include <metalsvm/stdio.h>
#include <metalsvm/tasks_types.h>
#include <metalsvm/spinlock.h>
#include <metalsvm/vma.h>
#include <metalsvm/errno.h>

/*
 * add a new virtual memory region to the list of VMAs
 */
int vma_add(task_t* task, size_t start, size_t end, uint32_t type)
{
	vma_t* new_vma;
	
	if (BUILTIN_EXPECT(!task || start > end, 0))
		return -EINVAL;

	new_vma = kmalloc(sizeof(new_vma));
	if (!new_vma)
		return -ENOMEM;

	spinlock_lock(&task->vma_lock);

	new_vma->start = start;
	new_vma->end = end;
	new_vma->type = type;

	if (!(task->vma_list)) {
		new_vma->next = new_vma->prev = NULL;
		task->vma_list = new_vma;
	} else {
		vma_t* tmp = task->vma_list;

		while (tmp->next && tmp->start < start)
			tmp = tmp->next;

		new_vma->next = tmp->next;
		new_vma->prev = tmp;
		tmp->next = new_vma;
	}

	spinlock_unlock(&task->vma_lock);

	return 0;
}

int vma_dump(task_t* task)
{
	vma_t* tmp;

	if (BUILTIN_EXPECT(!task, 0))
		return -EINVAL;

	spinlock_lock(&task->vma_lock);

	tmp = task->vma_list;
	while (tmp) {
		kprintf("%8x - %8x: ", tmp->start, tmp->end);

		if (tmp->type & VMA_READ)
			kputs("r");
		else
			kputs("-");

		if (tmp->type & VMA_WRITE)
			kputs("w");
		else
			kputs("-");

		if (tmp->type & VMA_EXECUTE)
			kputs("x");
		else
			kputs("-");
		kputs("\n");

		tmp = tmp->next;
	}

	spinlock_unlock(&task->vma_lock);

	return 0;
}