summaryrefslogtreecommitdiffstats
path: root/include/asm-arm/proc-armv/mm-init.h
blob: 2e861b213ed438735bbf8a340d9612b6add82d96 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
/*
 * linux/include/asm-arm/proc-armv/mm-init.h
 *
 * Copyright (C) 1996 Russell King
 *
 * This contains the code to setup the memory map on an ARM v3 or v4 machine.
 * This is both processor & architecture specific, and requires some
 * more work to get it to fit into our separate processor and architecture
 * structure.
 */

/*
 * On ebsa, we want the memory map set up so:
 *
 *   PHYS	  VIRT
 * 00000000	00000000	Zero page
 * 000003ff	000003ff	Zero page end
 * 00000000	c0000000	Kernel and all physical memory
 * 01ffffff	c1ffffff	End of physical (32MB)
 * e0000000	e0000000	IO start
 * ffffffff	ffffffff	IO end
 *
 * On rpc, we want:
 *
 *   PHYS	  VIRT
 * 10000000	00000000	Zero page
 * 100003ff	000003ff	Zero page end
 * 10000000	c0000000	Kernel and all physical memory
 * 1fffffff	cfffffff	End of physical (32MB)
 * 02000000	d?000000	Screen memory (first image)
 * 02000000	d8000000	Screen memory (second image)
 * 00000000	df000000	StrongARM cache invalidation area
 * 03000000	e0000000	IO start
 * 03ffffff	e0ffffff	IO end
 *
 * We set it up using the section page table entries.
 */
#include <asm/pgtable.h>
 
#define PTE_SIZE (PTRS_PER_PTE * 4)

extern unsigned long setup_io_pagetables(unsigned long start_mem);

/*
 * Add a SECTION mapping between VIRT and PHYS in domain DOMAIN with protection PROT
 */
static inline void
alloc_init_section(unsigned long *mem, unsigned long virt, unsigned long phys, int domain, int prot)
{
	pgd_t *pgdp;
	pmd_t *pmdp, pmd;

	pgdp = pgd_offset_k(virt);
	pmdp = pmd_offset(pgdp, virt);

	pmd_val(pmd) = phys | PMD_TYPE_SECT | PMD_DOMAIN(domain) | prot;
	set_pmd(pmdp, pmd);
}

/*
 * Clear any mapping
 */
static inline void
free_init_section(unsigned long virt)
{
	pgd_t *pgdp;
	pmd_t *pmdp;

	pgdp = pgd_offset_k(virt);
	pmdp = pmd_offset(pgdp, virt);

	pmd_clear(pmdp);
}

/*
 * Add a PAGE mapping between VIRT and PHYS in domain DOMAIN with protection PROT
 */
static inline void
alloc_init_page(unsigned long *mem, unsigned long virt, unsigned long phys, int domain, int prot)
{
	pgd_t *pgdp;
	pmd_t *pmdp, pmd;
	pte_t *ptep;

	pgdp = pgd_offset_k(virt);
	pmdp = pmd_offset(pgdp, virt);

	if (pmd_none(*pmdp)) {
		unsigned long memory = *mem;

		memory = (memory + PTE_SIZE - 1) & ~(PTE_SIZE - 1);

		ptep = (pte_t *)memory;
		memzero(ptep, PTE_SIZE);

		pmd_val(pmd) = __virt_to_phys(memory) | PMD_TYPE_TABLE | PMD_DOMAIN(domain);
		set_pmd(pmdp, pmd);

		*mem = memory + PTE_SIZE;
	}

	ptep = pte_offset(pmdp, virt);

	pte_val(*ptep) = phys | prot | PTE_TYPE_SMALL;
}

static inline unsigned long
setup_pagetables(unsigned long start_mem, unsigned long end_mem)
{
	unsigned long address;

	/*
	 * map in zero page
	 */
	alloc_init_page(&start_mem, 0, __virt_to_phys(PAGE_OFFSET), DOMAIN_USER, PTE_CACHEABLE);

	/*
	 * ensure no mappings in user space
	 */
	for (address = PGDIR_SIZE; address < PAGE_OFFSET; address += PGDIR_SIZE)
		free_init_section(address);

	/*
	 * map in physical ram & kernel
	 */
	for (address = PAGE_OFFSET; address < end_mem; address += PGDIR_SIZE)
		alloc_init_section(&start_mem, address, __virt_to_phys(address), DOMAIN_KERNEL,
				   PMD_SECT_CACHEABLE | PMD_SECT_BUFFERABLE | PMD_SECT_AP_WRITE);

	/*
	 * unmap everything else
	 */
	for (address = end_mem; address; address += PGDIR_SIZE)
		free_init_section(address);

	/*
	 * An area to invalidate the cache
	 */
	alloc_init_section(&start_mem, 0xdf000000, SAFE_ADDR, DOMAIN_KERNEL,
			   PMD_SECT_CACHEABLE | PMD_SECT_AP_READ);

	/*
	 * Now set up our IO mappings
	 */
	start_mem = setup_io_pagetables(start_mem);

	flush_cache_all();

	return start_mem;
}

static inline
void mark_usable_memory_areas(unsigned long *start_mem, unsigned long end_mem)
{
	unsigned long smem;

	*start_mem = smem = PAGE_ALIGN(*start_mem);

	while (smem < end_mem) {
	    	clear_bit(PG_reserved, &mem_map[MAP_NR(smem)].flags);
    		smem += PAGE_SIZE;
	}
}