Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ $(OUT_DIR)start.o: kernel/start.s
# Pattern rule for any .c → build/*.o
$(OUT_DIR)%.o: %.c
@mkdir -p $(OUT_DIR)
$(CC) $(CFLAGS) -c $< -o $@
$(CC) $(CFLAGS) -c $< -o $@ $(KFLAGS) # KFLAGS is used for custom kernel flags

# Link everything
$(OUT_DIR)kernel.elf: $(OUT_DIR)start.o $(OBJS) kernel.ld
Expand Down
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ Make sure you have an ARM cross-compiler installed (e.g., `arm-none-eabi-gcc`) a
make
```

Developers also have the option to run the kernel with custom flags such as:
```sh
make KFLAGS="-USE_KTESTS -MY_DEFFLAG"
```

> [!IMPORTANT]
>
> `make` will clean, build, and run the kernel in QEMU. You can also run
Expand Down Expand Up @@ -64,4 +69,4 @@ For more details about this kernel, refer to the [AstraKernel Documentation](htt

## License

This project is licensed under the GNU GENERAL PUBLIC License. See the [LICENSE](LICENSE) file for details.
This project is licensed under the GNU GENERAL PUBLIC License. See the [LICENSE](LICENSE) file for details.
56 changes: 56 additions & 0 deletions include/interrupt.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#ifndef INTERRUPT_H
#define INTERRUPT_H

#include <stdint.h>

#ifdef __cplusplus
extern "C"
{
#endif

// PL190 VIC (interrupt controller)
// ref: PrimeCell Vectored Interrupt Controller (PL190) TRM (Page3-7)
#define VIC_BASE 0x10140000u
#define VIC_INTSELECT (*(volatile uint32_t *)(VIC_BASE + 0x00C)) // 0=IRQ,1=FIQ
#define VIC_INTENABLE (*(volatile uint32_t *)(VIC_BASE + 0x010)) // set bit=enable
#define VIC_INT_ENCLR (*(volatile utin32_t *)(VIC_BASE + 0x014))
#define VIC_SOFT_INT (*(volatile uint32_t *)(VIC_BASE + 0x018))
#define VIC_SOFT_INTCLR (*(volatile uint32_t *)(VIC_BASE + 0x01C))

// SP804 Timer0 in the 0/1 block
// ref: ARM Dual-Time Module (SP804) TRM (Page 3-2)
#define T01_BASE 0x101E2000u
#define T0_LOAD (*(volatile uint32_t *)(T01_BASE + 0x00))
#define T0_VALUE (*(volatile uint32_t *)(T01_BASE + 0x04))
#define T0_CONTROL (*(volatile uint32_t *)(T01_BASE + 0x08))
#define T0_INTCLR (*(volatile uint32_t *)(T01_BASE + 0x0C))
#define T0_MIS (*(volatile uint32_t *)(T01_BASE + 0x14))

// Bits for CONTROL (SP804)
// ref: ARM Dual-Time Module (SP804) TRM (Page 3-5)
#define TCTRL_ENABLE (1u << 7) // EN=bit7
#define TCTRL_PERIODIC (1u << 6) // PERIODIC=bit6
#define TCTRL_INTEN (1u << 5) // INTEN=bit5
#define TCTRL_32BIT (1u << 1) // 32BIT=bit1

// VIC line number for Timer0/1 on Versatile
#define IRQ_TIMER01 4

static inline void timer0_start_periodic(uint32_t load)
{
T0_CONTROL = 0; // disable while reconfig
T0_LOAD = load; // ex: 10000 for ~100 Hz if TIMCLK≈1 MHz
T0_INTCLR = 1; // clear any pending interrupt
T0_CONTROL = TCTRL_32BIT | TCTRL_PERIODIC | TCTRL_INTEN | TCTRL_ENABLE;
}

static inline void vic_enable_timer01_irq(void)
{
VIC_INTSELECT &= ~(1u << IRQ_TIMER01); // route to IRQ
VIC_INTENABLE |= (1u << IRQ_TIMER01); // enable line 4
}
#ifdef __cplusplus
}
#endif

#endif // INTERRUPT_H
2 changes: 2 additions & 0 deletions kernel/irq.c
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
#include <stdint.h>

#include "irq.h"
#include "interrupt.h"

volatile unsigned int tick = 0;

void irq_handler(void)
{
T0_INTCLR = 1; // this ack/clear the device (SP804)
tick++;
}

Expand Down
29 changes: 28 additions & 1 deletion kernel/kernel.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "clear.h"
#include "string.h"
#include "irq.h"
#include "interrupt.h"


static const char *banner[] = {
Expand Down Expand Up @@ -54,7 +55,30 @@ void irq_sanity_check(void)
}
}

// This function is for testing purposes.
// It test that the timer interrupt is firing as expected.
void not_main(void)
{
puts("Time0 IRQ firing test!\r\n");

vic_enable_timer01_irq();
timer0_start_periodic(10000);
irq_enable();

unsigned last = 0;
for (;;)
{
unsigned n = tick;
if (n != last && (n % 100) == 0)
{
puts(".");
last = n;
}
}
}

/* The following macros are for testing purposes. */
#define TIMER_TICK_TEST not_main()
#define SANITY_CHECK irq_sanity_check()
#define CALL_SVC_0 __asm__ volatile ("svc #0")

Expand All @@ -63,9 +87,12 @@ void kernel_main(void)
{
clear();

/* TEST */
/* TESTS */
#ifdef USE_KTESTS
SANITY_CHECK;
CALL_SVC_0;
TIMER_TICK_TEST;
#endif

/* Back to normal operations */
init_message();
Expand Down
Binary file added literature/ARM_Compiler_User_Guide.pdf
Binary file not shown.
Binary file added literature/ARM_Dual-Time Module_SP804.pdf
Binary file not shown.
Binary file not shown.