1
/*
2
 * $Id$
3
 *
4
 * Copyright (C) 2003-2009 JNode.org
5
 *
6
 * This library is free software; you can redistribute it and/or modify it
7
 * under the terms of the GNU Lesser General Public License as published
8
 * by the Free Software Foundation; either version 2.1 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This library is distributed in the hope that it will be useful, but 
12
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
14
 * License for more details.
15
 *
16
 * You should have received a copy of the GNU Lesser General Public License
17
 * along with this library; If not, write to the Free Software Foundation, Inc., 
18
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
 */
20
 
21
package org.jnode.vm;
22
23
import java.nio.ByteOrder;
24
25
import org.jnode.security.JNodePermission;
26
import org.jnode.system.ResourceManager;
27
import org.jnode.annotation.Internal;
28
import org.jnode.annotation.KernelSpace;
29
import org.jnode.annotation.MagicPermission;
30
import org.jnode.vm.classmgr.TypeSizeInfo;
31
import org.jnode.vm.classmgr.VmIsolatedStatics;
32
import org.jnode.vm.classmgr.VmSharedStatics;
33
import org.jnode.vm.compiler.IMTCompiler;
34
import org.jnode.vm.compiler.NativeCodeCompiler;
35
import org.jnode.vm.scheduler.IRQManager;
36
import org.jnode.vm.scheduler.VmProcessor;
37
import org.jnode.vm.scheduler.VmScheduler;
38
import org.vmmagic.pragma.UninterruptiblePragma;
39
import org.vmmagic.unboxed.Address;
40
import org.vmmagic.unboxed.Extent;
41
import org.vmmagic.unboxed.Word;
42
43
/**
44
 * Class describing a specific system architecture.
45
 *
46
 * @author Ewout Prangsma (epr@users.sourceforge.net)
47
 */
48
@MagicPermission
49
public abstract class VmArchitecture extends VmSystemObject {
50
51
    private final JNodePermission MMAP_PERM = new JNodePermission("getMemoryMap");
52
    private transient MemoryMapEntry[] memoryMap;
53
    private transient VmMultiMediaSupport multiMediaSupport;
54
    private final int referenceSize;
55
    private final VmStackReader stackReader;
56
57
    protected VmArchitecture(int referenceSize, VmStackReader stackReader) {
58
        this.referenceSize = referenceSize;
59
        this.stackReader = stackReader;
60
    }
61
62
    /**
63
     * Gets the name of this architecture.
64
     * This name is the programmers name used to identify packages,
65
     * class name extensions etc.
66
     *
67
     * @return the architecture's name
68
     */
69
    public abstract String getName();
70
71
    /**
72
     * Gets the full name of this architecture, including operating mode.
73
     *
74
     * @return the architecture's full name
75
     */
76
    public abstract String getFullName();
77
78
    /**
79
     * Gets the byte ordering of this architecture.
80
     *
81
     * @return the architecture's ByteOrder
82
     */
83
    public abstract ByteOrder getByteOrder();
84
85
    /**
86
     * Gets the size in bytes of an object reference.
87
     *
88
     * @return the architecture's reference size in bytes; i.e. 4 or 8.
89
     */
90
    @KernelSpace
91
    public final int getReferenceSize() {
92
        return referenceSize;
93
    }
94
95
    /**
96
     * Gets the log base two of the size in bytes of an OS page in a given region
97
     *
98
     * @param region a {@link VirtualMemoryRegion} value
99
     * @return the log base two page size
100
     */
101
    public abstract byte getLogPageSize(int region)
102
        throws UninterruptiblePragma;
103
104
    /**
105
     * Gets the size in bytes of an OS page in a given region
106
     *
107
     * @param region a {@link VirtualMemoryRegion} value
108
     * @return the page size
109
     */
110
    public final Extent getPageSize(int region)
111
        throws UninterruptiblePragma {
112
        return Extent.fromIntZeroExtend(1 << getLogPageSize(region));
113
    }
114
115
    /**
116
     * Gets the type size information of this architecture.
117
     *
118
     * @return the architecture's type size information descriptor
119
     */
120
    public abstract TypeSizeInfo getTypeSizeInfo();
121
122
    /**
123
     * Gets the stackreader for this architecture.
124
     *
125
     * @return the architecture's stack reader
126
     */
127
    @KernelSpace
128
    public final VmStackReader getStackReader() {
129
        return stackReader;
130
    }
131
132
    /**
133
     * Gets all compilers for this architecture.
134
     *
135
     * @return The architecture's compilers, sorted by optimization level, from 
136
     * least optimizing to most optimizing.
137
     */
138
    public abstract NativeCodeCompiler[] getCompilers();
139
140
    /**
141
     * Gets all test compilers for this architecture.
142
     * This can be used to test new compilers in a running system.
143
     *
144
     * @return The architecture's test compilers, sorted by optimization level, from 
145
     * least optimizing to most optimizing.  If there are no configured test compilers,
146
     * {@code null} will be returned.
147
     */
148
    public abstract NativeCodeCompiler[] getTestCompilers();
149
150
    /**
151
     * Gets the compiler of IMT's.
152
     *
153
     * @return the IMT compiler
154
     */
155
    public abstract IMTCompiler getIMTCompiler();
156
157
    /**
158
     * Called early on in the boot process (before the initialization of
159
     * the memory manager) to initialize any architecture specific variables.
160
     * Do not allocate memory here.
161
     *
162
     * @param emptyMmap If true, all page mappings in the AVAILABLE region
163
     *                  are removed.
164
     */
165
    protected abstract void boot(boolean emptyMmap);
166
167
    /**
168
     * Find and start all processors in the system.
169
     * All all discovered processors to the given list.
170
     * The bootstrap processor is already on the given list.
171
     */
172
    protected abstract void initializeProcessors(ResourceManager rm);
173
174
    /**
175
     * Call this method to register a processor found in {@link #initializeProcessors(ResourceManager)}.
176
     *
177
     * @param cpu
178
     */
179
    protected final void addProcessor(VmProcessor cpu) {
180
        Vm.getVm().addProcessor(cpu);
181
    }
182
183
    /**
184
     * Create a processor instance for this architecture.
185
     *
186
     * @return The processor
187
     */
188
    protected abstract VmProcessor createProcessor(int id, VmSharedStatics sharedStatics,
189
                                                   VmIsolatedStatics isolatedStatics, VmScheduler scheduler);
190
191
    /**
192
     * Create the IRQ manager for this architecture.
193
     *
194
     * @return the IRQManager
195
     */
196
    @Internal
197
    public abstract IRQManager createIRQManager(VmProcessor processor);
198
199
    /**
200
     * Gets the start address of the given space.
201
     * 
202
     * @param space a {@link VirtualMemoryRegion}.
203
     * @return the start address of the region
204
     */
205
    public Address getStart(int space) {
206
        switch (space) {
207
            case VirtualMemoryRegion.BOOTIMAGE:
208
                return Unsafe.getKernelStart();
209
            case VirtualMemoryRegion.INITJAR:
210
                return Unsafe.getInitJarStart();
211
            default:
212
                throw new IllegalArgumentException("Unknown space " + space);
213
        }
214
    }
215
216
    /**
217
     * Gets the end address of the given space.
218
     *
219
     * @param space a {@link VirtualMemoryRegion}.
220
     * @return the end address of the region
221
     */
222
    public Address getEnd(int space) {
223
        switch (space) {
224
            case VirtualMemoryRegion.BOOTIMAGE:
225
                return Unsafe.getBootHeapEnd();
226
            case VirtualMemoryRegion.INITJAR:
227
                return Unsafe.getInitJarEnd();
228
            default:
229
                throw new IllegalArgumentException("Unknown space " + space);
230
        }
231
    }
232
233
    /**
234
     * Gets the physical address of the first whole page available for use
235
     * by the memory manager.
236
     *
237
     * @return a physical address aligned on the appropriate page boundary
238
     */
239
    protected final Word getFirstAvailableHeapPage() {
240
        return pageAlign(VirtualMemoryRegion.HEAP, Unsafe.getMemoryStart().toWord(), true);
241
    }
242
243
    /**
244
     * Page align a given address (represented as a Word) in a given region.
245
     *
246
     * @param v an address value
247
     * @param region a {@link VirtualMemoryRegion}.
248
     * @param up If true, the value will be rounded up, otherwise rounded down.
249
     * @return the corresponding page aligned address represented as a Word. 
250
     */
251
    public final Word pageAlign(int region, Word v, boolean up) {
252
        final int logPageSize = getLogPageSize(region);
253
        if (up) {
254
            v = v.add((1 << logPageSize) - 1);
255
        }
256
        return v.rshl(logPageSize).lsh(logPageSize);
257
    }
258
259
    /**
260
     * Page align a given address (represented as an Address) in a given region.
261
     *
262
     * @param v an address value
263
     * @param region a {@link VirtualMemoryRegion}.
264
     * @param up If true, the value will be rounded up, otherwise rounded down.
265
     * @return the corresponding page aligned address represented as a Address. 
266
     */
267
    public final Address pageAlign(int region, Address v, boolean up) {
268
        return pageAlign(region, v.toWord(), up).toAddress();
269
    }
270
271
    /**
272
     * Map a region of the virtual memory space. Note that you cannot allocate
273
     * memory in this memory, because it is used very early in the boot process.
274
     *
275
     * @param region   Memory region
276
     * @param start    The start of the virtual memory region to map
277
     * @param size     The size of the virtual memory region to map
278
     * @param physAddr The physical address to map the virtual address to. If this is
279
     *                 Address.max(), free pages are used instead.
280
     * @return true for success, false otherwise.
281
     */
282
    public abstract boolean mmap(int region, Address start, Extent size, Address physAddr)
283
        throws UninterruptiblePragma;
284
285
    /**
286
     * Unmap a region of the virtual memory space. Note that you cannot allocate
287
     * memory in this memory, because it is used very early in the boot process.
288
     *
289
     * @param region Memory region
290
     * @param start  The start of the virtual memory region to unmap. This value is
291
     *               aligned down on pagesize.
292
     * @param size   The size of the virtual memory region to unmap. This value is
293
     *               aligned up on pagesize.
294
     * @return true for success, false otherwise.
295
     */
296
    public abstract boolean munmap(int region, Address start, Extent size)
297
        throws UninterruptiblePragma;
298
299
    /**
300
     * Gets the memory map of the current system.  If no map has yet been created,
301
     * it will be created by calling {@link #createMemoryMap()}.
302
     *
303
     * @return the architecture's memory map.
304
     */
305
    public final MemoryMapEntry[] getMemoryMap() {
306
        final SecurityManager sm = System.getSecurityManager();
307
        if (sm != null) {
308
            sm.checkPermission(MMAP_PERM);
309
        }
310
        if (memoryMap == null) {
311
            memoryMap = createMemoryMap();
312
        }
313
        return memoryMap;
314
    }
315
316
    /**
317
     * Create the memory map of the current system.
318
     *
319
     * @return the memory map.
320
     */
321
    protected abstract MemoryMapEntry[] createMemoryMap();
322
323
    /**
324
     * Create a multi-media memory resource wrapping the given memory resource.
325
     *
326
     * @param res a memory resource
327
     * @return The created instance, which is never {@code null}.
328
     */
329
    final MultiMediaMemoryResourceImpl createMultiMediaMemoryResource(MemoryResourceImpl res) {
330
        if (multiMediaSupport == null) {
331
            multiMediaSupport = createMultiMediaSupport();
332
        }
333
        return new MultiMediaMemoryResourceImpl((MemoryResourceImpl) res, multiMediaSupport);
334
    }
335
336
    /**
337
     * Creates a multi-media support instance.  The default implementation returns a
338
     * generic support instance.  This method may be overriden to provide an architecture 
339
     * optimized {@link VmMultiMediaSupport} implementation.
340
     * @return a multi-media support instance.
341
     */
342
    protected VmMultiMediaSupport createMultiMediaSupport() {
343
        return new VmJavaMultiMediaSupport();
344
    }
345
}