Skip to content

Commit a0e3af4

Browse files
Implemented IntelPIC, IntelAPIC interrupt controllers and generic IO module.
The Intel kernel now uses the APIC timer for process switching, and falls back to the IntelPIT if not available. Implemented a IntController class interface for use in various interrupt controller implementations, including BCM2835Interrupt for ARM. Added MemoryContext::current() to retrieve the currently active MemoryContext. Added IntelPIT::wait() to await trigger moment in a busy loop, which is used to calibrate the APIC timer.
1 parent be3912e commit a0e3af4

42 files changed

Lines changed: 1228 additions & 311 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

kernel/API/IOCtl.cpp

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,30 +15,33 @@
1515
* along with this program. If not, see <http://www.gnu.org/licenses/>.
1616
*/
1717

18+
#include <FreeNOS/System.h>
1819
#include "IOCtl.h"
1920

2021
Error IOCtlHandler(IOOperation op, Address addr, ulong value)
2122
{
23+
Arch::IO io;
24+
2225
DEBUG("op =" << op << " addr=" << addr << " value=" << value);
2326

2427
switch (op)
2528
{
2629
case IOByteRead:
27-
return IO::inb(addr);
30+
return io.inb(addr);
2831

2932
case IOByteWrite:
30-
IO::outb(addr, value);
33+
io.outb(addr, value);
3134
break;
3235

3336
case IOWordRead:
34-
return IO::inw(addr);
37+
return io.inw(addr);
3538

3639
case IOWordWrite:
37-
IO::outw(addr, value);
40+
io.outw(addr, value);
3841
break;
3942

4043
case IOLongWrite:
41-
IO::outl(addr, value);
44+
io.outl(addr, value);
4245
break;
4346
}
4447
return API::Success;

kernel/API/ProcessCtl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ Error ProcessCtlHandler(ProcessID procID, ProcessOperation action, Address addr)
8080
break;
8181

8282
case WatchIRQ:
83-
Kernel::instance->hookInterrupt(IRQ(addr), (InterruptHandler *)interruptNotify, (ulong)proc);
83+
Kernel::instance->hookIntVector(IRQ(addr), (InterruptHandler *)interruptNotify, (ulong)proc);
8484
break;
8585

8686
case EnableIRQ:

kernel/Kernel.cpp

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <SplitAllocator.h>
2121
#include <BubbleAllocator.h>
2222
#include <PoolAllocator.h>
23+
#include <IntController.h>
2324
#include <BootImage.h>
2425
#include "Kernel.h"
2526
#include "Memory.h"
@@ -43,6 +44,7 @@ Kernel::Kernel(Memory::Range kernel, Memory::Range memory)
4344
m_alloc = new SplitAllocator(memory, highMem);
4445
m_procs = new ProcessManager(new Scheduler());
4546
m_api = new API();
47+
m_intControl = 0;
4648
m_bootImageAddress = 0;
4749

4850
// Mark kernel memory used (first 4MB in phys memory)
@@ -101,7 +103,18 @@ MemoryContext * Kernel::getMemoryContext()
101103
return m_procs->current()->getMemoryContext();
102104
}
103105

104-
void Kernel::hookInterrupt(u32 vec, InterruptHandler h, ulong p)
106+
void Kernel::enableIRQ(u32 irq, bool enabled)
107+
{
108+
if (m_intControl)
109+
{
110+
if (enabled)
111+
m_intControl->enable(irq);
112+
else
113+
m_intControl->disable(irq);
114+
}
115+
}
116+
117+
void Kernel::hookIntVector(u32 vec, InterruptHandler h, ulong p)
105118
{
106119
InterruptHook hook(h, p);
107120

@@ -117,7 +130,7 @@ void Kernel::hookInterrupt(u32 vec, InterruptHandler h, ulong p)
117130
}
118131
}
119132

120-
void Kernel::executeInterrupt(u32 vec, CPUState *state)
133+
void Kernel::executeIntVector(u32 vec, CPUState *state)
121134
{
122135
// Auto-Mask the IRQ. Any interrupt handler or user program
123136
// needs to re-enable the IRQ to receive it again. This prevents

kernel/Kernel.h

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,10 @@
2626
#include "Process.h"
2727
#include "ProcessManager.h"
2828

29-
/** Forward declaration. */
29+
/** Forward declarations. */
3030
class API;
3131
class SplitAllocator;
32+
class IntController;
3233
struct CPUState;
3334

3435
/**
@@ -37,6 +38,10 @@ struct CPUState;
3738
* @param state State of the CPU on the moment the interrupt occurred.
3839
* @param param Optional parameter for the handler.
3940
*/
41+
42+
// TODO: move this to libarch's IntController? The IntController
43+
// could take care of invocing a certain ISR when interrupt is raised.
44+
4045
typedef void InterruptHandler(struct CPUState *state, ulong param);
4146

4247
/**
@@ -146,29 +151,30 @@ class Kernel : public Singleton<Kernel>
146151
*/
147152
int run();
148153

154+
/**
155+
* Enable or disable an hardware interrupt (IRQ).
156+
*
157+
* @param irq IRQ number.
158+
* @param enabled True to enable, and false to disable.
159+
*/
160+
void enableIRQ(u32 irq, bool enabled);
161+
149162
/**
150163
* Hooks a function to an hardware interrupt.
151164
*
152165
* @param vec Interrupt vector to hook on.
153166
* @param h Handler function.
154167
* @param p Parameter to pass to the handler function.
155168
*/
156-
virtual void hookInterrupt(u32 vec, InterruptHandler h, ulong p);
169+
virtual void hookIntVector(u32 vec, InterruptHandler h, ulong p);
157170

158171
/**
159172
* Execute an interrupt handler.
160173
*
161-
* @param vec Interrupt Vector.
174+
* @param vec Interrupt vector.
162175
* @param state CPU state.
163176
*/
164-
virtual void executeInterrupt(u32 vec, CPUState *state);
165-
166-
/**
167-
* Enable or disable an hardware interrupt (IRQ).
168-
* @param vector IRQ number.
169-
* @param enabled True to enable, and false to disable.
170-
*/
171-
virtual void enableIRQ(u32 vector, bool enabled) = 0;
177+
virtual void executeIntVector(u32 vec, CPUState *state);
172178

173179
/**
174180
* Loads the boot image.
@@ -203,6 +209,9 @@ class Kernel : public Singleton<Kernel>
203209

204210
/** Interrupt handlers. */
205211
Vector<List<InterruptHook *> *> m_interrupts;
212+
213+
/** Interrupt Controller. */
214+
IntController *m_intControl;
206215
};
207216

208217
/**

kernel/arm/ARMKernel.cpp

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ ARMKernel::ARMKernel(Memory::Range kernel,
3131
{
3232
NOTICE("");
3333

34-
m_intr = intr;
34+
m_intControl = intr;
3535
intr->install(ARMInterrupt::UndefinedInstruction, undefinedInstruction);
3636
intr->install(ARMInterrupt::SoftwareInterrupt, trap);
3737
intr->install(ARMInterrupt::PrefetchAbort, prefetchAbort);
@@ -42,7 +42,7 @@ ARMKernel::ARMKernel(Memory::Range kernel,
4242

4343
// Enable clocks and irqs
4444
m_timer.setInterval( 250 ); /* trigger timer interrupts at 250Hz (clock runs at 1Mhz) */
45-
m_intr->enableIRQ(BCM_IRQ_SYSTIMERM1);
45+
m_intControl->enable(BCM_IRQ_SYSTIMERM1);
4646

4747
// Set ARMCore modes
4848
ARMControl ctrl;
@@ -51,24 +51,15 @@ ARMKernel::ARMKernel(Memory::Range kernel,
5151
ctrl.unset(ARMControl::BigEndian);
5252
}
5353

54-
void ARMKernel::enableIRQ(u32 vector, bool enabled)
55-
{
56-
DEBUG("vector =" << vector << "enabled =" << enabled);
57-
58-
if (enabled)
59-
m_intr->enableIRQ(vector);
60-
else
61-
m_intr->disableIRQ(vector);
62-
}
63-
6454
void ARMKernel::interrupt(CPUState state)
6555
{
6656
ARMKernel *kernel = (ARMKernel *) Kernel::instance;
57+
ARMInterrupt *intr = (ARMInterrupt *) kernel->m_intControl;
6758

6859
//DEBUG("");
6960

7061
// TODO: remove BCM2835 specific code
71-
if (kernel->m_intr->isTriggered(BCM_IRQ_SYSTIMERM1))
62+
if (intr->isTriggered(BCM_IRQ_SYSTIMERM1))
7263
{
7364
kernel->m_timer.next();
7465
kernel->getProcessManager()->schedule();
@@ -77,8 +68,8 @@ void ARMKernel::interrupt(CPUState state)
7768
{
7869
for (uint i = 0; i < 64; i++)
7970
{
80-
if (kernel->m_intr->isTriggered(i))
81-
kernel->executeInterrupt(i, &state);
71+
if (intr->isTriggered(i))
72+
kernel->executeIntVector(i, &state);
8273
}
8374
}
8475
}

kernel/arm/ARMKernel.h

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -123,13 +123,6 @@ class ARMKernel : public Kernel
123123
ARMInterrupt *intr,
124124
Address atags);
125125

126-
/**
127-
* Enable or disable an hardware interrupt (IRQ).
128-
* @param vector IRQ number.
129-
* @param enabled True to enable, and false to disable.
130-
*/
131-
virtual void enableIRQ(u32 vector, bool enabled);
132-
133126
/**
134127
* Loads the boot image.
135128
*/
@@ -151,8 +144,6 @@ class ARMKernel : public Kernel
151144

152145
ARMTags m_tags;
153146

154-
ARMInterrupt *m_intr;
155-
156147
BCMSysTimer m_timer;
157148
};
158149

kernel/arm/raspberry/Main.cpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,6 @@
2727

2828
extern C int kernel_main(u32 r0, u32 r1, u32 r2)
2929
{
30-
// Enforce default I/O base offset
31-
IO::base = IO_BASE;
32-
3330
Arch::MemoryMap mem;
3431
BCM2835Interrupt irq;
3532

kernel/arm/raspberry/RaspiSerial.cpp

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,22 +28,22 @@ RaspiSerial::RaspiSerial()
2828
void RaspiSerial::init()
2929
{
3030
// Disable PL011.
31-
IO::write(PL011_CR, 0x00000000);
31+
m_io.write(PL011_CR, 0x00000000);
3232

3333
// Setup the GPIO pin 14 && 15.
3434
// Disable pull up/down for all GPIO pins & delay for 150 cycles.
35-
IO::write(GPPUD, 0x00000000);
35+
m_io.write(GPPUD, 0x00000000);
3636
delay(150);
3737

3838
// Disable pull up/down for pin 14,15 & delay for 150 cycles.
39-
IO::write(GPPUDCLK0, (1 << 14) | (1 << 15));
39+
m_io.write(GPPUDCLK0, (1 << 14) | (1 << 15));
4040
delay(150);
4141

4242
// Write 0 to GPPUDCLK0 to make it take effect.
43-
IO::write(GPPUDCLK0, 0x00000000);
43+
m_io.write(GPPUDCLK0, 0x00000000);
4444

4545
// Clear pending interrupts.
46-
IO::write(PL011_ICR, 0x7FF);
46+
m_io.write(PL011_ICR, 0x7FF);
4747

4848
// Set integer & fractional part of baud rate.
4949
// Divider = UART_CLOCK/(16 * Baud)
@@ -52,42 +52,42 @@ void RaspiSerial::init()
5252

5353
// Divider = 3000000/(16 * 115200) = 1.627 = ~1.
5454
// Fractional part register = (.627 * 64) + 0.5 = 40.6 = ~40.
55-
IO::write(PL011_IBRD, 1);
56-
IO::write(PL011_FBRD, 40);
55+
m_io.write(PL011_IBRD, 1);
56+
m_io.write(PL011_FBRD, 40);
5757

5858
// Disable FIFO, use 8 bit data transmission, 1 stop bit, no parity
59-
IO::write(PL011_LCRH, PL011_LCRH_WLEN_8BIT);
59+
m_io.write(PL011_LCRH, PL011_LCRH_WLEN_8BIT);
6060

6161
// Mask all interrupts.
62-
IO::write(PL011_IMSC, (1 << 1) | (1 << 4) | (1 << 5) |
62+
m_io.write(PL011_IMSC, (1 << 1) | (1 << 4) | (1 << 5) |
6363
(1 << 6) | (1 << 7) | (1 << 8) |
6464
(1 << 9) | (1 << 10));
6565

6666
// Enable PL011, receive & transfer part of UART.
67-
IO::write(PL011_CR, (1 << 0) | (1 << 8) | (1 << 9));
67+
m_io.write(PL011_CR, (1 << 0) | (1 << 8) | (1 << 9));
6868
}
6969

7070
void RaspiSerial::put(u8 byte)
7171
{
7272
// wait for UART to become ready to transmit
7373
while(true)
74-
if (!(IO::read(PL011_FR) & (1 << 5)))
74+
if (!(m_io.read(PL011_FR) & (1 << 5)))
7575
break;
7676

77-
IO::write(PL011_DR, byte);
77+
m_io.write(PL011_DR, byte);
7878
}
7979

8080
u8 RaspiSerial::get(void)
8181
{
8282
// wait for UART to have recieved something
8383
while(true)
8484
{
85-
if (!(IO::read(PL011_FR) & (1 << 4)))
85+
if (!(m_io.read(PL011_FR) & (1 << 4)))
8686
{
8787
break;
8888
}
8989
}
90-
return IO::read(PL011_DR);
90+
return m_io.read(PL011_DR);
9191
}
9292

9393
void RaspiSerial::write(const char *str)

kernel/arm/raspberry/RaspiSerial.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ class RaspiSerial : public Log
3434
/*
3535
* Initialize UART0.
3636
*/
37-
static void init(void);
37+
void init(void);
3838

3939
/*
4040
* Receive a byte via UART0.
@@ -116,7 +116,10 @@ class RaspiSerial : public Log
116116
* This just loops <delay> times in a way that the compiler
117117
* wont optimize away.
118118
*/
119-
static void delay(s32 count);
119+
void delay(s32 count);
120+
121+
/** I/O instance */
122+
ARMIO m_io;
120123
};
121124

122125
#endif /* __ARM_RASPISERIAL_H */

kernel/intel/IntelBoot.S

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,10 @@
2626
#define KERNEL_LOWMEM ((1024 * 1024 * 1024) - (1024 * 1024 * 128))
2727
#define STACK_SIZE 0x4000
2828

29-
/* TODO: move interrupt handling and IDT setup to libarch's IntelCore code. */
29+
/*
30+
* TODO: move interrupt handling and IDT setup to libarch's IntelCore code.
31+
* see Desktop/scratch1
32+
*/
3033

3134
/**
3235
* Generates interrupt handlers.
@@ -82,6 +85,12 @@ _start:
8285
/* Disable interrupts. */
8386
cli
8487

88+
#warning rewrite this so that cpu1 uses a different physical memory base and remaps the kernel here to 0x0 virtual.
89+
#warning CPU0 will need to prepare a info struct somewhere, so that CPU1 can know which address it owns.
90+
#warning We need to use the boot parameters maybe?
91+
#warning Better solution: use a struct which we can read in this file, CPU0 will use its address + cpu1 base for writing
92+
#warning it when inserting the kernel memory (from coreserver)
93+
8594
/* Setup temporary boot stack. */
8695
movl $(stack + STACK_SIZE), %esp
8796
movl %esp, %ebp
@@ -136,6 +145,7 @@ _start:
136145
idtEntry 45, 0x8e
137146
idtEntry 46, 0x8e
138147
idtEntry 47, 0x8e
148+
idtEntry 48, 0x8e
139149
idtEntry 0x90, 0xee
140150

141151
/* Load IDT. */
@@ -232,6 +242,7 @@ interruptHandler 44, 0
232242
interruptHandler 45, 0
233243
interruptHandler 46, 0
234244
interruptHandler 47, 0
245+
interruptHandler 48, 0
235246
interruptHandler 0x90, 0
236247

237248
.section ".bss"

0 commit comments

Comments
 (0)