source: mainline/kernel/arch/mips32/src/mm/frame.c@ 65f3117

ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 65f3117 was 65f3117, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 2 years ago

Make bootstrap stack statically, rather than dynamically allocated

With aligment requirements being part of the language now, it is
simple to allocate the extra stack area in kernel data, and we
don't need to go to so much trouble with manual allocation.
It also makes it slightly more straightforward to use the stack
from assembly, without having to dig through a saved context
structure.

  • Property mode set to 100644
File size: 7.6 KB
Line 
1/*
2 * Copyright (c) 2005 Jakub Jermar
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup kernel_mips32_mm
30 * @{
31 */
32/** @file
33 */
34
35#include <macros.h>
36#include <arch/mm/frame.h>
37#include <arch/mm/tlb.h>
38#include <interrupt.h>
39#include <mm/frame.h>
40#include <mm/asid.h>
41#include <config.h>
42#ifdef MACHINE_msim
43#include <arch/mach/msim/msim.h>
44#endif
45#include <arch/arch.h>
46#include <stdio.h>
47
48#define ZERO_PAGE_MASK TLB_PAGE_MASK_256K
49#define ZERO_FRAMES 2048
50#define ZERO_PAGE_WIDTH 18 /* 256K */
51#define ZERO_PAGE_SIZE (1 << ZERO_PAGE_WIDTH)
52#define ZERO_PAGE_ASID ASID_INVALID
53#define ZERO_PAGE_TLBI 0
54#define ZERO_PAGE_ADDR 0
55#define ZERO_PAGE_OFFSET (ZERO_PAGE_SIZE / sizeof(uint32_t) - 1)
56#define ZERO_PAGE_VALUE (((volatile uint32_t *) ZERO_PAGE_ADDR)[ZERO_PAGE_OFFSET])
57
58#define ZERO_PAGE_VALUE_KSEG1(frame) \
59 (((volatile uint32_t *) PA2KSEG1(frame << ZERO_PAGE_WIDTH))[ZERO_PAGE_OFFSET])
60
61#define MAX_REGIONS 32
62
63typedef struct {
64 pfn_t start;
65 pfn_t count;
66} phys_region_t;
67
68static size_t phys_regions_count = 0;
69static phys_region_t phys_regions[MAX_REGIONS];
70
71/** Check whether frame is available
72 *
73 * Returns true if given frame is generally available for use.
74 * Returns false if given frame is used for physical memory
75 * mapped devices and cannot be used.
76 *
77 */
78static bool frame_available(pfn_t frame)
79{
80#ifdef MACHINE_msim
81 /* MSIM device (dprinter) */
82 if (frame == (KSEG12PA(MSIM_VIDEORAM) >> ZERO_PAGE_WIDTH))
83 return false;
84
85 /* MSIM device (dkeyboard) */
86 if (frame == (KSEG12PA(MSIM_KBD_ADDRESS) >> ZERO_PAGE_WIDTH))
87 return false;
88#endif
89
90#if defined(MACHINE_lmalta) || defined(MACHINE_bmalta)
91 if (frame >= (sdram_size >> ZERO_PAGE_WIDTH))
92 return false;
93#endif
94
95 return true;
96}
97
98/** Check whether frame is safe to write
99 *
100 * Returns true if given frame is safe for read/write test.
101 * Returns false if given frame should not be touched.
102 *
103 */
104static bool frame_safe(pfn_t frame)
105{
106 /* Kernel structures */
107 if ((frame << ZERO_PAGE_WIDTH) < KA2PA(config.base))
108 return false;
109
110 /* Kernel */
111 if (overlaps(frame << ZERO_PAGE_WIDTH, ZERO_PAGE_SIZE,
112 KA2PA(config.base), config.kernel_size))
113 return false;
114
115 /* Init tasks */
116 bool safe = true;
117 size_t i;
118 for (i = 0; i < init.cnt; i++)
119 if (overlaps(frame << ZERO_PAGE_WIDTH, ZERO_PAGE_SIZE,
120 init.tasks[i].paddr, init.tasks[i].size)) {
121 safe = false;
122 break;
123 }
124
125 return safe;
126}
127
128static void frame_add_region(pfn_t start_frame, pfn_t end_frame, bool low)
129{
130 if (end_frame <= start_frame)
131 return;
132
133 uintptr_t base = start_frame << ZERO_PAGE_WIDTH;
134 size_t size = (end_frame - start_frame) << ZERO_PAGE_WIDTH;
135
136 if (!frame_adjust_zone_bounds(low, &base, &size))
137 return;
138
139 pfn_t first = ADDR2PFN(base);
140 size_t count = SIZE2FRAMES(size);
141 pfn_t conf_frame;
142
143 if (low) {
144 /* Interrupt vector frame is blacklisted */
145 if (first == 0)
146 conf_frame = 1;
147 else
148 conf_frame = first;
149 zone_create(first, count, conf_frame,
150 ZONE_AVAILABLE | ZONE_LOWMEM);
151 } else {
152 conf_frame = zone_external_conf_alloc(count);
153 if (conf_frame != 0)
154 zone_create(first, count, conf_frame,
155 ZONE_AVAILABLE | ZONE_HIGHMEM);
156 }
157
158 if (phys_regions_count < MAX_REGIONS) {
159 phys_regions[phys_regions_count].start = first;
160 phys_regions[phys_regions_count].count = count;
161 phys_regions_count++;
162 }
163}
164
165/** Create memory zones
166 *
167 * Walk through available 256 KB chunks of physical
168 * memory and create zones.
169 *
170 * Note: It is assumed that the TLB is not yet being
171 * used in any way, thus there is no interference.
172 *
173 */
174void frame_low_arch_init(void)
175{
176 ipl_t ipl = interrupts_disable();
177
178 /* Clear and initialize TLB */
179 cp0_pagemask_write(ZERO_PAGE_MASK);
180 cp0_entry_lo0_write(0);
181 cp0_entry_lo1_write(0);
182 cp0_entry_hi_write(0);
183
184 size_t i;
185 for (i = 0; i < TLB_ENTRY_COUNT; i++) {
186 cp0_index_write(i);
187 tlbwi();
188 }
189
190 pfn_t start_frame = 0;
191 pfn_t frame;
192 bool avail = true;
193
194 /* Walk through all 1 MB frames */
195 for (frame = 0; frame < ZERO_FRAMES; frame++) {
196 if (!frame_available(frame))
197 avail = false;
198 else {
199 if (frame_safe(frame)) {
200 entry_lo_t lo0;
201 entry_lo_t lo1;
202 entry_hi_t hi;
203 tlb_prepare_entry_lo(&lo0, false, true, true, false, frame << (ZERO_PAGE_WIDTH - 12));
204 tlb_prepare_entry_lo(&lo1, false, false, false, false, 0);
205 tlb_prepare_entry_hi(&hi, ZERO_PAGE_ASID, ZERO_PAGE_ADDR);
206
207 cp0_pagemask_write(ZERO_PAGE_MASK);
208 cp0_entry_lo0_write(lo0.value);
209 cp0_entry_lo1_write(lo1.value);
210 cp0_entry_hi_write(hi.value);
211 cp0_index_write(ZERO_PAGE_TLBI);
212 tlbwi();
213
214 ZERO_PAGE_VALUE = 0;
215 if (ZERO_PAGE_VALUE != 0)
216 avail = false;
217 else {
218 ZERO_PAGE_VALUE = 0xdeadbeef;
219 if (ZERO_PAGE_VALUE != 0xdeadbeef)
220 avail = false;
221 }
222 }
223 }
224
225 if (!avail) {
226 frame_add_region(start_frame, frame, true);
227 start_frame = frame + 1;
228 avail = true;
229 }
230 }
231
232 frame_add_region(start_frame, frame, true);
233
234 /* Blacklist interrupt vector frame */
235 frame_mark_unavailable(0, 1);
236
237#if defined(MACHINE_lmalta) || defined(MACHINE_bmalta)
238 /*
239 * Blacklist memory regions used by YAMON.
240 *
241 * The YAMON User's Manual vaguely says the following physical addresses
242 * are taken by YAMON:
243 *
244 * 0x1000 YAMON functions
245 * 0x5000 YAMON code
246 *
247 * These addresses overlap with the beginning of the SDRAM so we need to
248 * make sure they cannot be allocated.
249 *
250 * The User's Manual unfortunately does not say where does the SDRAM
251 * portion used by YAMON end.
252 *
253 * Looking into the YAMON 02.21 sources, it looks like the first free
254 * address is computed dynamically and depends on the size of the YAMON
255 * image. From the YAMON binary, it appears to be 0xc0d50 or roughly
256 * 772 KiB for that particular version.
257 *
258 * Linux is linked to 1MiB which seems to be a safe bet and a reasonable
259 * upper bound for memory taken by YAMON. We will use it too.
260 */
261 frame_mark_unavailable(0, 1024 * 1024 / FRAME_SIZE);
262#endif
263
264 /* Cleanup */
265 cp0_pagemask_write(ZERO_PAGE_MASK);
266 cp0_entry_lo0_write(0);
267 cp0_entry_lo1_write(0);
268 cp0_entry_hi_write(0);
269 cp0_index_write(ZERO_PAGE_TLBI);
270 tlbwi();
271
272 interrupts_restore(ipl);
273}
274
275void frame_high_arch_init(void)
276{
277}
278
279void physmem_print(void)
280{
281 printf("[base ] [size ]\n");
282
283 size_t i;
284 for (i = 0; i < phys_regions_count; i++) {
285 printf("%#010x %10u\n",
286 PFN2ADDR(phys_regions[i].start), PFN2ADDR(phys_regions[i].count));
287 }
288}
289
290/** @}
291 */
Note: See TracBrowser for help on using the repository browser.