-BUILD_NUM = 2158
+BUILD_NUM = 2159
;
; Calls a user fault handler
;
-[global Proc_AlterUserReturnAddr]
+[global Proc_ReturnToUser]
[extern Proc_GetCurThread]
-Proc_AlterUserReturnAddr:
+Proc_ReturnToUser:
; EBP is the handler to use
call Proc_GetCurThread
- xchg bx, bx
; EAX is the current thread
mov ebx, eax
extern void Threads_Dump();
extern tThread *Threads_CloneTCB(Uint *Err, Uint Flags);
extern void Isr8(); // Double Fault
-extern void Proc_AlterUserReturnAddr();
+extern void Proc_ReturnToUser();
// === PROTOTYPES ===
void ArchThreads_Init();
{
// Rewinds the stack and calls the user function
// Never returns
- __asm__ __volatile__ ("mov %0, %%ebp;\n\tcall Proc_AlterUserReturnAddr" :: "r"(Thread->FaultHandler));
+ __asm__ __volatile__ ("mov %0, %%ebp;\n\tcall Proc_ReturnToUser" :: "r"(Thread->FaultHandler));
for(;;);
}
;
[BITS 64]
-MM_LOCALAPIC equ 0xFFFFFD0000000000
-
-[section .text]
-Desctab_Init:
- ; Install IRQ Handlers
-
-[section .data]
-gIDT:
- times 256 dw 0x00080000, 0x00008E00, 0, 0 ; 64-bit Interrupt Gate, CS = 0x8, IST0
-
-%macro DEFERR 1
-Isr%1:
- push 0
- push %1
- jmp ErrorCommon
-%endmacro
-%macro DEFERRNO 1
-Isr%1:
- push %1
- jmp ErrorCommon
-%endmacro
-
-%macro DEFIRQ 1
-Irq%1:
- push 0
- push %1
- jmp IrqCommon
-%endmacro
+%define NUM_IRQ_CALLBACKS 4
-%macro PUSH_EX 1-*
- %rep %0
- push %1
- %rotate 1
- %endrep
-%endmacro
-%macro POP_EX 1-*
- %rep %0
- %rotate -1
- pop %1
- %endrep
-%endmacro
+MM_LOCALAPIC equ 0xFFFFFD0000000000
%macro PUSH_GPR 0
+ mov [rsp-0x60], rsp
mov [rsp-0x08], r15
mov [rsp-0x10], r14
mov [rsp-0x18], r13
mov [rsp-0x48], rdi
mov [rsp-0x50], rsi
mov [rsp-0x58], rbp
- mov [rsp-0x60], rsp
mov [rsp-0x68], rbx
mov [rsp-0x70], rdx
mov [rsp-0x78], rcx
mov r12, [rsp-0x20]
mov r11, [rsp-0x28]
mov r10, [rsp-0x30]
- mov r9, [rsp-0x38]
- mov r8, [rsp-0x40]
+ mov r9, [rsp-0x38]
+ mov r8, [rsp-0x40]
mov rdi, [rsp-0x48]
mov rsi, [rsp-0x50]
mov rbp, [rsp-0x58]
mov rax, [rsp-0x80]
%endmacro
+[section .text]
+Desctab_Init:
+ ; Install IRQ Handlers
+ ret
+
+; int IRQ_AddHandler(int IRQ, void (*Handler)(int IRQ))
+; Return Values:
+; 0 on Success
+; -1 on an invalid IRQ Number
+; -2 when no slots are avaliable
+[global IRQ_AddHandler]
+IRQ_AddHandler:
+ ; RDI - IRQ Number
+ ; RSI - Callback
+
+ cmp rdi, 16
+ jb .numOK
+ xor rax, rax
+ dec rax
+ jmp .ret
+.numOK:
+
+ mov rax, rdi
+ shr rax, 3+2
+ mov rcx, gaIRQ_Handlers
+ add rax, rcx
+
+ ; Find a free callback slot
+ %rep NUM_IRQ_CALLBACKS
+ mov rdx, [rax]
+ test rdx, rdx
+ jz .assign
+ add rax, 8
+ %endrep
+ ; None found, return -2
+ xor rax, rax
+ dec rax
+ dec rax
+ jmp .ret
+
+ ; Assign the IRQ Callback
+.assign:
+ mov [rax], rsi
+ xor rax, rax
+
+.ret:
+ ret
+
+%macro DEFERR 1
+Isr%1:
+ push 0
+ push %1
+ jmp ErrorCommon
+%endmacro
+%macro DEFERRNO 1
+Isr%1:
+ push %1
+ jmp ErrorCommon
+%endmacro
+
+%macro DEFIRQ 1
+Irq%1:
+ push 0
+ push %1
+ jmp IrqCommon
+%endmacro
+
+IrqCommon:
+ PUSH_GPR
+
+ mov rbx, [rsp+16*8] ; Calculate address
+ shr rbx, 3+2 ; *8*4
+ mov rax, gaIRQ_Handlers
+ add rbx, rax
+
+ %assign i 0
+ %rep NUM_IRQ_CALLBACKS
+ mov rax, [rbx]
+ test rax, rax
+ mov rdi, [rsp+16*8] ; Get IRQ number
+ jz .skip.%[i]
+ call rax ; 2 Bytes (Op and Mod/RM)
+.skip.%[i]:
+ add rbx, 8
+ %assign i i+1
+ %endrep
+
+ mov rdi, [rsp+16*8] ; Get IRQ number
+ cmp rdi, 8
+ mov al, 0x20
+ jb .skipAckSecondary
+ mov dx, 0x00A0
+ out dx, al
+.skipAckSecondary:
+ mov dx, 0x0020
+ out dx, al
+
+ POP_GPR
+ add rsp, 16
+ iret
+
[extern Proc_Scheduler]
SchedulerIRQ:
; TODO: Find Current CPU
;POP_FPU
POP_GPR
iret
+
+[section .data]
+gIDT:
+ times 256 dw 0x00080000, 0x00008E00, 0, 0 ; 64-bit Interrupt Gate, CS = 0x8, IST0
+
+gaIRQ_Handlers:
+ times 16*NUM_IRQ_CALLBACKS dq 0
// TODO: Fix this structure
typedef struct sSyscallRegs
{
- Uint Arg4, Arg5; // RDI, RSI
- Uint Arg6; // RBP
- Uint Resvd2[1]; // Kernel RSP
union {
- Uint Arg1;
- Uint Error;
- }; // RBX
- union {
- Uint Arg3;
- Uint RetHi; // High 64 bits of ret
- }; // RDX
- Uint Arg2; // RCX
- union {
- Uint Num;
- Uint Return;
+ Uint Num;
+ Uint Return;
}; // RAX
- Uint Resvd3[5]; // Int, Err, rip, CS, ...
- Uint StackPointer; // RSP
- Uint Resvd4[1]; // SS
+ Uint Arg4; // RCX
+ Uint Arg3; // RDX
+ Uint Error; // RBX
+ Uint Resvd1[2]; // Kernel RSP, RBP
+ Uint Arg2; // RSI
+ Uint Arg1; // RDI
+ Uint Arg5; // R8
+ Uint Arg6; // R9
+ Uint Resvd2[6]; // R10 - R15
+ Uint Resvd3[5]; // IntNum, ErrCode, RIP, CS, RFLAGS
+
+ Uint Resvd4[5]; // Int, Err, rip, CS, ...
+ Uint StackPointer; // RSP
+ Uint Resvd5[1]; // SS
} tSyscallRegs;
#endif
// Register Structure
// TODO: Rebuild once IDT code is done
typedef struct {
- Uint ds, es, fs, gs;
- Uint r15, r14, r13, r12;
- Uint r11, r10, r9, r8;
- Uint rdi, rsi, rbp, krsp;
- Uint rbx, rdx, rcx, rax;
+ Uint rax, rcx, rdx, rbx;
+ Uint krsp, rbp, rsi, rdi;
+ Uint r8, r9, r10, r11;
+ Uint r12, r13, r14, r15;
Uint int_num, err_code;
- Uint eip, cs;
- Uint eflags, esp, ss;
+ Uint rip, cs;
+ Uint rflags, rsp, ss;
} tRegs;
/**
* Physical Memory Manager
*/
#include <acess.h>
+#include <mboot.h>
//#include <mm_phys.h>
enum eMMPhys_Ranges
Uint64 giMaxPhysPage = 0; // Maximum Physical page
// === CODE ===
-void MM_InitPhys()
+void MM_InitPhys(tMBoot_Info *MBoot)
{
+ tMBoot_MMapEnt *mmapStart;
+ tMBoot_MMapEnt *ent;
+ Uint64 maxAddr = 0;
+
+ // Scan the physical memory map
+ mmapStart = (void *)( KERNEL_BASE | MBoot->MMapAddr );
+ ent = mmapStart;
+ while( (Uint)ent < (Uint)mmapStart + MBoot->MMapLength )
+ {
+ // Adjust for the size of the entry
+ ent->Size += 4;
+
+ // If entry is RAM and is above `maxAddr`, change `maxAddr`
+ if(ent->Type == 1 && ent->Base + ent->Length > maxAddr)
+ maxAddr = ent->Base + ent->Length;
+ // Go to next entry
+ ent = (tMBoot_MMapEnt *)( (Uint)ent + ent->Size );
+ }
+
+ if(maxAddr == 0) {
+ giMaxPhysPage = (MBoot->HighMem >> 2) + 256; // HighMem is a kByte value
+ }
+ else {
+ giMaxPhysPage = maxAddr >> 12;
+ }
}
/**
return MM_AllocPhysRange(1, -1);
}
+/**
+ * \brief Reference a physical page
+ */
void MM_RefPhys(tPAddr PAddr)
{
- if( PAddr > giMaxPhysPage ) return ;
+ if( PAddr >> 12 > giMaxPhysPage ) return ;
gaiPageReferences[ PAddr >> 12 ] ++;
gaPrimaryBitmap[PAddr >> 18] |= 1 << ((PAddr>>12) & 63);
gaSuperBitmap[PAddr >> 24] |= 1 << ((PAddr >> 18) & 64);
}
+/**
+ * \brief Dereference a physical page
+ */
void MM_DerefPhys(tPAddr PAddr)
{
- if( PAddr > giMaxPhysPage ) return ;
+ if( PAddr >> 12 > giMaxPhysPage ) return ;
gaiPageReferences[ PAddr >> 12 ] --;
if( gaiPageReferences[ PAddr >> 12 ] )
{
return 1;
}
+void MM_Unmap(tVAddr VAddr)
+{
+ // Check PML4
+ if( !(PAGEMAPLVL4(VAddr >> 39) & 1) ) return ;
+ // Check PDP
+ if( !(PAGEDIRPTR(VAddr >> 30) & 1) ) return ;
+ // Check Page Dir
+ if( !(PAGEDIR(VAddr >> 21) & 1) ) return ;
+
+ PAGETABLE(VAddr >> 12) = 0;
+}
+
/**
* \brief Allocate a block of memory at the specified virtual address
*/
return ret;
}
+void MM_Deallocate(tVAddr VAddr)
+{
+ tPAddr phys;
+
+ phys = MM_GetPhysAddr(VAddr);
+ if(!phys) return ;
+
+ MM_Unmap(VAddr);
+
+ MM_DerefPhys(phys);
+}
+
/**
* \brief Get the physical address of a virtual location
*/
}
}
+/**
+ * \brief Get the flags applied to a page
+ */
Uint MM_GetFlags(tVAddr VAddr)
{
tPAddr *ent;
return ret;
}
+
+// --- Hardware Mappings ---
+/**
+ * \brief Map a range of hardware pages
+ */
+tVAddr MM_MapHWPages(tPAddr PAddr, Uint Number)
+{
+ Log_KernelPanic("MM", "TODO: Implement MM_MapHWPages");
+ return 0;
+}
+
+/**
+ * \brief Free a range of hardware pages
+ */
+void MM_UnmapHWPages(tVAddr VAddr, Uint Number)
+{
+ Log_KernelPanic("MM", "TODO: Implement MM_UnmapHWPages");
+}
+
+// --- Tempory Mappings ---
+tVAddr MM_MapTemp(tPAddr PAddr)
+{
+ Log_KernelPanic("MM", "TODO: Implement MM_MapTemp");
+ return 0;
+}
+
+void MM_FreeTemp(tVAddr VAddr)
+{
+ Log_KernelPanic("MM", "TODO: Implement MM_FreeTemp");
+ return ;
+}
extern tThread *Threads_GetNextToRun(int CPU);
extern void Threads_Dump();
extern tThread *Threads_CloneTCB(Uint *Err, Uint Flags);
-extern void Proc_AlterUserReturnAddr();
+extern void Proc_ReturnToUser();
// === PROTOTYPES ===
void ArchThreads_Init();
// Change the Segment Registers
Regs->cs = (((Dest+1)<<4) | Dest) - 8;
Regs->ss = ((Dest+1)<<4) | Dest;
- // Check if the GP Segs are GDT, then change them
- if(!(Regs->ds & 4)) Regs->ds = ((Dest+1)<<4) | Dest;
- if(!(Regs->es & 4)) Regs->es = ((Dest+1)<<4) | Dest;
- if(!(Regs->fs & 4)) Regs->fs = ((Dest+1)<<4) | Dest;
- if(!(Regs->gs & 4)) Regs->gs = ((Dest+1)<<4) | Dest;
return 0;
}
{
// Rewinds the stack and calls the user function
// Never returns
- __asm__ __volatile__ ("mov %0, %%rbp;\n\tcall Proc_AlterUserReturnAddr" :: "r"(Thread->FaultHandler));
+ __asm__ __volatile__ ("mov %0, %%rbp;\n\tcall Proc_ReturnToUser" :: "r"(Thread->FaultHandler));
for(;;);
}
mov rax, [rsp]
ret
+KSTACK_USERSTATE_SIZE equ (4+8+1+5)*4 ; SRegs, GPRegs, CPU, IRET
+[global Proc_ReturnToUser]
+[extern Proc_GetCurThread]
+Proc_ReturnToUser:
+ ; RBP is the handler to use
+
+ call Proc_GetCurThread
+
+ ; EAX is the current thread
+ mov rbx, rax
+ mov rax, [rbx+40] ; Get Kernel Stack
+ sub rax, KSTACK_USERSTATE_SIZE
+
+ ;
+ ; NOTE: This can cause corruption if the signal happens while the user
+ ; has called a kernel operation.
+ ; Good thing this can only be called on a user fault.
+ ;
+
+ ; Get and alter User SP
+ mov rcx, [rax+KSTACK_USERSTATE_SIZE-3*8]
+ mov rdx, [rbx+60] ; Get Signal Number
+ mov [rcx-8], rdx
+ mov QWORD [rcx-16], User_Syscall_RetAndExit
+ sub rcx, 16
+
+ ; Restore Segment Registers
+ mov ax, 0x23
+ mov ds, ax
+ mov es, ax
+
+ push 0x23 ; SS
+ push rcx ; RSP
+ push 0x202 ; RFLAGS (IF and Rsvd)
+ push 0x1B ; CS
+ push rbp ; RIP
+
+ iret
+
+[section .usertext]
+User_Syscall_RetAndExit:
+ mov rdi, rax
+ jmp User_Syscall_Exit
+User_Syscall_Exit:
+ xor rax, rax
+ ; RDI: Return Value
+ int 0xAC
+
[section .bss]
[global gInitialKernelStack]
resd 1024*1 ; 1 Page
gInitialKernelStack:
+