Removed unsupported architectures.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@32071 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -1,69 +0,0 @@
|
|||||||
OUTPUT_FORMAT("elf32-shl", "elf32-shl", "elf32-shl")
|
|
||||||
OUTPUT_ARCH(sh)
|
|
||||||
|
|
||||||
ENTRY(__start)
|
|
||||||
SEARCH_DIR("libgcc");
|
|
||||||
SECTIONS
|
|
||||||
{
|
|
||||||
. = 0xc0000000 + SIZEOF_HEADERS;
|
|
||||||
|
|
||||||
.interp : { *(.interp) }
|
|
||||||
.hash : { *(.hash) }
|
|
||||||
.dynsym : { *(.dynsym) }
|
|
||||||
.dynstr : { *(.dynstr) }
|
|
||||||
.rel.text : { *(.rel.text) *(.rel.gnu.linkonce.t*) }
|
|
||||||
.rela.text : { *(.rela.text) *(.rela.gnu.linkonce.t*) }
|
|
||||||
.rel.data : { *(.rel.data) *(.rel.gnu.linkonce.d*) }
|
|
||||||
.rela.data : { *(.rela.data) *(.rela.gnu.linkonce.d*) }
|
|
||||||
.rel.rodata : { *(.rel.rodata) *(.rel.gnu.linkonce.r*) }
|
|
||||||
.rela.rodata : { *(.rela.rodata) *(.rela.gnu.linkonce.r*) }
|
|
||||||
.rel.got : { *(.rel.got) }
|
|
||||||
.rela.got : { *(.rela.got) }
|
|
||||||
.rel.ctors : { *(.rel.ctors) }
|
|
||||||
.rela.ctors : { *(.rela.ctors) }
|
|
||||||
.rel.dtors : { *(.rel.dtors) }
|
|
||||||
.rela.dtors : { *(.rela.dtors) }
|
|
||||||
.rel.init : { *(.rel.init) }
|
|
||||||
.rela.init : { *(.rela.init) }
|
|
||||||
.rel.fini : { *(.rel.fini) }
|
|
||||||
.rela.fini : { *(.rela.fini) }
|
|
||||||
.rel.bss : { *(.rel.bss) }
|
|
||||||
.rela.bss : { *(.rela.bss) }
|
|
||||||
.rel.plt : { *(.rel.plt) }
|
|
||||||
.rela.plt : { *(.rela.plt) }
|
|
||||||
.init : { *(.init) } =0x9090
|
|
||||||
.plt : { *(.plt) }
|
|
||||||
|
|
||||||
/* text/read-only data */
|
|
||||||
.text : { *(.text .gnu.linkonce.t.*) } =0x9090
|
|
||||||
|
|
||||||
.rodata :
|
|
||||||
{
|
|
||||||
*(.rodata)
|
|
||||||
. = ALIGN(0x1000);
|
|
||||||
} =0x9000
|
|
||||||
|
|
||||||
/* writable data */
|
|
||||||
. = ALIGN(0x1000) + (. & (0x1000 - 1));
|
|
||||||
___data_start = .;
|
|
||||||
.data : { *(.data .gnu.linkonce.d.*) }
|
|
||||||
|
|
||||||
___ctor_list = .;
|
|
||||||
.ctors : { *(.ctors) }
|
|
||||||
___ctor_end = .;
|
|
||||||
___dtor_list = .;
|
|
||||||
.dtors : { *(.dtors) }
|
|
||||||
___dtor_end = .;
|
|
||||||
.got : { *(.got.plt) *(.got) }
|
|
||||||
.dynamic : { *(.dynamic) }
|
|
||||||
|
|
||||||
/* unintialized data (in same segment as writable data) */
|
|
||||||
___bss_start = .;
|
|
||||||
.bss : { *(.bss) }
|
|
||||||
|
|
||||||
. = ALIGN(0x1000);
|
|
||||||
_end = . ;
|
|
||||||
|
|
||||||
/* Strip unnecessary stuff */
|
|
||||||
/DISCARD/ : { *(.comment .note .eh_frame) }
|
|
||||||
}
|
|
||||||
@@ -1,312 +0,0 @@
|
|||||||
/*
|
|
||||||
** Copyright 2001, Travis Geiselbrecht. All rights reserved.
|
|
||||||
** Distributed under the terms of the NewOS License.
|
|
||||||
*/
|
|
||||||
#define FUNCTION(name) .align 2 ; .globl _##name ; .type _##name,@function ; _##name
|
|
||||||
|
|
||||||
.text
|
|
||||||
FUNCTION(reboot):
|
|
||||||
mov.l disable_exceptions_addr,r1
|
|
||||||
jsr @r1
|
|
||||||
nop
|
|
||||||
|
|
||||||
mov.l reboot_vector,r0
|
|
||||||
jmp @r0
|
|
||||||
nop
|
|
||||||
|
|
||||||
FUNCTION(dbg_save_registers):
|
|
||||||
rts
|
|
||||||
nop
|
|
||||||
|
|
||||||
.align 2
|
|
||||||
reboot_vector: .long 0xa0000000
|
|
||||||
disable_exceptions_addr: .long _disable_exceptions
|
|
||||||
|
|
||||||
FUNCTION(atomic_add):
|
|
||||||
mov.l r8,@-r15
|
|
||||||
sts.l pr,@-r15
|
|
||||||
|
|
||||||
/* disable interrupts */
|
|
||||||
mov.l disable_interrupts_addr,r1
|
|
||||||
jsr @r1
|
|
||||||
nop
|
|
||||||
|
|
||||||
/* load the value, save it, add to it, and store it back */
|
|
||||||
mov.l @r4,r3
|
|
||||||
mov r3,r8
|
|
||||||
add r5,r3
|
|
||||||
mov.l r3,@r4
|
|
||||||
|
|
||||||
/* restore interrupts */
|
|
||||||
mov.l restore_interrupts_addr,r1
|
|
||||||
jsr @r1
|
|
||||||
mov r0,r4
|
|
||||||
|
|
||||||
/* return value will be old value */
|
|
||||||
mov r8,r0
|
|
||||||
|
|
||||||
/* restore the stack */
|
|
||||||
lds.l @r15+,pr
|
|
||||||
rts
|
|
||||||
mov.l @r15+,r8
|
|
||||||
|
|
||||||
FUNCTION(atomic_and):
|
|
||||||
mov.l r8,@-r15
|
|
||||||
sts.l pr,@-r15
|
|
||||||
|
|
||||||
/* disable interrupts */
|
|
||||||
mov.l disable_interrupts_addr,r1
|
|
||||||
jsr @r1
|
|
||||||
nop
|
|
||||||
|
|
||||||
/* load the value, save it, and it, and store it back */
|
|
||||||
mov.l @r4,r3
|
|
||||||
mov r3,r8
|
|
||||||
and r5,r3
|
|
||||||
mov.l r3,@r4
|
|
||||||
|
|
||||||
/* restore interrupts */
|
|
||||||
mov.l restore_interrupts_addr,r1
|
|
||||||
jsr @r1
|
|
||||||
mov r0,r4
|
|
||||||
|
|
||||||
/* return value will be old value */
|
|
||||||
mov r8,r0
|
|
||||||
|
|
||||||
/* restore the stack */
|
|
||||||
lds.l @r15+,pr
|
|
||||||
rts
|
|
||||||
mov.l @r15+,r8
|
|
||||||
|
|
||||||
FUNCTION(atomic_or):
|
|
||||||
mov.l r8,@-r15
|
|
||||||
sts.l pr,@-r15
|
|
||||||
|
|
||||||
/* disable interrupts */
|
|
||||||
mov.l disable_interrupts_addr,r1
|
|
||||||
jsr @r1
|
|
||||||
nop
|
|
||||||
|
|
||||||
/* load the value, save it, or it, and store it back */
|
|
||||||
mov.l @r4,r3
|
|
||||||
mov r3,r8
|
|
||||||
or r5,r3
|
|
||||||
mov.l r3,@r4
|
|
||||||
|
|
||||||
/* restore interrupts */
|
|
||||||
mov.l restore_interrupts_addr,r1
|
|
||||||
jsr @r1
|
|
||||||
mov r0,r4
|
|
||||||
|
|
||||||
/* return value will be old value */
|
|
||||||
mov r8,r0
|
|
||||||
|
|
||||||
/* restore the stack */
|
|
||||||
lds.l @r15+,pr
|
|
||||||
rts
|
|
||||||
mov.l @r15+,r8
|
|
||||||
|
|
||||||
FUNCTION(atomic_set):
|
|
||||||
mov.l r8,@-r15
|
|
||||||
sts.l pr,@-r15
|
|
||||||
|
|
||||||
/* disable interrupts */
|
|
||||||
mov.l disable_interrupts_addr,r1
|
|
||||||
jsr @r1
|
|
||||||
nop
|
|
||||||
|
|
||||||
/* load the value, save it, and store the new value */
|
|
||||||
mov.l @r4,r8
|
|
||||||
mov.l r5,@r4
|
|
||||||
|
|
||||||
/* restore interrupts */
|
|
||||||
mov.l restore_interrupts_addr,r1
|
|
||||||
jsr @r1
|
|
||||||
mov r0,r4
|
|
||||||
|
|
||||||
/* return value will be old value */
|
|
||||||
mov r8,r0
|
|
||||||
|
|
||||||
/* restore the stack */
|
|
||||||
lds.l @r15+,pr
|
|
||||||
rts
|
|
||||||
mov.l @r15+,r8
|
|
||||||
|
|
||||||
/* int test_and_set(int *val, int set_to, int test_val) */
|
|
||||||
FUNCTION(test_and_set):
|
|
||||||
mov.l r8,@-r15
|
|
||||||
sts.l pr,@-r15
|
|
||||||
|
|
||||||
/* disable interrupts */
|
|
||||||
mov.l disable_interrupts_addr,r1
|
|
||||||
jsr @r1
|
|
||||||
nop
|
|
||||||
|
|
||||||
/* load the value, save it, and store the new value */
|
|
||||||
mov.l @r4,r8 /* load the dest, it will be the return value */
|
|
||||||
cmp/eq r8,r6 /* compare against the test_val */
|
|
||||||
bf _not_equal
|
|
||||||
|
|
||||||
mov.l r5,@r4 /* put the set_to value into the target */
|
|
||||||
|
|
||||||
_not_equal:
|
|
||||||
/* restore interrupts */
|
|
||||||
mov.l restore_interrupts_addr,r1
|
|
||||||
jsr @r1
|
|
||||||
mov r0,r4
|
|
||||||
|
|
||||||
/* return value will be old value */
|
|
||||||
mov r8,r0
|
|
||||||
|
|
||||||
/* restore the stack */
|
|
||||||
lds.l @r15+,pr
|
|
||||||
rts
|
|
||||||
mov.l @r15+,r8
|
|
||||||
|
|
||||||
.align 2
|
|
||||||
disable_interrupts_addr: .long _arch_int_disable_interrupts
|
|
||||||
restore_interrupts_addr: .long _arch_int_restore_interrupts
|
|
||||||
|
|
||||||
FUNCTION(disable_exceptions):
|
|
||||||
mov.l bl_bit_mask,r0
|
|
||||||
stc sr,r1
|
|
||||||
or r0,r1
|
|
||||||
ldc r1,sr /* turn off interrupts/exceptions */
|
|
||||||
rts
|
|
||||||
nop
|
|
||||||
|
|
||||||
FUNCTION(enable_exceptions):
|
|
||||||
mov.l bl_bit_mask,r0
|
|
||||||
not r0,r0
|
|
||||||
stc sr,r1
|
|
||||||
and r0,r1
|
|
||||||
ldc r1,sr
|
|
||||||
rts
|
|
||||||
nop
|
|
||||||
|
|
||||||
.align 2
|
|
||||||
bl_bit_mask: .long 0x10000000
|
|
||||||
|
|
||||||
FUNCTION(arch_int_restore_interrupts):
|
|
||||||
mov.l inverse_imask_bit_mask,r0
|
|
||||||
stc sr,r1 /* get the sr register */
|
|
||||||
and r0,r1 /* zero out the imask part */
|
|
||||||
or r4,r1 /* or in the passed in imask, should only contain imask bits */
|
|
||||||
ldc r1,sr /* put the new status into the sr register */
|
|
||||||
rts
|
|
||||||
nop
|
|
||||||
|
|
||||||
FUNCTION(arch_int_enable_interrupts):
|
|
||||||
mov.l inverse_imask_bit_mask,r0
|
|
||||||
stc sr,r1 /* load the sr register */
|
|
||||||
and r0,r1 /* set the imask to 0 */
|
|
||||||
ldc r1,sr /* put the new status into the sr register */
|
|
||||||
rts
|
|
||||||
nop
|
|
||||||
|
|
||||||
.align 2
|
|
||||||
inverse_imask_bit_mask: .long 0xffffff0f
|
|
||||||
|
|
||||||
FUNCTION(arch_int_disable_interrupts):
|
|
||||||
mov.l imask_bit_mask,r2
|
|
||||||
stc sr,r1 /* load the sr register */
|
|
||||||
mov r1,r0 /* save the old sr register */
|
|
||||||
or r2,r1 /* or in 0xf for the imask */
|
|
||||||
ldc r1,sr /* set the new sr register with the interrupts masked */
|
|
||||||
rts
|
|
||||||
and r2,r0 /* make sure the return value contains only the imask part */
|
|
||||||
|
|
||||||
FUNCTION(arch_int_is_interrupts_enabled):
|
|
||||||
mov.l imask_bit_mask,r2
|
|
||||||
stc sr,r0 /* load the sr register */
|
|
||||||
and r2,r0 /* mask out just the interrupt level */
|
|
||||||
cmp/eq #0,r0 /* check for zero */
|
|
||||||
bt _ints_is_enabled
|
|
||||||
nop
|
|
||||||
|
|
||||||
rts
|
|
||||||
mov #0,r0 /* return false */
|
|
||||||
|
|
||||||
_ints_is_enabled:
|
|
||||||
rts
|
|
||||||
mov #1,r0 /* return true */
|
|
||||||
|
|
||||||
.align 2
|
|
||||||
imask_bit_mask: .long 0x000000f0
|
|
||||||
|
|
||||||
FUNCTION(get_sr):
|
|
||||||
stc sr,r0
|
|
||||||
rts
|
|
||||||
nop
|
|
||||||
|
|
||||||
FUNCTION(get_fpscr):
|
|
||||||
sts fpscr,r0
|
|
||||||
rts
|
|
||||||
nop
|
|
||||||
|
|
||||||
// void sh4_context_switch(unsigned int **old_esp, unsigned int *new_esp);
|
|
||||||
FUNCTION(sh4_context_switch):
|
|
||||||
fmov.s fr12,@-r15
|
|
||||||
fmov.s fr13,@-r15
|
|
||||||
fmov.s fr14,@-r15
|
|
||||||
fmov.s fr15,@-r15
|
|
||||||
sts.l fpscr,@-r15
|
|
||||||
sts.l mach,@-r15
|
|
||||||
sts.l macl,@-r15
|
|
||||||
mov.l r8,@-r15
|
|
||||||
mov.l r9,@-r15
|
|
||||||
mov.l r10,@-r15
|
|
||||||
mov.l r11,@-r15
|
|
||||||
mov.l r12,@-r15
|
|
||||||
mov.l r13,@-r15
|
|
||||||
mov.l r14,@-r15
|
|
||||||
sts.l pr,@-r15
|
|
||||||
|
|
||||||
mov.l r15,@r4
|
|
||||||
mov r5,r15
|
|
||||||
|
|
||||||
lds.l @r15+,pr
|
|
||||||
mov.l @r15+,r14
|
|
||||||
mov.l @r15+,r13
|
|
||||||
mov.l @r15+,r12
|
|
||||||
mov.l @r15+,r11
|
|
||||||
mov.l @r15+,r10
|
|
||||||
mov.l @r15+,r9
|
|
||||||
mov.l @r15+,r8
|
|
||||||
lds.l @r15+,macl
|
|
||||||
lds.l @r15+,mach
|
|
||||||
lds.l @r15+,fpscr
|
|
||||||
fmov.s @r15+,fr15
|
|
||||||
fmov.s @r15+,fr14
|
|
||||||
fmov.s @r15+,fr13
|
|
||||||
fmov.s @r15+,fr12
|
|
||||||
|
|
||||||
rts
|
|
||||||
nop
|
|
||||||
|
|
||||||
FUNCTION(sh4_function_caller):
|
|
||||||
_fc_loop:
|
|
||||||
mov.l @r15+,r2
|
|
||||||
jsr @r2
|
|
||||||
nop
|
|
||||||
bra _fc_loop
|
|
||||||
nop
|
|
||||||
|
|
||||||
// void sh4_switch_stack_and_call(addr stack, void (*func)(void *), void *arg);
|
|
||||||
FUNCTION(sh4_switch_stack_and_call):
|
|
||||||
mov r4,r15
|
|
||||||
jsr @r5
|
|
||||||
mov r6,r4
|
|
||||||
|
|
||||||
// void sh4_enter_uspace(addr entry, void *args, addr ustack_top);
|
|
||||||
FUNCTION(sh4_enter_uspace):
|
|
||||||
ldc r4,spc // load the program counter it will switch to
|
|
||||||
mov r5,r4 // load the args
|
|
||||||
mov r6,r15 // restore the user stack
|
|
||||||
mov.l uspace_sr,r0
|
|
||||||
ldc r0,ssr
|
|
||||||
rte
|
|
||||||
nop
|
|
||||||
|
|
||||||
uspace_sr: .long 0x00000000
|
|
||||||
|
|
||||||
@@ -1,142 +0,0 @@
|
|||||||
/*
|
|
||||||
** Copyright 2001, Travis Geiselbrecht. All rights reserved.
|
|
||||||
** Distributed under the terms of the NewOS License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <SupportDefs.h>
|
|
||||||
|
|
||||||
#include <ktypes.h>
|
|
||||||
#include <user_atomic.h>
|
|
||||||
|
|
||||||
// The code below does only work on single CPU SH4 systems.
|
|
||||||
// Interrupts must be disabled during execution, too.
|
|
||||||
|
|
||||||
int32
|
|
||||||
_user_atomic_add(vint32 *uval, int32 incr)
|
|
||||||
{
|
|
||||||
int32 val;
|
|
||||||
int32 ret;
|
|
||||||
|
|
||||||
if ((addr)uval >= KERNEL_BASE && (addr)uval <= KERNEL_TOP)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
if (user_memcpy(&val, (int32 *)uval, sizeof(val)) < 0)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
ret = val;
|
|
||||||
val += incr;
|
|
||||||
|
|
||||||
if (user_memcpy((int32 *)uval, &val, sizeof(val)) < 0)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
error:
|
|
||||||
// XXX kill the app
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int32
|
|
||||||
_user_atomic_and(vint32 *uval, int32 incr)
|
|
||||||
{
|
|
||||||
int val;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if ((addr)uval >= KERNEL_BASE && (addr)uval <= KERNEL_TOP)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
if (user_memcpy(&val, (int32 *)uval, sizeof(val)) < 0)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
ret = val;
|
|
||||||
val &= incr;
|
|
||||||
|
|
||||||
if (user_memcpy((int32 *)uval, &val, sizeof(val)) < 0)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
error:
|
|
||||||
// XXX kill the app
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int32
|
|
||||||
_user_atomic_or(vint32 *uval, int32 incr)
|
|
||||||
{
|
|
||||||
int val;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if ((addr)uval >= KERNEL_BASE && (addr)uval <= KERNEL_TOP)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
if (user_memcpy(&val, (int32 *)uval, sizeof(val)) < 0)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
ret = val;
|
|
||||||
val |= incr;
|
|
||||||
|
|
||||||
if (user_memcpy((int32 *)uval, &val, sizeof(val)) < 0)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
error:
|
|
||||||
// XXX kill the app
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int32
|
|
||||||
_user_atomic_set(vint32 *uval, int32 set_to)
|
|
||||||
{
|
|
||||||
int val;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if ((addr)uval >= KERNEL_BASE && (addr)uval <= KERNEL_TOP)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
if (user_memcpy(&val, (int32 *)uval, sizeof(val)) < 0)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
ret = val;
|
|
||||||
val = set_to;
|
|
||||||
|
|
||||||
if (user_memcpy((int32 *)uval, &val, sizeof(val)) < 0)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
error:
|
|
||||||
// XXX kill the app
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int32
|
|
||||||
_user_atomic_test_and_set(vint32 *uval, int32 set_to, int32 test_val)
|
|
||||||
{
|
|
||||||
int val;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if ((addr)uval >= KERNEL_BASE && (addr)uval <= KERNEL_TOP)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
if (user_memcpy(&val, (int32 *)uval, sizeof(val)) < 0)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
ret = val;
|
|
||||||
if (val == test_val) {
|
|
||||||
val = set_to;
|
|
||||||
if (user_memcpy((int32 *)uval, &val, sizeof(val)) < 0)
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
error:
|
|
||||||
// XXX kill the app
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
@@ -1,173 +0,0 @@
|
|||||||
/*
|
|
||||||
** Copyright 2001, Travis Geiselbrecht. All rights reserved.
|
|
||||||
** Distributed under the terms of the NewOS License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <kernel/arch/cpu.h>
|
|
||||||
#include <kernel/debug.h>
|
|
||||||
#include <kernel/int.h>
|
|
||||||
#include <boot/stage2.h>
|
|
||||||
|
|
||||||
static vcpu_struct *vcpu;
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
arch_cpu_preboot_init(kernel_args *ka)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
arch_cpu_init(kernel_args *ka)
|
|
||||||
{
|
|
||||||
vcpu = ka->arch_args.vcpu;
|
|
||||||
|
|
||||||
vcpu->kernel_asid = 0;
|
|
||||||
vcpu->user_asid = 0;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
arch_cpu_init2(kernel_args *ka)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
sh4_set_kstack(addr kstack)
|
|
||||||
{
|
|
||||||
// dprintf("sh4_set_kstack: setting kstack to 0x%x\n", kstack);
|
|
||||||
vcpu->kstack = (unsigned int *)kstack;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
sh4_set_user_pgdir(addr pgdir)
|
|
||||||
{
|
|
||||||
// dprintf("sh4_set_user_pgdir: setting pgdir to 0x%x\n", pgdir);
|
|
||||||
if((addr)vcpu->user_pgdir != pgdir)
|
|
||||||
arch_cpu_global_TLB_invalidate();
|
|
||||||
vcpu->user_pgdir = (unsigned int *)pgdir;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
sh4_invl_page(addr va)
|
|
||||||
{
|
|
||||||
int state;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
va = ROUNDOWN(va, PAGE_SIZE);
|
|
||||||
|
|
||||||
state = int_disable_interrupts();
|
|
||||||
|
|
||||||
// wipe it out of the data tlbs
|
|
||||||
for(i=0; i<UTLB_COUNT; i++) {
|
|
||||||
struct utlb_addr_array *ua = (struct utlb_addr_array *)(UTLB + (i << UTLB_ADDR_SHIFT));
|
|
||||||
if(ua->vpn == (va >> 10))
|
|
||||||
ua->valid = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// wipe it out of the instruction tlbs
|
|
||||||
for(i=0; i<ITLB_COUNT; i++) {
|
|
||||||
struct itlb_addr_array *ia = (struct itlb_addr_array *)(ITLB + (i << ITLB_ADDR_SHIFT));
|
|
||||||
if(ia->vpn == (va >> 10))
|
|
||||||
ia->valid = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int_restore_interrupts(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
arch_cpu_invalidate_TLB_range(addr start, addr end)
|
|
||||||
{
|
|
||||||
int num_pages = end/PAGE_SIZE - start/PAGE_SIZE;
|
|
||||||
while ( num_pages-- >= 0 ) {
|
|
||||||
sh4_invl_page(start);
|
|
||||||
start += PAGE_SIZE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
arch_cpu_invalidate_TLB_list(addr pages[], int num_pages)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
for(i=0; i<num_pages; i++) {
|
|
||||||
sh4_invl_page(pages[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
arch_cpu_global_TLB_invalidate()
|
|
||||||
{
|
|
||||||
int state;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
state = int_disable_interrupts();
|
|
||||||
|
|
||||||
// wipe out the data tlbs
|
|
||||||
for(i=0; i<UTLB_COUNT; i++) {
|
|
||||||
struct utlb_addr_array *ua = (struct utlb_addr_array *)(UTLB + (i << UTLB_ADDR_SHIFT));
|
|
||||||
ua->valid = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// wipe out the instruction tlbs
|
|
||||||
for(i=0; i<ITLB_COUNT; i++) {
|
|
||||||
struct itlb_addr_array *ia = (struct itlb_addr_array *)(ITLB + (i << ITLB_ADDR_SHIFT));
|
|
||||||
ia->valid = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int_restore_interrupts(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
arch_cpu_user_memcpy(void *to, const void *from, size_t size, addr *fault_handler)
|
|
||||||
{
|
|
||||||
char *tmp = (char *)to;
|
|
||||||
char *s = (char *)from;
|
|
||||||
|
|
||||||
*fault_handler = (addr)&&error;
|
|
||||||
|
|
||||||
while(size--)
|
|
||||||
*tmp++ = *s++;
|
|
||||||
|
|
||||||
*fault_handler = 0;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
error:
|
|
||||||
*fault_handler = 0;
|
|
||||||
return ERR_VM_BAD_USER_MEMORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
arch_cpu_user_memset(void *s, char c, size_t count, addr *fault_handler)
|
|
||||||
{
|
|
||||||
char *xs = (char *) s;
|
|
||||||
|
|
||||||
*fault_handler = (addr)&&error;
|
|
||||||
|
|
||||||
while (count--)
|
|
||||||
*xs++ = c;
|
|
||||||
|
|
||||||
*fault_handler = 0;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
error:
|
|
||||||
*fault_handler = 0;
|
|
||||||
return ERR_VM_BAD_USER_MEMORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
arch_cpu_idle(void)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
@@ -1,115 +0,0 @@
|
|||||||
/*
|
|
||||||
** Copyright 2001, Travis Geiselbrecht. All rights reserved.
|
|
||||||
** Distributed under the terms of the NewOS License.
|
|
||||||
*/
|
|
||||||
#include <kernel/kernel.h>
|
|
||||||
#include <boot/stage2.h>
|
|
||||||
|
|
||||||
#include <kernel/arch/dbg_console.h>
|
|
||||||
|
|
||||||
int arch_dbg_con_init(kernel_args *ka)
|
|
||||||
{
|
|
||||||
volatile uint16 *scif16 = (uint16*)0xffe80000;
|
|
||||||
volatile uint8 *scif8 = (uint8*)0xffe80000;
|
|
||||||
int x;
|
|
||||||
|
|
||||||
/* Disable interrupts, transmit/receive, and use internal clock */
|
|
||||||
scif16[8/2] = 0;
|
|
||||||
|
|
||||||
/* 8N1, use P0 clock */
|
|
||||||
scif16[0] = 0;
|
|
||||||
|
|
||||||
/* Set baudrate, N = P0/(32*B)-1 */
|
|
||||||
// scif8[4] = (50000000 / (32 * baud_rate)) - 1;
|
|
||||||
|
|
||||||
// scif8[4] = 80; // 19200
|
|
||||||
// scif8[4] = 40; // 38400
|
|
||||||
// scif8[4] = 26; // 57600
|
|
||||||
scif8[4] = 13; // 115200
|
|
||||||
|
|
||||||
/* Reset FIFOs, enable hardware flow control */
|
|
||||||
scif16[24/2] = 4; //12;
|
|
||||||
|
|
||||||
for(x = 0; x < 100000; x++);
|
|
||||||
scif16[24/2] = 0; //8;
|
|
||||||
|
|
||||||
/* Disable manual pin control */
|
|
||||||
scif16[32/2] = 0;
|
|
||||||
|
|
||||||
/* Clear status */
|
|
||||||
scif16[16/2] = 0x60;
|
|
||||||
scif16[36/2] = 0;
|
|
||||||
|
|
||||||
/* Enable transmit/receive */
|
|
||||||
scif16[8/2] = 0x30;
|
|
||||||
|
|
||||||
for(x = 0; x < 100000; x++);
|
|
||||||
|
|
||||||
arch_dbg_con_puts("serial initted\n");
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
char arch_dbg_con_read()
|
|
||||||
{
|
|
||||||
volatile uint16 *status = (uint16*)0xffe8001c;
|
|
||||||
volatile uint16 *ack = (uint16*)0xffe80010;
|
|
||||||
volatile uint8 *fifo = (uint8*)0xffe80014;
|
|
||||||
char c;
|
|
||||||
|
|
||||||
/* Check input FIFO */
|
|
||||||
while ((*status & 0x1f) == 0);
|
|
||||||
|
|
||||||
/* Get the input char */
|
|
||||||
c = *fifo;
|
|
||||||
|
|
||||||
/* Ack */
|
|
||||||
*ack &= 0x6d;
|
|
||||||
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Flush all FIFO'd bytes out of the serial port buffer */
|
|
||||||
static void arch_dbg_con_flush() {
|
|
||||||
volatile uint16 *ack = (uint16*)0xffe80010;
|
|
||||||
|
|
||||||
*ack &= 0xbf;
|
|
||||||
while (!(*ack & 0x40))
|
|
||||||
;
|
|
||||||
*ack &= 0xbf;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _arch_dbg_con_putch(const char c)
|
|
||||||
{
|
|
||||||
volatile uint16 *ack = (uint16*)0xffe80010;
|
|
||||||
volatile uint8 *fifo = (uint8*)0xffe8000c;
|
|
||||||
|
|
||||||
/* Wait until the transmit buffer has space */
|
|
||||||
while (!(*ack & 0x20))
|
|
||||||
;
|
|
||||||
/* Send the char */
|
|
||||||
*fifo = c;
|
|
||||||
|
|
||||||
/* Clear status */
|
|
||||||
*ack &= 0x9f;
|
|
||||||
}
|
|
||||||
|
|
||||||
char arch_dbg_con_putch(const char c)
|
|
||||||
{
|
|
||||||
if (c == '\n') {
|
|
||||||
_arch_dbg_con_putch('\r');
|
|
||||||
_arch_dbg_con_putch('\n');
|
|
||||||
} else if (c != '\r')
|
|
||||||
_arch_dbg_con_putch(c);
|
|
||||||
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
void arch_dbg_con_puts(const char *s)
|
|
||||||
{
|
|
||||||
while(*s != '\0') {
|
|
||||||
arch_dbg_con_putch(*s);
|
|
||||||
s++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
/*
|
|
||||||
** Copyright 2001, Travis Geiselbrecht. All rights reserved.
|
|
||||||
** Distributed under the terms of the NewOS License.
|
|
||||||
*/
|
|
||||||
#include <kernel/kernel.h>
|
|
||||||
#include <kernel/debug.h>
|
|
||||||
#include <kernel/arch/debug.h>
|
|
||||||
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
/*
|
|
||||||
** Copyright 2001, Travis Geiselbrecht. All rights reserved.
|
|
||||||
** Distributed under the terms of the NewOS License.
|
|
||||||
*/
|
|
||||||
#include <boot/stage2.h>
|
|
||||||
|
|
||||||
int arch_faults_init(kernel_args *ka)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,176 +0,0 @@
|
|||||||
/*
|
|
||||||
** Copyright 2001, Travis Geiselbrecht. All rights reserved.
|
|
||||||
** Distributed under the terms of the NewOS License.
|
|
||||||
*/
|
|
||||||
#include <boot/stage2.h>
|
|
||||||
#include <arch/sh4/vcpu.h>
|
|
||||||
#include <arch/sh4/sh4.h>
|
|
||||||
|
|
||||||
#include <kernel/debug.h>
|
|
||||||
#include <kernel/int.h>
|
|
||||||
#include <kernel/thread.h>
|
|
||||||
#include <kernel/vm_priv.h>
|
|
||||||
#include <kernel/faults_priv.h>
|
|
||||||
#include <kernel/syscalls.h>
|
|
||||||
|
|
||||||
#include <kernel/arch/sh4/cpu.h>
|
|
||||||
|
|
||||||
#define MAX_ARGS 16
|
|
||||||
|
|
||||||
struct vector *vector_table;
|
|
||||||
|
|
||||||
void arch_int_enable_io_interrupt(int irq)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void arch_int_disable_io_interrupt(int irq)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int sh4_handle_exception(void *_frame)
|
|
||||||
//static int sh4_handle_exception(unsigned int code, unsigned int pc, unsigned int trap, unsigned int page_fault_addr)
|
|
||||||
{
|
|
||||||
struct iframe *frame = (struct iframe *)_frame;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
// NOTE: not safe to do anything that may involve the FPU before
|
|
||||||
// it is certain it is not an fpu exception
|
|
||||||
|
|
||||||
// dprintf("sh4_handle_exception: frame 0x%x code 0x%x, pc 0x%x, ssr 0x%x, sr 0x%x, pr 0x%x\n",
|
|
||||||
// frame, frame->excode, frame->spc, frame->ssr, get_sr(), frame->pr);
|
|
||||||
// dprintf("regs: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
|
|
||||||
// frame->r0, frame->r1, frame->r2, frame->r3, frame->r4, frame->r5, frame->r6, frame->r7,
|
|
||||||
// frame->r8, frame->r9, frame->r10, frame->r11, frame->r12, frame->r13, frame->r14, frame->sgr);
|
|
||||||
switch(frame->excode) {
|
|
||||||
case 0: // reset
|
|
||||||
case 1: // manual reset
|
|
||||||
case 5: // TLB protection violation (read)
|
|
||||||
case 6: // TLB protection violation (write)
|
|
||||||
case 7: // data address error (read)
|
|
||||||
case 8: // data address error (write)
|
|
||||||
case 10: // TLB multi hit
|
|
||||||
case 12: // illegal instruction
|
|
||||||
case 13: // slot illegal instruction
|
|
||||||
dprintf("about to gpf at pc 0x%x, excode %d\n", frame->spc, frame->excode);
|
|
||||||
ret = general_protection_fault(frame->excode);
|
|
||||||
break;
|
|
||||||
case 11: { // TRAPA
|
|
||||||
/*
|
|
||||||
** arg layout:
|
|
||||||
** r4-r7: arg 1 - 4
|
|
||||||
** r0-r3: arg 5 - 8
|
|
||||||
** r8-r13: arg 8 - 13
|
|
||||||
*/
|
|
||||||
unsigned int *trap = (unsigned int *)0xff000020;
|
|
||||||
uint64 retcode;
|
|
||||||
unsigned int args[MAX_ARGS];
|
|
||||||
|
|
||||||
int_enable_interrupts();
|
|
||||||
|
|
||||||
thread_atkernel_entry();
|
|
||||||
|
|
||||||
// XXX redo this to be stack-based
|
|
||||||
args[0] = frame->r4;
|
|
||||||
args[1] = frame->r5;
|
|
||||||
args[2] = frame->r6;
|
|
||||||
args[3] = frame->r7;
|
|
||||||
args[4] = frame->r0;
|
|
||||||
args[5] = frame->r1;
|
|
||||||
args[6] = frame->r2;
|
|
||||||
args[7] = frame->r3;
|
|
||||||
args[8] = frame->r8;
|
|
||||||
|
|
||||||
ret = syscall_dispatcher(*trap >> 2, args, &retcode);
|
|
||||||
frame->r0 = retcode & 0xffffffff;
|
|
||||||
frame->r1 = retcode >> 32;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 9: { // FPU exception
|
|
||||||
int fpu_fault_code;
|
|
||||||
switch(frame->fpscr & 0x0003f000) {
|
|
||||||
case 0x1000:
|
|
||||||
fpu_fault_code = FPU_FAULT_CODE_INEXACT;
|
|
||||||
break;
|
|
||||||
case 0x2000:
|
|
||||||
fpu_fault_code = FPU_FAULT_CODE_UNDERFLOW;
|
|
||||||
break;
|
|
||||||
case 0x4000:
|
|
||||||
fpu_fault_code = FPU_FAULT_CODE_OVERFLOW;
|
|
||||||
break;
|
|
||||||
case 0x8000:
|
|
||||||
fpu_fault_code = FPU_FAULT_CODE_DIVBYZERO;
|
|
||||||
break;
|
|
||||||
case 0x10000:
|
|
||||||
fpu_fault_code = FPU_FAULT_CODE_INVALID_OP;
|
|
||||||
break;
|
|
||||||
case 0x20000:
|
|
||||||
fpu_fault_code = FPU_FAULT_CODE_UNKNOWN;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
// XXX handle better
|
|
||||||
fpu_fault_code = FPU_FAULT_CODE_UNKNOWN;
|
|
||||||
}
|
|
||||||
ret = fpu_fault(fpu_fault_code);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 64: // FPU disable exception
|
|
||||||
case 65: // Slot FPU disable exception
|
|
||||||
ret = fpu_disable_fault();
|
|
||||||
break;
|
|
||||||
case EXCEPTION_PAGE_FAULT_READ:
|
|
||||||
case EXCEPTION_PAGE_FAULT_WRITE: {
|
|
||||||
addr newip;
|
|
||||||
if((frame->ssr & 0x000000f0) == 0) {
|
|
||||||
// dprintf("page_fault: enabling interrupts\n");
|
|
||||||
int_enable_interrupts();
|
|
||||||
}
|
|
||||||
ret = vm_page_fault(frame->page_fault_addr, frame->spc,
|
|
||||||
frame->excode == EXCEPTION_PAGE_FAULT_WRITE, (frame->ssr & 0x40000000) == 0, &newip);
|
|
||||||
if(newip != 0)
|
|
||||||
frame->spc = newip;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
ret = int_io_interrupt_handler(frame->excode);
|
|
||||||
}
|
|
||||||
if(ret == INT_RESCHEDULE) {
|
|
||||||
int state = int_disable_interrupts();
|
|
||||||
GRAB_THREAD_LOCK();
|
|
||||||
thread_resched();
|
|
||||||
RELEASE_THREAD_LOCK();
|
|
||||||
int_restore_interrupts(state);
|
|
||||||
}
|
|
||||||
if(!(frame->ssr & 0x40000000) || (frame->excode == 11)) {
|
|
||||||
thread_atkernel_exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
// dprintf("sh4_handle_exception: exit\n");
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int arch_int_init(kernel_args *ka)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
dprintf("arch_int_init: entry\n");
|
|
||||||
|
|
||||||
vector_table = (struct vector *)ka->arch_args.vcpu->vt;
|
|
||||||
dprintf("arch_int_init: vector table 0x%x\n", vector_table);
|
|
||||||
|
|
||||||
// set up the vectors
|
|
||||||
// handle all of them
|
|
||||||
for(i=0; i<256; i++)
|
|
||||||
vector_table[i].func = &sh4_handle_exception;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int arch_int_init2(kernel_args *ka)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,151 +0,0 @@
|
|||||||
/*
|
|
||||||
** Copyright 2001, Travis Geiselbrecht. All rights reserved.
|
|
||||||
** Distributed under the terms of the NewOS License.
|
|
||||||
*/
|
|
||||||
#include <kernel/kernel.h>
|
|
||||||
#include <kernel/vm.h>
|
|
||||||
#include <kernel/vm_priv.h>
|
|
||||||
#include <kernel/debug.h>
|
|
||||||
|
|
||||||
#include <kernel/arch/pmap.h>
|
|
||||||
|
|
||||||
#include <boot/stage2.h>
|
|
||||||
#include <arch/sh4/sh4.h>
|
|
||||||
#include <arch/sh4/vcpu.h>
|
|
||||||
|
|
||||||
#include <nulibc/string.h>
|
|
||||||
|
|
||||||
#define CHATTY_PMAP 0
|
|
||||||
|
|
||||||
static vcpu_struct *vcpu;
|
|
||||||
|
|
||||||
#define PHYS_TO_P1(x) ((x) + P1_AREA)
|
|
||||||
|
|
||||||
int arch_pmap_init(kernel_args *ka)
|
|
||||||
{
|
|
||||||
dprintf("arch_pmap_init: entry\n");
|
|
||||||
|
|
||||||
vcpu = ka->arch_args.vcpu;
|
|
||||||
|
|
||||||
dprintf("examining vcpu structure @ 0x%x:\n", vcpu);
|
|
||||||
dprintf("kernel_pgdir = 0x%x\n", vcpu->kernel_pgdir);
|
|
||||||
dprintf("user_pgdir = 0x%x\n", vcpu->user_pgdir);
|
|
||||||
dprintf("kernel_asid = 0x%x\n", vcpu->kernel_asid);
|
|
||||||
dprintf("user_asid = 0x%x\n", vcpu->user_asid);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int arch_pmap_init2(kernel_args *ka)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int pmap_map_page(addr paddr, addr vaddr, int lock)
|
|
||||||
{
|
|
||||||
struct pdent *pd = NULL;
|
|
||||||
struct ptent *pt;
|
|
||||||
unsigned int index = 0;
|
|
||||||
|
|
||||||
#if CHATTY_PMAP
|
|
||||||
dprintf("pmap_map_page: entry paddr 0x%x vaddr 0x%x lock 0x%x\n", paddr, vaddr, lock);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if(vaddr < P1_AREA) {
|
|
||||||
pd = (struct pdent *)vcpu->user_pgdir;
|
|
||||||
index = vaddr >> 22;
|
|
||||||
} else if(vaddr >= P3_AREA && vaddr < P4_AREA) {
|
|
||||||
pd = (struct pdent *)vcpu->kernel_pgdir;
|
|
||||||
index = (vaddr & 0x7fffffff) >> 22;
|
|
||||||
} else {
|
|
||||||
// invalid area to map pages
|
|
||||||
panic("pmap_map_page: invalid vaddr 0x%x\n", vaddr);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(pd[index].v == 0) {
|
|
||||||
// need to allocate a pagetable
|
|
||||||
unsigned int pgtable;
|
|
||||||
|
|
||||||
// get a free page for a pagetable
|
|
||||||
vm_get_free_page(&pgtable);
|
|
||||||
pgtable *= PAGE_SIZE;
|
|
||||||
|
|
||||||
// zero out the page
|
|
||||||
memset((void *)PHYS_TO_P1(pgtable), 0, PAGE_SIZE);
|
|
||||||
|
|
||||||
// stick it in the page dir
|
|
||||||
pd[index].ppn = pgtable >> 12;
|
|
||||||
pd[index].v = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the pagetable
|
|
||||||
pt = (struct ptent *)PHYS_TO_P1(pd[index].ppn << 12);
|
|
||||||
index = (vaddr >> 12) & 0x000003ff;
|
|
||||||
|
|
||||||
// insert the mapping
|
|
||||||
pt[index].wt = 0;
|
|
||||||
pt[index].pr = (lock & LOCK_KERNEL) ? (lock & 0x1) : (lock | 0x2);
|
|
||||||
pt[index].ppn = paddr >> 12;
|
|
||||||
pt[index].tlb_ent = 0;
|
|
||||||
pt[index].c = 1;
|
|
||||||
pt[index].sz = 0x1; // 4k page
|
|
||||||
pt[index].sh = 0; // XXX shared?
|
|
||||||
pt[index].d = 0;
|
|
||||||
pt[index].v = 1;
|
|
||||||
|
|
||||||
arch_pmap_invl_page(vaddr);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int pmap_unmap_page(addr vaddr)
|
|
||||||
{
|
|
||||||
panic("pmap_unmap_page unimplemented!\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void arch_pmap_invl_page(addr vaddr)
|
|
||||||
{
|
|
||||||
#if CHATTY_PMAP
|
|
||||||
dprintf("arch_pmap_invl_page: vaddr 0x%x\n", vaddr);
|
|
||||||
#endif
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int pmap_get_page_mapping(addr vaddr, addr *paddr)
|
|
||||||
{
|
|
||||||
struct pdent *pd = NULL;
|
|
||||||
struct ptent *pt;
|
|
||||||
unsigned int index = 0;
|
|
||||||
|
|
||||||
if(vaddr < P1_AREA) {
|
|
||||||
pd = (struct pdent *)vcpu->user_pgdir;
|
|
||||||
index = vaddr >> 22;
|
|
||||||
} else if(vaddr >= P3_AREA && vaddr < P4_AREA) {
|
|
||||||
pd = (struct pdent *)vcpu->kernel_pgdir;
|
|
||||||
index = (vaddr & 0x7fffffff) >> 22;
|
|
||||||
} else if(vaddr >= P1_AREA && vaddr < P2_AREA) {
|
|
||||||
// this region is identity mapped with a shift
|
|
||||||
*paddr = vaddr - P1_AREA;
|
|
||||||
return 0;
|
|
||||||
} else if(vaddr >= P2_AREA && vaddr < P3_AREA) {
|
|
||||||
// this region is identity mapped with a shift
|
|
||||||
*paddr = vaddr - P2_AREA;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(pd[index].v == 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the pagetable
|
|
||||||
pt = (struct ptent *)PHYS_TO_P1(pd[index].ppn << 12);
|
|
||||||
index = (vaddr >> 12) & 0x000003ff;
|
|
||||||
|
|
||||||
if(pt[index].v == 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
*paddr = pt[index].ppn << 12;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
/*
|
|
||||||
** Copyright 2001, Travis Geiselbrecht. All rights reserved.
|
|
||||||
** Distributed under the terms of the NewOS License.
|
|
||||||
*/
|
|
||||||
#include <kernel/debug.h>
|
|
||||||
#include <kernel/arch/smp.h>
|
|
||||||
|
|
||||||
int arch_smp_init(kernel_args *ka)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int arch_smp_get_current_cpu()
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void arch_smp_send_ici(int target_cpu)
|
|
||||||
{
|
|
||||||
panic("called arch_smp_send_ici!\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void arch_smp_send_broadcast_ici()
|
|
||||||
{
|
|
||||||
panic("called arch_smp_send_broadcast_ici\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,134 +0,0 @@
|
|||||||
/*
|
|
||||||
** Copyright 2001, Travis Geiselbrecht. All rights reserved.
|
|
||||||
** Distributed under the terms of the NewOS License.
|
|
||||||
*/
|
|
||||||
#include <kernel/kernel.h>
|
|
||||||
#include <kernel/thread.h>
|
|
||||||
#include <kernel/debug.h>
|
|
||||||
#include <kernel/int.h>
|
|
||||||
#include <kernel/vm_priv.h>
|
|
||||||
#include <kernel/arch/cpu.h>
|
|
||||||
#include <nulibc/string.h>
|
|
||||||
|
|
||||||
static struct thread *curr_thread = NULL;
|
|
||||||
|
|
||||||
int arch_proc_init_proc_struct(struct proc *p, bool kernel)
|
|
||||||
{
|
|
||||||
#if 0
|
|
||||||
if(!kernel) {
|
|
||||||
unsigned int page;
|
|
||||||
if(vm_get_free_page(&page) < 0) {
|
|
||||||
panic("arch_proc_init_proc_struct: could not find free frame for page dir\n");
|
|
||||||
}
|
|
||||||
p->arch_info.pgdir = (unsigned int *)PHYS_ADDR_TO_P1(page * PAGE_SIZE);
|
|
||||||
memset(p->arch_info.pgdir, 0, PAGE_SIZE);
|
|
||||||
} else {
|
|
||||||
p->arch_info.pgdir = NULL;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int arch_thread_init_thread_struct(struct thread *t)
|
|
||||||
{
|
|
||||||
t->arch_info.sp = NULL;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int arch_thread_initialize_kthread_stack(struct thread *t, int (*start_func)(void), void (*entry_func)(void), void (*exit_func)(void))
|
|
||||||
{
|
|
||||||
unsigned int *kstack = (unsigned int *)t->kernel_stack_base;
|
|
||||||
unsigned int kstack_size = KSTACK_SIZE;
|
|
||||||
unsigned int *kstack_top = kstack + kstack_size / sizeof(unsigned int);
|
|
||||||
int i;
|
|
||||||
|
|
||||||
// clear the kernel stack
|
|
||||||
memset(kstack, 0, kstack_size);
|
|
||||||
|
|
||||||
// set the final return address to be thread_kthread_exit
|
|
||||||
kstack_top--;
|
|
||||||
*kstack_top = (unsigned int)exit_func;
|
|
||||||
|
|
||||||
// set the return address to be the start of the first function
|
|
||||||
kstack_top--;
|
|
||||||
*kstack_top = (unsigned int)start_func;
|
|
||||||
|
|
||||||
// set the return address to be the start of the entry (thread setup) function
|
|
||||||
kstack_top--;
|
|
||||||
*kstack_top = (unsigned int)entry_func;
|
|
||||||
|
|
||||||
// simulate the important registers being pushed
|
|
||||||
for(i=0; i<7+2+5; i++) {
|
|
||||||
kstack_top--;
|
|
||||||
*kstack_top = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// set the address of the function caller function
|
|
||||||
// that will in turn call all of the above functions
|
|
||||||
// pushed onto the stack
|
|
||||||
kstack_top--;
|
|
||||||
*kstack_top = (unsigned int)sh4_function_caller;
|
|
||||||
|
|
||||||
// save the sp
|
|
||||||
t->arch_info.sp = kstack_top;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void arch_thread_context_switch(struct thread *t_from, struct thread *t_to)
|
|
||||||
{
|
|
||||||
#if 0
|
|
||||||
int i;
|
|
||||||
dprintf("arch_thread_context_switch: 0x%x->0x%x to sp 0x%x\n",
|
|
||||||
t_from->id, t_to->id, t_to->arch_info.sp);
|
|
||||||
#endif
|
|
||||||
#if 0
|
|
||||||
for(i=0; i<8; i++) {
|
|
||||||
dprintf("sp[%d] = 0x%x\n", i, t_to->arch_info.sp[i]);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
sh4_set_kstack(t_to->kernel_stack_base + KSTACK_SIZE);
|
|
||||||
|
|
||||||
if(t_to->proc->aspace != NULL) {
|
|
||||||
sh4_set_user_pgdir(vm_translation_map_get_pgdir(&t_to->proc->aspace->translation_map));
|
|
||||||
} else {
|
|
||||||
sh4_set_user_pgdir(NULL);
|
|
||||||
}
|
|
||||||
sh4_context_switch(&t_from->arch_info.sp, t_to->arch_info.sp);
|
|
||||||
}
|
|
||||||
|
|
||||||
void arch_thread_dump_info(void *info)
|
|
||||||
{
|
|
||||||
struct arch_thread *at = (struct arch_thread *)info;
|
|
||||||
dprintf("\tsp: 0x%x\n", at->sp);
|
|
||||||
}
|
|
||||||
|
|
||||||
void arch_thread_enter_uspace(addr entry, void *args, addr ustack_top)
|
|
||||||
{
|
|
||||||
dprintf("arch_thread_entry_uspace: entry 0x%x, ustack_top 0x%x\n",
|
|
||||||
entry, ustack_top);
|
|
||||||
|
|
||||||
int_disable_interrupts();
|
|
||||||
|
|
||||||
sh4_set_kstack(thread_get_current_thread()->kernel_stack_base + KSTACK_SIZE);
|
|
||||||
|
|
||||||
sh4_enter_uspace(entry, args, ustack_top - 4);
|
|
||||||
// never get to here
|
|
||||||
}
|
|
||||||
|
|
||||||
void arch_thread_switch_kstack_and_call(struct thread *t, addr new_kstack, void (*func)(void *), void *arg)
|
|
||||||
{
|
|
||||||
sh4_switch_stack_and_call(new_kstack, func, arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct thread *arch_thread_get_current_thread(void)
|
|
||||||
{
|
|
||||||
return curr_thread;
|
|
||||||
}
|
|
||||||
|
|
||||||
void arch_thread_set_current_thread(struct thread *t)
|
|
||||||
{
|
|
||||||
curr_thread = t;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,147 +0,0 @@
|
|||||||
/*
|
|
||||||
** Copyright 2001, Travis Geiselbrecht. All rights reserved.
|
|
||||||
** Distributed under the terms of the NewOS License.
|
|
||||||
*/
|
|
||||||
#include <kernel/kernel.h>
|
|
||||||
#include <boot/stage2.h>
|
|
||||||
#include <arch/sh4/sh4.h>
|
|
||||||
#include <kernel/int.h>
|
|
||||||
#include <kernel/debug.h>
|
|
||||||
#include <kernel/timer.h>
|
|
||||||
#include <kernel/arch/cpu.h>
|
|
||||||
|
|
||||||
#define timer_rate 12500000
|
|
||||||
#define max_timer_interval ((bigtime_t)0xffffffff * 1000000 / timer_rate)
|
|
||||||
#define min_timer_interval ((bigtime_t)0x1000)
|
|
||||||
|
|
||||||
#define SYSTEM_TIME_TIMER_QUANTA 0xffffffff
|
|
||||||
static const bigtime_t system_time_timer_period = (bigtime_t)SYSTEM_TIME_TIMER_QUANTA * timer_rate / 1000000;
|
|
||||||
static volatile bigtime_t base_system_time = 0;
|
|
||||||
|
|
||||||
bigtime_t system_time()
|
|
||||||
{
|
|
||||||
bigtime_t outtime;
|
|
||||||
uint32 timer_val;
|
|
||||||
int state = int_disable_interrupts();
|
|
||||||
|
|
||||||
restart:
|
|
||||||
timer_val = SYSTEM_TIME_TIMER_QUANTA - *(uint32 *)TCNT1;
|
|
||||||
|
|
||||||
if(*(uint16 *)TCR1 & 0x0100) {
|
|
||||||
// underflow has occurred already
|
|
||||||
outtime = base_system_time + system_time_timer_period + (bigtime_t)timer_val * 1000000 / timer_rate;
|
|
||||||
} else {
|
|
||||||
outtime = base_system_time + (bigtime_t)timer_val * 1000000 / timer_rate;
|
|
||||||
if(*(uint16 *)TCR1 & 0x0100) {
|
|
||||||
// an underflow must have happened since we checked last, redo
|
|
||||||
goto restart;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int_restore_interrupts(state);
|
|
||||||
|
|
||||||
return outtime;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void start_timer(int timer)
|
|
||||||
{
|
|
||||||
uint8 old_val = *(uint8 *)TSTR;
|
|
||||||
*(uint8 *)TSTR = old_val | (0x1 << timer % 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void stop_timer(int timer)
|
|
||||||
{
|
|
||||||
uint8 old_val = *(uint8 *)TSTR;
|
|
||||||
*(uint8 *)TSTR = old_val & ~(0x1 << timer %3);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void setup_timer(int timer, bigtime_t relative_timeout)
|
|
||||||
{
|
|
||||||
uint32 timer_val;
|
|
||||||
|
|
||||||
if(relative_timeout < min_timer_interval) {
|
|
||||||
timer_val = min_timer_interval * timer_rate / 1000000;
|
|
||||||
} else if(relative_timeout < max_timer_interval) {
|
|
||||||
timer_val = relative_timeout * timer_rate / 1000000;
|
|
||||||
} else {
|
|
||||||
timer_val = 0xffffffff;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(timer) {
|
|
||||||
case 0:
|
|
||||||
*(uint16 *)TCR0 = 0x0020;
|
|
||||||
*(uint32 *)TCNT0 = timer_val;
|
|
||||||
*(uint32 *)TCOR0 = timer_val;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
*(uint16 *)TCR1 = 0x0020;
|
|
||||||
*(uint32 *)TCNT1 = timer_val;
|
|
||||||
*(uint32 *)TCOR1 = timer_val;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
*(uint16 *)TCR2 = 0x0020;
|
|
||||||
*(uint32 *)TCNT2 = timer_val;
|
|
||||||
*(uint32 *)TCOR2 = timer_val;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void arch_timer_set_hardware_timer(bigtime_t timeout)
|
|
||||||
{
|
|
||||||
stop_timer(0);
|
|
||||||
setup_timer(0, timeout);
|
|
||||||
start_timer(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void arch_timer_clear_hardware_timer()
|
|
||||||
{
|
|
||||||
stop_timer(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int timer_interrupt0()
|
|
||||||
{
|
|
||||||
stop_timer(0);
|
|
||||||
return timer_interrupt();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void setup_system_time_timer()
|
|
||||||
{
|
|
||||||
*(uint16 *)TCR1 = 0x0020;
|
|
||||||
*(uint32 *)TCNT1 = SYSTEM_TIME_TIMER_QUANTA;
|
|
||||||
*(uint32 *)TCOR1 = SYSTEM_TIME_TIMER_QUANTA;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int timer_interrupt1()
|
|
||||||
{
|
|
||||||
base_system_time += system_time_timer_period;
|
|
||||||
*(uint16 *)TCR1 = 0x0020; // mask out the underflow bit
|
|
||||||
return INT_NO_RESCHEDULE;
|
|
||||||
}
|
|
||||||
|
|
||||||
int arch_init_timer(kernel_args *ka)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
uint8 old_val8;
|
|
||||||
uint16 old_val16;
|
|
||||||
dprintf("arch_init_timer: entry\n");
|
|
||||||
|
|
||||||
int_set_io_interrupt_handler(32, &timer_interrupt0, NULL);
|
|
||||||
int_set_io_interrupt_handler(33, &timer_interrupt1, NULL);
|
|
||||||
|
|
||||||
// stop all of the timers
|
|
||||||
*(uint8 *)TSTR = 0;
|
|
||||||
|
|
||||||
// enable the interrupt on timer 0 & 1 & disable 2
|
|
||||||
old_val16 = *(uint16 *)IPRA;
|
|
||||||
*(uint16 *)IPRA = (old_val16 & 0x000f) | 0xef00;
|
|
||||||
|
|
||||||
// start timer 1 counting forever
|
|
||||||
base_system_time = 0;
|
|
||||||
setup_system_time_timer();
|
|
||||||
start_timer(1);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
/*
|
|
||||||
** Copyright 2001, Travis Geiselbrecht. All rights reserved.
|
|
||||||
** Distributed under the terms of the NewOS License.
|
|
||||||
*/
|
|
||||||
#include <kernel/kernel.h>
|
|
||||||
#include <kernel/debug.h>
|
|
||||||
#include <kernel/arch/vm.h>
|
|
||||||
#include <kernel/arch/sh4/cpu.h>
|
|
||||||
#include <boot/stage2.h>
|
|
||||||
|
|
||||||
int arch_vm_init(kernel_args *ka)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int arch_vm_init2(kernel_args *ka)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int arch_vm_init_endvm(kernel_args *ka)
|
|
||||||
{
|
|
||||||
|
|
||||||
dprintf("arch_vm_init_endvm: entry\n");
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void arch_vm_aspace_swap(vm_address_space *aspace)
|
|
||||||
{
|
|
||||||
sh4_set_user_pgdir(vm_translation_map_get_pgdir(&aspace->translation_map));
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,424 +0,0 @@
|
|||||||
/*
|
|
||||||
** Copyright 2001, Travis Geiselbrecht. All rights reserved.
|
|
||||||
** Distributed under the terms of the NewOS License.
|
|
||||||
*/
|
|
||||||
#include <kernel/kernel.h>
|
|
||||||
#include <kernel/arch/vm_translation_map.h>
|
|
||||||
#include <kernel/heap.h>
|
|
||||||
#include <kernel/int.h>
|
|
||||||
#include <kernel/smp.h>
|
|
||||||
#include <kernel/vm.h>
|
|
||||||
#include <kernel/vm_page.h>
|
|
||||||
#include <kernel/vm_priv.h>
|
|
||||||
#include <kernel/arch/cpu.h>
|
|
||||||
#include <kernel/debug.h>
|
|
||||||
#include <nulibc/string.h>
|
|
||||||
#include <boot/stage2.h>
|
|
||||||
|
|
||||||
#include <arch/sh4/sh4.h>
|
|
||||||
#include <arch/sh4/vcpu.h>
|
|
||||||
|
|
||||||
typedef struct vm_translation_map_arch_info_struct {
|
|
||||||
addr pgdir_virt;
|
|
||||||
addr pgdir_phys;
|
|
||||||
bool is_user;
|
|
||||||
} vm_translation_map_arch_info;
|
|
||||||
|
|
||||||
static vcpu_struct *vcpu;
|
|
||||||
|
|
||||||
#define CHATTY_TMAP 0
|
|
||||||
|
|
||||||
#define PHYS_TO_P1(x) ((x) + P1_AREA)
|
|
||||||
|
|
||||||
static void destroy_tmap(vm_translation_map *map)
|
|
||||||
{
|
|
||||||
int state;
|
|
||||||
vm_translation_map *entry;
|
|
||||||
vm_translation_map *last = NULL;
|
|
||||||
|
|
||||||
if(map == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if(map->arch_data->pgdir_virt != NULL)
|
|
||||||
kfree((void *)map->arch_data->pgdir_virt);
|
|
||||||
|
|
||||||
kfree(map->arch_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int lock_tmap(vm_translation_map *map)
|
|
||||||
{
|
|
||||||
// dprintf("lock_tmap: map 0x%x\n", map);
|
|
||||||
if(recursive_lock_lock(&map->lock) == true) {
|
|
||||||
// we were the first one to grab the lock
|
|
||||||
// dprintf("clearing invalidated page count\n");
|
|
||||||
// map->arch_data->num_invalidate_pages = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;}
|
|
||||||
|
|
||||||
static int unlock_tmap(vm_translation_map *map)
|
|
||||||
{
|
|
||||||
if(recursive_lock_get_recursion(&map->lock) == 1) {
|
|
||||||
// XXX flush any TLB ents we wanted to
|
|
||||||
}
|
|
||||||
recursive_lock_unlock(&map->lock);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int map_tmap(vm_translation_map *map, addr va, addr pa, unsigned int lock)
|
|
||||||
{
|
|
||||||
struct pdent *pd = NULL;
|
|
||||||
struct ptent *pt;
|
|
||||||
unsigned int index;
|
|
||||||
|
|
||||||
#if CHATTY_TMAP
|
|
||||||
dprintf("map_tmap: va 0x%x pa 0x%x lock 0x%x\n", va, pa, lock);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if(map->arch_data->is_user) {
|
|
||||||
if(va >= P1_AREA) {
|
|
||||||
// invalid
|
|
||||||
panic("map_tmap: asked to map va 0x%x in user space aspace\n", va);
|
|
||||||
}
|
|
||||||
pd = (struct pdent *)map->arch_data->pgdir_phys;
|
|
||||||
index = va >> 22;
|
|
||||||
} else {
|
|
||||||
if(va < P3_AREA && va >= P4_AREA) {
|
|
||||||
panic("map_tmap: asked to map va 0x%x in kernel space aspace\n", va);
|
|
||||||
}
|
|
||||||
pd = (struct pdent *)vcpu->kernel_pgdir;
|
|
||||||
index = (va & 0x7fffffff) >> 22;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(pd[index].v == 0) {
|
|
||||||
vm_page *page;
|
|
||||||
unsigned int pgtable;
|
|
||||||
|
|
||||||
page = vm_page_allocate_page(PAGE_STATE_CLEAR);
|
|
||||||
pgtable = page->ppn * PAGE_SIZE;
|
|
||||||
|
|
||||||
// XXX remove when real clear pages support is there
|
|
||||||
memset((void *)PHYS_TO_P1(pgtable), 0, PAGE_SIZE);
|
|
||||||
|
|
||||||
pd[index].ppn = pgtable >> 12;
|
|
||||||
pd[index].v = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the pagetable
|
|
||||||
pt = (struct ptent *)PHYS_TO_P1(pd[index].ppn << 12);
|
|
||||||
index = (va >> 12) & 0x000003ff;
|
|
||||||
|
|
||||||
if(pt[index].v)
|
|
||||||
panic("map_tmap: va 0x%x already mapped to pa 0x%x\n", va, pt[index].ppn << 12);
|
|
||||||
|
|
||||||
// insert the mapping
|
|
||||||
pt[index].wt = 0;
|
|
||||||
pt[index].pr = (lock & LOCK_KERNEL) ? (lock & 0x1) : (lock | 0x2);
|
|
||||||
pt[index].ppn = pa >> 12;
|
|
||||||
pt[index].tlb_ent = 0;
|
|
||||||
pt[index].c = 1;
|
|
||||||
pt[index].sz = 0x1; // 4k page
|
|
||||||
pt[index].sh = 0;
|
|
||||||
pt[index].d = 0;
|
|
||||||
pt[index].v = 1;
|
|
||||||
|
|
||||||
sh4_invl_page(va);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int unmap_tmap(vm_translation_map *map, addr start, addr end)
|
|
||||||
{
|
|
||||||
struct pdent *pd;
|
|
||||||
struct ptent *pt;
|
|
||||||
unsigned int index;
|
|
||||||
|
|
||||||
start = ROUNDOWN(start, PAGE_SIZE);
|
|
||||||
end = ROUNDUP(end, PAGE_SIZE);
|
|
||||||
|
|
||||||
#if CHATTY_TMAP
|
|
||||||
dprintf("unmap_tmap: asked to free pages 0x%x to 0x%x\n", start, end);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
for(; start < end; start += PAGE_SIZE) {
|
|
||||||
if(map->arch_data->is_user) {
|
|
||||||
if(start >= P1_AREA) {
|
|
||||||
// invalid
|
|
||||||
panic("unmap_tmap: asked to unmap va 0x%x in user space aspace\n", start);
|
|
||||||
}
|
|
||||||
pd = (struct pdent *)map->arch_data->pgdir_phys;
|
|
||||||
index = start >> 22;
|
|
||||||
} else {
|
|
||||||
if(start < P3_AREA && start >= P4_AREA) {
|
|
||||||
panic("unmap_tmap: asked to unmap va 0x%x in kernel space aspace\n", start);
|
|
||||||
}
|
|
||||||
pd = (struct pdent *)vcpu->kernel_pgdir;
|
|
||||||
index = (start & 0x7fffffff) >> 22;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(pd[index].v == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// get the pagetable
|
|
||||||
pt = (struct ptent *)PHYS_TO_P1(pd[index].ppn << 12);
|
|
||||||
index = (start >> 12) & 0x000003ff;
|
|
||||||
|
|
||||||
if(pt[index].v == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
pt[index].v = 0;
|
|
||||||
|
|
||||||
sh4_invl_page(start);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int query_tmap(vm_translation_map *map, addr va, addr *out_physical, unsigned int *out_flags)
|
|
||||||
{
|
|
||||||
struct pdent *pd;
|
|
||||||
struct ptent *pt;
|
|
||||||
unsigned int index;
|
|
||||||
|
|
||||||
// default the flags to not present
|
|
||||||
*out_flags = 0;
|
|
||||||
*out_physical = 0;
|
|
||||||
|
|
||||||
if(map->arch_data->is_user) {
|
|
||||||
if(va >= P1_AREA) {
|
|
||||||
// invalid
|
|
||||||
return ERR_VM_GENERAL;
|
|
||||||
}
|
|
||||||
pd = (struct pdent *)map->arch_data->pgdir_phys;
|
|
||||||
index = va >> 22;
|
|
||||||
} else {
|
|
||||||
if(va < P3_AREA && va >= P4_AREA) {
|
|
||||||
return ERR_VM_GENERAL;
|
|
||||||
}
|
|
||||||
pd = (struct pdent *)vcpu->kernel_pgdir;
|
|
||||||
index = (va & 0x7fffffff) >> 22;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(pd[index].v == 0) {
|
|
||||||
return NO_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the pagetable
|
|
||||||
pt = (struct ptent *)PHYS_TO_P1(pd[index].ppn << 12);
|
|
||||||
index = (va >> 12) & 0x000003ff;
|
|
||||||
|
|
||||||
*out_physical = pt[index].ppn << 12;
|
|
||||||
|
|
||||||
// read in the page state flags, clearing the modified and accessed flags in the process
|
|
||||||
*out_flags = 0;
|
|
||||||
*out_flags |= (pt[index].pr & 0x1) ? LOCK_RW : LOCK_RO;
|
|
||||||
*out_flags |= (pt[index].pr & 0x2) ? 0 : LOCK_KERNEL;
|
|
||||||
*out_flags |= pt[index].d ? PAGE_MODIFIED : 0;
|
|
||||||
// *out_flags |= pt[index].accessed ? PAGE_ACCESSED : 0; // not emulating the accessed bit yet
|
|
||||||
*out_flags |= pt[index].v ? PAGE_PRESENT : 0;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static addr get_mapped_size_tmap(vm_translation_map *map)
|
|
||||||
{
|
|
||||||
return map->map_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int protect_tmap(vm_translation_map *map, addr base, addr top, unsigned int attributes)
|
|
||||||
{
|
|
||||||
// XXX finish
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int clear_flags_tmap(vm_translation_map *map, addr va, unsigned int flags)
|
|
||||||
{
|
|
||||||
struct pdent *pd;
|
|
||||||
struct ptent *pt;
|
|
||||||
unsigned int index;
|
|
||||||
int tlb_flush = false;
|
|
||||||
|
|
||||||
if(map->arch_data->is_user) {
|
|
||||||
if(va >= P1_AREA) {
|
|
||||||
// invalid
|
|
||||||
return ERR_VM_GENERAL;
|
|
||||||
}
|
|
||||||
pd = (struct pdent *)map->arch_data->pgdir_phys;
|
|
||||||
index = va >> 22;
|
|
||||||
} else {
|
|
||||||
if(va < P3_AREA && va >= P4_AREA) {
|
|
||||||
return ERR_VM_GENERAL;
|
|
||||||
}
|
|
||||||
pd = (struct pdent *)vcpu->kernel_pgdir;
|
|
||||||
index = (va & 0x7fffffff) >> 22;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(pd[index].v == 0) {
|
|
||||||
return NO_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the pagetable
|
|
||||||
pt = (struct ptent *)PHYS_TO_P1(pd[index].ppn << 12);
|
|
||||||
index = (va >> 12) & 0x000003ff;
|
|
||||||
|
|
||||||
// clear out the flags we've been requested to clear
|
|
||||||
if(flags & PAGE_MODIFIED) {
|
|
||||||
pt[index].d = 0;
|
|
||||||
tlb_flush = true;
|
|
||||||
}
|
|
||||||
if(flags & PAGE_ACCESSED) {
|
|
||||||
// pt[index].accessed = 0;
|
|
||||||
// tlb_flush = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(tlb_flush)
|
|
||||||
sh4_invl_page(va);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void flush_tmap(vm_translation_map *map)
|
|
||||||
{
|
|
||||||
// no-op, we aren't caching any tlb invalidations
|
|
||||||
}
|
|
||||||
|
|
||||||
static int get_physical_page_tmap(addr pa, addr *va, int flags)
|
|
||||||
{
|
|
||||||
if(pa >= PHYS_ADDR_SIZE)
|
|
||||||
panic("get_physical_page_tmap: passed invalid address 0x%x\n", pa);
|
|
||||||
*va = PHYS_ADDR_TO_P1(pa);
|
|
||||||
return NO_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int put_physical_page_tmap(addr va)
|
|
||||||
{
|
|
||||||
if(va < P1_AREA && va >= P2_AREA)
|
|
||||||
panic("put_physical_page_tmap: bad address passed 0x%x\n", va);
|
|
||||||
return NO_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
static vm_translation_map_ops tmap_ops = {
|
|
||||||
destroy_tmap,
|
|
||||||
lock_tmap,
|
|
||||||
unlock_tmap,
|
|
||||||
map_tmap,
|
|
||||||
unmap_tmap,
|
|
||||||
query_tmap,
|
|
||||||
get_mapped_size_tmap,
|
|
||||||
protect_tmap,
|
|
||||||
clear_flags_tmap,
|
|
||||||
flush_tmap,
|
|
||||||
get_physical_page_tmap,
|
|
||||||
put_physical_page_tmap
|
|
||||||
};
|
|
||||||
|
|
||||||
int vm_translation_map_create(vm_translation_map *new_map, bool kernel)
|
|
||||||
{
|
|
||||||
if(new_map == NULL)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
// initialize the new object
|
|
||||||
new_map->ops = &tmap_ops;
|
|
||||||
new_map->map_count = 0;
|
|
||||||
if(recursive_lock_create(&new_map->lock) < 0)
|
|
||||||
return ERR_NO_MEMORY;
|
|
||||||
|
|
||||||
new_map->arch_data = kmalloc(sizeof(vm_translation_map_arch_info));
|
|
||||||
if(new_map == NULL)
|
|
||||||
panic("error allocating translation map object!\n");
|
|
||||||
|
|
||||||
if(!kernel) {
|
|
||||||
// user
|
|
||||||
// allocate a pgdir
|
|
||||||
new_map->arch_data->pgdir_virt = (addr)kmalloc(PAGE_SIZE);
|
|
||||||
if(new_map->arch_data->pgdir_virt == NULL) {
|
|
||||||
kfree(new_map->arch_data);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if(((addr)new_map->arch_data->pgdir_virt % PAGE_SIZE) != 0)
|
|
||||||
panic("vm_translation_map_create: malloced pgdir and found it wasn't aligned!\n");
|
|
||||||
vm_get_page_mapping(vm_get_kernel_aspace_id(), (addr)new_map->arch_data->pgdir_virt, (addr *)&new_map->arch_data->pgdir_phys);
|
|
||||||
new_map->arch_data->pgdir_phys = PHYS_TO_P1(new_map->arch_data->pgdir_phys);
|
|
||||||
// zero out the new pgdir
|
|
||||||
memset((void *)new_map->arch_data->pgdir_virt, 0, PAGE_SIZE);
|
|
||||||
new_map->arch_data->is_user = true;
|
|
||||||
} else {
|
|
||||||
// kernel
|
|
||||||
// we already know the kernel pgdir mapping
|
|
||||||
(addr)new_map->arch_data->pgdir_virt = NULL;
|
|
||||||
(addr)new_map->arch_data->pgdir_phys = vcpu->kernel_pgdir;
|
|
||||||
new_map->arch_data->is_user = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int vm_translation_map_module_init(kernel_args *ka)
|
|
||||||
{
|
|
||||||
vcpu = ka->arch_args.vcpu;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int vm_translation_map_module_init2(kernel_args *ka)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void vm_translation_map_module_init_post_sem(kernel_args *ka)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
// XXX horrible back door to map a page quickly regardless of translation map object, etc.
|
|
||||||
// used only during VM setup
|
|
||||||
int vm_translation_map_quick_map(kernel_args *ka, addr va, addr pa, unsigned int lock, addr (*get_free_page)(kernel_args *))
|
|
||||||
{
|
|
||||||
struct pdent *pd = NULL;
|
|
||||||
struct ptent *pt;
|
|
||||||
unsigned int index;
|
|
||||||
|
|
||||||
#if CHATTY_TMAP
|
|
||||||
dprintf("quick_tmap: va 0x%x pa 0x%x lock 0x%x\n", va, pa, lock);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if(va < P3_AREA && va >= P4_AREA) {
|
|
||||||
panic("quick_tmap: asked to map invalid va 0x%x\n", va);
|
|
||||||
}
|
|
||||||
pd = (struct pdent *)vcpu->kernel_pgdir;
|
|
||||||
index = (va & 0x7fffffff) >> 22;
|
|
||||||
|
|
||||||
if(pd[index].v == 0) {
|
|
||||||
vm_page *page;
|
|
||||||
unsigned int pgtable;
|
|
||||||
|
|
||||||
pgtable = (*get_free_page)(ka) * PAGE_SIZE;
|
|
||||||
|
|
||||||
memset((void *)PHYS_TO_P1(pgtable), 0, PAGE_SIZE);
|
|
||||||
|
|
||||||
pd[index].ppn = pgtable >> 12;
|
|
||||||
pd[index].v = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the pagetable
|
|
||||||
pt = (struct ptent *)PHYS_TO_P1(pd[index].ppn << 12);
|
|
||||||
index = (va >> 12) & 0x000003ff;
|
|
||||||
|
|
||||||
// insert the mapping
|
|
||||||
pt[index].wt = 0;
|
|
||||||
pt[index].pr = (lock & LOCK_KERNEL) ? (lock & 0x1) : (lock | 0x2);
|
|
||||||
pt[index].ppn = pa >> 12;
|
|
||||||
pt[index].tlb_ent = 0;
|
|
||||||
pt[index].c = 1;
|
|
||||||
pt[index].sz = 0x1; // 4k page
|
|
||||||
pt[index].sh = 0;
|
|
||||||
pt[index].d = 0;
|
|
||||||
pt[index].v = 1;
|
|
||||||
|
|
||||||
sh4_invl_page(va);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
addr vm_translation_map_get_pgdir(vm_translation_map *map)
|
|
||||||
{
|
|
||||||
return (addr)map->arch_data->pgdir_phys;
|
|
||||||
}
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
OUTPUT_FORMAT("elf32-shl", "elf32-shl", "elf32-shl")
|
|
||||||
OUTPUT_ARCH(sh)
|
|
||||||
|
|
||||||
ENTRY(__start)
|
|
||||||
SEARCH_DIR("libgcc");
|
|
||||||
SECTIONS
|
|
||||||
{
|
|
||||||
. = 0xc0000000 + SIZEOF_HEADERS;
|
|
||||||
|
|
||||||
.interp : { *(.interp) }
|
|
||||||
.hash : { *(.hash) }
|
|
||||||
.dynsym : { *(.dynsym) }
|
|
||||||
.dynstr : { *(.dynstr) }
|
|
||||||
.rel.text : { *(.rel.text) *(.rel.gnu.linkonce.t*) }
|
|
||||||
.rela.text : { *(.rela.text) *(.rela.gnu.linkonce.t*) }
|
|
||||||
.rel.data : { *(.rel.data) *(.rel.gnu.linkonce.d*) }
|
|
||||||
.rela.data : { *(.rela.data) *(.rela.gnu.linkonce.d*) }
|
|
||||||
.rel.rodata : { *(.rel.rodata) *(.rel.gnu.linkonce.r*) }
|
|
||||||
.rela.rodata : { *(.rela.rodata) *(.rela.gnu.linkonce.r*) }
|
|
||||||
.rel.got : { *(.rel.got) }
|
|
||||||
.rela.got : { *(.rela.got) }
|
|
||||||
.rel.ctors : { *(.rel.ctors) }
|
|
||||||
.rela.ctors : { *(.rela.ctors) }
|
|
||||||
.rel.dtors : { *(.rel.dtors) }
|
|
||||||
.rela.dtors : { *(.rela.dtors) }
|
|
||||||
.rel.init : { *(.rel.init) }
|
|
||||||
.rela.init : { *(.rela.init) }
|
|
||||||
.rel.fini : { *(.rel.fini) }
|
|
||||||
.rela.fini : { *(.rela.fini) }
|
|
||||||
.rel.bss : { *(.rel.bss) }
|
|
||||||
.rela.bss : { *(.rela.bss) }
|
|
||||||
.rel.plt : { *(.rel.plt) }
|
|
||||||
.rela.plt : { *(.rela.plt) }
|
|
||||||
.init : { *(.init) } =0x9090
|
|
||||||
.plt : { *(.plt) }
|
|
||||||
|
|
||||||
/* text/read-only data */
|
|
||||||
.text : { *(.text .gnu.linkonce.t.*) } =0x9090
|
|
||||||
|
|
||||||
.rodata :
|
|
||||||
{
|
|
||||||
*(.rodata)
|
|
||||||
. = ALIGN(0x1000);
|
|
||||||
} =0x9000
|
|
||||||
|
|
||||||
/* writable data */
|
|
||||||
. = ALIGN(0x1000);
|
|
||||||
___data_start = .;
|
|
||||||
.data : { *(.data .gnu.linkonce.d.*) }
|
|
||||||
|
|
||||||
___ctor_list = .;
|
|
||||||
.ctors : { *(.ctors) }
|
|
||||||
___ctor_end = .;
|
|
||||||
___dtor_list = .;
|
|
||||||
.dtors : { *(.dtors) }
|
|
||||||
___dtor_end = .;
|
|
||||||
.got : { *(.got.plt) *(.got) }
|
|
||||||
.dynamic : { *(.dynamic) }
|
|
||||||
|
|
||||||
/* unintialized data (in same segment as writable data) */
|
|
||||||
___bss_start = .;
|
|
||||||
.bss : { *(.bss) }
|
|
||||||
|
|
||||||
. = ALIGN(0x1000);
|
|
||||||
_end = . ;
|
|
||||||
|
|
||||||
/* Strip unnecessary stuff */
|
|
||||||
/DISCARD/ : { *(.comment .note .eh_frame) }
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
# sparc kernel makefile
|
|
||||||
# included from kernel.mk
|
|
||||||
KERNEL_ARCH_OBJ_DIR = $(KERNEL_ARCH_DIR)/$(OBJ_DIR)
|
|
||||||
KERNEL_OBJS += \
|
|
||||||
|
|
||||||
KERNEL_ARCH_INCLUDES = $(KERNEL_INCLUDES)
|
|
||||||
|
|
||||||
$(KERNEL_ARCH_OBJ_DIR)/%.o: $(KERNEL_ARCH_DIR)/%.c
|
|
||||||
@mkdir -p $(KERNEL_ARCH_OBJ_DIR)
|
|
||||||
$(CC) -c $< $(GLOBAL_CFLAGS) $(KERNEL_ARCH_INCLUDES) -o $@
|
|
||||||
|
|
||||||
$(KERNEL_ARCH_OBJ_DIR)/%.d: $(KERNEL_ARCH_DIR)/%.c
|
|
||||||
@mkdir -p $(KERNEL_ARCH_OBJ_DIR)
|
|
||||||
@echo "making deps for $<..."
|
|
||||||
@(echo -n $(dir $@); $(CC) $(GLOBAL_CFLAGS) $(KERNEL_ARCH_INCLUDES) -M -MG $<) > $@
|
|
||||||
|
|
||||||
$(KERNEL_ARCH_OBJ_DIR)/%.d: $(KERNEL_ARCH_DIR)/%.S
|
|
||||||
@mkdir -p $(KERNEL_ARCH_OBJ_DIR)
|
|
||||||
@echo "making deps for $<..."
|
|
||||||
@(echo -n $(dir $@);$(CC) $(GLOBAL_CFLAGS) $(KERNEL_ARCH_INCLUDES) -M -MG $<) > $@
|
|
||||||
|
|
||||||
$(KERNEL_ARCH_OBJ_DIR)/%.o: $(KERNEL_ARCH_DIR)/%.S
|
|
||||||
@mkdir -p $(KERNEL_ARCH_OBJ_DIR)
|
|
||||||
$(CC) -c $< $(GLOBAL_CFLAGS) $(KERNEL_ARCH_INCLUDES) -o $@
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
# sparc64 kernel makefile
|
|
||||||
# included from kernel.mk
|
|
||||||
KERNEL_ARCH_OBJ_DIR = $(KERNEL_ARCH_DIR)/$(OBJ_DIR)
|
|
||||||
KERNEL_OBJS += \
|
|
||||||
|
|
||||||
KERNEL_ARCH_INCLUDES = $(KERNEL_INCLUDES)
|
|
||||||
|
|
||||||
$(KERNEL_ARCH_OBJ_DIR)/%.o: $(KERNEL_ARCH_DIR)/%.c
|
|
||||||
@mkdir -p $(KERNEL_ARCH_OBJ_DIR)
|
|
||||||
$(CC) -c $< $(GLOBAL_CFLAGS) $(KERNEL_ARCH_INCLUDES) -o $@
|
|
||||||
|
|
||||||
$(KERNEL_ARCH_OBJ_DIR)/%.d: $(KERNEL_ARCH_DIR)/%.c
|
|
||||||
@mkdir -p $(KERNEL_ARCH_OBJ_DIR)
|
|
||||||
@echo "making deps for $<..."
|
|
||||||
@($(ECHO) -n $(dir $@); $(CC) $(GLOBAL_CFLAGS) $(KERNEL_ARCH_INCLUDES) -M -MG $<) > $@
|
|
||||||
|
|
||||||
$(KERNEL_ARCH_OBJ_DIR)/%.d: $(KERNEL_ARCH_DIR)/%.S
|
|
||||||
@mkdir -p $(KERNEL_ARCH_OBJ_DIR)
|
|
||||||
@echo "making deps for $<..."
|
|
||||||
@($(ECHO) -n $(dir $@);$(CC) $(GLOBAL_CFLAGS) $(KERNEL_ARCH_INCLUDES) -M -MG $<) > $@
|
|
||||||
|
|
||||||
$(KERNEL_ARCH_OBJ_DIR)/%.o: $(KERNEL_ARCH_DIR)/%.S
|
|
||||||
@mkdir -p $(KERNEL_ARCH_OBJ_DIR)
|
|
||||||
$(CC) -c $< $(GLOBAL_CFLAGS) $(KERNEL_ARCH_INCLUDES) -o $@
|
|
||||||
Reference in New Issue
Block a user