;
; helpers.asm
;
; Copyright (C) 2016 Aleksandar Andrejevic <theflash@sdf.lonestar.org>
;
; This program is free software: you can redistribute it and/or modify
; it under the terms of the GNU Affero General Public License as
; published by the Free Software Foundation, either version 3 of the
; License, or (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
; GNU Affero General Public License for more details.
;
; You should have received a copy of the GNU Affero General Public License
; along with this program.  If not, see <http://www.gnu.org/licenses/>.
;

CONTEXT_SWITCH_MAGIC    EQU 0xDEADBEEF

bits 32

global init_cpu_gdt
global vm86_start
global exception_return
global save_kernel_handler
global syscall_function
global reschedule

extern set_exception_handler
extern set_kernel_esp
extern scheduler

gdtr                    DW 0
                        DD 0

;********************************************************************************
; void init_cpu_gdt(gdt_descriptor_t *table,
;                   size_t table_size,
;                   word_t code_selector,
;                   word_t data_selector,
;                   word_t tss_selector)
;********************************************************************************
init_cpu_gdt:           push ebp
                        mov ebp, esp
                        pushfd
                        cli
                        mov eax, dword [ebp + 8]
                        mov dword [gdtr + 2], eax
                        mov eax, dword [ebp + 12]
                        dec eax
                        mov word [gdtr], ax
                        mov eax, dword [ebp + 16]
                        mov word [.code_seg], ax
                        mov eax, dword [ebp + 20]
                        lgdt [gdtr]
                        DB 0xEA
                        DD .continue
.code_seg:              DW 0
.continue:              mov es, ax
                        mov ss, ax
                        mov ds, ax
                        mov fs, ax
                        mov gs, ax
                        mov eax, dword [ebp + 24]
                        ltr ax
                        popfd
                        leave
                        ret

;********************************************************************************
; void vm86_start(vm86_registers_t regs)
;********************************************************************************
vm86_start:             pushfd
                        push cs
                        push dword [esp + 8]
                        push 0
                        pushad
                        push ds
                        push esp
                        call set_kernel_esp
                        cli
                        add esp, 60
                        popad
                        iret

;********************************************************************************
; void exception_return(register_t regs)
;********************************************************************************
exception_return:       lea esi, [esp + 0x04]
                        mov edi, dword [esp + 0x14]
                        sub edi, 13 * 4
                        mov esp, edi
                        mov ecx, 13
                        cld
                        rep movsd
                        add esp, 4
                        popad
                        add esp, 4
                        iret

;********************************************************************************
; void save_kernel_handler(exception_handler_t *old_handler)
;********************************************************************************
save_kernel_handler:    pushfd
                        push cs
                        push dword [esp + 8]
                        push 0
                        pushad
                        add dword [esp + 12], 16
                        push ds
                        push dword [esp + 56]
                        push 0
                        lea eax, [esp + 8]
                        push eax
                        call set_exception_handler
                        add esp, 64
                        xor eax, eax
                        ret

;********************************************************************************
; qword_t syscall_function(void *function,
;                          dword_t *parameters,
;                          size_t parameters_size)
;********************************************************************************
syscall_function:       push ebp
                        mov ebp, esp
                        mov eax, dword [ebp + 0x08]
                        mov esi, dword [ebp + 0x0C]
                        mov ecx, dword [ebp + 0x10]
                        or ecx, ecx
                        jz .no_params
                        sub esp, ecx
                        mov edi, esp
                        cld
                        rep movsb
.no_params:             call eax
                        add esp, dword [ebp + 0x10]
                        pop ebp
                        ret

;********************************************************************************
; void reschedule(void)
;********************************************************************************
reschedule:             push cs
                        push dword [esp + 4]
                        push 0
                        pushad
                        pushfd
                        cli
                        pop eax
                        mov dword [esp + 44], eax
                        add dword [esp + 12], 16
                        push ds
                        push esp
                        call scheduler
                        add esp, 4
                        cmp dword [esp + 0x24], CONTEXT_SWITCH_MAGIC
                        jnz .no_stack_switch
                        mov esp, dword [esp + 0x10]
.no_stack_switch:       pop eax
                        mov ds, ax
                        mov es, ax
                        mov fs, ax
                        mov gs, ax
                        popad
                        add esp, 4
                        iret
