FreeNOS
Kernel.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2015 Niek Linnenbank
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include <FreeNOS/System.h>
19#include <FreeNOS/Config.h>
20#include <Log.h>
21#include <ListIterator.h>
22#include <SplitAllocator.h>
23#include <BubbleAllocator.h>
24#include <PoolAllocator.h>
25#include <IntController.h>
26#include <BootImageStorage.h>
27#include <CoreInfo.h>
28#include "Kernel.h"
29#include "Memory.h"
30#include "Process.h"
31#include "ProcessManager.h"
32
34 : WeakSingleton<Kernel>(this)
35 , m_interrupts(256)
36{
37 // Output log banners on the boot core
38 if (info->coreId == 0)
39 {
41 Log::instance()->append(COPYRIGHT "\r\n");
42 }
43
44 // Setup physical memory allocator
45 const Arch::MemoryMap map;
46 const Memory::Range kernelData = map.range(MemoryMap::KernelData);
47 const Allocator::Range physRange = { info->memory.phys, info->memory.size, PAGESIZE };
48 const Allocator::Range virtRange = { kernelData.virt, kernelData.size, PAGESIZE };
49 m_alloc = new SplitAllocator(physRange, virtRange, PAGESIZE);
50
51 // Initialize other class members
52 m_procs = new ProcessManager();
53 m_api = new API();
54 m_coreInfo = info;
56 m_timer = ZERO;
57
58 // Print memory map
59 NOTICE("kernel @ " << (void *) info->kernel.phys << ".." <<
60 (void *) (info->kernel.phys + info->kernel.size));
61 NOTICE("bootImage @ " << (void *) info->bootImageAddress << ".." <<
62 (void *) (info->bootImageAddress + info->bootImageSize));
63 NOTICE("heap @ " << (void *) (m_alloc->toPhysical(info->heapAddress)) << ".." <<
64 (void *) (m_alloc->toPhysical(info->heapAddress + info->heapSize)));
65
66 if (info->coreChannelSize)
67 {
68 NOTICE("coreChannel @ " << (void *) info->coreChannelAddress << ".." <<
69 (void *) (info->coreChannelAddress + info->coreChannelSize - 1));
70 }
71
72 // Verify coreInfo memory ranges
73 assert(info->kernel.phys >= info->memory.phys);
74 assert(info->bootImageAddress >= info->kernel.phys + info->kernel.size);
76
77 // Only secondary cores need to allocate coreChannels
78 if (info->coreId == 0)
79 {
81 assert(info->coreChannelSize == ZERO);
82 }
83 else
84 {
86 }
87
88 // Mark all kernel memory used
89 for (Size i = 0; i < info->kernel.size; i += PAGESIZE)
90 m_alloc->allocate(info->kernel.phys + i);
91
92 // Mark BootImage memory used
93 for (Size i = 0; i < m_coreInfo->bootImageSize; i += PAGESIZE)
95
96 // Mark heap memory used
97 for (Size i = 0; i < m_coreInfo->heapSize; i += PAGESIZE)
99
100 // Reserve CoreChannel memory
101 for (Size i = 0; i < m_coreInfo->coreChannelSize; i += PAGESIZE)
103
104 // Clear interrupts table
106}
107
109{
110 // Calculate proper heap address: heap starts after the boot image.
112 heapPhysical += PAGESIZE - (coreInfo.bootImageSize % PAGESIZE);
113
114 // Heap must be a virtual address (see SplitAllocator)
115 const Arch::MemoryMap map;
116 const Memory::Range kernelData = map.range(MemoryMap::KernelData);
117 coreInfo.heapAddress = heapPhysical - (coreInfo.memory.phys - kernelData.virt);
119
120 // Prepare allocators
121 Size metaData = sizeof(BubbleAllocator) + sizeof(PoolAllocator);
122 Allocator *bubble, *pool;
123 const Allocator::Range bubbleRange = { coreInfo.heapAddress + metaData,
124 coreInfo.heapSize - metaData, sizeof(u32) };
125
126 // Clear the heap first
128
129 // Setup the dynamic memory heap
130 bubble = new (coreInfo.heapAddress) BubbleAllocator(bubbleRange);
131 pool = new (coreInfo.heapAddress + sizeof(BubbleAllocator)) PoolAllocator(bubble);
132
133 // Set default allocator
135 return 0;
136}
137
142
147
149{
150 return m_api;
151}
152
157
159{
160 return m_coreInfo;
161}
162
164{
165 return m_timer;
166}
167
168void Kernel::enableIRQ(u32 irq, bool enabled)
169{
170 if (m_intControl)
171 {
172 if (enabled)
173 m_intControl->enable(irq);
174 else
175 m_intControl->disable(irq);
176 }
177}
178
180{
181 if (m_intControl)
182 {
184 if (r != IntController::Success)
185 {
186 ERROR("failed to send IPI to core" << coreId << ": " << (uint) r);
187 return IOError;
188 }
189 }
190
191 return Success;
192}
193
195{
196 InterruptHook hook(h, p);
197
198 // Insert into interrupts; create List if neccesary
199 if (!m_interrupts[vec])
200 {
202 }
203 // Just append it. */
204 if (!m_interrupts[vec]->contains(&hook))
205 {
206 m_interrupts[vec]->append(new InterruptHook(h, p));
207 }
208}
209
211{
212 // Auto-Mask the IRQ. Any interrupt handler or user program
213 // needs to re-enable the IRQ to receive it again. This prevents
214 // interrupt loops in case the kernel cannot clear the IRQ immediately.
215 enableIRQ(vec, false);
216
217 // Fetch the list of interrupt hooks (for this vector)
219 if (lst)
220 {
221 // Execute them all
222 for (ListIterator<InterruptHook *> i(lst); i.hasCurrent(); i++)
223 {
224 i.current()->handler(state, i.current()->param, vec);
225 }
226 }
227
228 // Raise any interrupt notifications for processes. Note that the IRQ
229 // base should be subtracted, since userspace doesn't know about re-mapped
230 // IRQ's, such as is done for the PIC on intel
232 {
233 FATAL("failed to raise interrupt notification for IRQ #" << vec);
234 }
235}
236
238{
240
241 // Initialize the BootImageStorage object
242 const FileSystem::Result result = bootImage.initialize();
243 if (result != FileSystem::Success)
244 {
245 FATAL("failed to initialize BootImageStorage: result = " << (int) result);
246 }
247
248 NOTICE("bootimage: " << (void *) m_coreInfo->bootImageAddress <<
249 " (" << m_coreInfo->bootImageSize << " bytes)");
250
251 // Read header
252 const BootImage image = bootImage.bootImage();
253
254 // Loop BootPrograms
255 for (Size i = 0; i < image.symbolTableCount; i++)
256 {
257 BootSymbol program;
258
259 const FileSystem::Result readResult = bootImage.read(
260 image.symbolTableOffset + (sizeof(BootSymbol) * i),
261 &program,
262 sizeof(BootSymbol)
263 );
264
265 if (readResult != FileSystem::Success)
266 {
267 FATAL("failed to read BootSymbol: result = " << (int) readResult);
268 }
269
270 // Ignore non-BootProgram entries
271 if (program.type != BootProgram && program.type != BootPrivProgram)
272 {
273 continue;
274 }
275
276 // Load the program
277 const Result loadResult = loadBootProgram(bootImage, program);
278 if (loadResult != Success)
279 {
280 FATAL("failed to load BootSymbol " << program.name << ": result = " << (int) loadResult);
281 return IOError;
282 }
283 }
284
285 return Success;
286}
287
289 const BootSymbol &program)
290{
291 const BootImage image = bootImage.bootImage();
292 const Arch::MemoryMap map;
293
294 // Only BootProgram entries allowed
295 assert(program.type == BootProgram || program.type == BootPrivProgram);
296
297 // Create process
298 Process *proc = m_procs->create(program.entry, map, true, program.type == BootPrivProgram);
299 if (!proc)
300 {
301 FATAL("failed to create boot program: " << program.name);
302 return ProcessError;
303 }
304
305 // Obtain process memory
306 MemoryContext *mem = proc->getMemoryContext();
307
308 // Map program segment into it's virtual memory
309 for (Size i = 0; i < program.segmentsCount; i++)
310 {
311 BootSegment segment;
312
313 // Read the next BootSegment
314 const FileSystem::Result result = bootImage.read(
315 image.segmentsTableOffset + ((program.segmentsOffset + i) * sizeof(BootSegment)),
316 &segment,
317 sizeof(BootSegment)
318 );
319
320 if (result != FileSystem::Success)
321 {
322 FATAL("failed to read BootSegment for BootProgram " <<
323 program.name << ": result = " << (int) result);
324 return ProcessError;
325 }
326
327 // Map memory
328 Memory::Range range;
329 range.phys = 0;
330 range.virt = segment.virtualAddress;
331 range.size = segment.size;
333
334 const MemoryContext::Result mapResult = mem->mapRangeContiguous(&range);
335 if (mapResult != MemoryContext::Success)
336 {
337 FATAL("failed to map BootSegment at " << (void *) segment.virtualAddress <<
338 " for BootProgram " << program.name << ": result = " << (int) mapResult);
339 return ProcessError;
340 }
341
342 // Read from BootImage to physical memory of the program
343 // This assumes direct access to that physical memory.
344 const FileSystem::Result readResult = bootImage.read(
345 segment.offset,
346 (void *) m_alloc->toVirtual(range.phys),
347 segment.size
348 );
349
350 if (readResult != FileSystem::Success)
351 {
352 FATAL("failed to read BootSegment data at " << (void *) segment.virtualAddress <<
353 " for BootProgram " << program.name << ": result = " << (int) readResult);
354 return ProcessError;
355
356 }
357 }
358
359 // Allocate page for program arguments
362
363 Allocator::Range alloc_args;
364 alloc_args.address = 0;
365 alloc_args.size = argRange.size;
366 alloc_args.alignment = PAGESIZE;
367
368 if (m_alloc->allocate(alloc_args) != Allocator::Success)
369 {
370 FATAL("failed to allocate program arguments page");
371 return ProcessError;
372 }
373 argRange.phys = alloc_args.address;
374
375 // Map program arguments in the process
376 if (mem->mapRangeContiguous(&argRange) != MemoryContext::Success)
377 {
378 FATAL("failed to map program arguments page");
379 return ProcessError;
380 }
381
382 // Copy program arguments
383 char *args = (char *) m_alloc->toVirtual(argRange.phys);
384 MemoryBlock::set(args, 0, argRange.size);
386
387 // Done
388 NOTICE("loaded: " << program.name);
389 return Success;
390}
391
393{
394 NOTICE("");
395
396 // Load boot image programs
398
399 // Start the scheduler
400 m_procs->schedule();
401
402 // Never actually returns.
403 return 0;
404}
u8 coreId
Definition IntelACPI.h:1
Generic Kernel API implementation.
Definition API.h:40
Memory mapping for the kernel and user processes on the ARM architecture.
Definition ARMMap.h:38
Memory Allocator.
Definition Allocator.h:47
static void setDefault(Allocator *alloc)
Makes the given Allocator the default.
Definition Allocator.cpp:59
Uses a BootImage as a storage provider.
const BootImage bootImage() const
Get BootImage header.
virtual FileSystem::Result initialize()
Initialize the Storage device.
virtual FileSystem::Result read(const u64 offset, void *buffer, const Size size) const
Reads data from the boot image.
Keeps growing allocated memory, and can't actually free memory (hence the name).
virtual Result disable(uint irq)=0
Disable hardware interrupt (IRQ).
uint getBase() const
Get interrupt number base offset.
virtual Result send(const uint targetCoreId, const uint irq)
Send an inter-processor-interrupt (IPI).
virtual Result enable(uint irq)=0
Enable hardware interrupt (IRQ).
Result
Result codes.
FreeNOS kernel implementation.
Definition Kernel.h:93
CoreInfo * m_coreInfo
CoreInfo object for this core.
Definition Kernel.h:236
Kernel(CoreInfo *info)
Constructor function.
Definition Kernel.cpp:33
API * m_api
API handlers object.
Definition Kernel.h:233
CoreInfo * getCoreInfo()
Get CoreInfo.
Definition Kernel.cpp:158
virtual Result sendIRQ(const uint coreId, const uint irq)
Send a inter-processor-interrupt (IPI) to another core.
Definition Kernel.cpp:179
Vector< List< InterruptHook * > * > m_interrupts
Interrupt handlers.
Definition Kernel.h:239
SplitAllocator * getAllocator()
Get physical memory allocator.
Definition Kernel.cpp:138
SplitAllocator * m_alloc
Physical memory allocator.
Definition Kernel.h:227
Timer * getTimer()
Get Timer.
Definition Kernel.cpp:163
virtual Result loadBootProgram(const BootImageStorage &bootImage, const BootSymbol &program)
Load a boot program.
Definition Kernel.cpp:288
API * getAPI()
Get API.
Definition Kernel.cpp:148
virtual void hookIntVector(u32 vec, InterruptHandler h, ulong p)
Hooks a function to an hardware interrupt.
Definition Kernel.cpp:194
virtual void executeIntVector(u32 vec, CPUState *state)
Execute an interrupt handler.
Definition Kernel.cpp:210
IntController * m_intControl
Interrupt Controller.
Definition Kernel.h:242
static Error initializeHeap()
Initialize heap.
Definition Kernel.cpp:108
virtual void enableIRQ(u32 irq, bool enabled)
Enable or disable an hardware interrupt (IRQ).
Definition Kernel.cpp:168
ProcessManager * m_procs
Process Manager.
Definition Kernel.h:230
int run()
Execute the kernel.
Definition Kernel.cpp:392
Timer * m_timer
Timer device.
Definition Kernel.h:245
ProcessManager * getProcessManager()
Get process manager.
Definition Kernel.cpp:143
MemoryContext * getMemoryContext()
Get the current MMU context.
Definition Kernel.cpp:153
virtual Result loadBootImage()
Loads the boot image.
Definition Kernel.cpp:237
Result
Result codes.
Definition Kernel.h:100
@ IOError
Definition Kernel.h:104
@ ProcessError
Definition Kernel.h:103
@ Success
Definition Kernel.h:101
Iterate through a List.
virtual bool hasCurrent() const
Check if there is a current item on the List.
Simple linked list template class.
Definition List.h:37
void append(const char *str)
Append to buffered output.
Definition Log.cpp:53
static void * set(void *dest, int ch, unsigned count)
Fill memory with a constant byte.
static Size copy(void *dest, const void *src, Size count)
Copy memory from one place to another.
Virtual memory abstract interface.
Result
Result codes.
virtual Result mapRangeContiguous(Memory::Range *range)
Map a range of contiguous physical pages to virtual addresses.
@ UserArgs
< Used for copying program arguments and file descriptors
Definition MemoryMap.h:61
@ KernelData
< Kernel program data from libexec, e.g.
Definition MemoryMap.h:54
Memory::Range range(Region region) const
Get memory range for the given region.
Definition MemoryMap.cpp:36
Memory allocator which uses pools that each manage same-sized objects.
Represents a process which may run on the host.
Process * create(const Address entry, const MemoryMap &map, const bool readyToRun=false, const bool privileged=false)
Create a new Process.
Result schedule()
Schedule next process to run.
Result interruptNotify(const u32 vector)
Raise interrupt notifications for a interrupt vector.
Process * current()
Current process running.
Represents a process which may run on the host.
Definition Process.h:45
MemoryContext * getMemoryContext()
Get MMU memory context.
Definition Process.cpp:95
virtual void fill(T value)
Fill the Sequence with the given value.
Definition Sequence.h:73
Allocator which separates kernel mapped memory at virtual and physical addresses.
Address toPhysical(const Address virt) const
Convert Address to physical pointer.
virtual Result allocate(Range &args)
Allocate physical memory.
Address toVirtual(const Address phys) const
Convert Address to virtual pointer.
Represents a configurable timer device.
Definition Timer.h:36
virtual int insert(const T &item)
Adds the given item to the Vector, if possible.
Definition Vector.h:93
Singleton design pattern: only one instance is allowed.
Definition Singleton.h:70
static Log * instance()
Retrieve the instance.
Definition Singleton.h:86
void InterruptHandler(struct CPUState *state, ulong param, ulong vector)
Function which is called when the CPU is interrupted.
Definition Kernel.h:53
#define PAGESIZE
ARM uses 4K pages.
Definition ARMConstant.h:97
CoreInfo coreInfo
Local CoreInfo instance.
#define BOOTIMAGE_NAMELEN
Maximum length of BootSymbol names.
Definition BootImage.h:39
@ BootProgram
Executable program.
Definition BootImage.h:74
@ BootPrivProgram
Privileged executable program.
Definition BootImage.h:75
#define assert(exp)
Insert program diagnostics.
Definition assert.h:60
unsigned int u32
Unsigned 32-bit number.
Definition Types.h:53
slong Error
Error code defined in Error.h.
Definition Types.h:159
#define MegaByte(v)
Convert megabytes to bytes.
Definition Macros.h:57
#define ERROR(msg)
Output an error message.
Definition Log.h:61
#define NOTICE(msg)
Output a notice message.
Definition Log.h:75
unsigned long ulong
Unsigned long number.
Definition Types.h:47
#define FATAL(msg)
Output a critical message and terminate program immediatly.
Definition Log.h:50
unsigned int uint
Unsigned integer number.
Definition Types.h:44
unsigned int Size
Any sane size indicator cannot go negative.
Definition Types.h:128
#define ZERO
Zero value.
Definition Macros.h:43
#define BANNER
Print this banner per default on new Terminals.
Definition Terminal.h:38
Result
Result code for filesystem Actions.
Definition FileSystem.h:53
@ Executable
Definition Memory.h:43
@ User
Definition Memory.h:44
@ Readable
Definition Memory.h:41
@ Writable
Definition Memory.h:42
Describes a range of memory.
Definition Allocator.h:66
Size alignment
Alignment in bytes or ZERO for default alignment.
Definition Allocator.h:69
Address address
Starting address of the memory range.
Definition Allocator.h:67
Size size
Amount of memory in bytes.
Definition Allocator.h:68
BootImage contains executable programs to be loaded at system bootup.
Definition BootImage.h:45
u16 symbolTableCount
Number of entries in the symbols table.
Definition BootImage.h:59
u32 segmentsTableOffset
Offset of the segments table.
Definition BootImage.h:62
u32 symbolTableOffset
Offset of the symbol table.
Definition BootImage.h:56
Memory segment.
Definition BootImage.h:110
u32 size
Total size of the segment.
Definition BootImage.h:115
u32 virtualAddress
Virtual memory address to load the segment.
Definition BootImage.h:112
u32 offset
Offset in the boot image of the segment contents.
Definition BootImage.h:118
Program embedded in the BootImage.
Definition BootImage.h:85
u16 segmentsCount
Number of contiguous entries in the segment table.
Definition BootImage.h:99
u32 entry
Program entry point (only valid for BootProgram symbols).
Definition BootImage.h:93
u32 segmentsOffset
Offset in the segments table.
Definition BootImage.h:96
BootSymbolType type
Type of boot symbol.
Definition BootImage.h:90
char name[BOOTIMAGE_NAMELEN]
Name of the boot symbol.
Definition BootImage.h:87
Contains all the CPU registers.
Definition ARMCore.h:244
Per-Core information structure.
Definition CoreInfo.h:61
Address bootImageSize
Boot image size in bytes.
Definition CoreInfo.h:84
Memory::Range kernel
Kernel memory range.
Definition CoreInfo.h:75
Size coreChannelSize
Size of the IPC channel in bytes.
Definition CoreInfo.h:90
uint coreId
Core identifier.
Definition CoreInfo.h:66
Address coreChannelAddress
Physical memory address of IPC channel for CoreServer of this core.
Definition CoreInfo.h:87
Address bootImageAddress
Boot image physical memory address.
Definition CoreInfo.h:81
Memory::Range memory
Defines the physical memory available to the core.
Definition CoreInfo.h:69
Size heapSize
Size in bytes of the kernel heap.
Definition CoreInfo.h:96
Address heapAddress
Physical memory address of the kernel heap.
Definition CoreInfo.h:93
Interrupt hook class.
Definition Kernel.h:59
Memory range.
Definition Memory.h:56
Size size
Size in number of bytes.
Definition Memory.h:59
Address phys
Physical address.
Definition Memory.h:58
Address virt
Virtual address.
Definition Memory.h:57
Access access
Page access flags.
Definition Memory.h:60