NanoPayload

Annotated stage2/tasks.c

194:aac340efb570
2016-05-14 Paul Boddie Introduced memory layout headers and consolidated memory-related definitions. Made the linker scripts more consistent.
paul@156 1
/*
paul@156 2
 * Task handling.
paul@156 3
 *
paul@156 4
 * Copyright (C) 2015, 2016 Paul Boddie <paul@boddie.org.uk>
paul@156 5
 *
paul@156 6
 * This program is free software: you can redistribute it and/or modify
paul@156 7
 * it under the terms of the GNU General Public License as published by
paul@156 8
 * the Free Software Foundation, either version 3 of the License, or
paul@156 9
 * (at your option) any later version.
paul@156 10
 *
paul@156 11
 * This program is distributed in the hope that it will be useful,
paul@156 12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
paul@156 13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
paul@156 14
 * GNU General Public License for more details.
paul@156 15
 *
paul@156 16
 * You should have received a copy of the GNU General Public License
paul@156 17
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
paul@156 18
 */
paul@156 19
paul@156 20
#include "cpu.h"
paul@186 21
#include "cpu_op.h"
paul@194 22
#include "memory.h"
paul@193 23
#include "mips.h"
paul@156 24
#include "paging.h"
paul@159 25
#include "tasks.h"
paul@156 26
paul@156 27
/* Task tables and data. */
paul@156 28
paul@156 29
static u32 stack_pointers[max_tasks];
paul@156 30
static u32 registers[max_tasks][32];
paul@156 31
paul@156 32
u8 current_task;
paul@156 33
u32 *current_stack_pointer;
paul@156 34
u32 *current_registers;
paul@156 35
paul@179 36
/* A reference to locations for the symbol tables. */
paul@179 37
paul@179 38
extern u32 _got_start, _got_copy_start, _got_copy_end;
paul@156 39
paul@189 40
/* A reference to the start of the payload and end of memory locations. */
paul@179 41
paul@189 42
extern u32 _payload_start, _memory_end;
paul@156 43
paul@156 44
/* Task management functions. */
paul@156 45
paul@156 46
void init_tasks()
paul@156 47
{
paul@166 48
	current_task = 1;
paul@160 49
	init_task();
paul@160 50
}
paul@160 51
paul@160 52
void init_task()
paul@160 53
{
paul@156 54
	current_stack_pointer = &stack_pointers[current_task];
paul@156 55
	current_registers = registers[current_task];
paul@156 56
}
paul@156 57
paul@159 58
void start_task(unsigned short task, void (*function)(), u32 args[], u8 nargs)
paul@156 59
{
paul@179 60
	u32 virtual, physical, address;
paul@156 61
paul@156 62
	/*
paul@156 63
	Each task employs a stack at a multiple of the given start address in
paul@193 64
	physical memory, but at the same address in virtual memory. Task zero
paul@193 65
	is never started.
paul@156 66
	*/
paul@156 67
paul@194 68
	virtual = STAGE2_TASK_STACK;
paul@194 69
	physical = STAGE2_TASK_STACK - STAGE2_TASK_STACK_SIZE * task;
paul@156 70
paul@194 71
	init_page_table(STAGE2_PAGE_TABLE, virtual - STAGE2_PAGESIZE * 2, physical - STAGE2_PAGESIZE * 2, STAGE2_PAGESIZE, TLB_WRITE, task);
paul@156 72
paul@156 73
	/*
paul@156 74
	Subtract from the stack pointer to prevent the called function from
paul@156 75
	reaching into unmapped memory.
paul@156 76
	*/
paul@156 77
paul@156 78
	stack_pointers[task] = virtual - 12;
paul@156 79
paul@156 80
	/*
paul@156 81
	Set the registers for the new task, initialising the global pointer and
paul@156 82
	return address.
paul@156 83
	*/
paul@156 84
paul@173 85
	init_registers(registers[task], (u32) &_got_copy_start, function, args, nargs);
paul@179 86
paul@179 87
	/* Map the global object table for the task. */
paul@179 88
paul@194 89
	init_page_table(STAGE2_PAGE_TABLE, user_address((u32) &_got_start), user_address((u32) &_got_copy_start), STAGE2_PAGESIZE, TLB_READ, task);
paul@179 90
paul@179 91
	/* Map all shared pages for the task. */
paul@179 92
paul@194 93
	for (address = (u32) &_payload_start; address < (u32) &_got_start; address += STAGE2_PAGESIZE * 2)
paul@179 94
	{
paul@194 95
		init_page_table(STAGE2_PAGE_TABLE, user_address(address), user_address(address), STAGE2_PAGESIZE, TLB_READ, task);
paul@179 96
	}
paul@179 97
paul@194 98
	for (address = (u32) &_got_copy_end + STAGE2_PAGESIZE * 2; address < (u32) &_memory_end; address += STAGE2_PAGESIZE * 2)
paul@179 99
	{
paul@194 100
		init_page_table(STAGE2_PAGE_TABLE, user_address(address), user_address(address), STAGE2_PAGESIZE, TLB_WRITE, task);
paul@179 101
	}
paul@156 102
}
paul@156 103
paul@165 104
void start_task_now()
paul@165 105
{
paul@171 106
	invoke_task(current_task, current_registers, current_stack_pointer);
paul@165 107
}
paul@165 108
paul@156 109
void switch_task()
paul@156 110
{
paul@156 111
	/* Switch the current task. */
paul@156 112
paul@156 113
	current_task++;
paul@166 114
	if (current_task == max_tasks) current_task = 1;
paul@160 115
	init_task();
paul@156 116
}