summaryrefslogtreecommitdiffhomepage
path: root/dev/Kernel/HALKit/ARM64/HalApplicationProcessor.cc
blob: 12fb27aecd9375400600de7407eddf2bc1645493 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/* -------------------------------------------

	Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved.

------------------------------------------- */

#include <HALKit/ARM64/Processor.h>
#include <KernelKit/DebugOutput.h>
#include <HALKit/ARM64/ApplicationProcessor.h>
#include <KernelKit/UserProcessScheduler.h>

#define GICD_BASE 0x08000000 // Distributor base address
#define GICC_BASE 0x08010000 // CPU interface base address

#define GICD_CTLR		0x000 // Distributor Control Register
#define GICD_ISENABLER	0x100 // Interrupt Set-Enable Registers
#define GICD_ICENABLER	0x180 // Interrupt Clear-Enable Registers
#define GICD_ISPENDR	0x200 // Interrupt Set-Pending Registers
#define GICD_ICPENDR	0x280 // Interrupt Clear-Pending Registers
#define GICD_IPRIORITYR 0x400 // Interrupt Priority Registers
#define GICD_ITARGETSR	0x800 // Interrupt Processor Targets Registers
#define GICD_ICFGR		0xC00 // Interrupt Configuration Registers

#define GICC_CTLR 0x000 // CPU Interface Control Register
#define GICC_PMR  0x004 // Interrupt Priority Mask Register
#define GICC_IAR  0x00C // Interrupt Acknowledge Register
#define GICC_EOIR 0x010 // End of Interrupt Register

// ================================================================= //

namespace NeOS
{
	struct PROCESS_CONTROL_BLOCK final
	{
		HAL::StackFramePtr mFrame;
	};

	STATIC PROCESS_CONTROL_BLOCK kProcessBlocks[kSchedProcessLimitPerTeam] = {0};

	namespace Detail
	{
		STATIC BOOL kGICEnabled = NO;

		STATIC void mp_hang_fn(void)
		{
			while (YES)
				;
		}

		Void mp_setup_gic_el0(Void)
		{
			// enable distributor.
			HAL::hal_mmio_write(GICD_BASE + GICD_CTLR, YES);

			UInt32 gicc_ctlr = HAL::hal_mmio_read<UInt32>(GICC_BASE + GICC_CTLR);

			const auto kEnableSignalInt = YES;

			gicc_ctlr |= kEnableSignalInt;		  // Enable signaling of interrupts
			gicc_ctlr |= (kEnableSignalInt << 1); // Allow Group 1 interrupts in EL0

			HAL::hal_mmio_write(GICC_BASE + GICC_CTLR, gicc_ctlr);

			// Set priority mask (accept all priorities)
			HAL::hal_mmio_write(GICC_BASE + GICC_PMR, 0xFF);

			UInt32 icfgr = HAL::hal_mmio_read<UInt32>(GICD_BASE + GICD_ICFGR + (32 / 16) * 4);

			icfgr |= (0x2 << ((32 % 16) * 2)); // Edge-triggered
			HAL::hal_mmio_write(GICD_BASE + GICD_ICFGR + (32 / 16) * 4, icfgr);

			// Target interrupt 32 to CPU 1
			HAL::hal_mmio_write(GICD_BASE + GICD_ITARGETSR + (32 / 4) * 4, 0x2 << ((32 % 4) * 8));

			// Set interrupt 32 priority to lowest (0xFF)
			HAL::hal_mmio_write(GICD_BASE + GICD_IPRIORITYR + (32 / 4) * 4, 0xFF << ((32 % 4) * 8));

			// Enable interrupt 32 for AP.
			HAL::hal_mmio_write(GICD_BASE + GICD_ISENABLER + (32 / 32) * 4, 0x01 << (32 % 32));

			kout << "AP's GIC configured in ISR 32." << endl;
		}

		BOOL mp_handle_gic_interrupt_el0(Void)
		{
			// Read the interrupt ID
			UInt32 interrupt_id = HAL::hal_mmio_read<UInt32>(GICC_BASE + GICC_IAR);

			// Check if it's a valid interrupt (not spurious)
			if ((interrupt_id & 0x3FF) < 1020)
			{
				kout << "Handling interrupt for AP: " << (interrupt_id & 0x3FF) << endl;

				// TODO: Handle code here.

				// End the interrupt

				HAL::hal_mmio_write(GICC_BASE + GICC_EOIR, interrupt_id);

				return YES;
			}

			// spurious interrupt
			return NO;
		}
	} // namespace Detail

	EXTERN_C HAL::StackFramePtr mp_get_current_context(ProcessID pid)
	{
		return kProcessBlocks[pid % kSchedProcessLimitPerTeam].mFrame;
	}

	EXTERN_C Bool mp_register_process(HAL::StackFramePtr stack_frame, ProcessID pid)
	{
		MUST_PASS(stack_frame);

		const auto process_index = pid % kSchedProcessLimitPerTeam;

		kProcessBlocks[process_index].mFrame = stack_frame;

		return YES;
	}

	BOOL mp_initialize_gic(Void)
	{
		if (!Detail::kGICEnabled)
		{
			Detail::kGICEnabled = YES;
			Detail::mp_setup_gic_el0();
		}

		return Detail::kGICEnabled;
	}
} // namespace NeOS