Rev 803 | Rev 808 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
#
# Copyright (C) 2005 Ondrej Palkovsky
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# - Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# - Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# - The name of the author may not be used to endorse or promote products
# derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Mask for interrupts 0 - 31 (bits 0 - 31) where 0 means that int has no error word
# and 1 means interrupt with error word
#define ERROR_WORD_INTERRUPT_LIST 0x00027D00
#include <arch/pm.h>
#include <arch/context_offset.h>
.text
.global interrupt_handlers
.global syscall_entry
.global panic_printf
panic_printf:
movq $halt, (%rsp)
jmp printf
.global memcpy
memcpy:
jmp _memcpy
.global cpuid
.global has_cpuid
.global rdtsc
.global read_efer_flag
.global set_efer_flag
## Determine CPUID support
#
# Return 0 in EAX if CPUID is not support, 1 if supported.
#
has_cpuid:
pushfq # store flags
popq %rax # read flags
movq %rax,%rdx # copy flags
btcl $21,%edx # swap the ID bit
pushq %rdx
popfq # propagate the change into flags
pushfq
popq %rdx # read flags
andl $(1<<21),%eax # interested only in ID bit
andl $(1<<21),%edx
xorl %edx,%eax # 0 if not supported, 1 if supported
ret
cpuid:
movq %rbx, %r10 # we have to preserve rbx across function calls
movl %edi,%eax # load the command into %eax
cpuid
movl %eax,0(%rsi)
movl %ebx,4(%rsi)
movl %ecx,8(%rsi)
movl %edx,12(%rsi)
movq %r10, %rbx
ret
rdtsc:
xorq %rax,%rax
rdtsc
ret
set_efer_flag:
movq $0xc0000080, %rcx
rdmsr
btsl %edi, %eax
wrmsr
ret
read_efer_flag:
movq $0xc0000080, %rcx
rdmsr
ret
# Push all general purpose registers on stack except %rbp, %rsp
.macro save_all_gpr
movq %rbp, IOFFSET_RBP(%rsp)
movq %rax, IOFFSET_RAX(%rsp)
movq %rbx, IOFFSET_RBX(%rsp)
movq %rcx, IOFFSET_RCX(%rsp)
movq %rdx, IOFFSET_RDX(%rsp)
movq %rsi, IOFFSET_RSI(%rsp)
movq %rdi, IOFFSET_RDI(%rsp)
movq %r8, IOFFSET_R8(%rsp)
movq %r9, IOFFSET_R9(%rsp)
movq %r10, IOFFSET_R10(%rsp)
movq %r11, IOFFSET_R11(%rsp)
movq %r12, IOFFSET_R12(%rsp)
movq %r13, IOFFSET_R13(%rsp)
movq %r14, IOFFSET_R14(%rsp)
movq %r15, IOFFSET_R15(%rsp)
.endm
.macro restore_all_gpr
movq IOFFSET_RBP(%rsp), %rbp
movq IOFFSET_RAX(%rsp), %rax
movq IOFFSET_RBX(%rsp), %rbx
movq IOFFSET_RCX(%rsp), %rcx
movq IOFFSET_RDX(%rsp), %rdx
movq IOFFSET_RSI(%rsp), %rsi
movq IOFFSET_RDI(%rsp), %rdi
movq IOFFSET_R8(%rsp), %r8
movq IOFFSET_R9(%rsp), %r9
movq IOFFSET_R10(%rsp), %r10
movq IOFFSET_R11(%rsp), %r11
movq IOFFSET_R12(%rsp), %r12
movq IOFFSET_R13(%rsp), %r13
movq IOFFSET_R14(%rsp), %r14
movq IOFFSET_R15(%rsp), %r15
.endm
## Declare interrupt handlers
#
# Declare interrupt handlers for n interrupt
# vectors starting at vector i.
#
# The handlers setup data segment registers
# and call exc_dispatch().
#
.macro handler i n
subq $IREGISTER_SPACE, %rsp
save_all_gpr
movq $(\i),%rdi # %rdi - first parameter
movq %rsp, %rsi # %rsi - pointer to interrupt_context
call exc_dispatch # exc_dispatch(i, stack)
# Test if this is interrupt with error word or not
mov $\i,%cl;
movl $1,%eax;
test $0xe0,%cl;
jnz 0f;
and $0x1f,%cl;
shl %cl,%eax;
and $ERROR_WORD_INTERRUPT_LIST,%eax;
jz 0f;
# Return with error word
restore_all_gpr
# $8 = Skip error word
addq $IREGISTER_SPACE + 0x8, %rsp
iretq
0:
# Return with no error word
restore_all_gpr
addq $IREGISTER_SPACE, %rsp
iretq
.if (\n-\i)-1
handler "(\i+1)",\n
.endif
.endm
interrupt_handlers:
h_start:
handler 0 IDT_ITEMS
h_end:
syscall_entry:
# Switch to hidden gs
swapgs
# TODO: I would like LEA instead of thes 2 instrs,
# why does not it work???
mov %gs:0, %r10 # We have a stack in r10
addq $0x0ff0, %r10
movq %rsp, 0(%r10) # Save old stack pointer to stack
movq %r10, %rsp # Change to new stack
pushq %rcx # Return address
pushq %r11 # Save flags
# Switch back to remain consistent
swapgs
movq %r9, %rcx # Exchange last parameter as a third
call syscall_handler
popq %r11
popq %rcx
movq 0(%rsp), %rsp
sysretq
.data
.global interrupt_handler_size
interrupt_handler_size: .long (h_end-h_start)/IDT_ITEMS