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
23 changes: 18 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ graph TD
subgraph Userspace ["Userspace (EL0/Ring 3)"]
GUI[Window Manager & GUI Apps]
Shell[Terminal / Shell]
ProcMgr[Process Manager]
Doom[Doom Engine]
end

Expand All @@ -78,9 +79,10 @@ graph TD

subgraph Subsystems
VFS[Virtual File System]
Process[Process Scheduler]
Process["Process Scheduler + Threading"]
Net[TCP/IP Networking Stack]
Mem["Memory Manager (PMM/VMM)"]
SMP["SMP (Multi-CPU)"]
end

subgraph Drivers
Expand All @@ -95,6 +97,7 @@ graph TD

GUI --> Syscall
Shell --> Syscall
ProcMgr --> Syscall
Doom --> Syscall

Syscall --> VFS
Expand All @@ -104,6 +107,7 @@ graph TD
VFS --> RamFS
Net --> VirtioNet
Process --> Mem
Process --> SMP

Drivers --> Hardware
```
Expand Down Expand Up @@ -141,6 +145,9 @@ graph TD
### 🛠 Core System
- **Multi-Architecture Kernel**: Supports ARM64 and x86_64 with clean abstraction layer
- **Preemptive Multitasking**: Priority-based scheduler with context switching
- **Process Manager**: GUI app showing all running processes with kill functionality
- **Multi-threading**: Full thread support via `clone()` syscall with `CLONE_VM` for shared memory
- **SMP Support**: Symmetric Multi-Processing infrastructure (boots on CPU 0, secondary CPU support ready)
- **Memory Management**: 4-level paging (ARM64) and 4-level paging (x86_64)
- **Virtual Memory**: Full MMU support with demand paging
- **Interrupt Handling**:
Expand Down Expand Up @@ -174,6 +181,7 @@ graph TD
- **Notepad**: Text editor with save/load functionality backed by VFS
- **Image Viewer**: JPEG image viewer with zoom and pan support
- **Audio Player**: MP3 playback support via minimp3 decoder
- **Process Manager**: View running processes (PID, name, state) with kill button
- **Snake**: Classic game with graphics and score tracking
- **Calculator**: Basic arithmetic operations with GUI
- **File Manager**: Browse, create, rename, and delete files (click images/audio to open)
Expand Down Expand Up @@ -334,23 +342,28 @@ Use UTM (https://mac.getutm.app/):
- ✅ GUI system with windows, dock, and applications
- ✅ File system (RamFS) with file manager
- ✅ Networking (TCP/IP stack, virtio-net)
- ✅ Process management and scheduling
- ✅ Process management with GUI process manager
- ✅ Multi-threading via clone() syscall
- ✅ SMP infrastructure initialized
- ✅ Input (keyboard and mouse)
- ✅ Doom runs with full graphics
- ✅ MP3 audio playback (via minimp3)
- ✅ JPEG image viewing (via picojpeg)

### Known Issues
1. **Sound Support**: Intel HDA driver initializes but audio playback is unstable
1. **Sound Support**: Intel HDA driver works but audio may be choppy in QEMU
2. **Persistent Storage**: Currently RAM-only (RamFS) - data lost on reboot
3. **x86_64 Testing**: Needs more real hardware testing
4. **Network Settings UI**: Not fully implemented
5. **Web Browser**: Basic rendering only, no full HTML parser

### Roadmap
- [x] ~~**Multi-core**: SMP support for multiple CPUs~~ *(Infrastructure complete)*
- [x] ~~**Process Manager**: View and kill running processes~~ *(Done)*
- [x] ~~**Multi-threading**: Thread creation via clone()~~ *(Done)*
- [ ] **Persistent Storage**: Implement EXT4/FAT32 write support
- [ ] **x86 32-bit**: Complete kernel implementation
- [ ] **Audio**: Stabilize Intel HDA buffer management
- [ ] **USB Support**: Add USB mass storage and HID drivers
- [ ] **Multi-core**: SMP support for multiple CPUs
- [ ] **User Accounts**: Login screen and multi-user support
- [ ] **Package Manager**: Install/remove applications
- [ ] **PNG Support**: Add PNG image decoder
Expand Down
251 changes: 251 additions & 0 deletions kernel/arch/arm64/arch.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,257 @@
extern uint64_t timer_get_count(void);
extern uint64_t timer_get_frequency(void);

/* ===================================================================== */
/* SMP (Symmetric Multi-Processing) Support */
/* ===================================================================== */

#define MAX_CPUS 8

/* Per-CPU data */
struct cpu_data {
uint32_t cpu_id;
uint32_t online;
void *stack;
void (*entry)(void);
};

static struct cpu_data cpu_info[MAX_CPUS];
static volatile uint32_t num_cpus_online = 1; /* Boot CPU is online */
static volatile uint32_t smp_initialized = 0;

/* Spinlock for SMP synchronization */
typedef struct {
volatile uint32_t lock;
} spinlock_t;

#define SPINLOCK_INIT { 0 }

static inline void spin_lock(spinlock_t *lock)
{
uint32_t tmp;
asm volatile(
"sevl\n"
"1: wfe\n"
"2: ldaxr %w0, [%1]\n"
" cbnz %w0, 1b\n"
" stxr %w0, %w2, [%1]\n"
" cbnz %w0, 2b\n"
: "=&r" (tmp)
: "r" (&lock->lock), "r" (1)
: "memory"
);
}

static inline void spin_unlock(spinlock_t *lock)
{
asm volatile("stlr wzr, [%0]" :: "r" (&lock->lock) : "memory");
}

/* Global kernel lock for SMP safety */
static spinlock_t kernel_lock = SPINLOCK_INIT;

void smp_lock(void)
{
spin_lock(&kernel_lock);
}

void smp_unlock(void)
{
spin_unlock(&kernel_lock);
}

/* Get current CPU ID */
uint32_t smp_processor_id(void)
{
uint64_t mpidr;
asm volatile("mrs %0, mpidr_el1" : "=r" (mpidr));
return mpidr & 0xFF; /* Aff0 is the CPU ID on most systems */
}

/* Get number of online CPUs */
uint32_t smp_num_cpus(void)
{
return num_cpus_online;
}

/* Secondary CPU entry point (called from assembly) */
void secondary_cpu_init(void)
{
uint32_t cpu_id = smp_processor_id();

printk(KERN_INFO "SMP: CPU %u coming online\n", cpu_id);

/* Initialize GIC for this CPU */
gic_cpu_init();

/* Mark CPU as online */
cpu_info[cpu_id].online = 1;
__atomic_add_fetch(&num_cpus_online, 1, __ATOMIC_SEQ_CST);

/* Enable interrupts */
arch_irq_enable();

printk(KERN_INFO "SMP: CPU %u online\n", cpu_id);

/* Enter idle loop - wait for work */
while (1) {
asm volatile("wfe"); /* Wait for event */
}
}

/* Boot secondary CPUs (PSCI method for QEMU virt) */
int smp_boot_secondary(uint32_t cpu_id, void (*entry)(void), void *stack)
{
if (cpu_id >= MAX_CPUS || cpu_id == 0) return -1;
if (cpu_info[cpu_id].online) return 0; /* Already online */

cpu_info[cpu_id].cpu_id = cpu_id;
cpu_info[cpu_id].entry = entry;
cpu_info[cpu_id].stack = stack;

/* Use PSCI CPU_ON to start the secondary CPU */
/* PSCI function IDs */
#define PSCI_CPU_ON_64 0xC4000003

uint64_t target_cpu = cpu_id;
uint64_t entry_point = (uint64_t)entry;
uint64_t context_id = cpu_id;
int64_t ret;

asm volatile(
"mov x0, %1\n" /* PSCI function ID */
"mov x1, %2\n" /* target CPU */
"mov x2, %3\n" /* entry point */
"mov x3, %4\n" /* context ID */
"hvc #0\n" /* Hypervisor call */
"mov %0, x0\n" /* Return value */
: "=r" (ret)
: "r" ((uint64_t)PSCI_CPU_ON_64), "r" (target_cpu),
"r" (entry_point), "r" (context_id)
: "x0", "x1", "x2", "x3", "memory"
);

if (ret == 0) {
printk(KERN_INFO "SMP: Booting CPU %u\n", cpu_id);
return 0;
} else {
printk(KERN_WARNING "SMP: Failed to boot CPU %u (PSCI error %lld)\n",
cpu_id, (long long)ret);
return -1;
}
}

/* Initialize SMP subsystem */
void smp_init(void)
{
if (smp_initialized) return;

printk(KERN_INFO "SMP: Initializing multiprocessor support\n");

/* Initialize boot CPU info */
cpu_info[0].cpu_id = 0;
cpu_info[0].online = 1;

smp_initialized = 1;

printk(KERN_INFO "SMP: Boot CPU (CPU 0) initialized\n");

/* Note: Secondary CPUs are not auto-booted.
* Call smp_boot_secondary() to start them when ready.
* For QEMU virt with -smp N, CPUs wait for PSCI CPU_ON.
*/
}

/* ===================================================================== */
/* Userspace Entry */
/* ===================================================================== */

/**
* arch_enter_userspace - Jump to userspace execution (EL0)
* @entry: Entry point address in userspace
* @sp: User stack pointer
* @argc: Argument count (passed in x0)
* @argv: Argument vector pointer (passed in x1)
*
* This function sets up the CPU state to execute at EL0 (userspace)
* and uses ERET to jump there. It does not return.
*/
void arch_enter_userspace(uint64_t entry, uint64_t sp, uint64_t argc, uint64_t argv)
{
printk(KERN_INFO "ARM64: Entering userspace at 0x%llx, sp=0x%llx\n",
(unsigned long long)entry, (unsigned long long)sp);

/*
* Set up SPSR_EL1 for EL0:
* - M[3:0] = 0b0000 (EL0t - EL0 with SP_EL0)
* - DAIF cleared (interrupts enabled)
* - NZCV = 0
*/
uint64_t spsr = 0; /* EL0t mode, interrupts enabled */

asm volatile(
/* Set ELR_EL1 to user entry point */
"msr elr_el1, %[entry]\n"

/* Set SPSR_EL1 for EL0 execution */
"msr spsr_el1, %[spsr]\n"

/* Set SP_EL0 (user stack pointer) */
"msr sp_el0, %[sp]\n"

/* Set up arguments in x0, x1 */
"mov x0, %[argc]\n"
"mov x1, %[argv]\n"

/* Clear other general-purpose registers for security */
"mov x2, #0\n"
"mov x3, #0\n"
"mov x4, #0\n"
"mov x5, #0\n"
"mov x6, #0\n"
"mov x7, #0\n"
"mov x8, #0\n"
"mov x9, #0\n"
"mov x10, #0\n"
"mov x11, #0\n"
"mov x12, #0\n"
"mov x13, #0\n"
"mov x14, #0\n"
"mov x15, #0\n"
"mov x16, #0\n"
"mov x17, #0\n"
"mov x18, #0\n"
"mov x19, #0\n"
"mov x20, #0\n"
"mov x21, #0\n"
"mov x22, #0\n"
"mov x23, #0\n"
"mov x24, #0\n"
"mov x25, #0\n"
"mov x26, #0\n"
"mov x27, #0\n"
"mov x28, #0\n"
"mov x29, #0\n" /* Frame pointer */
"mov x30, #0\n" /* Link register */

/* Ensure all changes take effect */
"isb\n"

/* Jump to userspace */
"eret\n"
:
: [entry] "r" (entry),
[sp] "r" (sp),
[spsr] "r" (spsr),
[argc] "r" (argc),
[argv] "r" (argv)
: "memory"
);

/* Should never reach here */
__builtin_unreachable();
}

/* ===================================================================== */
/* Early Initialization */
/* ===================================================================== */
Expand Down
8 changes: 8 additions & 0 deletions kernel/arch/arm64/gic.c
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,14 @@ void gic_init(void)
printk(KERN_INFO "GIC: Initialization complete\n");
}

/* Initialize GIC for secondary CPUs (SMP support) */
void gic_cpu_init(void)
{
/* Each secondary CPU needs to initialize its redistributor and CPU interface */
gic_init_redistributor();
gic_init_cpu_interface();
}

/* ===================================================================== */
/* IRQ management */
/* ===================================================================== */
Expand Down
Loading