NanoPayload

Annotated stage2/cpu.c

186:59eede5312e3
2016-05-04 Paul Boddie Moved almost all assembly language fragments into a separate file.
paul@62 1
/*
paul@90 2
 * CPU-specific routines originally from U-Boot.
paul@62 3
 * See: uboot-xburst/files/arch/mips/cpu/xburst/cpu.c
paul@62 4
 * See: u-boot/arch/mips/include/asm/cacheops.h
paul@62 5
 *
paul@62 6
 * Copyright (C) 2000-2009 Wolfgang Denk, DENX Software Engineering, <wd@denx.de>
paul@90 7
 * Copyright (C) 2015, 2016 Paul Boddie <paul@boddie.org.uk>
paul@62 8
 *
paul@62 9
 * This program is free software; you can redistribute it and/or
paul@62 10
 * modify it under the terms of the GNU General Public License as
paul@62 11
 * published by the Free Software Foundation; either version 2 of
paul@62 12
 * the License, or (at your option) any later version.
paul@62 13
 *
paul@62 14
 * This program is distributed in the hope that it will be useful,
paul@62 15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
paul@62 16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
paul@62 17
 * GNU General Public License for more details.
paul@62 18
 *
paul@62 19
 * You should have received a copy of the GNU General Public License
paul@62 20
 * along with this program; if not, write to the Free Software
paul@62 21
 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
paul@62 22
 * Boston, MA  02110-1301, USA
paul@62 23
 */
paul@62 24
paul@113 25
#include "cpu.h"
paul@186 26
#include "cpu_op.h"
paul@62 27
#include "sdram.h"
paul@151 28
#include "paging.h"
paul@62 29
paul@62 30
void flush_icache_all(void)
paul@62 31
{
paul@186 32
	u32 addr;
paul@62 33
paul@186 34
	flush_icache_tag();
paul@62 35
paul@186 36
	for (addr = KSEG0; addr < KSEG0 + CONFIG_SYS_ICACHE_SIZE; addr += CONFIG_SYS_CACHELINE_SIZE)
paul@186 37
		flush_icache_region(addr);
paul@62 38
paul@186 39
	flush_icache_config();
paul@62 40
}
paul@62 41
paul@62 42
void flush_dcache_all(void)
paul@62 43
{
paul@62 44
	u32 addr;
paul@62 45
paul@186 46
	for (addr = KSEG0; addr < KSEG0 + CONFIG_SYS_DCACHE_SIZE; addr += CONFIG_SYS_CACHELINE_SIZE)
paul@186 47
		flush_dcache_region(addr);
paul@62 48
paul@62 49
	asm volatile ("sync");
paul@62 50
}
paul@62 51
paul@62 52
void flush_cache_all(void)
paul@62 53
{
paul@62 54
	flush_dcache_all();
paul@62 55
	flush_icache_all();
paul@62 56
}
paul@67 57
paul@145 58
void init_registers(u32 *base, u32 got, void (*function)(), u32 args[], u8 nargs)
paul@133 59
{
paul@133 60
	u8 i;
paul@133 61
paul@133 62
	/* Provide arguments to the function. */
paul@133 63
paul@133 64
	for (i = 0; i < nargs; i++)
paul@133 65
	{
paul@145 66
		base[i+4] = args[i];
paul@133 67
	}
paul@133 68
paul@133 69
	/* Store essential data for the function environment. */
paul@133 70
paul@145 71
	base[25] = (u32) function - 0x80000000;	/* store the function address as t9 */
paul@145 72
	base[26] = got - 0x80000000;		/* store the global pointer */
paul@145 73
	base[29] = (u32) function - 0x80000000;	/* store the function address as EPC (for the handler) */
paul@133 74
}
paul@133 75
paul@73 76
void init_tlb(void)
paul@73 77
{
paul@186 78
	u32 limit = configure_tlb(), i;
paul@147 79
paul@147 80
	/* Reset the mappings. The total number is bits 30..25 of Config1. */
paul@147 81
paul@147 82
	for (i = 0; i < ((limit >> 25) & 0x3f); i++)
paul@147 83
	{
paul@157 84
		map_page_index(0, 0, 4096, 0, 0, i);
paul@147 85
	}
paul@117 86
}
paul@83 87
paul@117 88
void map_page_index(u32 virtual, u32 physical, u32 pagesize, u8 flags, u8 asid, u32 index)
paul@117 89
{
paul@130 90
	u32 start = (virtual & 0xffffe000) | asid; /* VPN2 | ASID*/
paul@117 91
	u32 lower = ((physical & 0xfffff000) >> 6) | flags;
paul@117 92
	u32 upper = (((physical + pagesize) & 0xfffff000) >> 6) | flags;
paul@117 93
	u32 pagemask = ((pagesize - 1) & 0xfffff000) << 1;
paul@117 94
paul@186 95
	map_page_set_index(index);
paul@186 96
	map_page_index_op(lower, upper, start, pagemask);
paul@113 97
}
paul@83 98
paul@136 99
void init_page_table(u32 page_table, u32 virtual, u32 physical, u32 pagesize, u8 flags, u8 asid)
paul@136 100
{
paul@136 101
	u32 lower = ((physical & 0xfffff000) >> 6) | flags;
paul@136 102
	u32 upper = (((physical + pagesize) & 0xfffff000) >> 6) | flags;
paul@136 103
paul@136 104
	/*
paul@136 105
	With a complete address space mapping involving pairs of 4KB pages
paul@136 106
	described by two values for each entry, there would be...
paul@136 107
paul@136 108
	an address space of 0x100000000 requiring...
paul@136 109
paul@136 110
	0x100000000 / (8 * 1024) == 0x100000000 >> 13
paul@136 111
	== 524288 entries
paul@136 112
	== 0x80000 entries
paul@136 113
paul@136 114
	Thus, each task's entries would require...
paul@136 115
paul@136 116
	0x80000 * 8 == 0x400000 bytes
paul@136 117
paul@136 118
	The kseg2 region thus permits 256 tasks occupying 0x40000000 bytes.
paul@136 119
paul@136 120
	However, for more modest address spaces occupying as much as 32MB there
paul@136 121
	would be...
paul@136 122
paul@136 123
	an address space of 0x02000000 requiring...
paul@136 124
paul@136 125
	0x02000000 / (8 * 1024) == 0x02000000 >> 13
paul@136 126
	== 4096 entries
paul@136 127
	== 0x1000 entries
paul@136 128
paul@136 129
	Thus, each task's entries would only require...
paul@136 130
paul@136 131
	0x1000 * 8 == 0x8000 bytes
paul@136 132
	*/
paul@136 133
paul@136 134
	u32 base = page_table + page_table_task_size * asid;
paul@136 135
paul@136 136
	/* Each page table entry corresponds to a pair of 4KB pages and holds two values. */
paul@136 137
paul@136 138
	u32 entry = ((virtual & 0xffffe000) >> 13) * 8;
paul@185 139
	u32 *address = (u32 *) (base + entry);
paul@136 140
paul@136 141
	/* The page tables should be permanently mapped to avoid hierarchical TLB miss handling. */
paul@136 142
paul@185 143
	*address = lower;
paul@185 144
	*(address + 1) = upper;
paul@136 145
}
paul@136 146
paul@117 147
void map_page(u32 virtual, u32 physical, u32 pagesize, u8 flags, u8 asid)
paul@113 148
{
paul@130 149
	u32 start = (virtual & 0xffffe000) | asid; /* VPN2 | ASID*/
paul@116 150
	u32 lower = ((physical & 0xfffff000) >> 6) | flags;
paul@116 151
	u32 upper = (((physical + pagesize) & 0xfffff000) >> 6) | flags;
paul@113 152
	u32 pagemask = ((pagesize - 1) & 0xfffff000) << 1;
paul@113 153
paul@186 154
	map_page_op(lower, upper, start, pagemask);
paul@135 155
}