NanoPayload

stage2/tasks.c

216:95be7694d999
2017-06-28 Paul Boddie Employ structure member names to make initialisation clearer.
     1 /*     2  * Task handling.     3  *     4  * Copyright (C) 2015, 2016 Paul Boddie <paul@boddie.org.uk>     5  *     6  * This program is free software: you can redistribute it and/or modify     7  * it under the terms of the GNU General Public License as published by     8  * the Free Software Foundation, either version 3 of the License, or     9  * (at your option) any later version.    10  *    11  * This program is distributed in the hope that it will be useful,    12  * but WITHOUT ANY WARRANTY; without even the implied warranty of    13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    14  * GNU General Public License for more details.    15  *    16  * You should have received a copy of the GNU General Public License    17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.    18  */    19     20 #include "cpu.h"    21 #include "cpu_op.h"    22 #include "memory.h"    23 #include "mips.h"    24 #include "paging.h"    25 #include "tasks.h"    26 #include "tasks/manifest.h"    27     28 /* Task tables and data. */    29     30 static u32 stack_pointers[max_tasks];    31 static u32 registers[max_tasks][32];    32     33 u8 current_task;    34 u32 *current_stack_pointer;    35 u32 *current_registers;    36     37 /* A reference to locations for the symbol tables. */    38     39 extern u32 _got_start, _got_copy_start, _got_copy_end;    40     41 /* A reference to the start of the payload and end of memory locations. */    42     43 extern u32 _payload_start, _memory_end;    44     45 /* Task management functions. */    46     47 void init_tasks()    48 {    49 	current_task = 1;    50 	init_task();    51 }    52     53 void init_task()    54 {    55 	current_stack_pointer = &stack_pointers[current_task];    56 	current_registers = registers[current_task];    57 }    58     59 void start_tasks()    60 {    61 	void (**starter)(unsigned short);    62 	int i;    63     64 	for (i = 1, starter = initial_tasks; *starter; i++, starter++)    65 		(*starter)(i);    66 }    67     68 void start_task(unsigned short task, void (*function)(), u32 args[], u8 nargs)    69 {    70 	u32 virtual, physical, address;    71     72 	/*    73 	Each task employs a stack at a multiple of the given start address in    74 	physical memory, but at the same address in virtual memory. Task zero    75 	is never started.    76 	*/    77     78 	virtual = TASK_STACK_TOP;    79     80 	/* NOTE: Should allocate pages generally, not according to this simple calculation. */    81     82 	physical = TASK_STACK_PHYSICAL - TASK_STACK_SIZE * task;    83     84 	init_page_table(STAGE2_PAGE_TABLE_BASE,    85 		previous_page(virtual, STAGE2_PAGESIZE),    86 		previous_page(physical, STAGE2_PAGESIZE),    87 		STAGE2_PAGESIZE, TLB_WRITE, task);    88     89 	/*    90 	Subtract from the stack pointer to prevent the called function from    91 	reaching into unmapped memory.    92 	*/    93     94 	stack_pointers[task] = virtual - 12;    95     96 	/*    97 	Set the registers for the new task, initialising the global pointer and    98 	return address.    99 	*/   100    101 	init_registers(registers[task], (u32) &_got_copy_start, function, args, nargs);   102    103 	/* Map the global object table for the task. */   104    105 	init_page_table(STAGE2_PAGE_TABLE_BASE,   106 		user_address((u32) &_got_start),   107 		user_address((u32) &_got_copy_start),   108 		STAGE2_PAGESIZE, TLB_READ, task);   109    110 	/* Map all shared pages for the task. First, the read-only code region. */   111    112 	for (address = (u32) &_payload_start;   113 		address < (u32) &_got_start;   114 		address = next_page(address, STAGE2_PAGESIZE))   115 	{   116 		init_page_table(STAGE2_PAGE_TABLE_BASE,   117 			user_address(address),   118 			user_address(address),   119 			STAGE2_PAGESIZE, TLB_READ, task);   120 	}   121    122 	/* Make the pages after the code writable. */   123    124 	for (address = next_page((u32) &_got_copy_end, STAGE2_PAGESIZE);   125 		address < (u32) &_memory_end;   126 		address = next_page(address, STAGE2_PAGESIZE))   127 	{   128 		init_page_table(STAGE2_PAGE_TABLE_BASE,   129 			user_address(address),   130 			user_address(address),   131 			STAGE2_PAGESIZE, TLB_WRITE, task);   132 	}   133 }   134    135 void start_task_now()   136 {   137 	invoke_task(current_task, current_registers, current_stack_pointer);   138 }   139    140 void switch_task()   141 {   142 	/* Switch the current task. */   143    144 	current_task++;   145 	if ((current_task == max_tasks) || !(initial_tasks[current_task - 1]))   146 		current_task = 1;   147 	init_task();   148 }