ARM support for kernel and vm
This commit is contained in:
parent
e35c4f78d2
commit
471a03a362
57 changed files with 5648 additions and 12 deletions
|
@ -116,7 +116,14 @@ arm/vm.h
|
|||
*/
|
||||
#define ARM_VM_PFE_TLB_CONFLICT 0x10 /* Caused by TLB conflict abort
|
||||
*/
|
||||
#define ARM_VM_PFE_W (1<<11) /* Caused by write (otherwise read) */
|
||||
|
||||
#define ARM_VM_PFE_W (1<<11) /* Caused by write (otherwise read) */
|
||||
#define ARM_VM_PFE_FS4 (1<<10) /* Fault status (bit 4) */
|
||||
#define ARM_VM_PFE_FS3_0 0xf /* Fault status (bits 3:0) */
|
||||
|
||||
/* Fault status */
|
||||
#define ARM_VM_PFE_FS(s) \
|
||||
((((s) & ARM_VM_PFE_FS4) >> 6) | ((s) & ARM_VM_PFE_FS3_0))
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
|
|
58
kernel/arch/arm/Makefile.inc
Normal file
58
kernel/arch/arm/Makefile.inc
Normal file
|
@ -0,0 +1,58 @@
|
|||
|
||||
# Makefile for arch-dependent kernel code
|
||||
.include <bsd.own.mk>
|
||||
|
||||
HERE=${.CURDIR}/arch/${MACHINE_ARCH}
|
||||
.PATH: ${HERE}
|
||||
|
||||
# objects we want unpaged from -lminlib, -lminc
|
||||
MINLIB_OBJS_UNPAGED=get_bp.o
|
||||
MINC_OBJS_UNPAGED=strcat.o strlen.o memcpy.o strcpy.o strncmp.o memset.o \
|
||||
memmove.o strcmp.o atoi.o ctype_.o _stdfile.o strtol.o _errno.o errno.o
|
||||
# udivdi3.o umoddi3.o qdivrem.o
|
||||
SYS_OBJS_UNPAGED=kprintf.o vprintf.o assert.o stacktrace.o
|
||||
LIBGCC_OBJS_UNPAGED=_divsi3.o _udivsi3.o _divdi3.o _udivdi3.o _umoddi3.o \
|
||||
_dvmd_tls.o _aeabi_uldivmod.o _clzsi2.o bpabi.o
|
||||
|
||||
# some object files we give a symbol prefix (or namespace) of __k_unpaged_
|
||||
# that must live in their own unique namespace.
|
||||
#
|
||||
.for UNPAGED_OBJ in head.o pre_init.o direct_tty_utils.o \
|
||||
pg_utils.o klib.o omap_serial.o utility.o arch_reset.o \
|
||||
$(MINLIB_OBJS_UNPAGED) $(MINC_OBJS_UNPAGED) $(SYS_OBJS_UNPAGED) $(LIBGCC_OBJS_UNPAGED)
|
||||
unpaged_${UNPAGED_OBJ}: ${UNPAGED_OBJ}
|
||||
${OBJCOPY} --prefix-symbols=__k_unpaged_ ${UNPAGED_OBJ} unpaged_${UNPAGED_OBJ}
|
||||
UNPAGED_OBJS += unpaged_${UNPAGED_OBJ}
|
||||
ORIG_UNPAGED_OBJS += ${UNPAGED_OBJ}
|
||||
.endfor
|
||||
|
||||
# we have to extract some object files from libminc.a and libminlib.a
|
||||
$(MINLIB_OBJS_UNPAGED) $(MINC_OBJS_UNPAGED) $(SYS_OBJS_UNPAGED) $(LIBGCC_OBJS_UNPAGED): $(LIBMINLIB) $(LIBMINC) $(LIBSYS) $(LIBGCC)
|
||||
${AR} x $(LIBMINLIB) $(MINLIB_OBJS_UNPAGED)
|
||||
${AR} x $(LIBMINC) $(MINC_OBJS_UNPAGED)
|
||||
${AR} x $(LIBSYS) $(SYS_OBJS_UNPAGED)
|
||||
${AR} x $(LIBGCC) $(LIBGCC_OBJS_UNPAGED)
|
||||
|
||||
CLEANFILES+= $(ORIG_UNPAGED_OBJS)
|
||||
|
||||
SRCS+= mpx.S arch_clock.c arch_do_vmctl.c arch_system.c \
|
||||
omap_serial.c omap_timer.c omap_intr.c exception.c \
|
||||
io_intr.S klib.S memory.c \
|
||||
protect.c direct_tty_utils.c arch_reset.c \
|
||||
pg_utils.c phys_copy.S phys_memset.S exc.S
|
||||
OBJS.kernel+= ${UNPAGED_OBJS}
|
||||
|
||||
klib.d mpx.d head.d: procoffsets.h
|
||||
|
||||
# It's OK to hardcode the arch as arm here as this and procoffsets.cf
|
||||
# are arm-specific.
|
||||
TMP=procoffsets.h.tmp
|
||||
INCLS=../include/arch/arm/include/
|
||||
PROCOFFSETSCF=procoffsets.cf
|
||||
|
||||
procoffsets.h: $(PROCOFFSETSCF) kernel.h proc.h $(INCLS)/stackframe.h $(INCLS)/archtypes.h
|
||||
${_MKTARGET_CREATE}
|
||||
cat ${HERE}/$(PROCOFFSETSCF) | \
|
||||
${TOOL_GENASSYM} -- ${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} >$TMP && \
|
||||
mv -f $TMP $@
|
||||
|
141
kernel/arch/arm/arch_clock.c
Normal file
141
kernel/arch/arm/arch_clock.c
Normal file
|
@ -0,0 +1,141 @@
|
|||
|
||||
/* ARM-specific clock functions. */
|
||||
|
||||
#include "kernel/kernel.h"
|
||||
|
||||
#include "kernel/clock.h"
|
||||
#include "kernel/proc.h"
|
||||
#include "kernel/interrupt.h"
|
||||
#include <minix/u64.h>
|
||||
#include "glo.h"
|
||||
#include "profile.h"
|
||||
|
||||
|
||||
#include "spinlock.h"
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
#include "kernel/smp.h"
|
||||
#endif
|
||||
|
||||
#include "omap_timer.h"
|
||||
#include "omap_intr.h"
|
||||
|
||||
static unsigned tsc_per_ms[CONFIG_MAX_CPUS];
|
||||
|
||||
int init_local_timer(unsigned freq)
|
||||
{
|
||||
omap3_timer_init(freq);
|
||||
/* always only 1 cpu in the system */
|
||||
tsc_per_ms[0] = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void stop_local_timer(void)
|
||||
{
|
||||
omap3_timer_stop();
|
||||
}
|
||||
|
||||
void arch_timer_int_handler(void)
|
||||
{
|
||||
omap3_timer_int_handler();
|
||||
}
|
||||
|
||||
void cycles_accounting_init(void)
|
||||
{
|
||||
read_tsc_64(get_cpu_var_ptr(cpu, tsc_ctr_switch));
|
||||
|
||||
make_zero64(get_cpu_var(cpu, cpu_last_tsc));
|
||||
make_zero64(get_cpu_var(cpu, cpu_last_idle));
|
||||
}
|
||||
|
||||
void context_stop(struct proc * p)
|
||||
{
|
||||
u64_t tsc, tsc_delta;
|
||||
u64_t * __tsc_ctr_switch = get_cpulocal_var_ptr(tsc_ctr_switch);
|
||||
|
||||
read_tsc_64(&tsc);
|
||||
p->p_cycles = add64(p->p_cycles, sub64(tsc, *__tsc_ctr_switch));
|
||||
|
||||
tsc_delta = sub64(tsc, *__tsc_ctr_switch);
|
||||
|
||||
if(kbill_ipc) {
|
||||
kbill_ipc->p_kipc_cycles =
|
||||
add64(kbill_ipc->p_kipc_cycles, tsc_delta);
|
||||
kbill_ipc = NULL;
|
||||
}
|
||||
|
||||
if(kbill_kcall) {
|
||||
kbill_kcall->p_kcall_cycles =
|
||||
add64(kbill_kcall->p_kcall_cycles, tsc_delta);
|
||||
kbill_kcall = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* deduct the just consumed cpu cycles from the cpu time left for this
|
||||
* process during its current quantum. Skip IDLE and other pseudo kernel
|
||||
* tasks
|
||||
*/
|
||||
if (p->p_endpoint >= 0) {
|
||||
#if DEBUG_RACE
|
||||
make_zero64(p->p_cpu_time_left);
|
||||
#else
|
||||
/* if (tsc_delta < p->p_cpu_time_left) in 64bit */
|
||||
if (ex64hi(tsc_delta) < ex64hi(p->p_cpu_time_left) ||
|
||||
(ex64hi(tsc_delta) == ex64hi(p->p_cpu_time_left) &&
|
||||
ex64lo(tsc_delta) < ex64lo(p->p_cpu_time_left)))
|
||||
{
|
||||
p->p_cpu_time_left = sub64(p->p_cpu_time_left, tsc_delta);
|
||||
}
|
||||
else {
|
||||
make_zero64(p->p_cpu_time_left);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
*__tsc_ctr_switch = tsc;
|
||||
}
|
||||
|
||||
void context_stop_idle(void)
|
||||
{
|
||||
int is_idle;
|
||||
#ifdef CONFIG_SMP
|
||||
unsigned cpu = cpuid;
|
||||
#endif
|
||||
|
||||
is_idle = get_cpu_var(cpu, cpu_is_idle);
|
||||
get_cpu_var(cpu, cpu_is_idle) = 0;
|
||||
|
||||
context_stop(get_cpulocal_var_ptr(idle_proc));
|
||||
|
||||
if (is_idle)
|
||||
restart_local_timer();
|
||||
#if SPROFILE
|
||||
if (sprofiling)
|
||||
get_cpulocal_var(idle_interrupted) = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
void restart_local_timer(void)
|
||||
{
|
||||
}
|
||||
|
||||
int register_local_timer_handler(const irq_handler_t handler)
|
||||
{
|
||||
return omap3_register_timer_handler(handler);
|
||||
}
|
||||
|
||||
u64_t ms_2_cpu_time(unsigned ms)
|
||||
{
|
||||
return mul64u(tsc_per_ms[cpuid], ms);
|
||||
}
|
||||
|
||||
unsigned cpu_time_2_ms(u64_t cpu_time)
|
||||
{
|
||||
return div64u(cpu_time, tsc_per_ms[cpuid]);
|
||||
}
|
||||
|
||||
short cpu_load(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
58
kernel/arch/arm/arch_do_vmctl.c
Normal file
58
kernel/arch/arm/arch_do_vmctl.c
Normal file
|
@ -0,0 +1,58 @@
|
|||
/* The kernel call implemented in this file:
|
||||
* m_type: SYS_VMCTL
|
||||
*
|
||||
* The parameters for this kernel call are:
|
||||
* SVMCTL_WHO which process
|
||||
* SVMCTL_PARAM set this setting (VMCTL_*)
|
||||
* SVMCTL_VALUE to this value
|
||||
*/
|
||||
|
||||
#include "kernel/system.h"
|
||||
#include <assert.h>
|
||||
#include <minix/type.h>
|
||||
|
||||
#include "arch_proto.h"
|
||||
|
||||
static void set_ttbr(struct proc *p, u32_t ttbr, u32_t *v)
|
||||
{
|
||||
/* Set process TTBR. */
|
||||
p->p_seg.p_ttbr = ttbr;
|
||||
assert(p->p_seg.p_ttbr);
|
||||
p->p_seg.p_ttbr_v = v;
|
||||
if(p == get_cpulocal_var(ptproc)) {
|
||||
write_ttbr0(p->p_seg.p_ttbr);
|
||||
}
|
||||
if(p->p_nr == VM_PROC_NR) {
|
||||
if (arch_enable_paging(p) != OK)
|
||||
panic("arch_enable_paging failed");
|
||||
}
|
||||
RTS_UNSET(p, RTS_VMINHIBIT);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* arch_do_vmctl *
|
||||
*===========================================================================*/
|
||||
int arch_do_vmctl(m_ptr, p)
|
||||
register message *m_ptr; /* pointer to request message */
|
||||
struct proc *p;
|
||||
{
|
||||
switch(m_ptr->SVMCTL_PARAM) {
|
||||
case VMCTL_GET_PDBR:
|
||||
/* Get process page directory base reg (TTBR). */
|
||||
m_ptr->SVMCTL_VALUE = p->p_seg.p_ttbr;
|
||||
return OK;
|
||||
case VMCTL_SETADDRSPACE:
|
||||
set_ttbr(p, m_ptr->SVMCTL_PTROOT, (u32_t *) m_ptr->SVMCTL_PTROOT_V);
|
||||
return OK;
|
||||
case VMCTL_FLUSHTLB:
|
||||
{
|
||||
reload_ttbr0();
|
||||
return OK;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
printf("arch_do_vmctl: strange param %d\n", m_ptr->SVMCTL_PARAM);
|
||||
return EINVAL;
|
||||
}
|
45
kernel/arch/arm/arch_reset.c
Normal file
45
kernel/arch/arm/arch_reset.c
Normal file
|
@ -0,0 +1,45 @@
|
|||
|
||||
#include "kernel/kernel.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <machine/cpu.h>
|
||||
#include <assert.h>
|
||||
#include <signal.h>
|
||||
#include <machine/vm.h>
|
||||
|
||||
#include <minix/u64.h>
|
||||
|
||||
#include "archconst.h"
|
||||
#include "arch_proto.h"
|
||||
#include "serial.h"
|
||||
#include "kernel/proc.h"
|
||||
#include "kernel/debug.h"
|
||||
#include "direct_utils.h"
|
||||
#include <machine/multiboot.h>
|
||||
|
||||
void halt_cpu(void)
|
||||
{
|
||||
asm volatile("dsb");
|
||||
asm volatile("wfi");
|
||||
}
|
||||
|
||||
void
|
||||
reset(void)
|
||||
{
|
||||
while (1);
|
||||
}
|
||||
|
||||
__dead void arch_shutdown(int how)
|
||||
{
|
||||
while (1);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_SERIAL
|
||||
void ser_putc(char c)
|
||||
{
|
||||
omap3_ser_putc(c);
|
||||
}
|
||||
|
||||
#endif
|
182
kernel/arch/arm/arch_system.c
Normal file
182
kernel/arch/arm/arch_system.c
Normal file
|
@ -0,0 +1,182 @@
|
|||
/* system dependent functions for use inside the whole kernel. */
|
||||
|
||||
#include "kernel/kernel.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <minix/cpufeature.h>
|
||||
#include <assert.h>
|
||||
#include <signal.h>
|
||||
#include <machine/vm.h>
|
||||
|
||||
#include <minix/u64.h>
|
||||
|
||||
#include "archconst.h"
|
||||
#include "arch_proto.h"
|
||||
#include "serial.h"
|
||||
#include "kernel/proc.h"
|
||||
#include "kernel/debug.h"
|
||||
|
||||
#include "glo.h"
|
||||
|
||||
void * k_stacks;
|
||||
|
||||
static void ser_init(void);
|
||||
|
||||
void fpu_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
void save_local_fpu(struct proc *pr, int retain)
|
||||
{
|
||||
}
|
||||
|
||||
void save_fpu(struct proc *pr)
|
||||
{
|
||||
}
|
||||
|
||||
void arch_proc_reset(struct proc *pr)
|
||||
{
|
||||
assert(pr->p_nr < NR_PROCS);
|
||||
|
||||
/* Clear process state. */
|
||||
memset(&pr->p_reg, 0, sizeof(pr->p_reg));
|
||||
if(iskerneln(pr->p_nr))
|
||||
pr->p_reg.psr = INIT_TASK_PSR;
|
||||
else
|
||||
pr->p_reg.psr = INIT_PSR;
|
||||
}
|
||||
|
||||
void arch_proc_setcontext(struct proc *p, struct stackframe_s *state, int isuser)
|
||||
{
|
||||
}
|
||||
|
||||
void arch_set_secondary_ipc_return(struct proc *p, u32_t val)
|
||||
{
|
||||
p->p_reg.r1 = val;
|
||||
}
|
||||
|
||||
int restore_fpu(struct proc *pr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cpu_identify(void)
|
||||
{
|
||||
u32_t midr;
|
||||
unsigned cpu = cpuid;
|
||||
|
||||
asm volatile("mrc p15, 0, %[midr], c0, c0, 0 @ read MIDR\n\t"
|
||||
: [midr] "=r" (midr));
|
||||
|
||||
cpu_info[cpu].implementer = midr >> 24;
|
||||
cpu_info[cpu].variant = (midr >> 20) & 0xF;
|
||||
cpu_info[cpu].arch = (midr >> 16) & 0xF;
|
||||
cpu_info[cpu].part = (midr >> 4) & 0xFFF;
|
||||
cpu_info[cpu].revision = midr & 0xF;
|
||||
}
|
||||
|
||||
void arch_init(void)
|
||||
{
|
||||
k_stacks = (void*) &k_stacks_start;
|
||||
assert(!((vir_bytes) k_stacks % K_STACK_SIZE));
|
||||
|
||||
#ifndef CONFIG_SMP
|
||||
/*
|
||||
* use stack 0 and cpu id 0 on a single processor machine, SMP
|
||||
* configuration does this in smp_init() for all cpus at once
|
||||
*/
|
||||
tss_init(0, get_k_stack_top(0));
|
||||
#endif
|
||||
|
||||
ser_init();
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* do_ser_debug *
|
||||
*===========================================================================*/
|
||||
void do_ser_debug()
|
||||
{
|
||||
}
|
||||
|
||||
void arch_do_syscall(struct proc *proc)
|
||||
{
|
||||
/* do_ipc assumes that it's running because of the current process */
|
||||
assert(proc == get_cpulocal_var(proc_ptr));
|
||||
/* Make the system call, for real this time. */
|
||||
proc->p_reg.retreg =
|
||||
do_ipc(proc->p_reg.retreg, proc->p_reg.r1, proc->p_reg.r2);
|
||||
}
|
||||
|
||||
reg_t svc_stack;
|
||||
|
||||
struct proc * arch_finish_switch_to_user(void)
|
||||
{
|
||||
char * stk;
|
||||
struct proc * p;
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
stk = (char *)tss[cpuid].sp0;
|
||||
#else
|
||||
stk = (char *)tss[0].sp0;
|
||||
#endif
|
||||
svc_stack = (reg_t)stk;
|
||||
/* set pointer to the process to run on the stack */
|
||||
p = get_cpulocal_var(proc_ptr);
|
||||
*((reg_t *)stk) = (reg_t) p;
|
||||
|
||||
/* make sure I bit is clear in PSR so that interrupts won't be disabled
|
||||
* once p's context is restored. this should not be possible.
|
||||
*/
|
||||
assert(!(p->p_reg.psr & PSR_I));
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
void fpu_sigcontext(struct proc *pr, struct sigframe *fr, struct sigcontext *sc)
|
||||
{
|
||||
}
|
||||
|
||||
reg_t arch_get_sp(struct proc *p) { return p->p_reg.sp; }
|
||||
|
||||
void get_randomness(struct k_randomness *rand, int source)
|
||||
{
|
||||
}
|
||||
|
||||
static void ser_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
/*===========================================================================*/
|
||||
/* __switch_address_space */
|
||||
/*===========================================================================*/
|
||||
/*
|
||||
* sets the ttbr register to the supplied value if it is not already set to the
|
||||
* same value in which case it would only result in an extra TLB flush which is
|
||||
* not desirable
|
||||
*/
|
||||
void __switch_address_space(struct proc *p, struct proc **__ptproc)
|
||||
{
|
||||
reg_t orig_ttbr, new_ttbr;
|
||||
|
||||
new_ttbr = p->p_seg.p_ttbr;
|
||||
if (new_ttbr == 0)
|
||||
return;
|
||||
|
||||
orig_ttbr = read_ttbr0();
|
||||
|
||||
/*
|
||||
* test if ttbr is loaded with the current value to avoid unnecessary
|
||||
* TLB flushes
|
||||
*/
|
||||
if (new_ttbr == orig_ttbr)
|
||||
return;
|
||||
|
||||
refresh_tlb();
|
||||
write_ttbr0(new_ttbr);
|
||||
|
||||
*__ptproc = p;
|
||||
|
||||
return;
|
||||
}
|
42
kernel/arch/arm/direct_tty_utils.c
Normal file
42
kernel/arch/arm/direct_tty_utils.c
Normal file
|
@ -0,0 +1,42 @@
|
|||
|
||||
#include "kernel.h"
|
||||
#include <minix/minlib.h>
|
||||
#include <minix/const.h>
|
||||
#include <minix/cpufeature.h>
|
||||
#include <minix/types.h>
|
||||
#include <minix/type.h>
|
||||
#include <minix/com.h>
|
||||
#include <sys/param.h>
|
||||
#include <libexec.h>
|
||||
#include "string.h"
|
||||
#include "arch_proto.h"
|
||||
#include "libexec.h"
|
||||
#include "direct_utils.h"
|
||||
#include "serial.h"
|
||||
#include "glo.h"
|
||||
#include <machine/multiboot.h>
|
||||
|
||||
void direct_cls(void)
|
||||
{
|
||||
/* Do nothing */
|
||||
}
|
||||
|
||||
void direct_print_char(char c)
|
||||
{
|
||||
if(c == '\n')
|
||||
ser_putc('\r');
|
||||
ser_putc(c);
|
||||
}
|
||||
|
||||
void direct_print(const char *str)
|
||||
{
|
||||
while (*str) {
|
||||
direct_print_char(*str);
|
||||
str++;
|
||||
}
|
||||
}
|
||||
|
||||
int direct_read_char(unsigned char *ch)
|
||||
{
|
||||
return 0;
|
||||
}
|
22
kernel/arch/arm/exc.S
Normal file
22
kernel/arch/arm/exc.S
Normal file
|
@ -0,0 +1,22 @@
|
|||
#include <machine/asm.h>
|
||||
|
||||
IMPORT(undefined_inst_entry)
|
||||
IMPORT(svc_entry)
|
||||
IMPORT(prefetch_abort_entry)
|
||||
IMPORT(data_abort_entry)
|
||||
IMPORT(irq_entry)
|
||||
|
||||
.text
|
||||
.balign 4096
|
||||
LABEL(exc_vector_table)
|
||||
ldr pc, =invalid_exc /* Reset */
|
||||
ldr pc, =undefined_inst_entry /* Undefined Instruction */
|
||||
ldr pc, =svc_entry /* Supervisor Call */
|
||||
ldr pc, =prefetch_abort_entry /* Prefetch Abort */
|
||||
ldr pc, =data_abort_entry /* Data Abort */
|
||||
ldr pc, =invalid_exc /* Hypervisor Call */
|
||||
ldr pc, =irq_entry /* Interrupt */
|
||||
ldr pc, =invalid_exc /* Fast Interrupt */
|
||||
|
||||
ENTRY(invalid_exc)
|
||||
b .
|
223
kernel/arch/arm/exception.c
Normal file
223
kernel/arch/arm/exception.c
Normal file
|
@ -0,0 +1,223 @@
|
|||
/* This file contains a simple exception handler. Exceptions in user
|
||||
* processes are converted to signals. Exceptions in a kernel task cause
|
||||
* a panic.
|
||||
*/
|
||||
|
||||
#include "kernel/kernel.h"
|
||||
#include "arch_proto.h"
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "kernel/proc.h"
|
||||
#include "kernel/proto.h"
|
||||
#include <machine/vm.h>
|
||||
|
||||
struct ex_s {
|
||||
char *msg;
|
||||
int signum;
|
||||
};
|
||||
|
||||
static struct ex_s ex_data[] = {
|
||||
{ "Reset", 0},
|
||||
{ "Undefined instruction", SIGILL},
|
||||
{ "Supervisor call", 0},
|
||||
{ "Prefetch Abort", SIGILL},
|
||||
{ "Data Abort", SIGSEGV},
|
||||
{ "Hypervisor call", 0},
|
||||
{ "Interrupt", 0},
|
||||
{ "Fast Interrupt", 0},
|
||||
};
|
||||
|
||||
static void inkernel_disaster(struct proc *saved_proc,
|
||||
reg_t *saved_lr, struct ex_s *ep, int is_nested);
|
||||
|
||||
extern int catch_pagefaults;
|
||||
|
||||
static void proc_stacktrace_execute(struct proc *whichproc, reg_t v_bp, reg_t pc);
|
||||
|
||||
static void pagefault( struct proc *pr,
|
||||
reg_t *saved_lr,
|
||||
int is_nested)
|
||||
{
|
||||
int in_physcopy = 0, in_memset = 0;
|
||||
|
||||
reg_t pagefault_addr, pagefault_status;
|
||||
message m_pagefault;
|
||||
int err;
|
||||
|
||||
pagefault_addr = read_dfar();
|
||||
pagefault_status = read_dfsr();
|
||||
|
||||
#if 0
|
||||
printf("kernel: pagefault in pr %d, addr 0x%lx, his ttbr 0x%lx, actual ttbr 0x%lx\n",
|
||||
pr->p_endpoint, pagefault_addr, pr->p_seg.p_ttbr, read_ttbr0());
|
||||
#endif
|
||||
|
||||
in_physcopy = (*saved_lr > (vir_bytes) phys_copy) &&
|
||||
(*saved_lr < (vir_bytes) phys_copy_fault);
|
||||
|
||||
in_memset = (*saved_lr > (vir_bytes) phys_memset) &&
|
||||
(*saved_lr < (vir_bytes) memset_fault);
|
||||
|
||||
if((is_nested || iskernelp(pr)) &&
|
||||
catch_pagefaults && (in_physcopy || in_memset)) {
|
||||
#if 0
|
||||
printf("pf caught! addr 0x%lx\n", pagefault_addr);
|
||||
#endif
|
||||
if (is_nested) {
|
||||
if(in_physcopy) {
|
||||
assert(!in_memset);
|
||||
*saved_lr = (reg_t) phys_copy_fault_in_kernel;
|
||||
} else {
|
||||
*saved_lr = (reg_t) memset_fault_in_kernel;
|
||||
}
|
||||
}
|
||||
else {
|
||||
pr->p_reg.pc = (reg_t) phys_copy_fault;
|
||||
pr->p_reg.retreg = pagefault_addr;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if(is_nested) {
|
||||
printf("pagefault in kernel at pc 0x%lx address 0x%lx\n",
|
||||
*saved_lr, pagefault_addr);
|
||||
inkernel_disaster(pr, saved_lr, NULL, is_nested);
|
||||
}
|
||||
|
||||
/* VM can't handle page faults. */
|
||||
if(pr->p_endpoint == VM_PROC_NR) {
|
||||
/* Page fault we can't / don't want to
|
||||
* handle.
|
||||
*/
|
||||
printf("pagefault for VM on CPU %d, "
|
||||
"pc = 0x%x, addr = 0x%x, flags = 0x%x, is_nested %d\n",
|
||||
cpuid, pr->p_reg.pc, pagefault_addr, pagefault_status,
|
||||
is_nested);
|
||||
proc_stacktrace(pr);
|
||||
printf("pc of pagefault: 0x%lx\n", pr->p_reg.pc);
|
||||
panic("pagefault in VM");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Don't schedule this process until pagefault is handled. */
|
||||
RTS_SET(pr, RTS_PAGEFAULT);
|
||||
|
||||
/* tell Vm about the pagefault */
|
||||
m_pagefault.m_source = pr->p_endpoint;
|
||||
m_pagefault.m_type = VM_PAGEFAULT;
|
||||
m_pagefault.VPF_ADDR = pagefault_addr;
|
||||
m_pagefault.VPF_FLAGS = pagefault_status;
|
||||
|
||||
if ((err = mini_send(pr, VM_PROC_NR,
|
||||
&m_pagefault, FROM_KERNEL))) {
|
||||
panic("WARNING: pagefault: mini_send returned %d\n", err);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void inkernel_disaster(struct proc *saved_proc,
|
||||
reg_t *saved_lr, struct ex_s *ep,
|
||||
int is_nested)
|
||||
{
|
||||
#if USE_SYSDEBUG
|
||||
if(ep)
|
||||
printf("\n%s\n", ep->msg);
|
||||
|
||||
printf("cpu %d is_nested = %d ", cpuid, is_nested);
|
||||
|
||||
if (saved_proc) {
|
||||
printf("scheduled was: process %d (%s), ", saved_proc->p_endpoint, saved_proc->p_name);
|
||||
printf("pc = 0x%x\n", (unsigned) saved_proc->p_reg.pc);
|
||||
proc_stacktrace(saved_proc);
|
||||
|
||||
panic("Unhandled kernel exception");
|
||||
}
|
||||
|
||||
/* in an early stage of boot process we don't have processes yet */
|
||||
panic("exception in kernel while booting, no saved_proc yet");
|
||||
|
||||
#endif /* USE_SYSDEBUG */
|
||||
}
|
||||
|
||||
void exception_handler(int is_nested, reg_t *saved_lr, int vector)
|
||||
{
|
||||
/* An exception or unexpected interrupt has occurred. */
|
||||
struct ex_s *ep;
|
||||
struct proc *saved_proc;
|
||||
|
||||
saved_proc = get_cpulocal_var(proc_ptr);
|
||||
|
||||
ep = &ex_data[vector];
|
||||
|
||||
/*
|
||||
* handle special cases for nested problems as they might be tricky or filter
|
||||
* them out quickly if the traps are not nested
|
||||
*/
|
||||
if (is_nested) {
|
||||
/*
|
||||
* if a problem occured while copying a message from userspace because
|
||||
* of a wrong pointer supplied by userland, handle it the only way we
|
||||
* can handle it ...
|
||||
*/
|
||||
if (((void*)*saved_lr >= (void*)copy_msg_to_user &&
|
||||
(void*)*saved_lr <= (void*)__copy_msg_to_user_end) ||
|
||||
((void*)*saved_lr >= (void*)copy_msg_from_user &&
|
||||
(void*)*saved_lr <= (void*)__copy_msg_from_user_end)) {
|
||||
switch(vector) {
|
||||
/* these error are expected */
|
||||
case DATA_ABORT_VECTOR:
|
||||
*saved_lr = (reg_t) __user_copy_msg_pointer_failure;
|
||||
return;
|
||||
default:
|
||||
panic("Copy involving a user pointer failed unexpectedly!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (vector == DATA_ABORT_VECTOR) {
|
||||
pagefault(saved_proc, saved_lr, is_nested);
|
||||
return;
|
||||
}
|
||||
|
||||
/* If an exception occurs while running a process, the is_nested variable
|
||||
* will be zero. Exceptions in interrupt handlers or system traps will make
|
||||
* is_nested non-zero.
|
||||
*/
|
||||
if (is_nested == 0 && ! iskernelp(saved_proc)) {
|
||||
cause_sig(proc_nr(saved_proc), ep->signum);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Exception in system code. This is not supposed to happen. */
|
||||
inkernel_disaster(saved_proc, saved_lr, ep, is_nested);
|
||||
|
||||
panic("return from inkernel_disaster");
|
||||
}
|
||||
|
||||
#if USE_SYSDEBUG
|
||||
/*===========================================================================*
|
||||
* proc_stacktrace_execute *
|
||||
*===========================================================================*/
|
||||
static void proc_stacktrace_execute(struct proc *whichproc, reg_t v_bp, reg_t pc)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
void proc_stacktrace(struct proc *whichproc)
|
||||
{
|
||||
#if USE_SYSDEBUG
|
||||
proc_stacktrace_execute(whichproc, whichproc->p_reg.fp, whichproc->p_reg.pc);
|
||||
#endif /* USE_SYSDEBUG */
|
||||
}
|
||||
|
||||
void enable_fpu_exception(void)
|
||||
{
|
||||
}
|
||||
|
||||
void disable_fpu_exception(void)
|
||||
{
|
||||
}
|
9
kernel/arch/arm/glo.h
Normal file
9
kernel/arch/arm/glo.h
Normal file
|
@ -0,0 +1,9 @@
|
|||
#ifndef __GLO_ARM_H__
|
||||
#define __GLO_ARM_H__
|
||||
|
||||
#include "kernel/kernel.h"
|
||||
#include "arch_proto.h"
|
||||
|
||||
EXTERN struct tss_s tss[CONFIG_MAX_CPUS];
|
||||
|
||||
#endif /* __GLO_ARM_H__ */
|
53
kernel/arch/arm/head.S
Normal file
53
kernel/arch/arm/head.S
Normal file
|
@ -0,0 +1,53 @@
|
|||
#include "kernel/kernel.h" /* configures the kernel */
|
||||
|
||||
/* sections */
|
||||
|
||||
#include <machine/vm.h>
|
||||
#include "../../kernel.h"
|
||||
#include <minix/config.h>
|
||||
#include <minix/const.h>
|
||||
#include <minix/com.h>
|
||||
#include <machine/asm.h>
|
||||
#include <machine/interrupt.h>
|
||||
#include "archconst.h"
|
||||
#include "kernel/const.h"
|
||||
#include "kernel/proc.h"
|
||||
#include "sconst.h"
|
||||
#include <machine/multiboot.h>
|
||||
#include <machine/cpu.h>
|
||||
|
||||
#include "arch_proto.h" /* K_STACK_SIZE */
|
||||
|
||||
.text
|
||||
/*===========================================================================*/
|
||||
/* MINIX */
|
||||
/*===========================================================================*/
|
||||
.global MINIX
|
||||
MINIX:
|
||||
/* this is the entry point for the MINIX kernel */
|
||||
b multiboot_init
|
||||
|
||||
multiboot_init:
|
||||
ldr sp, =load_stack_start /* make usable stack */
|
||||
mov fp, #0
|
||||
bl _C_LABEL(pre_init)
|
||||
|
||||
/* Kernel is mapped high now and ready to go, with
|
||||
* the boot info pointer returned in r0. Set the
|
||||
* highly mapped stack, initialize it, push the boot
|
||||
* info pointer and jump to the highly mapped kernel.
|
||||
*/
|
||||
ldr sp, =k_initial_stktop
|
||||
mov r1, #0
|
||||
push {r1} /* Terminate stack */
|
||||
/* r0 holds kinfo_t ptr */
|
||||
bl _C_LABEL(kmain)
|
||||
|
||||
/* not reached */
|
||||
hang:
|
||||
b hang
|
||||
|
||||
.data
|
||||
load_stack:
|
||||
.space 4096
|
||||
load_stack_start:
|
6
kernel/arch/arm/include/arch_clock.h
Normal file
6
kernel/arch/arm/include/arch_clock.h
Normal file
|
@ -0,0 +1,6 @@
|
|||
#ifndef __CLOCK_ARM_H__
|
||||
#define __CLOCK_ARM_H__
|
||||
|
||||
void arch_timer_int_handler(void);
|
||||
|
||||
#endif /* __CLOCK_ARM_H__ */
|
61
kernel/arch/arm/include/arch_proto.h
Normal file
61
kernel/arch/arm/include/arch_proto.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
|
||||
#ifndef _ARM_PROTO_H
|
||||
#define _ARM_PROTO_H
|
||||
|
||||
#include <machine/vm.h>
|
||||
|
||||
#define K_STACK_SIZE ARM_PAGE_SIZE
|
||||
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
#include "cpufunc.h"
|
||||
|
||||
/* klib */
|
||||
__dead void reset(void);
|
||||
phys_bytes vir2phys(void *);
|
||||
vir_bytes phys_memset(phys_bytes ph, u32_t c, phys_bytes bytes);
|
||||
|
||||
void __switch_address_space(struct proc *p, struct proc **__ptproc);
|
||||
#define switch_address_space(proc) \
|
||||
__switch_address_space(proc, get_cpulocal_var_ptr(ptproc))
|
||||
|
||||
void __copy_msg_from_user_end(void);
|
||||
void __copy_msg_to_user_end(void);
|
||||
void __user_copy_msg_pointer_failure(void);
|
||||
|
||||
/* multiboot.c */
|
||||
void multiboot_init(void);
|
||||
|
||||
/* protect.c */
|
||||
struct tss_s {
|
||||
reg_t sp0; /* stack pointer to use during interrupt */
|
||||
} __attribute__((packed));
|
||||
int tss_init(unsigned cpu, void * kernel_stack);
|
||||
|
||||
void add_memmap(kinfo_t *cbi, u64_t addr, u64_t len);
|
||||
phys_bytes alloc_lowest(kinfo_t *cbi, phys_bytes len);
|
||||
void vm_enable_paging(void);
|
||||
void cut_memmap(kinfo_t *cbi, phys_bytes start, phys_bytes end);
|
||||
phys_bytes pg_roundup(phys_bytes b);
|
||||
void pg_info(reg_t *, u32_t **);
|
||||
void pg_clear(void);
|
||||
void pg_identity(kinfo_t *);
|
||||
phys_bytes pg_load(void);
|
||||
void pg_map(phys_bytes phys, vir_bytes vaddr, vir_bytes vaddr_end, kinfo_t *cbi);
|
||||
int pg_mapkernel(void);
|
||||
void pg_mapproc(struct proc *p, struct boot_image *ip, kinfo_t *cbi);
|
||||
|
||||
EXTERN void * k_stacks_start;
|
||||
extern void * k_stacks;
|
||||
|
||||
#define get_k_stack_top(cpu) ((void *)(((char*)(k_stacks)) \
|
||||
+ 2 * ((cpu) + 1) * K_STACK_SIZE))
|
||||
|
||||
|
||||
/* functions defined in architecture-independent kernel source. */
|
||||
#include "kernel/proto.h"
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
#endif
|
6
kernel/arch/arm/include/arch_watchdog.h
Normal file
6
kernel/arch/arm/include/arch_watchdog.h
Normal file
|
@ -0,0 +1,6 @@
|
|||
#ifndef __ARM_WATCHDOG_H__
|
||||
#define __ARM_WATCHDOG_H__
|
||||
|
||||
#include "kernel/kernel.h"
|
||||
|
||||
#endif /* __ARM_WATCHDOG_H__ */
|
31
kernel/arch/arm/include/archconst.h
Normal file
31
kernel/arch/arm/include/archconst.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
|
||||
#ifndef _ARM_ACONST_H
|
||||
#define _ARM_ACONST_H
|
||||
|
||||
#include <machine/interrupt.h>
|
||||
#include <machine/memory.h>
|
||||
#include <machine/cpu.h>
|
||||
|
||||
/* Program stack words and masks. */
|
||||
#define INIT_PSR (MODE_USR | PSR_F) /* initial psr */
|
||||
#define INIT_TASK_PSR (MODE_SVC | PSR_F) /* initial psr for tasks */
|
||||
|
||||
/* Exception vector numbers */
|
||||
#define RESET_VECTOR 0
|
||||
#define UNDEFINED_INST_VECTOR 1
|
||||
#define SUPERVISOR_CALL_VECTOR 2
|
||||
#define PREFETCH_ABORT_VECTOR 3
|
||||
#define DATA_ABORT_VECTOR 4
|
||||
#define HYPERVISOR_CALL_VECTOR 5
|
||||
#define INTERRUPT_VECTOR 6
|
||||
#define FAST_INTERRUPT_VECTOR 7
|
||||
|
||||
/*
|
||||
* defines how many bytes are reserved at the top of the kernel stack for global
|
||||
* information like currently scheduled process or current cpu id
|
||||
*/
|
||||
#define ARM_STACK_TOP_RESERVED (2 * sizeof(reg_t))
|
||||
|
||||
#define PG_ALLOCATEME ((phys_bytes)-1)
|
||||
|
||||
#endif /* _ARM_ACONST_H */
|
273
kernel/arch/arm/include/cpufunc.h
Normal file
273
kernel/arch/arm/include/cpufunc.h
Normal file
|
@ -0,0 +1,273 @@
|
|||
#ifndef _ARM_CPUFUNC_H
|
||||
#define _ARM_CPUFUNC_H
|
||||
|
||||
/* Data memory barrier */
|
||||
static inline void dmb(void)
|
||||
{
|
||||
asm volatile("dmb" : : : "memory");
|
||||
}
|
||||
|
||||
/* Data synchronization barrier */
|
||||
static inline void dsb(void)
|
||||
{
|
||||
asm volatile("dsb" : : : "memory");
|
||||
}
|
||||
|
||||
/* Instruction synchronization barrier */
|
||||
static inline void isb(void)
|
||||
{
|
||||
asm volatile("isb" : : : "memory");
|
||||
}
|
||||
|
||||
static inline void barrier(void)
|
||||
{
|
||||
dsb();
|
||||
isb();
|
||||
}
|
||||
|
||||
static inline void refresh_tlb(void)
|
||||
{
|
||||
dsb();
|
||||
/* Invalidate entire unified TLB */
|
||||
asm volatile("mcr p15, 0, r0, c8, c7, 0 @ TLBIALL\n\t");
|
||||
dsb();
|
||||
isb();
|
||||
}
|
||||
|
||||
|
||||
/* Read System Control Register */
|
||||
static inline u32_t read_sctlr()
|
||||
{
|
||||
u32_t ctl;
|
||||
|
||||
asm volatile("mrc p15, 0, %[ctl], c1, c0, 0 @ Read SCTLR\n\t"
|
||||
: [ctl] "=r" (ctl));
|
||||
return ctl;
|
||||
}
|
||||
|
||||
/* Write System Control Register */
|
||||
static inline void write_sctlr(u32_t ctl)
|
||||
{
|
||||
asm volatile("mcr p15, 0, %[ctl], c1, c0, 0 @ Write SCTLR\n\t"
|
||||
: : [ctl] "r" (ctl));
|
||||
}
|
||||
|
||||
/* Read Translation Table Base Register 0 */
|
||||
static inline u32_t read_ttbr0()
|
||||
{
|
||||
u32_t bar;
|
||||
|
||||
asm volatile("mrc p15, 0, %[bar], c2, c0, 0 @ Read TTBR0\n\t"
|
||||
: [bar] "=r" (bar));
|
||||
return bar;
|
||||
}
|
||||
|
||||
/* Write Translation Table Base Register 0 */
|
||||
static inline void write_ttbr0(u32_t bar)
|
||||
{
|
||||
barrier();
|
||||
asm volatile("mcr p15, 0, %[bar], c2, c0, 0 @ Write TTBR0\n\t"
|
||||
: : [bar] "r" (bar));
|
||||
refresh_tlb();
|
||||
}
|
||||
|
||||
/* Reload Translation Table Base Register 0 */
|
||||
static inline void reload_ttbr0(void)
|
||||
{
|
||||
reg_t ttbr = read_ttbr0();
|
||||
write_ttbr0(ttbr);
|
||||
refresh_tlb();
|
||||
}
|
||||
|
||||
/* Read Translation Table Base Register 1 */
|
||||
static inline u32_t read_ttbr1()
|
||||
{
|
||||
u32_t bar;
|
||||
|
||||
asm volatile("mrc p15, 0, %[bar], c2, c0, 1 @ Read TTBR1\n\t"
|
||||
: [bar] "=r" (bar));
|
||||
return bar;
|
||||
}
|
||||
|
||||
/* Write Translation Table Base Register 1 */
|
||||
static inline void write_ttbr1(u32_t bar)
|
||||
{
|
||||
barrier();
|
||||
asm volatile("mcr p15, 0, %[bar], c2, c0, 1 @ Write TTBR1\n\t"
|
||||
: : [bar] "r" (bar));
|
||||
refresh_tlb();
|
||||
}
|
||||
|
||||
/* Reload Translation Table Base Register 1 */
|
||||
static inline void reload_ttbr1(void)
|
||||
{
|
||||
reg_t ttbr = read_ttbr1();
|
||||
write_ttbr1(ttbr);
|
||||
refresh_tlb();
|
||||
}
|
||||
|
||||
/* Read Translation Table Base Control Register */
|
||||
static inline u32_t read_ttbcr()
|
||||
{
|
||||
u32_t bcr;
|
||||
|
||||
asm volatile("mrc p15, 0, %[bcr], c2, c0, 2 @ Read TTBCR\n\t"
|
||||
: [bcr] "=r" (bcr));
|
||||
return bcr;
|
||||
}
|
||||
|
||||
/* Write Translation Table Base Control Register */
|
||||
static inline void write_ttbcr(u32_t bcr)
|
||||
{
|
||||
asm volatile("mcr p15, 0, %[bcr], c2, c0, 2 @ Write TTBCR\n\t"
|
||||
: : [bcr] "r" (bcr));
|
||||
}
|
||||
|
||||
/* Read Domain Access Control Register */
|
||||
static inline u32_t read_dacr()
|
||||
{
|
||||
u32_t dacr;
|
||||
|
||||
asm volatile("mrc p15, 0, %[dacr], c3, c0, 0 @ Read DACR\n\t"
|
||||
: [dacr] "=r" (dacr));
|
||||
return dacr;
|
||||
}
|
||||
|
||||
/* Write Domain Access Control Register */
|
||||
static inline void write_dacr(u32_t dacr)
|
||||
{
|
||||
asm volatile("mcr p15, 0, %[dacr], c3, c0, 0 @ Write DACR\n\t"
|
||||
: : [dacr] "r" (dacr));
|
||||
}
|
||||
|
||||
/* Read Data Fault Status Register */
|
||||
static inline u32_t read_dfsr()
|
||||
{
|
||||
u32_t fsr;
|
||||
|
||||
asm volatile("mrc p15, 0, %[fsr], c5, c0, 0 @ Read DFSR\n\t"
|
||||
: [fsr] "=r" (fsr));
|
||||
return fsr;
|
||||
}
|
||||
|
||||
/* Write Data Fault Status Register */
|
||||
static inline void write_dfsr(u32_t fsr)
|
||||
{
|
||||
asm volatile("mcr p15, 0, %[fsr], c5, c0, 0 @ Write DFSR\n\t"
|
||||
: : [fsr] "r" (fsr));
|
||||
}
|
||||
|
||||
/* Read Instruction Fault Status Register */
|
||||
static inline u32_t read_ifsr()
|
||||
{
|
||||
u32_t fsr;
|
||||
|
||||
asm volatile("mrc p15, 0, %[fsr], c5, c0, 1 @ Read IFSR\n\t"
|
||||
: [fsr] "=r" (fsr));
|
||||
return fsr;
|
||||
}
|
||||
|
||||
/* Write Instruction Fault Status Register */
|
||||
static inline void write_ifsr(u32_t fsr)
|
||||
{
|
||||
asm volatile("mcr p15, 0, %[fsr], c5, c0, 1 @ Write IFSR\n\t"
|
||||
: : [fsr] "r" (fsr));
|
||||
}
|
||||
|
||||
/* Read Data Fault Address Register */
|
||||
static inline u32_t read_dfar()
|
||||
{
|
||||
u32_t far;
|
||||
|
||||
asm volatile("mrc p15, 0, %[far], c6, c0, 0 @ Read DFAR\n\t"
|
||||
: [far] "=r" (far));
|
||||
return far;
|
||||
}
|
||||
|
||||
/* Write Data Fault Address Register */
|
||||
static inline void write_dfar(u32_t far)
|
||||
{
|
||||
asm volatile("mcr p15, 0, %[far], c6, c0, 0 @ Write DFAR\n\t"
|
||||
: : [far] "r" (far));
|
||||
}
|
||||
|
||||
/* Read Instruction Fault Address Register */
|
||||
static inline u32_t read_ifar()
|
||||
{
|
||||
u32_t far;
|
||||
|
||||
asm volatile("mrc p15, 0, %[far], c6, c0, 2 @ Read IFAR\n\t"
|
||||
: [far] "=r" (far));
|
||||
return far;
|
||||
}
|
||||
|
||||
/* Write Instruction Fault Address Register */
|
||||
static inline void write_ifar(u32_t far)
|
||||
{
|
||||
asm volatile("mcr p15, 0, %[far], c6, c0, 2 @ Write IFAR\n\t"
|
||||
: : [far] "r" (far));
|
||||
}
|
||||
|
||||
/* Read Vector Base Address Register */
|
||||
static inline u32_t read_vbar()
|
||||
{
|
||||
u32_t vbar;
|
||||
|
||||
asm volatile("mrc p15, 0, %[vbar], c12, c0, 0 @ Read VBAR\n\t"
|
||||
: [vbar] "=r" (vbar));
|
||||
return vbar;
|
||||
}
|
||||
|
||||
/* Write Vector Base Address Register */
|
||||
static inline void write_vbar(u32_t vbar)
|
||||
{
|
||||
asm volatile("mcr p15, 0, %[vbar], c12, c0, 0 @ Write VBAR\n\t"
|
||||
: : [vbar] "r" (vbar));
|
||||
asm volatile("dsb");
|
||||
}
|
||||
|
||||
/* Read the Main ID Register */
|
||||
static inline u32_t read_midr()
|
||||
{
|
||||
u32_t id;
|
||||
|
||||
asm volatile("mrc p15, 0, %[id], c0, c0, 0 @ read MIDR\n\t"
|
||||
: [id] "=r" (id));
|
||||
return id;
|
||||
}
|
||||
|
||||
/* Read Auxiliary Control Register */
|
||||
static inline u32_t read_actlr()
|
||||
{
|
||||
u32_t ctl;
|
||||
|
||||
asm volatile("mrc p15, 0, %[ctl], c1, c0, 1 @ Read ACTLR\n\t"
|
||||
: [ctl] "=r" (ctl));
|
||||
return ctl;
|
||||
}
|
||||
|
||||
/* Write Auxiliary Control Register */
|
||||
static inline void write_actlr(u32_t ctl)
|
||||
{
|
||||
asm volatile("mcr p15, 0, %[ctl], c1, c0, 1 @ Write ACTLR\n\t"
|
||||
: : [ctl] "r" (ctl));
|
||||
}
|
||||
|
||||
/* Read Current Program Status Register */
|
||||
static inline u32_t read_cpsr()
|
||||
{
|
||||
u32_t status;
|
||||
|
||||
asm volatile("mrs %[status], cpsr @ read CPSR"
|
||||
: [status] "=r" (status));
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Write Current Program Status Register */
|
||||
static inline void write_cpsr(u32_t status)
|
||||
{
|
||||
asm volatile("msr cpsr_c, %[status] @ write CPSR"
|
||||
: : [status] "r" (status));
|
||||
}
|
||||
|
||||
#endif /* _ARM_CPUFUNC_H */
|
11
kernel/arch/arm/include/direct_utils.h
Normal file
11
kernel/arch/arm/include/direct_utils.h
Normal file
|
@ -0,0 +1,11 @@
|
|||
#ifndef MB_UTILS_H
|
||||
#define MB_UTILS_H
|
||||
|
||||
#include "kernel/kernel.h"
|
||||
|
||||
void direct_cls(void);
|
||||
void direct_print(const char*);
|
||||
void direct_print_char(char);
|
||||
int direct_read_char(unsigned char*);
|
||||
|
||||
#endif
|
14
kernel/arch/arm/include/hw_intr.h
Normal file
14
kernel/arch/arm/include/hw_intr.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
#ifndef __HW_INTR_ARM_H__
|
||||
#define __HW_INTR_ARM_H__
|
||||
|
||||
#include "kernel/kernel.h"
|
||||
void irq_handle(int irq);
|
||||
|
||||
#define hw_intr_mask(irq) omap3_irq_mask(irq)
|
||||
#define hw_intr_unmask(irq) omap3_irq_unmask(irq)
|
||||
#define hw_intr_ack(irq)
|
||||
#define hw_intr_used(irq)
|
||||
#define hw_intr_not_used(irq)
|
||||
#define hw_intr_disable_all()
|
||||
|
||||
#endif /* __HW_INTR_ARM_H__ */
|
16
kernel/arch/arm/include/io.h
Normal file
16
kernel/arch/arm/include/io.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
#ifndef _ARM_IO_H_
|
||||
#define _ARM_IO_H_
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
/* Access memory-mapped I/O devices */
|
||||
#define mmio_read(a) (*(volatile u32_t *)(a))
|
||||
#define mmio_write(a,v) (*(volatile u32_t *)(a) = (v))
|
||||
#define mmio_set(a,v) mmio_write((a), mmio_read((a)) | (v))
|
||||
#define mmio_clear(a,v) mmio_write((a), mmio_read((a)) & ~(v))
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
#endif /* _ARM_IO_H_ */
|
14
kernel/arch/arm/io_intr.S
Normal file
14
kernel/arch/arm/io_intr.S
Normal file
|
@ -0,0 +1,14 @@
|
|||
/* intr_disable(), intr_enable - Disable/Enable hardware interrupts. */
|
||||
/* void intr_disable(void); */
|
||||
/* void intr_enable(void); */
|
||||
#include <machine/asm.h>
|
||||
|
||||
ENTRY(intr_disable)
|
||||
dsb
|
||||
cpsid i
|
||||
bx lr
|
||||
|
||||
ENTRY(intr_enable)
|
||||
dsb
|
||||
cpsie i
|
||||
bx lr
|
49
kernel/arch/arm/kernel.lds
Normal file
49
kernel/arch/arm/kernel.lds
Normal file
|
@ -0,0 +1,49 @@
|
|||
OUTPUT_ARCH("arm")
|
||||
ENTRY(__k_unpaged_MINIX)
|
||||
|
||||
_kern_phys_base = 0x80200000; /* phys 4MB aligned for convenient remapping */
|
||||
_kern_vir_base = 0xF0400000; /* map kernel high for max. user vir space */
|
||||
_kern_offset = (_kern_vir_base - _kern_phys_base);
|
||||
|
||||
__k_unpaged__kern_offset = _kern_offset;
|
||||
__k_unpaged__kern_vir_base = _kern_vir_base;
|
||||
__k_unpaged__kern_phys_base = _kern_phys_base;
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = _kern_phys_base;
|
||||
__k_unpaged__kern_unpaged_start = .;
|
||||
|
||||
.unpaged_text ALIGN(4096) : { unpaged_*.o(.text) }
|
||||
.unpaged_data ALIGN(4096) : { unpaged_*.o(.data .rodata*) }
|
||||
__k_unpaged__kern_unpaged__edata = .;
|
||||
__k_unpaged__edata = .;
|
||||
.unpaged_bss ALIGN(4096) : { unpaged_*.o(.bss COMMON) }
|
||||
__k_unpaged__kern_unpaged_end = .;
|
||||
__k_unpaged__end = .;
|
||||
|
||||
. += _kern_offset;
|
||||
|
||||
. = ALIGN(4096); usermapped_start = .;
|
||||
.usermapped_glo : AT(ADDR(.usermapped_glo) - _kern_offset) { usermapped_glo*.o }
|
||||
. = ALIGN(4096); usermapped_nonglo_start = .;
|
||||
.usermapped : AT(ADDR(.usermapped) - _kern_offset) { usermapped_*.o }
|
||||
. = ALIGN(4096); usermapped_end = .;
|
||||
.text : AT(ADDR(.text) - _kern_offset) { *(.text*) }
|
||||
_etext = .;
|
||||
.data ALIGN(4096) : AT(ADDR(.data) - _kern_offset) { *(.data .rodata* ) }
|
||||
. = ALIGN(4096);
|
||||
_edata = .;
|
||||
.bss ALIGN(4096) : AT(ADDR(.bss) - _kern_offset) { *(.bss* COMMON)
|
||||
__k_unpaged__kern_size = . - _kern_vir_base;
|
||||
_kern_size = __k_unpaged__kern_size;
|
||||
. += 4096;
|
||||
}
|
||||
_end = .;
|
||||
|
||||
/DISCARD/ :
|
||||
{
|
||||
*(.ARM.exidx*)
|
||||
}
|
||||
|
||||
}
|
93
kernel/arch/arm/klib.S
Normal file
93
kernel/arch/arm/klib.S
Normal file
|
@ -0,0 +1,93 @@
|
|||
/* sections */
|
||||
|
||||
|
||||
#include <minix/config.h>
|
||||
#include <minix/const.h>
|
||||
#include <machine/asm.h>
|
||||
#include <machine/interrupt.h>
|
||||
#include <machine/vm.h>
|
||||
#include "archconst.h"
|
||||
#include "kernel/const.h"
|
||||
#include "sconst.h"
|
||||
#include <machine/multiboot.h>
|
||||
|
||||
|
||||
/*===========================================================================*/
|
||||
/* copy_msg_from_user */
|
||||
/*===========================================================================*/
|
||||
/*
|
||||
* int copy_msg_from_user(message * user_mbuf, message * dst);
|
||||
*
|
||||
* Copies a message of 36 bytes from user process space to a kernel buffer. This
|
||||
* function assumes that the process address space is installed (cr3 loaded).
|
||||
*
|
||||
* This function from the callers point of view either succeeds or returns an
|
||||
* error which gives the caller a chance to respond accordingly. In fact it
|
||||
* either succeeds or if it generates a pagefault, general protection or other
|
||||
* exception, the trap handler has to redirect the execution to
|
||||
* __user_copy_msg_pointer_failure where the error is reported to the caller
|
||||
* without resolving the pagefault. It is not kernel's problem to deal with
|
||||
* wrong pointers from userspace and the caller should return an error to
|
||||
* userspace as if wrong values or request were passed to the kernel
|
||||
*/
|
||||
ENTRY(copy_msg_from_user)
|
||||
push {r4-r10, lr}
|
||||
/* load the source pointer */
|
||||
mov r9, r0
|
||||
/* load the destination pointer */
|
||||
mov r10, r1
|
||||
/* do the copy */
|
||||
ldm r9, {r0-r8}
|
||||
stm r10, {r0-r8}
|
||||
|
||||
LABEL(__copy_msg_from_user_end)
|
||||
pop {r4-r10, lr}
|
||||
mov r0, #0
|
||||
bx lr
|
||||
|
||||
/*===========================================================================*/
|
||||
/* copy_msg_to_user */
|
||||
/*===========================================================================*/
|
||||
/*
|
||||
* void copy_msg_to_user(message * src, message * user_mbuf);
|
||||
*
|
||||
* Copies a message of 36 bytes to user process space from a kernel buffer.
|
||||
*
|
||||
* All the other copy_msg_from_user() comments apply here as well!
|
||||
*/
|
||||
ENTRY(copy_msg_to_user)
|
||||
push {r4-r10, lr}
|
||||
/* load the source pointer */
|
||||
mov r9, r0
|
||||
/* load the destination pointer */
|
||||
mov r10, r1
|
||||
/* do the copy */
|
||||
ldm r9, {r0-r8}
|
||||
stm r10, {r0-r8}
|
||||
|
||||
LABEL(__copy_msg_to_user_end)
|
||||
pop {r4-r10, lr}
|
||||
mov r0, #0
|
||||
bx lr
|
||||
|
||||
/*
|
||||
* if a function from a selected set of copies from or to userspace fails, it is
|
||||
* because of a wrong pointer supplied by the userspace. We have to clean up and
|
||||
* and return -1 to indicated that something wrong has happend. The place it was
|
||||
* called from has to handle this situation. The exception handler redirect us
|
||||
* here to continue, clean up and report the error
|
||||
*/
|
||||
ENTRY(__user_copy_msg_pointer_failure)
|
||||
pop {r4-r10, lr}
|
||||
mov r0, #-1
|
||||
bx lr
|
||||
|
||||
ENTRY(interrupts_enable)
|
||||
dsb
|
||||
cpsie i
|
||||
bx lr
|
||||
|
||||
ENTRY(interrupts_disable)
|
||||
dsb
|
||||
cpsid i
|
||||
bx lr
|
775
kernel/arch/arm/memory.c
Normal file
775
kernel/arch/arm/memory.c
Normal file
|
@ -0,0 +1,775 @@
|
|||
|
||||
#include "kernel/kernel.h"
|
||||
#include "kernel/proc.h"
|
||||
#include "kernel/vm.h"
|
||||
|
||||
#include <machine/vm.h>
|
||||
|
||||
#include <minix/type.h>
|
||||
#include <minix/syslib.h>
|
||||
#include <minix/cpufeature.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <machine/vm.h>
|
||||
|
||||
#include "arch_proto.h"
|
||||
#include "kernel/proto.h"
|
||||
#include "kernel/debug.h"
|
||||
|
||||
phys_bytes device_mem_vaddr = 0;
|
||||
|
||||
#define HASPT(procptr) ((procptr)->p_seg.p_ttbr != 0)
|
||||
static int nfreepdes = 0;
|
||||
#define MAXFREEPDES 2
|
||||
static int freepdes[MAXFREEPDES];
|
||||
|
||||
static u32_t phys_get32(phys_bytes v);
|
||||
|
||||
void mem_clear_mapcache(void)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < nfreepdes; i++) {
|
||||
struct proc *ptproc = get_cpulocal_var(ptproc);
|
||||
int pde = freepdes[i];
|
||||
u32_t *ptv;
|
||||
assert(ptproc);
|
||||
ptv = ptproc->p_seg.p_ttbr_v;
|
||||
assert(ptv);
|
||||
ptv[pde] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* This function sets up a mapping from within the kernel's address
|
||||
* space to any other area of memory, either straight physical
|
||||
* memory (pr == NULL) or a process view of memory, in 1MB windows.
|
||||
* I.e., it maps in 1MB chunks of virtual (or physical) address space
|
||||
* to 1MB chunks of kernel virtual address space.
|
||||
*
|
||||
* It recognizes pr already being in memory as a special case (no
|
||||
* mapping required).
|
||||
*
|
||||
* The target (i.e. in-kernel) mapping area is one of the freepdes[]
|
||||
* VM has earlier already told the kernel about that is available. It is
|
||||
* identified as the 'pde' parameter. This value can be chosen freely
|
||||
* by the caller, as long as it is in range (i.e. 0 or higher and corresonds
|
||||
* to a known freepde slot). It is up to the caller to keep track of which
|
||||
* freepde's are in use, and to determine which ones are free to use.
|
||||
*
|
||||
* The logical number supplied by the caller is translated into an actual
|
||||
* pde number to be used, and a pointer to it (linear address) is returned
|
||||
* for actual use by phys_copy or memset.
|
||||
*/
|
||||
static phys_bytes createpde(
|
||||
const struct proc *pr, /* Requested process, NULL for physical. */
|
||||
const phys_bytes linaddr,/* Address after segment translation. */
|
||||
phys_bytes *bytes, /* Size of chunk, function may truncate it. */
|
||||
int free_pde_idx, /* index of the free slot to use */
|
||||
int *changed /* If mapping is made, this is set to 1. */
|
||||
)
|
||||
{
|
||||
u32_t pdeval;
|
||||
phys_bytes offset;
|
||||
int pde;
|
||||
|
||||
assert(free_pde_idx >= 0 && free_pde_idx < nfreepdes);
|
||||
pde = freepdes[free_pde_idx];
|
||||
assert(pde >= 0 && pde < 4096);
|
||||
|
||||
if(pr && ((pr == get_cpulocal_var(ptproc)) || iskernelp(pr))) {
|
||||
/* Process memory is requested, and
|
||||
* it's a process that is already in current page table, or
|
||||
* the kernel, which is always there.
|
||||
* Therefore linaddr is valid directly, with the requested
|
||||
* size.
|
||||
*/
|
||||
return linaddr;
|
||||
}
|
||||
|
||||
if(pr) {
|
||||
/* Requested address is in a process that is not currently
|
||||
* accessible directly. Grab the PDE entry of that process'
|
||||
* page table that corresponds to the requested address.
|
||||
*/
|
||||
assert(pr->p_seg.p_ttbr_v);
|
||||
pdeval = pr->p_seg.p_ttbr_v[ARM_VM_PDE(linaddr)];
|
||||
} else {
|
||||
/* Requested address is physical. Make up the PDE entry. */
|
||||
pdeval = (linaddr & ARM_VM_SECTION_MASK) |
|
||||
ARM_VM_SECTION |
|
||||
ARM_VM_SECTION_DOMAIN | ARM_VM_SECTION_USER;
|
||||
}
|
||||
|
||||
/* Write the pde value that we need into a pde that the kernel
|
||||
* can access, into the currently loaded page table so it becomes
|
||||
* visible.
|
||||
*/
|
||||
assert(get_cpulocal_var(ptproc)->p_seg.p_ttbr_v);
|
||||
if(get_cpulocal_var(ptproc)->p_seg.p_ttbr_v[pde] != pdeval) {
|
||||
get_cpulocal_var(ptproc)->p_seg.p_ttbr_v[pde] = pdeval;
|
||||
*changed = 1;
|
||||
}
|
||||
|
||||
/* Memory is now available, but only the 1MB window of virtual
|
||||
* address space that we have mapped; calculate how much of
|
||||
* the requested range is visible and return that in *bytes,
|
||||
* if that is less than the requested range.
|
||||
*/
|
||||
offset = linaddr & ARM_VM_OFFSET_MASK_1MB; /* Offset in 1MB window. */
|
||||
*bytes = MIN(*bytes, ARM_BIG_PAGE_SIZE - offset);
|
||||
|
||||
/* Return the linear address of the start of the new mapping. */
|
||||
return ARM_BIG_PAGE_SIZE*pde + offset;
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* check_resumed_caller *
|
||||
*===========================================================================*/
|
||||
static int check_resumed_caller(struct proc *caller)
|
||||
{
|
||||
/* Returns the result from VM if caller was resumed, otherwise OK. */
|
||||
if (caller && (caller->p_misc_flags & MF_KCALL_RESUME)) {
|
||||
assert(caller->p_vmrequest.vmresult != VMSUSPEND);
|
||||
return caller->p_vmrequest.vmresult;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* lin_lin_copy *
|
||||
*===========================================================================*/
|
||||
static int lin_lin_copy(struct proc *srcproc, vir_bytes srclinaddr,
|
||||
struct proc *dstproc, vir_bytes dstlinaddr, vir_bytes bytes)
|
||||
{
|
||||
u32_t addr;
|
||||
proc_nr_t procslot;
|
||||
|
||||
assert(get_cpulocal_var(ptproc));
|
||||
assert(get_cpulocal_var(proc_ptr));
|
||||
assert(read_ttbr0() == get_cpulocal_var(ptproc)->p_seg.p_ttbr);
|
||||
|
||||
procslot = get_cpulocal_var(ptproc)->p_nr;
|
||||
|
||||
assert(procslot >= 0 && procslot < ARM_VM_DIR_ENTRIES);
|
||||
|
||||
if(srcproc) assert(!RTS_ISSET(srcproc, RTS_SLOT_FREE));
|
||||
if(dstproc) assert(!RTS_ISSET(dstproc, RTS_SLOT_FREE));
|
||||
assert(!RTS_ISSET(get_cpulocal_var(ptproc), RTS_SLOT_FREE));
|
||||
assert(get_cpulocal_var(ptproc)->p_seg.p_ttbr_v);
|
||||
if(srcproc) assert(!RTS_ISSET(srcproc, RTS_VMINHIBIT));
|
||||
if(dstproc) assert(!RTS_ISSET(dstproc, RTS_VMINHIBIT));
|
||||
|
||||
while(bytes > 0) {
|
||||
phys_bytes srcptr, dstptr;
|
||||
vir_bytes chunk = bytes;
|
||||
int changed = 0;
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
unsigned cpu = cpuid;
|
||||
|
||||
if (srcproc && GET_BIT(srcproc->p_stale_tlb, cpu)) {
|
||||
changed = 1;
|
||||
UNSET_BIT(srcproc->p_stale_tlb, cpu);
|
||||
}
|
||||
if (dstproc && GET_BIT(dstproc->p_stale_tlb, cpu)) {
|
||||
changed = 1;
|
||||
UNSET_BIT(dstproc->p_stale_tlb, cpu);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Set up 1MB ranges. */
|
||||
srcptr = createpde(srcproc, srclinaddr, &chunk, 0, &changed);
|
||||
dstptr = createpde(dstproc, dstlinaddr, &chunk, 1, &changed);
|
||||
if(changed) {
|
||||
reload_ttbr0();
|
||||
refresh_tlb();
|
||||
}
|
||||
/* Copy pages. */
|
||||
PHYS_COPY_CATCH(srcptr, dstptr, chunk, addr);
|
||||
|
||||
if(addr) {
|
||||
/* If addr is nonzero, a page fault was caught. */
|
||||
|
||||
if(addr >= srcptr && addr < (srcptr + chunk)) {
|
||||
return EFAULT_SRC;
|
||||
}
|
||||
if(addr >= dstptr && addr < (dstptr + chunk)) {
|
||||
return EFAULT_DST;
|
||||
}
|
||||
|
||||
panic("lin_lin_copy fault out of range");
|
||||
|
||||
/* Not reached. */
|
||||
return EFAULT;
|
||||
}
|
||||
|
||||
/* Update counter and addresses for next iteration, if any. */
|
||||
bytes -= chunk;
|
||||
srclinaddr += chunk;
|
||||
dstlinaddr += chunk;
|
||||
}
|
||||
|
||||
if(srcproc) assert(!RTS_ISSET(srcproc, RTS_SLOT_FREE));
|
||||
if(dstproc) assert(!RTS_ISSET(dstproc, RTS_SLOT_FREE));
|
||||
assert(!RTS_ISSET(get_cpulocal_var(ptproc), RTS_SLOT_FREE));
|
||||
assert(get_cpulocal_var(ptproc)->p_seg.p_ttbr_v);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
static u32_t phys_get32(phys_bytes addr)
|
||||
{
|
||||
const u32_t v;
|
||||
int r;
|
||||
|
||||
if((r=lin_lin_copy(NULL, addr,
|
||||
proc_addr(SYSTEM), (phys_bytes) &v, sizeof(v))) != OK) {
|
||||
panic("lin_lin_copy for phys_get32 failed: %d", r);
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* umap_virtual *
|
||||
*===========================================================================*/
|
||||
phys_bytes umap_virtual(rp, seg, vir_addr, bytes)
|
||||
register struct proc *rp; /* pointer to proc table entry for process */
|
||||
int seg; /* T, D, or S segment */
|
||||
vir_bytes vir_addr; /* virtual address in bytes within the seg */
|
||||
vir_bytes bytes; /* # of bytes to be copied */
|
||||
{
|
||||
phys_bytes phys = 0;
|
||||
|
||||
if(vm_lookup(rp, vir_addr, &phys, NULL) != OK) {
|
||||
printf("SYSTEM:umap_virtual: vm_lookup of %s: seg 0x%x: 0x%lx failed\n", rp->p_name, seg, vir_addr);
|
||||
phys = 0;
|
||||
} else {
|
||||
if(phys == 0)
|
||||
panic("vm_lookup returned phys: %d", phys);
|
||||
}
|
||||
|
||||
if(phys == 0) {
|
||||
printf("SYSTEM:umap_virtual: lookup failed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Now make sure addresses are contiguous in physical memory
|
||||
* so that the umap makes sense.
|
||||
*/
|
||||
if(bytes > 0 && vm_lookup_range(rp, vir_addr, NULL, bytes) != bytes) {
|
||||
printf("umap_virtual: %s: %lu at 0x%lx (vir 0x%lx) not contiguous\n",
|
||||
rp->p_name, bytes, vir_addr, vir_addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* phys must be larger than 0 (or the caller will think the call
|
||||
* failed), and address must not cross a page boundary.
|
||||
*/
|
||||
assert(phys);
|
||||
|
||||
return phys;
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* vm_lookup *
|
||||
*===========================================================================*/
|
||||
int vm_lookup(const struct proc *proc, const vir_bytes virtual,
|
||||
phys_bytes *physical, u32_t *ptent)
|
||||
{
|
||||
u32_t *root, *pt;
|
||||
int pde, pte;
|
||||
u32_t pde_v, pte_v;
|
||||
|
||||
assert(proc);
|
||||
assert(physical);
|
||||
assert(!isemptyp(proc));
|
||||
assert(HASPT(proc));
|
||||
|
||||
/* Retrieve page directory entry. */
|
||||
root = (u32_t *) proc->p_seg.p_ttbr;
|
||||
assert(!((u32_t) root % ARM_PAGEDIR_SIZE));
|
||||
pde = ARM_VM_PDE(virtual);
|
||||
assert(pde >= 0 && pde < ARM_VM_DIR_ENTRIES);
|
||||
pde_v = phys_get32((u32_t) (root + pde));
|
||||
|
||||
if(!(pde_v & ARM_VM_PDE_PRESENT)) {
|
||||
return EFAULT;
|
||||
}
|
||||
|
||||
/* We don't expect to ever see this. */
|
||||
if(pde_v & ARM_VM_BIGPAGE) {
|
||||
*physical = pde_v & ARM_VM_SECTION_MASK;
|
||||
if(ptent) *ptent = pde_v;
|
||||
*physical += virtual & ARM_VM_OFFSET_MASK_1MB;
|
||||
} else {
|
||||
/* Retrieve page table entry. */
|
||||
pt = (u32_t *) (pde_v & ARM_VM_PDE_MASK);
|
||||
assert(!((u32_t) pt % ARM_PAGETABLE_SIZE));
|
||||
pte = ARM_VM_PTE(virtual);
|
||||
assert(pte >= 0 && pte < ARM_VM_PT_ENTRIES);
|
||||
pte_v = phys_get32((u32_t) (pt + pte));
|
||||
if(!(pte_v & ARM_VM_PTE_PRESENT)) {
|
||||
return EFAULT;
|
||||
}
|
||||
|
||||
if(ptent) *ptent = pte_v;
|
||||
|
||||
/* Actual address now known; retrieve it and add page offset. */
|
||||
*physical = pte_v & ARM_VM_PTE_MASK;
|
||||
*physical += virtual % ARM_PAGE_SIZE;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* vm_lookup_range *
|
||||
*===========================================================================*/
|
||||
size_t vm_lookup_range(const struct proc *proc, vir_bytes vir_addr,
|
||||
phys_bytes *phys_addr, size_t bytes)
|
||||
{
|
||||
/* Look up the physical address corresponding to linear virtual address
|
||||
* 'vir_addr' for process 'proc'. Return the size of the range covered
|
||||
* by contiguous physical memory starting from that address; this may
|
||||
* be anywhere between 0 and 'bytes' inclusive. If the return value is
|
||||
* nonzero, and 'phys_addr' is non-NULL, 'phys_addr' will be set to the
|
||||
* base physical address of the range. 'vir_addr' and 'bytes' need not
|
||||
* be page-aligned, but the caller must have verified that the given
|
||||
* linear range is valid for the given process at all.
|
||||
*/
|
||||
phys_bytes phys, next_phys;
|
||||
size_t len;
|
||||
|
||||
assert(proc);
|
||||
assert(bytes > 0);
|
||||
assert(HASPT(proc));
|
||||
|
||||
/* Look up the first page. */
|
||||
if (vm_lookup(proc, vir_addr, &phys, NULL) != OK)
|
||||
return 0;
|
||||
|
||||
if (phys_addr != NULL)
|
||||
*phys_addr = phys;
|
||||
|
||||
len = ARM_PAGE_SIZE - (vir_addr % ARM_PAGE_SIZE);
|
||||
vir_addr += len;
|
||||
next_phys = phys + len;
|
||||
|
||||
/* Look up any next pages and test physical contiguity. */
|
||||
while (len < bytes) {
|
||||
if (vm_lookup(proc, vir_addr, &phys, NULL) != OK)
|
||||
break;
|
||||
|
||||
if (next_phys != phys)
|
||||
break;
|
||||
|
||||
len += ARM_PAGE_SIZE;
|
||||
vir_addr += ARM_PAGE_SIZE;
|
||||
next_phys += ARM_PAGE_SIZE;
|
||||
}
|
||||
|
||||
/* We might now have overshot the requested length somewhat. */
|
||||
return MIN(bytes, len);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* vm_suspend *
|
||||
*===========================================================================*/
|
||||
static void vm_suspend(struct proc *caller, const struct proc *target,
|
||||
const vir_bytes linaddr, const vir_bytes len, const int type)
|
||||
{
|
||||
/* This range is not OK for this process. Set parameters
|
||||
* of the request and notify VM about the pending request.
|
||||
*/
|
||||
assert(!RTS_ISSET(caller, RTS_VMREQUEST));
|
||||
assert(!RTS_ISSET(target, RTS_VMREQUEST));
|
||||
|
||||
RTS_SET(caller, RTS_VMREQUEST);
|
||||
|
||||
caller->p_vmrequest.req_type = VMPTYPE_CHECK;
|
||||
caller->p_vmrequest.target = target->p_endpoint;
|
||||
caller->p_vmrequest.params.check.start = linaddr;
|
||||
caller->p_vmrequest.params.check.length = len;
|
||||
caller->p_vmrequest.params.check.writeflag = 1;
|
||||
caller->p_vmrequest.type = type;
|
||||
|
||||
/* Connect caller on vmrequest wait queue. */
|
||||
if(!(caller->p_vmrequest.nextrequestor = vmrequest))
|
||||
if(OK != send_sig(VM_PROC_NR, SIGKMEM))
|
||||
panic("send_sig failed");
|
||||
vmrequest = caller;
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* vm_check_range *
|
||||
*===========================================================================*/
|
||||
int vm_check_range(struct proc *caller, struct proc *target,
|
||||
vir_bytes vir_addr, size_t bytes)
|
||||
{
|
||||
/* Public interface to vm_suspend(), for use by kernel calls. On behalf
|
||||
* of 'caller', call into VM to check linear virtual address range of
|
||||
* process 'target', starting at 'vir_addr', for 'bytes' bytes. This
|
||||
* function assumes that it will called twice if VM returned an error
|
||||
* the first time (since nothing has changed in that case), and will
|
||||
* then return the error code resulting from the first call. Upon the
|
||||
* first call, a non-success error code is returned as well.
|
||||
*/
|
||||
int r;
|
||||
|
||||
if ((caller->p_misc_flags & MF_KCALL_RESUME) &&
|
||||
(r = caller->p_vmrequest.vmresult) != OK)
|
||||
return r;
|
||||
|
||||
vm_suspend(caller, target, vir_addr, bytes, VMSTYPE_KERNELCALL);
|
||||
|
||||
return VMSUSPEND;
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* delivermsg *
|
||||
*===========================================================================*/
|
||||
void delivermsg(struct proc *rp)
|
||||
{
|
||||
int r = OK;
|
||||
|
||||
assert(rp->p_misc_flags & MF_DELIVERMSG);
|
||||
assert(rp->p_delivermsg.m_source != NONE);
|
||||
|
||||
if (copy_msg_to_user(&rp->p_delivermsg,
|
||||
(message *) rp->p_delivermsg_vir)) {
|
||||
printf("WARNING wrong user pointer 0x%08lx from "
|
||||
"process %s / %d\n",
|
||||
rp->p_delivermsg_vir,
|
||||
rp->p_name,
|
||||
rp->p_endpoint);
|
||||
r = EFAULT;
|
||||
}
|
||||
|
||||
/* Indicate message has been delivered; address is 'used'. */
|
||||
rp->p_delivermsg.m_source = NONE;
|
||||
rp->p_misc_flags &= ~MF_DELIVERMSG;
|
||||
|
||||
if(!(rp->p_misc_flags & MF_CONTEXT_SET)) {
|
||||
rp->p_reg.retreg = r;
|
||||
}
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* vmmemset *
|
||||
*===========================================================================*/
|
||||
int vm_memset(struct proc* caller, endpoint_t who, phys_bytes ph, int c,
|
||||
phys_bytes count)
|
||||
{
|
||||
u32_t pattern;
|
||||
struct proc *whoptr = NULL;
|
||||
phys_bytes cur_ph = ph;
|
||||
phys_bytes left = count;
|
||||
phys_bytes ptr, chunk, pfa = 0;
|
||||
int new_ttbr, r = OK;
|
||||
|
||||
if ((r = check_resumed_caller(caller)) != OK)
|
||||
return r;
|
||||
|
||||
/* NONE for physical, otherwise virtual */
|
||||
if (who != NONE && !(whoptr = endpoint_lookup(who)))
|
||||
return ESRCH;
|
||||
|
||||
c &= 0xFF;
|
||||
pattern = c | (c << 8) | (c << 16) | (c << 24);
|
||||
|
||||
assert(get_cpulocal_var(ptproc)->p_seg.p_ttbr_v);
|
||||
assert(!catch_pagefaults);
|
||||
catch_pagefaults = 1;
|
||||
|
||||
/* We can memset as many bytes as we have remaining,
|
||||
* or as many as remain in the 1MB chunk we mapped in.
|
||||
*/
|
||||
while (left > 0) {
|
||||
new_ttbr = 0;
|
||||
chunk = left;
|
||||
ptr = createpde(whoptr, cur_ph, &chunk, 0, &new_ttbr);
|
||||
|
||||
if (new_ttbr) {
|
||||
reload_ttbr0();
|
||||
refresh_tlb();
|
||||
}
|
||||
/* If a page fault happens, pfa is non-null */
|
||||
if ((pfa = phys_memset(ptr, pattern, chunk))) {
|
||||
|
||||
/* If a process pagefaults, VM may help out */
|
||||
if (whoptr) {
|
||||
vm_suspend(caller, whoptr, ph, count,
|
||||
VMSTYPE_KERNELCALL);
|
||||
assert(catch_pagefaults);
|
||||
catch_pagefaults = 0;
|
||||
return VMSUSPEND;
|
||||
}
|
||||
|
||||
/* Pagefault when phys copying ?! */
|
||||
panic("vm_memset: pf %lx addr=%lx len=%lu\n",
|
||||
pfa , ptr, chunk);
|
||||
}
|
||||
|
||||
cur_ph += chunk;
|
||||
left -= chunk;
|
||||
}
|
||||
|
||||
assert(get_cpulocal_var(ptproc)->p_seg.p_ttbr_v);
|
||||
assert(catch_pagefaults);
|
||||
catch_pagefaults = 0;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* virtual_copy_f *
|
||||
*===========================================================================*/
|
||||
int virtual_copy_f(caller, src_addr, dst_addr, bytes, vmcheck)
|
||||
struct proc * caller;
|
||||
struct vir_addr *src_addr; /* source virtual address */
|
||||
struct vir_addr *dst_addr; /* destination virtual address */
|
||||
vir_bytes bytes; /* # of bytes to copy */
|
||||
int vmcheck; /* if nonzero, can return VMSUSPEND */
|
||||
{
|
||||
/* Copy bytes from virtual address src_addr to virtual address dst_addr. */
|
||||
struct vir_addr *vir_addr[2]; /* virtual source and destination address */
|
||||
int i, r;
|
||||
struct proc *procs[2];
|
||||
|
||||
assert((vmcheck && caller) || (!vmcheck && !caller));
|
||||
|
||||
/* Check copy count. */
|
||||
if (bytes <= 0) return(EDOM);
|
||||
|
||||
/* Do some more checks and map virtual addresses to physical addresses. */
|
||||
vir_addr[_SRC_] = src_addr;
|
||||
vir_addr[_DST_] = dst_addr;
|
||||
|
||||
for (i=_SRC_; i<=_DST_; i++) {
|
||||
endpoint_t proc_e = vir_addr[i]->proc_nr_e;
|
||||
int proc_nr;
|
||||
struct proc *p;
|
||||
|
||||
if(proc_e == NONE) {
|
||||
p = NULL;
|
||||
} else {
|
||||
if(!isokendpt(proc_e, &proc_nr)) {
|
||||
printf("virtual_copy: no reasonable endpoint\n");
|
||||
return ESRCH;
|
||||
}
|
||||
p = proc_addr(proc_nr);
|
||||
}
|
||||
|
||||
procs[i] = p;
|
||||
}
|
||||
|
||||
if ((r = check_resumed_caller(caller)) != OK)
|
||||
return r;
|
||||
|
||||
if((r=lin_lin_copy(procs[_SRC_], vir_addr[_SRC_]->offset,
|
||||
procs[_DST_], vir_addr[_DST_]->offset, bytes)) != OK) {
|
||||
struct proc *target = NULL;
|
||||
phys_bytes lin;
|
||||
if(r != EFAULT_SRC && r != EFAULT_DST)
|
||||
panic("lin_lin_copy failed: %d", r);
|
||||
if(!vmcheck || !caller) {
|
||||
return r;
|
||||
}
|
||||
|
||||
if(r == EFAULT_SRC) {
|
||||
lin = vir_addr[_SRC_]->offset;
|
||||
target = procs[_SRC_];
|
||||
} else if(r == EFAULT_DST) {
|
||||
lin = vir_addr[_DST_]->offset;
|
||||
target = procs[_DST_];
|
||||
} else {
|
||||
panic("r strange: %d", r);
|
||||
}
|
||||
|
||||
assert(caller);
|
||||
assert(target);
|
||||
|
||||
vm_suspend(caller, target, lin, bytes, VMSTYPE_KERNELCALL);
|
||||
return VMSUSPEND;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* data_copy *
|
||||
*===========================================================================*/
|
||||
int data_copy(const endpoint_t from_proc, const vir_bytes from_addr,
|
||||
const endpoint_t to_proc, const vir_bytes to_addr,
|
||||
size_t bytes)
|
||||
{
|
||||
struct vir_addr src, dst;
|
||||
|
||||
src.offset = from_addr;
|
||||
dst.offset = to_addr;
|
||||
src.proc_nr_e = from_proc;
|
||||
dst.proc_nr_e = to_proc;
|
||||
assert(src.proc_nr_e != NONE);
|
||||
assert(dst.proc_nr_e != NONE);
|
||||
|
||||
return virtual_copy(&src, &dst, bytes);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* data_copy_vmcheck *
|
||||
*===========================================================================*/
|
||||
int data_copy_vmcheck(struct proc * caller,
|
||||
const endpoint_t from_proc, const vir_bytes from_addr,
|
||||
const endpoint_t to_proc, const vir_bytes to_addr,
|
||||
size_t bytes)
|
||||
{
|
||||
struct vir_addr src, dst;
|
||||
|
||||
src.offset = from_addr;
|
||||
dst.offset = to_addr;
|
||||
src.proc_nr_e = from_proc;
|
||||
dst.proc_nr_e = to_proc;
|
||||
assert(src.proc_nr_e != NONE);
|
||||
assert(dst.proc_nr_e != NONE);
|
||||
|
||||
return virtual_copy_vmcheck(caller, &src, &dst, bytes);
|
||||
}
|
||||
|
||||
void memory_init(void)
|
||||
{
|
||||
assert(nfreepdes == 0);
|
||||
|
||||
freepdes[nfreepdes++] = kinfo.freepde_start++;
|
||||
freepdes[nfreepdes++] = kinfo.freepde_start++;
|
||||
|
||||
assert(kinfo.freepde_start < ARM_VM_DIR_ENTRIES);
|
||||
assert(nfreepdes == 2);
|
||||
assert(nfreepdes <= MAXFREEPDES);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* arch_proc_init *
|
||||
*===========================================================================*/
|
||||
void arch_proc_init(struct proc *pr, const u32_t ip, const u32_t sp, char *name)
|
||||
{
|
||||
arch_proc_reset(pr);
|
||||
strcpy(pr->p_name, name);
|
||||
|
||||
/* set custom state we know */
|
||||
pr->p_reg.pc = ip;
|
||||
pr->p_reg.sp = sp;
|
||||
}
|
||||
|
||||
static int device_mem_mapping_index = -1,
|
||||
usermapped_glo_index = -1,
|
||||
usermapped_index = -1, first_um_idx = -1;
|
||||
|
||||
char *device_mem;
|
||||
|
||||
extern char usermapped_start, usermapped_end, usermapped_nonglo_start;
|
||||
|
||||
int arch_phys_map(const int index,
|
||||
phys_bytes *addr,
|
||||
phys_bytes *len,
|
||||
int *flags)
|
||||
{
|
||||
static int first = 1;
|
||||
int freeidx = 0;
|
||||
u32_t glo_len = (u32_t) &usermapped_nonglo_start -
|
||||
(u32_t) &usermapped_start;
|
||||
|
||||
if(first) {
|
||||
device_mem_mapping_index = freeidx++;
|
||||
if(glo_len > 0) {
|
||||
usermapped_glo_index = freeidx++;
|
||||
}
|
||||
|
||||
usermapped_index = freeidx++;
|
||||
first_um_idx = usermapped_index;
|
||||
if(usermapped_glo_index != -1)
|
||||
first_um_idx = usermapped_glo_index;
|
||||
first = 0;
|
||||
}
|
||||
|
||||
if(index == usermapped_glo_index) {
|
||||
*addr = vir2phys(&usermapped_start);
|
||||
*len = glo_len;
|
||||
*flags = VMMF_USER | VMMF_GLO;
|
||||
return OK;
|
||||
}
|
||||
else if(index == usermapped_index) {
|
||||
*addr = vir2phys(&usermapped_nonglo_start);
|
||||
*len = (u32_t) &usermapped_end -
|
||||
(u32_t) &usermapped_nonglo_start;
|
||||
*flags = VMMF_USER;
|
||||
return OK;
|
||||
}
|
||||
else if (index == device_mem_mapping_index) {
|
||||
/* map device memory */
|
||||
*addr = 0x48000000;
|
||||
*len = 0x02000000;
|
||||
*flags = VMMF_UNCACHED | VMMF_WRITE;
|
||||
return OK;
|
||||
}
|
||||
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
int arch_phys_map_reply(const int index, const vir_bytes addr)
|
||||
{
|
||||
if(index == first_um_idx) {
|
||||
u32_t usermapped_offset;
|
||||
assert(addr > (u32_t) &usermapped_start);
|
||||
usermapped_offset = addr - (u32_t) &usermapped_start;
|
||||
memset(&minix_kerninfo, 0, sizeof(minix_kerninfo));
|
||||
#define FIXEDPTR(ptr) (void *) ((u32_t)ptr + usermapped_offset)
|
||||
#define FIXPTR(ptr) ptr = FIXEDPTR(ptr)
|
||||
#define ASSIGN(minixstruct) minix_kerninfo.minixstruct = FIXEDPTR(&minixstruct)
|
||||
ASSIGN(kinfo);
|
||||
ASSIGN(machine);
|
||||
ASSIGN(kmessages);
|
||||
ASSIGN(loadinfo);
|
||||
|
||||
/* adjust the pointers of the functions and the struct
|
||||
* itself to the user-accessible mapping
|
||||
*/
|
||||
minix_kerninfo.kerninfo_magic = KERNINFO_MAGIC;
|
||||
minix_kerninfo.minix_feature_flags = minix_feature_flags;
|
||||
minix_kerninfo_user = (vir_bytes) FIXEDPTR(&minix_kerninfo);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
if(index == usermapped_index) return OK;
|
||||
|
||||
if (index == device_mem_mapping_index) {
|
||||
device_mem_vaddr = addr;
|
||||
return OK;
|
||||
}
|
||||
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
int arch_enable_paging(struct proc * caller)
|
||||
{
|
||||
assert(caller->p_seg.p_ttbr);
|
||||
|
||||
/* load caller's page table */
|
||||
switch_address_space(caller);
|
||||
|
||||
device_mem = (char *) device_mem_vaddr;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
void release_address_space(struct proc *pr)
|
||||
{
|
||||
pr->p_seg.p_ttbr_v = NULL;
|
||||
refresh_tlb();
|
||||
}
|
295
kernel/arch/arm/mpx.S
Normal file
295
kernel/arch/arm/mpx.S
Normal file
|
@ -0,0 +1,295 @@
|
|||
/* This file is part of the lowest layer of the MINIX kernel. (The other part
|
||||
* is "proc.c".) The lowest layer does process switching and message handling.
|
||||
*
|
||||
* Kernel is entered either because of kernel-calls, ipc-calls, interrupts or
|
||||
* exceptions. TSS is set so that the kernel stack is loaded. The user context is
|
||||
* saved to the proc table and the handler of the event is called. Once the
|
||||
* handler is done, switch_to_user() function is called to pick a new process,
|
||||
* finish what needs to be done for the next process to run, sets its context
|
||||
* and switch to userspace.
|
||||
*/
|
||||
|
||||
#include "kernel/kernel.h" /* configures the kernel */
|
||||
|
||||
/* sections */
|
||||
|
||||
#include <machine/vm.h>
|
||||
#include "../../kernel.h"
|
||||
#include <minix/config.h>
|
||||
#include <minix/const.h>
|
||||
#include <minix/com.h>
|
||||
#include <machine/asm.h>
|
||||
#include <machine/interrupt.h>
|
||||
#include "archconst.h"
|
||||
#include "kernel/const.h"
|
||||
#include "kernel/proc.h"
|
||||
#include "sconst.h"
|
||||
#include <machine/multiboot.h>
|
||||
#include <machine/ipcconst.h>
|
||||
#include <machine/cpu.h>
|
||||
#include "omap_intr.h"
|
||||
|
||||
#include "arch_proto.h" /* K_STACK_SIZE */
|
||||
|
||||
IMPORT(svc_stack)
|
||||
|
||||
/*
|
||||
* Adjust lr, switch to SVC mode, and push pc/psr when exception triggered
|
||||
* The 'lr_offset' argument holds the adjustment. It differs based on
|
||||
* which mode the CPU is in.
|
||||
*/
|
||||
.macro switch_to_svc lr_offset
|
||||
sub lr, lr, #\lr_offset
|
||||
srsdb #MODE_SVC!
|
||||
cps #MODE_SVC
|
||||
.endm
|
||||
|
||||
/*
|
||||
* Test if the exception/interrupt occured in the kernel.
|
||||
* Jump to 'label' argument if it occurred in the kernel.
|
||||
*
|
||||
* NOTE: switch_to_svc must be called first
|
||||
*/
|
||||
.macro test_int_in_kernel, label
|
||||
push {r3}
|
||||
ldr r3, [sp, #8] /* spsr */
|
||||
and r3, r3, #PSR_MODE_MASK
|
||||
cmp r3, #MODE_USR
|
||||
pop {r3}
|
||||
bne \label /* In-kernel handling */
|
||||
.endm
|
||||
|
||||
/* Save the register context to the proc structure */
|
||||
.macro save_process_ctx
|
||||
push {lr}
|
||||
ldr lr, [sp, #12] /* proc ptr */
|
||||
stm lr, {r0-r14}^
|
||||
ldr r12, [sp, #8]
|
||||
str r12, [lr, #PSREG]
|
||||
ldr r12, [sp, #4]
|
||||
str r12, [lr, #PCREG]
|
||||
pop {lr}
|
||||
add sp, sp, #8
|
||||
.endm
|
||||
|
||||
.macro exception_handler exc_name, exc_num, lr_offset
|
||||
ENTRY(\exc_name\()_entry)
|
||||
switch_to_svc \lr_offset
|
||||
test_int_in_kernel \exc_name\()_entry_nested
|
||||
|
||||
\exc_name\()entry_from_user:
|
||||
save_process_ctx
|
||||
|
||||
/* save the pointer to the current process */
|
||||
ldr fp, [sp]
|
||||
/* save the exception pc (saved lr_user) */
|
||||
ldr r4, [fp, #PCREG]
|
||||
|
||||
/* stop user process cycles */
|
||||
mov r0, fp /* first param: caller proc ptr */
|
||||
mov fp, #0 /* for stack trace */
|
||||
bl _C_LABEL(context_stop)
|
||||
|
||||
/*
|
||||
* push a pointer to the interrupt state pushed by the cpu and the
|
||||
* vector number pushed by the vector handler just before calling
|
||||
* exception_entry and call the exception handler.
|
||||
*/
|
||||
mov r0, #0 /* it's not a nested exception */
|
||||
mov r1, r4 /* saved lr */
|
||||
mov r2, #\exc_num /* vector number */
|
||||
bl _C_LABEL(exception_handler)
|
||||
|
||||
b _C_LABEL(switch_to_user)
|
||||
|
||||
\exc_name\()_entry_nested:
|
||||
push {r0-r12, lr}
|
||||
mov r0, #1 /* it's a nested exception */
|
||||
add r1, sp, #56 /* saved lr */
|
||||
mov r2, #\exc_num /* vector number */
|
||||
bl _C_LABEL(exception_handler)
|
||||
pop {r0-r12, lr}
|
||||
rfeia sp!
|
||||
.endm
|
||||
|
||||
|
||||
/* Exception handlers */
|
||||
exception_handler data_abort DATA_ABORT_VECTOR 8
|
||||
exception_handler prefetch_abort PREFETCH_ABORT_VECTOR 4
|
||||
exception_handler undefined_inst UNDEFINED_INST_VECTOR 4
|
||||
|
||||
|
||||
ENTRY(irq_entry)
|
||||
switch_to_svc 4
|
||||
test_int_in_kernel irq_entry_from_kernel
|
||||
|
||||
irq_entry_from_user:
|
||||
save_process_ctx
|
||||
|
||||
/* save the pointer to the current process */
|
||||
ldr fp, [sp]
|
||||
|
||||
push {fp} /* save caller proc ptr */
|
||||
|
||||
/* stop user process cycles */
|
||||
mov r0, fp /* first param: caller proc ptr */
|
||||
mov fp, #0 /* for stack trace */
|
||||
bl _C_LABEL(context_stop)
|
||||
|
||||
/* get irq num */
|
||||
ldr r3, =OMAP3_INTR_SIR_IRQ
|
||||
ldr r0, [r3]
|
||||
and r0, r0, #OMAP3_INTR_ACTIVEIRQ_MASK /* irq */
|
||||
/* call handler */
|
||||
bl _C_LABEL(irq_handle) /* irq_handle(irq) */
|
||||
|
||||
pop {fp} /* caller proc ptr */
|
||||
|
||||
/* allow new interrupts */
|
||||
mov r1, #OMAP3_INTR_NEWIRQAGR
|
||||
ldr r3, =OMAP3_INTR_CONTROL
|
||||
str r1, [r3]
|
||||
|
||||
/* data synchronization barrier */
|
||||
dsb
|
||||
|
||||
b _C_LABEL(switch_to_user)
|
||||
|
||||
irq_entry_from_kernel:
|
||||
push {r0-r12, lr}
|
||||
bl _C_LABEL(context_stop_idle)
|
||||
|
||||
/* get irq num */
|
||||
ldr r3, =OMAP3_INTR_SIR_IRQ
|
||||
ldr r0, [r3]
|
||||
and r0, r0, #OMAP3_INTR_ACTIVEIRQ_MASK /* irq */
|
||||
/* call handler */
|
||||
bl _C_LABEL(irq_handle) /* irq_handle(irq) */
|
||||
|
||||
/* allow new interrupts */
|
||||
mov r1, #OMAP3_INTR_NEWIRQAGR
|
||||
ldr r3, =OMAP3_INTR_CONTROL
|
||||
str r1, [r3]
|
||||
|
||||
/* data synchronization barrier */
|
||||
dsb
|
||||
|
||||
pop {r0-r12, lr}
|
||||
rfeia sp!
|
||||
|
||||
|
||||
/*
|
||||
* supervisor call (SVC) kernel entry point
|
||||
*/
|
||||
ENTRY(svc_entry)
|
||||
srsdb #MODE_SVC!
|
||||
save_process_ctx
|
||||
|
||||
/* save the pointer to the current process */
|
||||
ldr fp, [sp]
|
||||
|
||||
cmp r3, #KERVEC
|
||||
beq kernel_call_entry
|
||||
cmp r3, #IPCVEC
|
||||
beq ipc_entry
|
||||
b invalid_svc
|
||||
|
||||
/*
|
||||
* kernel call is only from a process to kernel
|
||||
*/
|
||||
ENTRY(kernel_call_entry)
|
||||
/*
|
||||
* pass the syscall arguments from userspace to the handler.
|
||||
* save_process_ctx() does not clobber these registers, they are still
|
||||
* set as the userspace has set them
|
||||
*/
|
||||
push {fp} /* save caller proc ptr */
|
||||
push {r0} /* save msg ptr so it's not clobbered */
|
||||
|
||||
/* stop user process cycles */
|
||||
mov r0, fp /* first param: caller proc ptr */
|
||||
mov fp, #0 /* for stack trace */
|
||||
bl _C_LABEL(context_stop)
|
||||
|
||||
pop {r0} /* first param: msg ptr */
|
||||
pop {r1} /* second param: caller proc ptr */
|
||||
bl _C_LABEL(kernel_call)
|
||||
|
||||
b _C_LABEL(switch_to_user)
|
||||
|
||||
/*
|
||||
* IPC is only from a process to kernel
|
||||
*/
|
||||
ENTRY(ipc_entry)
|
||||
/*
|
||||
* pass the syscall arguments from userspace to the handler.
|
||||
* save_process_ctx() does not clobber these registers, they are still
|
||||
* set as the userspace have set them
|
||||
*/
|
||||
push {fp} /* save caller proc ptr */
|
||||
push {r0-r2} /* save regs so they're not clobbered */
|
||||
|
||||
/* stop user process cycles */
|
||||
mov r0, fp /* first param: caller proc ptr */
|
||||
mov fp, #0 /* for stack trace */
|
||||
bl _C_LABEL(context_stop)
|
||||
|
||||
pop {r0-r2} /* restore regs */
|
||||
bl _C_LABEL(do_ipc)
|
||||
|
||||
/* restore the current process pointer and save the return value */
|
||||
pop {fp} /* caller proc ptr */
|
||||
str r0, [fp, #REG0]
|
||||
|
||||
b _C_LABEL(switch_to_user)
|
||||
|
||||
ENTRY(invalid_svc)
|
||||
b .
|
||||
|
||||
ENTRY(restore_user_context)
|
||||
/* sp holds the proc ptr */
|
||||
mov sp, r0
|
||||
|
||||
/* Set SPSR and LR for return */
|
||||
ldr r0, [sp, #PSREG]
|
||||
msr spsr_fsxc, r0
|
||||
ldr lr, [sp, #PCREG]
|
||||
|
||||
/* Restore user-mode registers from proc struct */
|
||||
ldm sp, {r0-r14}^
|
||||
|
||||
ldr sp, =_C_LABEL(svc_stack)
|
||||
ldr sp, [sp]
|
||||
|
||||
/* To user mode! */
|
||||
movs pc, lr
|
||||
|
||||
/*===========================================================================*/
|
||||
/* data */
|
||||
/*===========================================================================*/
|
||||
|
||||
.data
|
||||
.short 0x526F /* this must be the first data entry (magic #) */
|
||||
.bss
|
||||
.data
|
||||
.balign 4
|
||||
k_initial_stack:
|
||||
.space K_STACK_SIZE
|
||||
LABEL(__k_unpaged_k_initial_stktop)
|
||||
|
||||
/*
|
||||
* the kernel stack
|
||||
*/
|
||||
k_boot_stack:
|
||||
.space K_STACK_SIZE /* kernel stack */ /* FIXME use macro here */
|
||||
LABEL(k_boot_stktop) /* top of kernel stack */
|
||||
|
||||
.balign K_STACK_SIZE
|
||||
LABEL(k_stacks_start)
|
||||
|
||||
/* two pages for each stack, one for data, other as a sandbox */
|
||||
.space 2 * (K_STACK_SIZE * CONFIG_MAX_CPUS)
|
||||
|
||||
LABEL(k_stacks_end)
|
||||
|
||||
/* top of kernel stack */
|
19
kernel/arch/arm/omap_intr.c
Normal file
19
kernel/arch/arm/omap_intr.c
Normal file
|
@ -0,0 +1,19 @@
|
|||
#include <sys/types.h>
|
||||
#include <machine/cpu.h>
|
||||
#include <io.h>
|
||||
#include "omap_intr.h"
|
||||
|
||||
int intr_init(const int auto_eoi)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void omap3_irq_unmask(int irq)
|
||||
{
|
||||
mmio_write(OMAP3_INTR_MIR_CLEAR(irq >> 5), 1 << (irq & 0x1f));
|
||||
}
|
||||
|
||||
void omap3_irq_mask(const int irq)
|
||||
{
|
||||
mmio_write(OMAP3_INTR_MIR_SET(irq >> 5), 1 << (irq & 0x1f));
|
||||
}
|
146
kernel/arch/arm/omap_intr.h
Normal file
146
kernel/arch/arm/omap_intr.h
Normal file
|
@ -0,0 +1,146 @@
|
|||
#ifndef _OMAP_INTR_H
|
||||
#define _OMAP_INTR_H
|
||||
|
||||
/* Interrupt controller memory map */
|
||||
#define OMAP3_INTR_BASE 0x48200000 /* INTCPS physical address */
|
||||
|
||||
/* Interrupt controller registers */
|
||||
#define OMAP3_INTCPS_REVISION 0x000 /* IP revision code */
|
||||
#define OMAP3_INTCPS_SYSCONFIG 0x010 /* Controls params */
|
||||
#define OMAP3_INTCPS_SYSSTATUS 0x014 /* Status */
|
||||
#define OMAP3_INTCPS_SIR_IRQ 0x040 /* Active IRQ number */
|
||||
#define OMAP3_INTCPS_SIR_FIQ 0x044 /* Active FIQ number */
|
||||
#define OMAP3_INTCPS_CONTROL 0x048 /* New int agreement bits */
|
||||
#define OMAP3_INTCPS_PROTECTION 0x04C /* Protection for other regs */
|
||||
#define OMAP3_INTCPS_IDLE 0x050 /* Clock auto-idle/gating */
|
||||
#define OMAP3_INTCPS_IRQ_PRIORITY 0x060 /* Active IRQ priority level */
|
||||
#define OMAP3_INTCPS_FIQ_PRIORITY 0x064 /* Active FIQ priority level */
|
||||
#define OMAP3_INTCPS_THRESHOLD 0x068 /* Priority threshold */
|
||||
#define OMAP3_INTCPS_ITR0 0x080 /* Raw pre-masking interrupt status */
|
||||
#define OMAP3_INTCPS_MIR0 0x084 /* Interrupt mask */
|
||||
#define OMAP3_INTCPS_MIR_CLEAR0 0x088 /* Clear interrupt mask bits */
|
||||
#define OMAP3_INTCPS_MIR_SET0 0x08C /* Set interrupt mask bits */
|
||||
#define OMAP3_INTCPS_ISR_SET0 0x090 /* Set software int bits */
|
||||
#define OMAP3_INTCPS_ISR_CLEAR0 0x094 /* Clear software int bits */
|
||||
#define OMAP3_INTCPS_PENDING_IRQ0 0x098 /* IRQ status post-masking */
|
||||
#define OMAP3_INTCPS_PENDING_FIQ0 0x09C /* FIQ status post-masking */
|
||||
#define OMAP3_INTCPS_ILR0 0x100 /* Priority for interrupts */
|
||||
|
||||
|
||||
#define OMAP3_INTR_REVISION (OMAP3_INTR_BASE + OMAP3_INTCPS_REVISION)
|
||||
#define OMAP3_INTR_SYSCONFIG (OMAP3_INTR_BASE + OMAP3_INTCPS_SYSCONFIG)
|
||||
#define OMAP3_INTR_SYSSTATUS (OMAP3_INTR_BASE + OMAP3_INTCPS_SYSSTATUS)
|
||||
#define OMAP3_INTR_SIR_IRQ (OMAP3_INTR_BASE + OMAP3_INTCPS_SIR_IRQ)
|
||||
#define OMAP3_INTR_SIR_FIQ (OMAP3_INTR_BASE + OMAP3_INTCPS_SIR_FIQ)
|
||||
#define OMAP3_INTR_CONTROL (OMAP3_INTR_BASE + OMAP3_INTCPS_CONTROL)
|
||||
#define OMAP3_INTR_PROTECTION (OMAP3_INTR_BASE + OMAP3_INTCPS_PROTECTION)
|
||||
#define OMAP3_INTR_IDLE (OMAP3_INTR_BASE + OMAP3_INTCPS_IDLE)
|
||||
#define OMAP3_INTR_IRQ_PRIORITY (OMAP3_INTR_BASE + OMAP3_INTCPS_IRQ_PRIORITY)
|
||||
#define OMAP3_INTR_FIQ_PRIORITY (OMAP3_INTR_BASE + OMAP3_INTCPS_FIQ_PRIORITY)
|
||||
#define OMAP3_INTR_THRESHOLD (OMAP3_INTR_BASE + OMAP3_INTCPS_THRESHOLD)
|
||||
|
||||
#define OMAP3_INTR_ITR(n) \
|
||||
(OMAP3_INTR_BASE + OMAP3_INTCPS_ITR0 + 0x20 * (n))
|
||||
#define OMAP3_INTR_MIR(n) \
|
||||
(OMAP3_INTR_BASE + OMAP3_INTCPS_MIR0 + 0x20 * (n))
|
||||
#define OMAP3_INTR_MIR_CLEAR(n) \
|
||||
(OMAP3_INTR_BASE + OMAP3_INTCPS_MIR_CLEAR0 + 0x20 * (n))
|
||||
#define OMAP3_INTR_MIR_SET(n) \
|
||||
(OMAP3_INTR_BASE + OMAP3_INTCPS_MIR_SET0 + 0x20 * (n))
|
||||
#define OMAP3_INTR_ISR_SET(n) \
|
||||
(OMAP3_INTR_BASE + OMAP3_INTCPS_ISR_SET0 + 0x20 * (n))
|
||||
#define OMAP3_INTR_ISR_CLEAR(n) \
|
||||
(OMAP3_INTR_BASE + OMAP3_INTCPS_ISR_CLEAR0 + 0x20 * (n))
|
||||
#define OMAP3_INTR_PENDING_IRQ(n) \
|
||||
(OMAP3_INTR_BASE + OMAP3_INTCPS_PENDING_IRQ0 + 0x20 * (n))
|
||||
#define OMAP3_INTR_PENDING_FIQ(n) \
|
||||
(OMAP3_INTR_BASE + OMAP3_INTCPS_PENDING_FIQ0 + 0x20 * (n))
|
||||
#define OMAP3_INTR_ILR(m) \
|
||||
(OMAP3_INTR_BASE + OMAP3_INTCPS_ILR0 + 0x4 * (m))
|
||||
|
||||
#define OMAP3_INTR_ACTIVEIRQ_MASK 0x7f /* Active IRQ mask for SIR_IRQ */
|
||||
#define OMAP3_INTR_NEWIRQAGR 0x1 /* New IRQ Generation */
|
||||
|
||||
#define OMAP3_NR_IRQ_VECTORS 96
|
||||
|
||||
/* Interrupt mappings */
|
||||
#define OMAP3_MCBSP2_ST_IRQ 4 /* Sidestone McBSP2 overflow */
|
||||
#define OMAP3_MCBSP3_ST_IRQ 5 /* Sidestone McBSP3 overflow */
|
||||
#define OMAP3_SYS_NIRQ 7 /* External source (active low) */
|
||||
#define OMAP3_SMX_DBG_IRQ 9 /* L3 interconnect error for debug */
|
||||
#define OMAP3_SMX_APP_IRQ 10 /* L3 interconnect error for application */
|
||||
#define OMAP3_PRCM_IRQ 11 /* PRCM module */
|
||||
#define OMAP3_SDMA0_IRQ 12 /* System DMA request 0 */
|
||||
#define OMAP3_SDMA1_IRQ 13 /* System DMA request 1 */
|
||||
#define OMAP3_SDMA2_IRQ 14 /* System DMA request 2 */
|
||||
#define OMAP3_SDMA3_IRQ 15 /* System DMA request 3 */
|
||||
#define OMAP3_MCBSP1_IRQ 16 /* McBSP module 1 */
|
||||
#define OMAP3_MCBSP2_IRQ 17 /* McBSP module 2 */
|
||||
#define OMAP3_GPMC_IRQ 20 /* General-purpose memory controller */
|
||||
#define OMAP3_SGX_IRQ 21 /* 2D/3D graphics module */
|
||||
#define OMAP3_MCBSP3_IRQ 22 /* McBSP module 3 */
|
||||
#define OMAP3_MCBSP4_IRQ 23 /* McBSP module 4 */
|
||||
#define OMAP3_CAM0_IRQ 24 /* Camera interface request 0 */
|
||||
#define OMAP3_DSS_IRQ 25 /* Display subsystem module */
|
||||
#define OMAP3_MAIL_U0_IRQ 26 /* Mailbox user 0 request */
|
||||
#define OMAP3_MCBSP5_IRQ 27 /* McBSP module 5 */
|
||||
#define OMAP3_IVA2_MMU_IRQ 28 /* IVA2 MMU */
|
||||
#define OMAP3_GPIO1_IRQ 29 /* GPIO module 1 */
|
||||
#define OMAP3_GPIO2_IRQ 30 /* GPIO module 2 */
|
||||
#define OMAP3_GPIO3_IRQ 31 /* GPIO module 3 */
|
||||
#define OMAP3_GPIO4_IRQ 32 /* GPIO module 4 */
|
||||
#define OMAP3_GPIO5_IRQ 33 /* GPIO module 5 */
|
||||
#define OMAP3_GPIO6_IRQ 34 /* GPIO module 6 */
|
||||
#define OMAP3_WDT3_IRQ 36 /* Watchdog timer module 3 overflow */
|
||||
#define OMAP3_GPT1_IRQ 37 /* General-purpose timer module 1 */
|
||||
#define OMAP3_GPT2_IRQ 38 /* General-purpose timer module 2 */
|
||||
#define OMAP3_GPT3_IRQ 39 /* General-purpose timer module 3 */
|
||||
#define OMAP3_GPT4_IRQ 40 /* General-purpose timer module 4 */
|
||||
#define OMAP3_GPT5_IRQ 41 /* General-purpose timer module 5 */
|
||||
#define OMAP3_GPT6_IRQ 42 /* General-purpose timer module 6 */
|
||||
#define OMAP3_GPT7_IRQ 43 /* General-purpose timer module 7 */
|
||||
#define OMAP3_GPT8_IRQ 44 /* General-purpose timer module 8 */
|
||||
#define OMAP3_GPT9_IRQ 45 /* General-purpose timer module 9 */
|
||||
#define OMAP3_GPT10_IRQ 46 /* General-purpose timer module 10 */
|
||||
#define OMAP3_GPT11_IRQ 47 /* General-purpose timer module 11 */
|
||||
#define OMAP3_SPI4_IRQ 48 /* McSPI module 4 */
|
||||
#define OMAP3_MCBSP4_TX_IRQ 54 /* McBSP module 4 transmit */
|
||||
#define OMAP3_MCBSP4_RX_IRQ 55 /* McBSP module 4 receive */
|
||||
#define OMAP3_I2C1_IRQ 56 /* I2C module 1 */
|
||||
#define OMAP3_I2C2_IRQ 57 /* I2C module 2 */
|
||||
#define OMAP3_HDQ_IRQ 58 /* HDQ/1-Wire */
|
||||
#define OMAP3_MCBSP1_TX_IRQ 59 /* McBSP module 1 transmit */
|
||||
#define OMAP3_MCBSP1_RX_IRQ 60 /* McBSP module 1 receive */
|
||||
#define OMAP3_I2C3_IRQ 61 /* I2C module 3 */
|
||||
#define OMAP3_MCBSP2_TX_IRQ 62 /* McBSP module 2 transmit */
|
||||
#define OMAP3_MCBSP2_RX_IRQ 63 /* McBSP module 2 receive */
|
||||
#define OMAP3_SPI1_IRQ 65 /* McSPI module 1 */
|
||||
#define OMAP3_SPI2_IRQ 66 /* McSPI module 2 */
|
||||
#define OMAP3_UART1_IRQ 72 /* UART module 1 */
|
||||
#define OMAP3_UART2_IRQ 73 /* UART module 2 */
|
||||
#define OMAP3_PBIAS_IRQ 75 /* Merged interrupt for PBIASlite 1/2 */
|
||||
#define OMAP3_OHCI_IRQ 76 /* OHCI HSUSB MP Host Interrupt */
|
||||
#define OMAP3_EHCI_IRQ 77 /* EHCI HSUSB MP Host Interrupt */
|
||||
#define OMAP3_TLL_IRQ 78 /* HSUSB MP TLL Interrupt */
|
||||
#define OMAP3_MCBSP5_TX_IRQ 81 /* McBSP module 5 transmit */
|
||||
#define OMAP3_MCBSP5_RX_IRQ 82 /* McBSP module 5 receive */
|
||||
#define OMAP3_MMC1_IRQ 83 /* MMC/SD module 1 */
|
||||
#define OMAP3_MMC2_IRQ 86 /* MMC/SD module 2 */
|
||||
#define OMAP3_ICR_IRQ 87 /* MPU ICR */
|
||||
#define OMAP3_D2DFRINT_IRQ 88 /* 3G coproc (in stacked modem config) */
|
||||
#define OMAP3_MCBSP3_TX_IRQ 89 /* McBSP module 3 transmit */
|
||||
#define OMAP3_MCBSP3_RX_IRQ 90 /* McBSP module 3 receive */
|
||||
#define OMAP3_SPI3_IRQ 91 /* McSPI module 3 */
|
||||
#define OMAP3_HSUSB_MC_IRQ 92 /* High-speed USB OTG */
|
||||
#define OMAP3_HSUSB_DMA_IRQ 93 /* High-speed USB OTG DMA */
|
||||
#define OMAP3_MMC3_IRQ 94 /* MMC/SD module 3 */
|
||||
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
void omap3_irq_unmask(int irq);
|
||||
void omap3_irq_mask(int irq);
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
#endif /* _OMAP_INTR_H */
|
17
kernel/arch/arm/omap_serial.c
Normal file
17
kernel/arch/arm/omap_serial.c
Normal file
|
@ -0,0 +1,17 @@
|
|||
#include <sys/types.h>
|
||||
#include <machine/cpu.h>
|
||||
#include <io.h>
|
||||
#include "omap_serial.h"
|
||||
|
||||
void omap3_ser_putc(char c)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Wait until FIFO's empty */
|
||||
for (i = 0; i < 100000; i++)
|
||||
if (mmio_read(OMAP3_UART3_LSR) & OMAP3_LSR_TX_FIFO_E)
|
||||
break;
|
||||
|
||||
/* Write character */
|
||||
mmio_write(OMAP3_UART3_THR, c);
|
||||
}
|
30
kernel/arch/arm/omap_serial.h
Normal file
30
kernel/arch/arm/omap_serial.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
#ifndef _OMAP_SERIAL_H
|
||||
#define _OMAP_SERIAL_H
|
||||
|
||||
/* UART register map */
|
||||
#define OMAP3_UART1_BASE 0x4806A000 /* UART1 physical address */
|
||||
#define OMAP3_UART2_BASE 0x4806C000 /* UART2 physical address */
|
||||
#define OMAP3_UART3_BASE 0x49020000 /* UART3 physical address */
|
||||
|
||||
/* UART registers */
|
||||
#define OMAP3_THR 0x000 /* Transmit holding register */
|
||||
#define OMAP3_LSR 0x014 /* Line status register */
|
||||
#define OMAP3_SSR 0x044 /* Supplementary status register */
|
||||
|
||||
/* Line status register fields */
|
||||
#define OMAP3_LSR_TX_FIFO_E (1 << 5) /* Transmit FIFO empty */
|
||||
|
||||
/* Supplementary status register fields */
|
||||
#define OMAP3_SSR_TX_FIFO_FULL (1 << 0) /* Transmit FIFO full */
|
||||
|
||||
#define OMAP3_UART3_THR (OMAP3_UART3_BASE + OMAP3_THR)
|
||||
#define OMAP3_UART3_LSR (OMAP3_UART3_BASE + OMAP3_LSR)
|
||||
#define OMAP3_UART3_SSR (OMAP3_UART3_BASE + OMAP3_SSR)
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
void omap3_ser_putc(char c);
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
#endif /* _OMAP_SERIAL_H */
|
66
kernel/arch/arm/omap_timer.c
Normal file
66
kernel/arch/arm/omap_timer.c
Normal file
|
@ -0,0 +1,66 @@
|
|||
#include "kernel/kernel.h"
|
||||
#include "kernel/clock.h"
|
||||
#include <sys/types.h>
|
||||
#include <machine/cpu.h>
|
||||
#include <io.h>
|
||||
#include "arch_proto.h"
|
||||
#include "omap_timer.h"
|
||||
#include "omap_intr.h"
|
||||
|
||||
static irq_hook_t omap3_timer_hook; /* interrupt handler hook */
|
||||
|
||||
int omap3_register_timer_handler(const irq_handler_t handler)
|
||||
{
|
||||
/* Initialize the CLOCK's interrupt hook. */
|
||||
omap3_timer_hook.proc_nr_e = NONE;
|
||||
omap3_timer_hook.irq = OMAP3_GPT1_IRQ;
|
||||
|
||||
put_irq_handler(&omap3_timer_hook, OMAP3_GPT1_IRQ, handler);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void omap3_timer_init(unsigned freq)
|
||||
{
|
||||
/* Stop timer */
|
||||
mmio_clear(OMAP3_GPTIMER1_TCLR, OMAP3_TCLR_ST);
|
||||
|
||||
/* Use 32 KHz clock source for GPTIMER1 */
|
||||
mmio_clear(OMAP3_CM_CLKSEL_WKUP, OMAP3_CLKSEL_GPT1);
|
||||
|
||||
/* Use 1-ms tick mode for GPTIMER1 */
|
||||
mmio_write(OMAP3_GPTIMER1_TPIR, 232000);
|
||||
mmio_write(OMAP3_GPTIMER1_TNIR, -768000);
|
||||
mmio_write(OMAP3_GPTIMER1_TLDR, 0xffffffe0);
|
||||
mmio_write(OMAP3_GPTIMER1_TCRR, 0xffffffe0);
|
||||
|
||||
/* Set frequency */
|
||||
mmio_write(OMAP3_GPTIMER1_TOWR, TIMER_COUNT(freq));
|
||||
|
||||
/* Set up overflow interrupt */
|
||||
mmio_write(OMAP3_GPTIMER1_TISR, ~0);
|
||||
mmio_write(OMAP3_GPTIMER1_TIER, OMAP3_TIER_OVF_IT_ENA);
|
||||
omap3_irq_unmask(OMAP3_GPT1_IRQ);
|
||||
|
||||
/* Start timer */
|
||||
mmio_set(OMAP3_GPTIMER1_TCLR,
|
||||
OMAP3_TCLR_OVF_TRG|OMAP3_TCLR_AR|OMAP3_TCLR_ST);
|
||||
}
|
||||
|
||||
void omap3_timer_stop()
|
||||
{
|
||||
mmio_clear(OMAP3_GPTIMER1_TCLR, OMAP3_TCLR_ST);
|
||||
}
|
||||
|
||||
static u64_t tsc;
|
||||
void omap3_timer_int_handler()
|
||||
{
|
||||
/* Clear the interrupt */
|
||||
mmio_write(OMAP3_GPTIMER1_TISR, ~0);
|
||||
tsc++;
|
||||
}
|
||||
|
||||
void read_tsc_64(u64_t *t)
|
||||
{
|
||||
*t = tsc;
|
||||
}
|
95
kernel/arch/arm/omap_timer.h
Normal file
95
kernel/arch/arm/omap_timer.h
Normal file
|
@ -0,0 +1,95 @@
|
|||
#ifndef _OMAP_TIMER_H
|
||||
#define _OMAP_TIMER_H
|
||||
|
||||
/* General-purpose timer register map */
|
||||
#define OMAP3_GPTIMER1_BASE 0x48318000 /* GPTIMER1 physical address */
|
||||
#define OMAP3_GPTIMER2_BASE 0x49032000 /* GPTIMER2 physical address */
|
||||
#define OMAP3_GPTIMER3_BASE 0x49034000 /* GPTIMER3 physical address */
|
||||
#define OMAP3_GPTIMER4_BASE 0x49036000 /* GPTIMER4 physical address */
|
||||
#define OMAP3_GPTIMER5_BASE 0x49038000 /* GPTIMER5 physical address */
|
||||
#define OMAP3_GPTIMER6_BASE 0x4903A000 /* GPTIMER6 physical address */
|
||||
#define OMAP3_GPTIMER7_BASE 0x4903C000 /* GPTIMER7 physical address */
|
||||
#define OMAP3_GPTIMER8_BASE 0x4903E000 /* GPTIMER8 physical address */
|
||||
#define OMAP3_GPTIMER9_BASE 0x49040000 /* GPTIMER9 physical address */
|
||||
#define OMAP3_GPTIMER10_BASE 0x48086000 /* GPTIMER10 physical address */
|
||||
#define OMAP3_GPTIMER11_BASE 0x48088000 /* GPTIMER11 physical address */
|
||||
|
||||
/* General-purpose timer registers */
|
||||
#define OMAP3_TIDR 0x000 /* IP revision code */
|
||||
#define OMAP3_TIOCP_CFG 0x010 /* Controls params for GP timer L4 interface */
|
||||
#define OMAP3_TISTAT 0x014 /* Status (excl. interrupt status) */
|
||||
#define OMAP3_TISR 0x018 /* Pending interrupt status */
|
||||
#define OMAP3_TIER 0x01C /* Interrupt enable */
|
||||
#define OMAP3_TWER 0x020 /* Wakeup enable */
|
||||
#define OMAP3_TCLR 0x024 /* Controls optional features */
|
||||
#define OMAP3_TCRR 0x028 /* Internal counter value */
|
||||
#define OMAP3_TLDR 0x02C /* Timer load value */
|
||||
#define OMAP3_TTGR 0x030 /* Triggers counter reload */
|
||||
#define OMAP3_TWPS 0x034 /* Indicates if Write-Posted pending */
|
||||
#define OMAP3_TMAR 0x038 /* Value to be compared with counter */
|
||||
#define OMAP3_TCAR1 0x03C /* First captured value of counter register */
|
||||
#define OMAP3_TSICR 0x040 /* Control posted mode and functional SW reset */
|
||||
#define OMAP3_TCAR2 0x044 /* Second captured value of counter register */
|
||||
#define OMAP3_TPIR 0x048 /* Positive increment (1 ms tick) */
|
||||
#define OMAP3_TNIR 0x04C /* Negative increment (1 ms tick) */
|
||||
#define OMAP3_TCVR 0x050 /* Defines TCRR is sub/over-period (1 ms tick) */
|
||||
#define OMAP3_TOCR 0x054 /* Masks tick interrupt */
|
||||
#define OMAP3_TOWR 0x058 /* Number of masked overflow interrupts */
|
||||
|
||||
/* Interrupt status register fields */
|
||||
#define OMAP3_TISR_MAT_IT_FLAG (1 << 0) /* Pending match interrupt status */
|
||||
#define OMAP3_TISR_OVF_IT_FLAG (1 << 1) /* Pending overflow interrupt status */
|
||||
#define OMAP3_TISR_TCAR_IT_FLAG (1 << 2) /* Pending capture interrupt status */
|
||||
|
||||
/* Interrupt enable register fields */
|
||||
#define OMAP3_TIER_MAT_IT_ENA (1 << 0) /* Enable match interrupt */
|
||||
#define OMAP3_TIER_OVF_IT_ENA (1 << 1) /* Enable overflow interrupt */
|
||||
#define OMAP3_TIER_TCAR_IT_ENA (1 << 2) /* Enable capture interrupt */
|
||||
|
||||
/* Timer control fields */
|
||||
#define OMAP3_TCLR_ST (1 << 0) /* Start/stop timer */
|
||||
#define OMAP3_TCLR_AR (1 << 1) /* Autoreload or one-shot mode */
|
||||
#define OMAP3_TCLR_OVF_TRG (1 << 10) /* Overflow trigger */
|
||||
|
||||
#define OMAP3_GPTIMER1_TIDR (OMAP3_GPTIMER1_BASE + OMAP3_TIDR)
|
||||
#define OMAP3_GPTIMER1_TIOCP_CFG (OMAP3_GPTIMER1_BASE + OMAP3_TIOCP_CFG)
|
||||
#define OMAP3_GPTIMER1_TISTAT (OMAP3_GPTIMER1_BASE + OMAP3_TISTAT)
|
||||
#define OMAP3_GPTIMER1_TISR (OMAP3_GPTIMER1_BASE + OMAP3_TISR)
|
||||
#define OMAP3_GPTIMER1_TIER (OMAP3_GPTIMER1_BASE + OMAP3_TIER)
|
||||
#define OMAP3_GPTIMER1_TWER (OMAP3_GPTIMER1_BASE + OMAP3_TWER)
|
||||
#define OMAP3_GPTIMER1_TCLR (OMAP3_GPTIMER1_BASE + OMAP3_TCLR)
|
||||
#define OMAP3_GPTIMER1_TCRR (OMAP3_GPTIMER1_BASE + OMAP3_TCRR)
|
||||
#define OMAP3_GPTIMER1_TLDR (OMAP3_GPTIMER1_BASE + OMAP3_TLDR)
|
||||
#define OMAP3_GPTIMER1_TTGR (OMAP3_GPTIMER1_BASE + OMAP3_TTGR)
|
||||
#define OMAP3_GPTIMER1_TWPS (OMAP3_GPTIMER1_BASE + OMAP3_TWPS)
|
||||
#define OMAP3_GPTIMER1_TMAR (OMAP3_GPTIMER1_BASE + OMAP3_TMAR)
|
||||
#define OMAP3_GPTIMER1_TCAR1 (OMAP3_GPTIMER1_BASE + OMAP3_TCAR1)
|
||||
#define OMAP3_GPTIMER1_TSICR (OMAP3_GPTIMER1_BASE + OMAP3_TSICR)
|
||||
#define OMAP3_GPTIMER1_TCAR2 (OMAP3_GPTIMER1_BASE + OMAP3_TCAR2)
|
||||
#define OMAP3_GPTIMER1_TPIR (OMAP3_GPTIMER1_BASE + OMAP3_TPIR)
|
||||
#define OMAP3_GPTIMER1_TNIR (OMAP3_GPTIMER1_BASE + OMAP3_TNIR)
|
||||
#define OMAP3_GPTIMER1_TCVR (OMAP3_GPTIMER1_BASE + OMAP3_TCVR)
|
||||
#define OMAP3_GPTIMER1_TOCR (OMAP3_GPTIMER1_BASE + OMAP3_TOCR)
|
||||
#define OMAP3_GPTIMER1_TOWR (OMAP3_GPTIMER1_BASE + OMAP3_TOWR)
|
||||
|
||||
#define OMAP3_CM_CLKSEL_WKUP 0x48004c40 /* source clock selection */
|
||||
#define OMAP3_CLKSEL_GPT1 (1 << 0) /* Selects GPTIMER 1 source
|
||||
* clock:
|
||||
*
|
||||
* 0: use 32KHz clock
|
||||
* 1: sys clock)
|
||||
*/
|
||||
|
||||
#define TIMER_FREQ 1000 /* clock frequency for OMAP timer (1ms) */
|
||||
#define TIMER_COUNT(freq) (TIMER_FREQ/(freq)) /* initial value for counter*/
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
void omap3_timer_init(unsigned freq);
|
||||
void omap3_timer_stop(void);
|
||||
int omap3_register_timer_handler(const irq_handler_t handler);
|
||||
void omap3_timer_int_handler(void);
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
#endif /* _OMAP_TIMER_H */
|
292
kernel/arch/arm/pg_utils.c
Normal file
292
kernel/arch/arm/pg_utils.c
Normal file
|
@ -0,0 +1,292 @@
|
|||
|
||||
#include <minix/cpufeature.h>
|
||||
|
||||
#include <minix/type.h>
|
||||
#include <libexec.h>
|
||||
#include <assert.h>
|
||||
#include "kernel.h"
|
||||
#include "arch_proto.h"
|
||||
#include <machine/cpu.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <libexec.h>
|
||||
#include <minix/type.h>
|
||||
|
||||
/* These are set/computed in kernel.lds. */
|
||||
extern char _kern_vir_base, _kern_phys_base, _kern_size;
|
||||
|
||||
/* Retrieve the absolute values to something we can use. */
|
||||
static phys_bytes kern_vir_start = (phys_bytes) &_kern_vir_base;
|
||||
static phys_bytes kern_phys_start = (phys_bytes) &_kern_phys_base;
|
||||
static phys_bytes kern_kernlen = (phys_bytes) &_kern_size;
|
||||
|
||||
/* page directory we can use to map things */
|
||||
static u32_t pagedir[4096] __aligned(16384);
|
||||
|
||||
void print_memmap(kinfo_t *cbi)
|
||||
{
|
||||
int m;
|
||||
assert(cbi->mmap_size < MAXMEMMAP);
|
||||
for(m = 0; m < cbi->mmap_size; m++) {
|
||||
phys_bytes addr = cbi->memmap[m].addr, endit = cbi->memmap[m].addr + cbi->memmap[m].len;
|
||||
printf("%08lx-%08lx ",addr, endit);
|
||||
}
|
||||
printf("\nsize %08lx\n", cbi->mmap_size);
|
||||
}
|
||||
|
||||
void cut_memmap(kinfo_t *cbi, phys_bytes start, phys_bytes end)
|
||||
{
|
||||
int m;
|
||||
phys_bytes o;
|
||||
|
||||
if((o=start % ARM_PAGE_SIZE))
|
||||
start -= o;
|
||||
if((o=end % ARM_PAGE_SIZE))
|
||||
end += ARM_PAGE_SIZE - o;
|
||||
|
||||
assert(kernel_may_alloc);
|
||||
|
||||
for(m = 0; m < cbi->mmap_size; m++) {
|
||||
phys_bytes substart = start, subend = end;
|
||||
phys_bytes memaddr = cbi->memmap[m].addr,
|
||||
memend = cbi->memmap[m].addr + cbi->memmap[m].len;
|
||||
|
||||
/* adjust cut range to be a subset of the free memory */
|
||||
if(substart < memaddr) substart = memaddr;
|
||||
if(subend > memend) subend = memend;
|
||||
if(substart >= subend) continue;
|
||||
|
||||
/* if there is any overlap, forget this one and add
|
||||
* 1-2 subranges back
|
||||
*/
|
||||
cbi->memmap[m].addr = cbi->memmap[m].len = 0;
|
||||
if(substart > memaddr)
|
||||
add_memmap(cbi, memaddr, substart-memaddr);
|
||||
if(subend < memend)
|
||||
add_memmap(cbi, subend, memend-subend);
|
||||
}
|
||||
}
|
||||
|
||||
phys_bytes alloc_lowest(kinfo_t *cbi, phys_bytes len)
|
||||
{
|
||||
/* Allocate the lowest physical page we have. */
|
||||
int m;
|
||||
#define EMPTY 0xffffffff
|
||||
phys_bytes lowest = EMPTY;
|
||||
assert(len > 0);
|
||||
len = roundup(len, ARM_PAGE_SIZE);
|
||||
|
||||
assert(kernel_may_alloc);
|
||||
|
||||
for(m = 0; m < cbi->mmap_size; m++) {
|
||||
if(cbi->memmap[m].len < len) continue;
|
||||
if(cbi->memmap[m].addr < lowest) lowest = cbi->memmap[m].addr;
|
||||
}
|
||||
assert(lowest != EMPTY);
|
||||
cut_memmap(cbi, lowest, len);
|
||||
return lowest;
|
||||
}
|
||||
|
||||
void add_memmap(kinfo_t *cbi, u64_t addr, u64_t len)
|
||||
{
|
||||
int m;
|
||||
#define LIMIT 0xFFFFF000
|
||||
/* Truncate available memory at 4GB as the rest of minix
|
||||
* currently can't deal with any bigger.
|
||||
*/
|
||||
if(addr > LIMIT) return;
|
||||
if(addr + len > LIMIT) {
|
||||
len -= (addr + len - LIMIT);
|
||||
}
|
||||
assert(cbi->mmap_size < MAXMEMMAP);
|
||||
if(len == 0) return;
|
||||
addr = roundup(addr, ARM_PAGE_SIZE);
|
||||
len = rounddown(len, ARM_PAGE_SIZE);
|
||||
|
||||
assert(kernel_may_alloc);
|
||||
|
||||
for(m = 0; m < MAXMEMMAP; m++) {
|
||||
phys_bytes highmark;
|
||||
if(cbi->memmap[m].len) continue;
|
||||
cbi->memmap[m].addr = addr;
|
||||
cbi->memmap[m].len = len;
|
||||
cbi->memmap[m].type = MULTIBOOT_MEMORY_AVAILABLE;
|
||||
if(m >= cbi->mmap_size)
|
||||
cbi->mmap_size = m+1;
|
||||
highmark = addr + len;
|
||||
if(highmark > cbi->mem_high_phys) {
|
||||
cbi->mem_high_phys = highmark;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
panic("no available memmap slot");
|
||||
}
|
||||
|
||||
u32_t *alloc_pagetable(phys_bytes *ph)
|
||||
{
|
||||
u32_t *ret;
|
||||
#define PG_PAGETABLES 24
|
||||
static u32_t pagetables[PG_PAGETABLES][256] __aligned(1024);
|
||||
static int pt_inuse = 0;
|
||||
if(pt_inuse >= PG_PAGETABLES) panic("no more pagetables");
|
||||
assert(sizeof(pagetables[pt_inuse]) == 1024);
|
||||
ret = pagetables[pt_inuse++];
|
||||
*ph = vir2phys(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define PAGE_KB (ARM_PAGE_SIZE / 1024)
|
||||
|
||||
phys_bytes pg_alloc_page(kinfo_t *cbi)
|
||||
{
|
||||
int m;
|
||||
multiboot_memory_map_t *mmap;
|
||||
|
||||
assert(kernel_may_alloc);
|
||||
|
||||
for(m = 0; m < cbi->mmap_size; m++) {
|
||||
mmap = &cbi->memmap[m];
|
||||
if(!mmap->len) continue;
|
||||
assert(mmap->len > 0);
|
||||
assert(!(mmap->len % ARM_PAGE_SIZE));
|
||||
assert(!(mmap->addr % ARM_PAGE_SIZE));
|
||||
|
||||
u32_t addr = mmap->addr;
|
||||
mmap->addr += ARM_PAGE_SIZE;
|
||||
mmap->len -= ARM_PAGE_SIZE;
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
panic("can't find free memory");
|
||||
}
|
||||
|
||||
void pg_identity(kinfo_t *cbi)
|
||||
{
|
||||
int i;
|
||||
phys_bytes phys;
|
||||
|
||||
/* We map memory that does not correspond to physical memory
|
||||
* as non-cacheable. Make sure we know what it is.
|
||||
*/
|
||||
assert(cbi->mem_high_phys);
|
||||
|
||||
/* Set up an identity mapping page directory */
|
||||
for(i = 0; i < ARM_VM_DIR_ENTRIES; i++) {
|
||||
u32_t flags = ARM_VM_SECTION |
|
||||
ARM_VM_SECTION_DOMAIN | ARM_VM_SECTION_USER;
|
||||
phys = i * ARM_BIG_PAGE_SIZE;
|
||||
pagedir[i] = phys | flags;
|
||||
}
|
||||
}
|
||||
|
||||
int pg_mapkernel(void)
|
||||
{
|
||||
int pde;
|
||||
u32_t mapped = 0, kern_phys = kern_phys_start;
|
||||
|
||||
assert(!(kern_vir_start % ARM_BIG_PAGE_SIZE));
|
||||
assert(!(kern_phys_start % ARM_BIG_PAGE_SIZE));
|
||||
pde = kern_vir_start / ARM_BIG_PAGE_SIZE; /* start pde */
|
||||
while(mapped < kern_kernlen) {
|
||||
pagedir[pde] = (kern_phys & ARM_VM_PDE_MASK) |
|
||||
ARM_VM_SECTION |
|
||||
ARM_VM_SECTION_DOMAIN | ARM_VM_SECTION_WB |
|
||||
ARM_VM_SECTION_SHAREABLE | ARM_VM_SECTION_SUPER;
|
||||
mapped += ARM_BIG_PAGE_SIZE;
|
||||
kern_phys += ARM_BIG_PAGE_SIZE;
|
||||
pde++;
|
||||
}
|
||||
return pde; /* free pde */
|
||||
}
|
||||
|
||||
void vm_enable_paging(void)
|
||||
{
|
||||
u32_t sctlr;
|
||||
|
||||
write_ttbcr(0);
|
||||
|
||||
/* Set all Domains to Client */
|
||||
write_dacr(0x55555555);
|
||||
|
||||
/* Enable MMU and access flag */
|
||||
sctlr = read_sctlr();
|
||||
sctlr |= (SCTLR_M);
|
||||
write_sctlr(sctlr);
|
||||
}
|
||||
|
||||
phys_bytes pg_load()
|
||||
{
|
||||
phys_bytes phpagedir = vir2phys(pagedir);
|
||||
refresh_tlb();
|
||||
write_ttbr0(phpagedir);
|
||||
return phpagedir;
|
||||
}
|
||||
|
||||
void pg_clear(void)
|
||||
{
|
||||
memset(pagedir, 0, sizeof(pagedir));
|
||||
}
|
||||
|
||||
phys_bytes pg_rounddown(phys_bytes b)
|
||||
{
|
||||
phys_bytes o;
|
||||
if(!(o = b % ARM_PAGE_SIZE))
|
||||
return b;
|
||||
return b - o;
|
||||
}
|
||||
|
||||
void pg_map(phys_bytes phys, vir_bytes vaddr, vir_bytes vaddr_end,
|
||||
kinfo_t *cbi)
|
||||
{
|
||||
static int mapped_pde = -1;
|
||||
static u32_t *pt = NULL;
|
||||
int pde, pte;
|
||||
|
||||
assert(kernel_may_alloc);
|
||||
|
||||
if(phys == PG_ALLOCATEME) {
|
||||
assert(!(vaddr % ARM_PAGE_SIZE));
|
||||
} else {
|
||||
assert((vaddr % ARM_PAGE_SIZE) == (phys % ARM_PAGE_SIZE));
|
||||
vaddr = pg_rounddown(vaddr);
|
||||
phys = pg_rounddown(phys);
|
||||
}
|
||||
assert(vaddr < kern_vir_start);
|
||||
|
||||
while(vaddr < vaddr_end) {
|
||||
phys_bytes source = phys;
|
||||
assert(!(vaddr % ARM_PAGE_SIZE));
|
||||
if(phys == PG_ALLOCATEME) {
|
||||
source = pg_alloc_page(cbi);
|
||||
} else {
|
||||
assert(!(phys % ARM_PAGE_SIZE));
|
||||
}
|
||||
assert(!(source % ARM_PAGE_SIZE));
|
||||
pde = ARM_VM_PDE(vaddr);
|
||||
pte = ARM_VM_PTE(vaddr);
|
||||
if(mapped_pde < pde) {
|
||||
phys_bytes ph;
|
||||
pt = alloc_pagetable(&ph);
|
||||
pagedir[pde] = (ph & ARM_VM_PDE_MASK)
|
||||
| ARM_VM_PAGEDIR | ARM_VM_PDE_DOMAIN;
|
||||
mapped_pde = pde;
|
||||
}
|
||||
assert(pt);
|
||||
pt[pte] = (source & ARM_VM_PTE_MASK)
|
||||
| ARM_VM_PAGETABLE
|
||||
| ARM_VM_PTE_WB | ARM_VM_PTE_SHAREABLE
|
||||
| ARM_VM_PTE_USER;
|
||||
vaddr += ARM_PAGE_SIZE;
|
||||
if(phys != PG_ALLOCATEME)
|
||||
phys += ARM_PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
void pg_info(reg_t *pagedir_ph, u32_t **pagedir_v)
|
||||
{
|
||||
*pagedir_ph = vir2phys(pagedir);
|
||||
*pagedir_v = pagedir;
|
||||
}
|
389
kernel/arch/arm/phys_copy.S
Normal file
389
kernel/arch/arm/phys_copy.S
Normal file
|
@ -0,0 +1,389 @@
|
|||
/* $NetBSD: memcpy_arm.S,v 1.2 2008/04/28 20:22:52 martin Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1997 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Neil A. Carson and Mark Brinicombe
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``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 FOUNDATION OR CONTRIBUTORS
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <machine/asm.h>
|
||||
|
||||
/*
|
||||
* This is one fun bit of code ...
|
||||
* Some easy listening music is suggested while trying to understand this
|
||||
* code e.g. Iron Maiden
|
||||
*
|
||||
* For anyone attempting to understand it :
|
||||
*
|
||||
* The core code is implemented here with simple stubs for memcpy().
|
||||
*
|
||||
* All local labels are prefixed with Lmemcpy_
|
||||
* Following the prefix a label starting f is used in the forward copy code
|
||||
* while a label using b is used in the backwards copy code
|
||||
* The source and destination addresses determine whether a forward or
|
||||
* backward copy is performed.
|
||||
* Separate bits of code are used to deal with the following situations
|
||||
* for both the forward and backwards copy.
|
||||
* unaligned source address
|
||||
* unaligned destination address
|
||||
* Separate copy routines are used to produce an optimised result for each
|
||||
* of these cases.
|
||||
* The copy code will use LDM/STM instructions to copy up to 32 bytes at
|
||||
* a time where possible.
|
||||
*
|
||||
* Note: r12 (aka ip) can be trashed during the function along with
|
||||
* r0-r3 although r0-r2 have defined uses i.e. src, dest, len through out.
|
||||
* Additional registers are preserved prior to use i.e. r4, r5 & lr
|
||||
*
|
||||
* Apologies for the state of the comments ;-)
|
||||
*/
|
||||
|
||||
/* For MINIX, we always spill r0, r4, r5, and lr, so we can easily
|
||||
* clean up the stack after a phys_copy fault. NetBSD, in contrast,
|
||||
* spills the minimum number of registers for each path.
|
||||
*/
|
||||
#if defined(__minix)
|
||||
/* LINTSTUB: Func: void *phys_copy(void *src, void *dst, size_t len) */
|
||||
ENTRY(phys_copy)
|
||||
/* switch the source and destination registers */
|
||||
eor r0, r1, r0
|
||||
eor r1, r0, r1
|
||||
eor r0, r1, r0
|
||||
#else
|
||||
/* LINTSTUB: Func: void *memcpy(void *dst, const void *src, size_t len) */
|
||||
ENTRY(memcpy)
|
||||
#endif
|
||||
/* save leaf functions having to store this away */
|
||||
#if defined(__minix)
|
||||
stmdb sp!, {r0, r4, r5, lr} /* memcpy() returns dest addr */
|
||||
#else
|
||||
stmdb sp!, {r0, lr} /* memcpy() returns dest addr */
|
||||
#endif
|
||||
|
||||
subs r2, r2, #4
|
||||
blt .Lmemcpy_l4 /* less than 4 bytes */
|
||||
ands r12, r0, #3
|
||||
bne .Lmemcpy_destul /* oh unaligned destination addr */
|
||||
ands r12, r1, #3
|
||||
bne .Lmemcpy_srcul /* oh unaligned source addr */
|
||||
|
||||
.Lmemcpy_t8:
|
||||
/* We have aligned source and destination */
|
||||
subs r2, r2, #8
|
||||
blt .Lmemcpy_l12 /* less than 12 bytes (4 from above) */
|
||||
subs r2, r2, #0x14
|
||||
blt .Lmemcpy_l32 /* less than 32 bytes (12 from above) */
|
||||
#if !defined(__minix)
|
||||
stmdb sp!, {r4} /* borrow r4 */
|
||||
#endif
|
||||
|
||||
/* blat 32 bytes at a time */
|
||||
/* XXX for really big copies perhaps we should use more registers */
|
||||
.Lmemcpy_loop32:
|
||||
ldmia r1!, {r3, r4, r12, lr}
|
||||
stmia r0!, {r3, r4, r12, lr}
|
||||
ldmia r1!, {r3, r4, r12, lr}
|
||||
stmia r0!, {r3, r4, r12, lr}
|
||||
subs r2, r2, #0x20
|
||||
bge .Lmemcpy_loop32
|
||||
|
||||
cmn r2, #0x10
|
||||
ldmgeia r1!, {r3, r4, r12, lr} /* blat a remaining 16 bytes */
|
||||
stmgeia r0!, {r3, r4, r12, lr}
|
||||
subge r2, r2, #0x10
|
||||
#if !defined(__minix)
|
||||
ldmia sp!, {r4} /* return r4 */
|
||||
#endif
|
||||
|
||||
.Lmemcpy_l32:
|
||||
adds r2, r2, #0x14
|
||||
|
||||
/* blat 12 bytes at a time */
|
||||
.Lmemcpy_loop12:
|
||||
ldmgeia r1!, {r3, r12, lr}
|
||||
stmgeia r0!, {r3, r12, lr}
|
||||
subges r2, r2, #0x0c
|
||||
bge .Lmemcpy_loop12
|
||||
|
||||
.Lmemcpy_l12:
|
||||
adds r2, r2, #8
|
||||
blt .Lmemcpy_l4
|
||||
|
||||
subs r2, r2, #4
|
||||
ldrlt r3, [r1], #4
|
||||
strlt r3, [r0], #4
|
||||
ldmgeia r1!, {r3, r12}
|
||||
stmgeia r0!, {r3, r12}
|
||||
subge r2, r2, #4
|
||||
|
||||
.Lmemcpy_l4:
|
||||
/* less than 4 bytes to go */
|
||||
adds r2, r2, #4
|
||||
#if defined(__minix)
|
||||
ldmeqia sp!, {r0, r4, r5}
|
||||
moveq r0, #0
|
||||
ldmeqia sp!, {pc}
|
||||
#else
|
||||
#ifdef __APCS_26_
|
||||
ldmeqia sp!, {r0, pc}^ /* done */
|
||||
#else
|
||||
ldmeqia sp!, {r0, pc} /* done */
|
||||
#endif
|
||||
#endif
|
||||
/* copy the crud byte at a time */
|
||||
cmp r2, #2
|
||||
ldrb r3, [r1], #1
|
||||
strb r3, [r0], #1
|
||||
ldrgeb r3, [r1], #1
|
||||
strgeb r3, [r0], #1
|
||||
ldrgtb r3, [r1], #1
|
||||
strgtb r3, [r0], #1
|
||||
#if defined(__minix)
|
||||
ldmia sp!, {r0, r4, r5}
|
||||
mov r0, #0
|
||||
ldmia sp!, {pc}
|
||||
#else
|
||||
ldmia sp!, {r0, pc}
|
||||
#endif
|
||||
|
||||
/* erg - unaligned destination */
|
||||
.Lmemcpy_destul:
|
||||
rsb r12, r12, #4
|
||||
cmp r12, #2
|
||||
|
||||
/* align destination with byte copies */
|
||||
ldrb r3, [r1], #1
|
||||
strb r3, [r0], #1
|
||||
ldrgeb r3, [r1], #1
|
||||
strgeb r3, [r0], #1
|
||||
ldrgtb r3, [r1], #1
|
||||
strgtb r3, [r0], #1
|
||||
subs r2, r2, r12
|
||||
blt .Lmemcpy_l4 /* less the 4 bytes */
|
||||
|
||||
ands r12, r1, #3
|
||||
beq .Lmemcpy_t8 /* we have an aligned source */
|
||||
|
||||
/* erg - unaligned source */
|
||||
/* This is where it gets nasty ... */
|
||||
.Lmemcpy_srcul:
|
||||
bic r1, r1, #3
|
||||
ldr lr, [r1], #4
|
||||
cmp r12, #2
|
||||
bgt .Lmemcpy_srcul3
|
||||
beq .Lmemcpy_srcul2
|
||||
cmp r2, #0x0c
|
||||
blt .Lmemcpy_srcul1loop4
|
||||
sub r2, r2, #0x0c
|
||||
#if !defined(__minix)
|
||||
stmdb sp!, {r4, r5}
|
||||
#endif
|
||||
|
||||
.Lmemcpy_srcul1loop16:
|
||||
#ifdef __ARMEB__
|
||||
mov r3, lr, lsl #8
|
||||
#else
|
||||
mov r3, lr, lsr #8
|
||||
#endif
|
||||
ldmia r1!, {r4, r5, r12, lr}
|
||||
#ifdef __ARMEB__
|
||||
orr r3, r3, r4, lsr #24
|
||||
mov r4, r4, lsl #8
|
||||
orr r4, r4, r5, lsr #24
|
||||
mov r5, r5, lsl #8
|
||||
orr r5, r5, r12, lsr #24
|
||||
mov r12, r12, lsl #8
|
||||
orr r12, r12, lr, lsr #24
|
||||
#else
|
||||
orr r3, r3, r4, lsl #24
|
||||
mov r4, r4, lsr #8
|
||||
orr r4, r4, r5, lsl #24
|
||||
mov r5, r5, lsr #8
|
||||
orr r5, r5, r12, lsl #24
|
||||
mov r12, r12, lsr #8
|
||||
orr r12, r12, lr, lsl #24
|
||||
#endif
|
||||
stmia r0!, {r3-r5, r12}
|
||||
subs r2, r2, #0x10
|
||||
bge .Lmemcpy_srcul1loop16
|
||||
#if !defined(__minix)
|
||||
ldmia sp!, {r4, r5}
|
||||
#endif
|
||||
adds r2, r2, #0x0c
|
||||
blt .Lmemcpy_srcul1l4
|
||||
|
||||
.Lmemcpy_srcul1loop4:
|
||||
#ifdef __ARMEB__
|
||||
mov r12, lr, lsl #8
|
||||
#else
|
||||
mov r12, lr, lsr #8
|
||||
#endif
|
||||
ldr lr, [r1], #4
|
||||
#ifdef __ARMEB__
|
||||
orr r12, r12, lr, lsr #24
|
||||
#else
|
||||
orr r12, r12, lr, lsl #24
|
||||
#endif
|
||||
str r12, [r0], #4
|
||||
subs r2, r2, #4
|
||||
bge .Lmemcpy_srcul1loop4
|
||||
|
||||
.Lmemcpy_srcul1l4:
|
||||
sub r1, r1, #3
|
||||
b .Lmemcpy_l4
|
||||
|
||||
.Lmemcpy_srcul2:
|
||||
cmp r2, #0x0c
|
||||
blt .Lmemcpy_srcul2loop4
|
||||
sub r2, r2, #0x0c
|
||||
#if !defined(__minix)
|
||||
stmdb sp!, {r4, r5}
|
||||
#endif
|
||||
|
||||
.Lmemcpy_srcul2loop16:
|
||||
#ifdef __ARMEB__
|
||||
mov r3, lr, lsl #16
|
||||
#else
|
||||
mov r3, lr, lsr #16
|
||||
#endif
|
||||
ldmia r1!, {r4, r5, r12, lr}
|
||||
#ifdef __ARMEB__
|
||||
orr r3, r3, r4, lsr #16
|
||||
mov r4, r4, lsl #16
|
||||
orr r4, r4, r5, lsr #16
|
||||
mov r5, r5, lsl #16
|
||||
orr r5, r5, r12, lsr #16
|
||||
mov r12, r12, lsl #16
|
||||
orr r12, r12, lr, lsr #16
|
||||
#else
|
||||
orr r3, r3, r4, lsl #16
|
||||
mov r4, r4, lsr #16
|
||||
orr r4, r4, r5, lsl #16
|
||||
mov r5, r5, lsr #16
|
||||
orr r5, r5, r12, lsl #16
|
||||
mov r12, r12, lsr #16
|
||||
orr r12, r12, lr, lsl #16
|
||||
#endif
|
||||
stmia r0!, {r3-r5, r12}
|
||||
subs r2, r2, #0x10
|
||||
bge .Lmemcpy_srcul2loop16
|
||||
#if !defined(__minix)
|
||||
ldmia sp!, {r4, r5}
|
||||
#endif
|
||||
adds r2, r2, #0x0c
|
||||
blt .Lmemcpy_srcul2l4
|
||||
|
||||
.Lmemcpy_srcul2loop4:
|
||||
#ifdef __ARMEB__
|
||||
mov r12, lr, lsl #16
|
||||
#else
|
||||
mov r12, lr, lsr #16
|
||||
#endif
|
||||
ldr lr, [r1], #4
|
||||
#ifdef __ARMEB__
|
||||
orr r12, r12, lr, lsr #16
|
||||
#else
|
||||
orr r12, r12, lr, lsl #16
|
||||
#endif
|
||||
str r12, [r0], #4
|
||||
subs r2, r2, #4
|
||||
bge .Lmemcpy_srcul2loop4
|
||||
|
||||
.Lmemcpy_srcul2l4:
|
||||
sub r1, r1, #2
|
||||
b .Lmemcpy_l4
|
||||
|
||||
.Lmemcpy_srcul3:
|
||||
cmp r2, #0x0c
|
||||
blt .Lmemcpy_srcul3loop4
|
||||
sub r2, r2, #0x0c
|
||||
#if !defined(__minix)
|
||||
stmdb sp!, {r4, r5}
|
||||
#endif
|
||||
|
||||
.Lmemcpy_srcul3loop16:
|
||||
#ifdef __ARMEB__
|
||||
mov r3, lr, lsl #24
|
||||
#else
|
||||
mov r3, lr, lsr #24
|
||||
#endif
|
||||
ldmia r1!, {r4, r5, r12, lr}
|
||||
#ifdef __ARMEB__
|
||||
orr r3, r3, r4, lsr #8
|
||||
mov r4, r4, lsl #24
|
||||
orr r4, r4, r5, lsr #8
|
||||
mov r5, r5, lsl #24
|
||||
orr r5, r5, r12, lsr #8
|
||||
mov r12, r12, lsl #24
|
||||
orr r12, r12, lr, lsr #8
|
||||
#else
|
||||
orr r3, r3, r4, lsl #8
|
||||
mov r4, r4, lsr #24
|
||||
orr r4, r4, r5, lsl #8
|
||||
mov r5, r5, lsr #24
|
||||
orr r5, r5, r12, lsl #8
|
||||
mov r12, r12, lsr #24
|
||||
orr r12, r12, lr, lsl #8
|
||||
#endif
|
||||
stmia r0!, {r3-r5, r12}
|
||||
subs r2, r2, #0x10
|
||||
bge .Lmemcpy_srcul3loop16
|
||||
#if !defined(__minix)
|
||||
ldmia sp!, {r4, r5}
|
||||
#endif
|
||||
adds r2, r2, #0x0c
|
||||
blt .Lmemcpy_srcul3l4
|
||||
|
||||
.Lmemcpy_srcul3loop4:
|
||||
#ifdef __ARMEB__
|
||||
mov r12, lr, lsl #24
|
||||
#else
|
||||
mov r12, lr, lsr #24
|
||||
#endif
|
||||
ldr lr, [r1], #4
|
||||
#ifdef __ARMEB__
|
||||
orr r12, r12, lr, lsr #8
|
||||
#else
|
||||
orr r12, r12, lr, lsl #8
|
||||
#endif
|
||||
str r12, [r0], #4
|
||||
subs r2, r2, #4
|
||||
bge .Lmemcpy_srcul3loop4
|
||||
|
||||
.Lmemcpy_srcul3l4:
|
||||
sub r1, r1, #1
|
||||
b .Lmemcpy_l4
|
||||
|
||||
#if defined(__minix)
|
||||
LABEL(phys_copy_fault) /* kernel can send us here */
|
||||
ldmia sp!, {r0, r4, r5}
|
||||
ldmia sp!, {pc}
|
||||
|
||||
LABEL(phys_copy_fault_in_kernel) /* kernel can send us here */
|
||||
ldmia sp!, {r0, r4, r5}
|
||||
mrc p15, 0, r0, c6, c0, 0 /* Read DFAR */
|
||||
ldmia sp!, {pc}
|
||||
#endif
|
274
kernel/arch/arm/phys_memset.S
Normal file
274
kernel/arch/arm/phys_memset.S
Normal file
|
@ -0,0 +1,274 @@
|
|||
/* $NetBSD: memset.S,v 1.1 2005/12/20 19:28:49 christos Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright 2003 Wasabi Systems, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Written by Steve C. Woodford for Wasabi Systems, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed for the NetBSD Project by
|
||||
* Wasabi Systems, Inc.
|
||||
* 4. The name of Wasabi Systems, Inc. may not be used to endorse
|
||||
* or promote products derived from this software without specific prior
|
||||
* written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC
|
||||
* 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.
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 1995 Mark Brinicombe.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by Mark Brinicombe.
|
||||
* 4. The name of the company nor the name of the author may 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 OR CONTRIBUTORS 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.
|
||||
*/
|
||||
|
||||
#include <machine/asm.h>
|
||||
|
||||
/*
|
||||
* memset: Sets a block of memory to the specified value
|
||||
*
|
||||
* On entry:
|
||||
* r0 - dest address
|
||||
* r1 - byte to write
|
||||
* r2 - number of bytes to write
|
||||
*
|
||||
* On exit:
|
||||
* r0 - dest address
|
||||
*/
|
||||
#ifdef _BZERO
|
||||
/* LINTSTUB: Func: void bzero(void *, size_t) */
|
||||
ENTRY(bzero)
|
||||
mov r3, #0x00
|
||||
#else
|
||||
#if defined(__minix)
|
||||
/* LINTSTUB: Func: void *phys_memset(void *, int, size_t) */
|
||||
ENTRY(phys_memset)
|
||||
#else
|
||||
/* LINTSTUB: Func: void *memset(void *, int, size_t) */
|
||||
ENTRY(memset)
|
||||
#endif
|
||||
and r3, r1, #0xff /* We deal with bytes */
|
||||
mov r1, r2
|
||||
#endif
|
||||
cmp r1, #0x04 /* Do we have less than 4 bytes */
|
||||
mov ip, r0
|
||||
blt .Lmemset_lessthanfour
|
||||
|
||||
/* Ok first we will word align the address */
|
||||
ands r2, ip, #0x03 /* Get the bottom two bits */
|
||||
bne .Lmemset_wordunaligned /* The address is not word aligned */
|
||||
|
||||
/* We are now word aligned */
|
||||
.Lmemset_wordaligned:
|
||||
#ifndef _BZERO
|
||||
orr r3, r3, r3, lsl #8 /* Extend value to 16-bits */
|
||||
#endif
|
||||
#ifdef __XSCALE__
|
||||
tst ip, #0x04 /* Quad-align for Xscale */
|
||||
#else
|
||||
cmp r1, #0x10
|
||||
#endif
|
||||
#ifndef _BZERO
|
||||
orr r3, r3, r3, lsl #16 /* Extend value to 32-bits */
|
||||
#endif
|
||||
#ifdef __XSCALE__
|
||||
subne r1, r1, #0x04 /* Quad-align if necessary */
|
||||
strne r3, [ip], #0x04
|
||||
cmp r1, #0x10
|
||||
#endif
|
||||
blt .Lmemset_loop4 /* If less than 16 then use words */
|
||||
mov r2, r3 /* Duplicate data */
|
||||
cmp r1, #0x80 /* If < 128 then skip the big loop */
|
||||
blt .Lmemset_loop32
|
||||
|
||||
/* Do 128 bytes at a time */
|
||||
.Lmemset_loop128:
|
||||
subs r1, r1, #0x80
|
||||
#ifdef __XSCALE__
|
||||
strged r2, [ip], #0x08
|
||||
strged r2, [ip], #0x08
|
||||
strged r2, [ip], #0x08
|
||||
strged r2, [ip], #0x08
|
||||
strged r2, [ip], #0x08
|
||||
strged r2, [ip], #0x08
|
||||
strged r2, [ip], #0x08
|
||||
strged r2, [ip], #0x08
|
||||
strged r2, [ip], #0x08
|
||||
strged r2, [ip], #0x08
|
||||
strged r2, [ip], #0x08
|
||||
strged r2, [ip], #0x08
|
||||
strged r2, [ip], #0x08
|
||||
strged r2, [ip], #0x08
|
||||
strged r2, [ip], #0x08
|
||||
strged r2, [ip], #0x08
|
||||
#else
|
||||
stmgeia ip!, {r2-r3}
|
||||
stmgeia ip!, {r2-r3}
|
||||
stmgeia ip!, {r2-r3}
|
||||
stmgeia ip!, {r2-r3}
|
||||
stmgeia ip!, {r2-r3}
|
||||
stmgeia ip!, {r2-r3}
|
||||
stmgeia ip!, {r2-r3}
|
||||
stmgeia ip!, {r2-r3}
|
||||
stmgeia ip!, {r2-r3}
|
||||
stmgeia ip!, {r2-r3}
|
||||
stmgeia ip!, {r2-r3}
|
||||
stmgeia ip!, {r2-r3}
|
||||
stmgeia ip!, {r2-r3}
|
||||
stmgeia ip!, {r2-r3}
|
||||
stmgeia ip!, {r2-r3}
|
||||
stmgeia ip!, {r2-r3}
|
||||
#endif
|
||||
bgt .Lmemset_loop128
|
||||
#if defined(__minix)
|
||||
moveq r0, #0
|
||||
#endif
|
||||
RETc(eq) /* Zero length so just exit */
|
||||
|
||||
add r1, r1, #0x80 /* Adjust for extra sub */
|
||||
|
||||
/* Do 32 bytes at a time */
|
||||
.Lmemset_loop32:
|
||||
subs r1, r1, #0x20
|
||||
#ifdef __XSCALE__
|
||||
strged r2, [ip], #0x08
|
||||
strged r2, [ip], #0x08
|
||||
strged r2, [ip], #0x08
|
||||
strged r2, [ip], #0x08
|
||||
#else
|
||||
stmgeia ip!, {r2-r3}
|
||||
stmgeia ip!, {r2-r3}
|
||||
stmgeia ip!, {r2-r3}
|
||||
stmgeia ip!, {r2-r3}
|
||||
#endif
|
||||
bgt .Lmemset_loop32
|
||||
#if defined(__minix)
|
||||
moveq r0, #0
|
||||
#endif
|
||||
RETc(eq) /* Zero length so just exit */
|
||||
|
||||
adds r1, r1, #0x10 /* Partially adjust for extra sub */
|
||||
|
||||
/* Deal with 16 bytes or more */
|
||||
#ifdef __XSCALE__
|
||||
strged r2, [ip], #0x08
|
||||
strged r2, [ip], #0x08
|
||||
#else
|
||||
stmgeia ip!, {r2-r3}
|
||||
stmgeia ip!, {r2-r3}
|
||||
#endif
|
||||
#if defined(__minix)
|
||||
moveq r0, #0
|
||||
#endif
|
||||
RETc(eq) /* Zero length so just exit */
|
||||
|
||||
addlt r1, r1, #0x10 /* Possibly adjust for extra sub */
|
||||
|
||||
/* We have at least 4 bytes so copy as words */
|
||||
.Lmemset_loop4:
|
||||
subs r1, r1, #0x04
|
||||
strge r3, [ip], #0x04
|
||||
bgt .Lmemset_loop4
|
||||
#if defined(__minix)
|
||||
moveq r0, #0
|
||||
#endif
|
||||
RETc(eq) /* Zero length so just exit */
|
||||
|
||||
#ifdef __XSCALE__
|
||||
/* Compensate for 64-bit alignment check */
|
||||
adds r1, r1, #0x04
|
||||
#if defined(__minix)
|
||||
moveq r0, #0
|
||||
#endif
|
||||
RETc(eq)
|
||||
cmp r1, #2
|
||||
#else
|
||||
cmp r1, #-2
|
||||
#endif
|
||||
|
||||
strb r3, [ip], #0x01 /* Set 1 byte */
|
||||
strgeb r3, [ip], #0x01 /* Set another byte */
|
||||
strgtb r3, [ip] /* and a third */
|
||||
#if defined(__minix)
|
||||
mov r0, #0
|
||||
#endif
|
||||
RET /* Exit */
|
||||
|
||||
.Lmemset_wordunaligned:
|
||||
rsb r2, r2, #0x004
|
||||
strb r3, [ip], #0x01 /* Set 1 byte */
|
||||
cmp r2, #0x02
|
||||
strgeb r3, [ip], #0x01 /* Set another byte */
|
||||
sub r1, r1, r2
|
||||
strgtb r3, [ip], #0x01 /* and a third */
|
||||
cmp r1, #0x04 /* More than 4 bytes left? */
|
||||
bge .Lmemset_wordaligned /* Yup */
|
||||
|
||||
.Lmemset_lessthanfour:
|
||||
cmp r1, #0x00
|
||||
#if defined(__minix)
|
||||
moveq r0, #0
|
||||
#endif
|
||||
RETc(eq) /* Zero length so exit */
|
||||
strb r3, [ip], #0x01 /* Set 1 byte */
|
||||
cmp r1, #0x02
|
||||
strgeb r3, [ip], #0x01 /* Set another byte */
|
||||
strgtb r3, [ip] /* and a third */
|
||||
#if defined(__minix)
|
||||
mov r0, #0
|
||||
#endif
|
||||
RET /* Exit */
|
||||
|
||||
#if defined(__minix)
|
||||
LABEL(memset_fault) /* kernel can send us here */
|
||||
mov r0, #0
|
||||
RET
|
||||
|
||||
LABEL(memset_fault_in_kernel) /* kernel can send us here */
|
||||
mrc p15, 0, r0, c6, c0, 0 /* Read DFAR */
|
||||
RET
|
||||
#endif
|
240
kernel/arch/arm/pre_init.c
Normal file
240
kernel/arch/arm/pre_init.c
Normal file
|
@ -0,0 +1,240 @@
|
|||
|
||||
#define UNPAGED 1 /* for proper kmain() prototype */
|
||||
|
||||
#include "kernel.h"
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <minix/minlib.h>
|
||||
#include <minix/const.h>
|
||||
#include <minix/types.h>
|
||||
#include <minix/type.h>
|
||||
#include <minix/com.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/reboot.h>
|
||||
#include "string.h"
|
||||
#include "arch_proto.h"
|
||||
#include "libexec.h"
|
||||
#include "direct_utils.h"
|
||||
#include "serial.h"
|
||||
#include "glo.h"
|
||||
#include <machine/multiboot.h>
|
||||
|
||||
#if USE_SYSDEBUG
|
||||
#define MULTIBOOT_VERBOSE 1
|
||||
#endif
|
||||
|
||||
/* to-be-built kinfo struct, diagnostics buffer */
|
||||
kinfo_t kinfo;
|
||||
struct kmessages kmessages;
|
||||
|
||||
/* pg_utils.c uses this; in this phase, there is a 1:1 mapping. */
|
||||
phys_bytes vir2phys(void *addr) { return (phys_bytes) addr; }
|
||||
|
||||
/* String length used for mb_itoa */
|
||||
#define ITOA_BUFFER_SIZE 20
|
||||
|
||||
/* Kernel may use memory */
|
||||
int kernel_may_alloc = 1;
|
||||
|
||||
static int mb_set_param(char *bigbuf, char *name, char *value, kinfo_t *cbi)
|
||||
{
|
||||
char *p = bigbuf;
|
||||
char *bufend = bigbuf + MULTIBOOT_PARAM_BUF_SIZE;
|
||||
char *q;
|
||||
int namelen = strlen(name);
|
||||
int valuelen = strlen(value);
|
||||
|
||||
/* Some variables we recognize */
|
||||
if(!strcmp(name, SERVARNAME)) { cbi->do_serial_debug = 1; }
|
||||
if(!strcmp(name, SERBAUDVARNAME)) { cbi->serial_debug_baud = atoi(value); }
|
||||
|
||||
/* Delete the item if already exists */
|
||||
while (*p) {
|
||||
if (strncmp(p, name, namelen) == 0 && p[namelen] == '=') {
|
||||
q = p;
|
||||
while (*q) q++;
|
||||
for (q++; q < bufend; q++, p++)
|
||||
*p = *q;
|
||||
break;
|
||||
}
|
||||
while (*p++)
|
||||
;
|
||||
p++;
|
||||
}
|
||||
|
||||
for (p = bigbuf; p < bufend && (*p || *(p + 1)); p++)
|
||||
;
|
||||
if (p > bigbuf) p++;
|
||||
|
||||
/* Make sure there's enough space for the new parameter */
|
||||
if (p + namelen + valuelen + 3 > bufend)
|
||||
return -1;
|
||||
|
||||
strcpy(p, name);
|
||||
p[namelen] = '=';
|
||||
strcpy(p + namelen + 1, value);
|
||||
p[namelen + valuelen + 1] = 0;
|
||||
p[namelen + valuelen + 2] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int overlaps(multiboot_module_t *mod, int n, int cmp_mod)
|
||||
{
|
||||
multiboot_module_t *cmp = &mod[cmp_mod];
|
||||
int m;
|
||||
|
||||
#define INRANGE(mod, v) ((v) >= mod->mod_start && (v) <= thismod->mod_end)
|
||||
#define OVERLAP(mod1, mod2) (INRANGE(mod1, mod2->mod_start) || \
|
||||
INRANGE(mod1, mod2->mod_end))
|
||||
for(m = 0; m < n; m++) {
|
||||
multiboot_module_t *thismod = &mod[m];
|
||||
if(m == cmp_mod) continue;
|
||||
if(OVERLAP(thismod, cmp))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void get_parameters(u32_t ebx, kinfo_t *cbi)
|
||||
{
|
||||
multiboot_memory_map_t *mmap;
|
||||
multiboot_info_t *mbi = &cbi->mbi;
|
||||
int var_i,value_i, m, k;
|
||||
char *p;
|
||||
extern char _kern_phys_base, _kern_vir_base, _kern_size,
|
||||
_kern_unpaged_start, _kern_unpaged_end;
|
||||
phys_bytes kernbase = (phys_bytes) &_kern_phys_base,
|
||||
kernsize = (phys_bytes) &_kern_size;
|
||||
#define BUF 1024
|
||||
static char cmdline[BUF];
|
||||
|
||||
/* get our own copy of the multiboot info struct and module list */
|
||||
memcpy((void *) mbi, (void *) ebx, sizeof(*mbi));
|
||||
|
||||
/* Set various bits of info for the higher-level kernel. */
|
||||
cbi->mem_high_phys = 0;
|
||||
cbi->user_sp = (vir_bytes) &_kern_vir_base;
|
||||
cbi->vir_kern_start = (vir_bytes) &_kern_vir_base;
|
||||
cbi->bootstrap_start = (vir_bytes) &_kern_unpaged_start;
|
||||
cbi->bootstrap_len = (vir_bytes) &_kern_unpaged_end -
|
||||
cbi->bootstrap_start;
|
||||
cbi->kmess = &kmess;
|
||||
|
||||
/* set some configurable defaults */
|
||||
cbi->do_serial_debug = 1;
|
||||
cbi->serial_debug_baud = 115200;
|
||||
|
||||
/* parse boot command line */
|
||||
if (mbi->flags&MULTIBOOT_INFO_CMDLINE) {
|
||||
static char var[BUF];
|
||||
static char value[BUF];
|
||||
|
||||
/* Override values with cmdline argument */
|
||||
memcpy(cmdline, (void *) mbi->cmdline, BUF);
|
||||
p = cmdline;
|
||||
while (*p) {
|
||||
var_i = 0;
|
||||
value_i = 0;
|
||||
while (*p == ' ') p++;
|
||||
if (!*p) break;
|
||||
while (*p && *p != '=' && *p != ' ' && var_i < BUF - 1)
|
||||
var[var_i++] = *p++ ;
|
||||
var[var_i] = 0;
|
||||
if (*p++ != '=') continue; /* skip if not name=value */
|
||||
while (*p && *p != ' ' && value_i < BUF - 1)
|
||||
value[value_i++] = *p++ ;
|
||||
value[value_i] = 0;
|
||||
|
||||
mb_set_param(cbi->param_buf, var, value, cbi);
|
||||
}
|
||||
}
|
||||
|
||||
/* round user stack down to leave a gap to catch kernel
|
||||
* stack overflow; and to distinguish kernel and user addresses
|
||||
* at a glance (0xf.. vs 0xe..)
|
||||
*/
|
||||
cbi->user_sp &= 0xF0000000;
|
||||
cbi->user_end = cbi->user_sp;
|
||||
|
||||
/* kernel bytes without bootstrap code/data that is currently
|
||||
* still needed but will be freed after bootstrapping.
|
||||
*/
|
||||
kinfo.kernel_allocated_bytes = (phys_bytes) &_kern_size;
|
||||
|
||||
assert(!(cbi->bootstrap_start % ARM_PAGE_SIZE));
|
||||
cbi->bootstrap_len = rounddown(cbi->bootstrap_len, ARM_PAGE_SIZE);
|
||||
assert(mbi->flags & MULTIBOOT_INFO_MODS);
|
||||
assert(mbi->mods_count < MULTIBOOT_MAX_MODS);
|
||||
assert(mbi->mods_count > 0);
|
||||
memcpy(&cbi->module_list, (void *) mbi->mods_addr,
|
||||
mbi->mods_count * sizeof(multiboot_module_t));
|
||||
|
||||
memset(cbi->memmap, 0, sizeof(cbi->memmap));
|
||||
/* mem_map has a variable layout */
|
||||
if(mbi->flags & MULTIBOOT_INFO_MEM_MAP) {
|
||||
cbi->mmap_size = 0;
|
||||
for (mmap = (multiboot_memory_map_t *) mbi->mmap_addr;
|
||||
(unsigned long) mmap < mbi->mmap_addr + mbi->mmap_length;
|
||||
mmap = (multiboot_memory_map_t *)
|
||||
((unsigned long) mmap + mmap->size + sizeof(mmap->size))) {
|
||||
if(mmap->type != MULTIBOOT_MEMORY_AVAILABLE) continue;
|
||||
add_memmap(cbi, mmap->addr, mmap->len);
|
||||
}
|
||||
} else {
|
||||
assert(mbi->flags & MULTIBOOT_INFO_MEMORY);
|
||||
add_memmap(cbi, 0, mbi->mem_lower_unused*1024);
|
||||
add_memmap(cbi, 0x100000, mbi->mem_upper_unused*1024);
|
||||
}
|
||||
|
||||
/* Sanity check: the kernel nor any of the modules may overlap
|
||||
* with each other. Pretend the kernel is an extra module for a
|
||||
* second.
|
||||
*/
|
||||
k = mbi->mods_count;
|
||||
assert(k < MULTIBOOT_MAX_MODS);
|
||||
cbi->module_list[k].mod_start = kernbase;
|
||||
cbi->module_list[k].mod_end = kernbase + kernsize;
|
||||
cbi->mods_with_kernel = mbi->mods_count+1;
|
||||
cbi->kern_mod = k;
|
||||
|
||||
for(m = 0; m < cbi->mods_with_kernel; m++) {
|
||||
#if 0
|
||||
printf("checking overlap of module %08lx-%08lx\n",
|
||||
cbi->module_list[m].mod_start, cbi->module_list[m].mod_end);
|
||||
#endif
|
||||
if(overlaps(cbi->module_list, cbi->mods_with_kernel, m))
|
||||
panic("overlapping boot modules/kernel");
|
||||
/* We cut out the bits of memory that we know are
|
||||
* occupied by the kernel and boot modules.
|
||||
*/
|
||||
cut_memmap(cbi,
|
||||
cbi->module_list[m].mod_start,
|
||||
cbi->module_list[m].mod_end);
|
||||
}
|
||||
}
|
||||
|
||||
kinfo_t *pre_init(u32_t magic, u32_t ebx)
|
||||
{
|
||||
/* Get our own copy boot params pointed to by ebx.
|
||||
* Here we find out whether we should do serial output.
|
||||
*/
|
||||
get_parameters(ebx, &kinfo);
|
||||
|
||||
/* Make and load a pagetable that will map the kernel
|
||||
* to where it should be; but first a 1:1 mapping so
|
||||
* this code stays where it should be.
|
||||
*/
|
||||
pg_clear();
|
||||
pg_identity(&kinfo);
|
||||
kinfo.freepde_start = pg_mapkernel();
|
||||
pg_load();
|
||||
vm_enable_paging();
|
||||
|
||||
/* Done, return boot info so it can be passed to kmain(). */
|
||||
return &kinfo;
|
||||
}
|
||||
|
||||
int send_sig(endpoint_t proc_nr, int sig_nr) { return 0; }
|
||||
void minix_shutdown(timer_t *t) { arch_shutdown(RBT_PANIC); }
|
||||
void busy_delay_ms(int x) { }
|
||||
|
24
kernel/arch/arm/procoffsets.cf
Normal file
24
kernel/arch/arm/procoffsets.cf
Normal file
|
@ -0,0 +1,24 @@
|
|||
|
||||
include "kernel.h"
|
||||
include "proc.h"
|
||||
|
||||
struct proc
|
||||
member REG0 p_reg.retreg
|
||||
member REG1 p_reg.r1
|
||||
member REG2 p_reg.r2
|
||||
member REG3 p_reg.r3
|
||||
member REG4 p_reg.r4
|
||||
member REG5 p_reg.r5
|
||||
member REG6 p_reg.r6
|
||||
member REG7 p_reg.r7
|
||||
member REG8 p_reg.r8
|
||||
member REG9 p_reg.r9
|
||||
member REG10 p_reg.r10
|
||||
member FPREG p_reg.fp
|
||||
member REG12 p_reg.r12
|
||||
member SPREG p_reg.sp
|
||||
member LRREG p_reg.lr
|
||||
member PCREG p_reg.pc
|
||||
member PSREG p_reg.psr
|
||||
member P_TTBR p_seg.p_ttbr
|
||||
|
159
kernel/arch/arm/protect.c
Normal file
159
kernel/arch/arm/protect.c
Normal file
|
@ -0,0 +1,159 @@
|
|||
/* This file contains code for initialization of protected mode, to initialize
|
||||
* code and data segment descriptors, and to initialize global descriptors
|
||||
* for local descriptors in the process table.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <machine/multiboot.h>
|
||||
|
||||
#include "kernel/kernel.h"
|
||||
#include "kernel/proc.h"
|
||||
#include "archconst.h"
|
||||
|
||||
#include "arch_proto.h"
|
||||
|
||||
#include <libexec.h>
|
||||
|
||||
struct tss_s tss[CONFIG_MAX_CPUS];
|
||||
extern int exc_vector_table;
|
||||
|
||||
int prot_init_done = 0;
|
||||
|
||||
phys_bytes vir2phys(void *vir)
|
||||
{
|
||||
extern char _kern_vir_base, _kern_phys_base; /* in kernel.lds */
|
||||
u32_t offset = (vir_bytes) &_kern_vir_base -
|
||||
(vir_bytes) &_kern_phys_base;
|
||||
return (phys_bytes)vir - offset;
|
||||
}
|
||||
|
||||
int tss_init(unsigned cpu, void * kernel_stack)
|
||||
{
|
||||
|
||||
struct tss_s * t = &tss[cpu];
|
||||
|
||||
/*
|
||||
* make space for process pointer and cpu id and point to the first
|
||||
* usable word
|
||||
*/
|
||||
t->sp0 = ((unsigned) kernel_stack) - ARM_STACK_TOP_RESERVED;
|
||||
/*
|
||||
* set the cpu id at the top of the stack so we know on which cpu is
|
||||
* this stak in use when we trap to kernel
|
||||
*/
|
||||
*((reg_t *)(t->sp0 + 1 * sizeof(reg_t))) = cpu;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
multiboot_module_t *bootmod(int pnr)
|
||||
{
|
||||
int i;
|
||||
|
||||
assert(pnr >= 0);
|
||||
|
||||
/* Search for desired process in boot process
|
||||
* list. The first NR_TASKS ones do not correspond
|
||||
* to a module, however, so we don't search those.
|
||||
*/
|
||||
for(i = NR_TASKS; i < NR_BOOT_PROCS; i++) {
|
||||
int p;
|
||||
p = i - NR_TASKS;
|
||||
if(image[i].proc_nr == pnr) {
|
||||
assert(p < MULTIBOOT_MAX_MODS);
|
||||
assert(p < kinfo.mbi.mods_count);
|
||||
return &kinfo.module_list[p];
|
||||
}
|
||||
}
|
||||
|
||||
panic("boot module %d not found", pnr);
|
||||
}
|
||||
|
||||
int booting_cpu = 0;
|
||||
|
||||
void prot_init()
|
||||
{
|
||||
write_vbar((reg_t)&exc_vector_table);
|
||||
|
||||
/* Set up a new post-relocate bootstrap pagetable so that
|
||||
* we can map in VM, and we no longer rely on pre-relocated
|
||||
* data.
|
||||
*/
|
||||
|
||||
pg_clear();
|
||||
pg_identity(&kinfo); /* Still need 1:1 for device memory . */
|
||||
pg_mapkernel();
|
||||
pg_load();
|
||||
|
||||
prot_init_done = 1;
|
||||
}
|
||||
|
||||
static int alloc_for_vm = 0;
|
||||
|
||||
void arch_post_init(void)
|
||||
{
|
||||
/* Let memory mapping code know what's going on at bootstrap time */
|
||||
struct proc *vm;
|
||||
vm = proc_addr(VM_PROC_NR);
|
||||
get_cpulocal_var(ptproc) = vm;
|
||||
pg_info(&vm->p_seg.p_ttbr, &vm->p_seg.p_ttbr_v);
|
||||
}
|
||||
|
||||
int libexec_pg_alloc(struct exec_info *execi, off_t vaddr, size_t len)
|
||||
{
|
||||
pg_map(PG_ALLOCATEME, vaddr, vaddr+len, &kinfo);
|
||||
pg_load();
|
||||
memset((char *) vaddr, 0, len);
|
||||
alloc_for_vm += len;
|
||||
return OK;
|
||||
}
|
||||
|
||||
void arch_boot_proc(struct boot_image *ip, struct proc *rp)
|
||||
{
|
||||
multiboot_module_t *mod;
|
||||
|
||||
if(rp->p_nr < 0) return;
|
||||
|
||||
mod = bootmod(rp->p_nr);
|
||||
|
||||
/* Important special case: we put VM in the bootstrap pagetable
|
||||
* so it can run.
|
||||
*/
|
||||
|
||||
if(rp->p_nr == VM_PROC_NR) {
|
||||
struct exec_info execi;
|
||||
|
||||
memset(&execi, 0, sizeof(execi));
|
||||
|
||||
/* exec parameters */
|
||||
execi.stack_high = kinfo.user_sp;
|
||||
execi.stack_size = 32 * 1024; /* not too crazy as it must be preallocated */
|
||||
execi.proc_e = ip->endpoint;
|
||||
execi.hdr = (char *) mod->mod_start; /* phys mem direct */
|
||||
execi.hdr_len = mod->mod_end - mod->mod_start;
|
||||
strcpy(execi.progname, ip->proc_name);
|
||||
execi.frame_len = 0;
|
||||
|
||||
/* callbacks for use in the kernel */
|
||||
execi.copymem = libexec_copy_memcpy;
|
||||
execi.clearmem = libexec_clear_memset;
|
||||
execi.allocmem_prealloc = libexec_pg_alloc;
|
||||
execi.allocmem_ondemand = libexec_pg_alloc;
|
||||
execi.clearproc = NULL;
|
||||
|
||||
/* parse VM ELF binary and alloc/map it into bootstrap pagetable */
|
||||
libexec_load_elf(&execi);
|
||||
|
||||
/* Initialize the server stack pointer. Take it down three words
|
||||
* to give startup code something to use as "argc", "argv" and "envp".
|
||||
*/
|
||||
arch_proc_init(rp, execi.pc, kinfo.user_sp - 3*4, ip->proc_name);
|
||||
|
||||
/* Free VM blob that was just copied into existence. */
|
||||
cut_memmap(&kinfo, mod->mod_start, mod->mod_end);
|
||||
|
||||
/* Remember them */
|
||||
kinfo.vm_allocated_bytes = alloc_for_vm;
|
||||
}
|
||||
}
|
7
kernel/arch/arm/sconst.h
Normal file
7
kernel/arch/arm/sconst.h
Normal file
|
@ -0,0 +1,7 @@
|
|||
#ifndef __SCONST_H__
|
||||
#define __SCONST_H__
|
||||
|
||||
#include "kernel/const.h"
|
||||
#include "kernel/procoffsets.h"
|
||||
|
||||
#endif /* __SCONST_H__ */
|
7
kernel/arch/arm/serial.h
Normal file
7
kernel/arch/arm/serial.h
Normal file
|
@ -0,0 +1,7 @@
|
|||
|
||||
#ifndef _KERN_SERIAL_H
|
||||
#define _KERN_SERIAL_H
|
||||
|
||||
#include "omap_serial.h"
|
||||
|
||||
#endif
|
7
kernel/arch/arm/timer.h
Normal file
7
kernel/arch/arm/timer.h
Normal file
|
@ -0,0 +1,7 @@
|
|||
|
||||
#ifndef _KERN_TIMER_H
|
||||
#define _KERN_TIMER_H
|
||||
|
||||
#include "omap_timer.h"
|
||||
|
||||
#endif
|
|
@ -68,6 +68,10 @@ void stop_8253A_timer(void)
|
|||
outb(TIMER0, 0);
|
||||
}
|
||||
|
||||
void arch_timer_int_handler(void)
|
||||
{
|
||||
}
|
||||
|
||||
static int calib_cpu_handler(irq_hook_t * UNUSED(hook))
|
||||
{
|
||||
u64_t tsc;
|
||||
|
|
|
@ -5,5 +5,6 @@
|
|||
|
||||
int init_8253A_timer(unsigned freq);
|
||||
void stop_8253A_timer(void);
|
||||
void arch_timer_int_handler(void);
|
||||
|
||||
#endif /* __CLOCK_X86_H__ */
|
||||
|
|
|
@ -146,6 +146,8 @@ int timer_int_handler(void)
|
|||
|
||||
}
|
||||
|
||||
arch_timer_int_handler();
|
||||
|
||||
return(1); /* reenable interrupts */
|
||||
}
|
||||
|
||||
|
|
|
@ -251,12 +251,16 @@ void print_proc(struct proc *pp)
|
|||
endpoint_t dep;
|
||||
|
||||
printf("%d: %s %d prio %d time %d/%d cycles 0x%x%08x cpu %2d "
|
||||
"cr3 0x%lx rts %s misc %s sched %s ",
|
||||
"pdbr 0x%lx rts %s misc %s sched %s ",
|
||||
proc_nr(pp), pp->p_name, pp->p_endpoint,
|
||||
pp->p_priority, pp->p_user_time,
|
||||
pp->p_sys_time, ex64hi(pp->p_cycles),
|
||||
ex64lo(pp->p_cycles), pp->p_cpu,
|
||||
#if defined(__i386__)
|
||||
pp->p_seg.p_cr3,
|
||||
#elif defined(__arm__)
|
||||
pp->p_seg.p_ttbr,
|
||||
#endif
|
||||
rtsflagstr(pp->p_rts_flags), miscflagstr(pp->p_misc_flags),
|
||||
schedulerstr(pp->p_scheduler));
|
||||
|
||||
|
|
|
@ -380,7 +380,11 @@ check_misc_flags:
|
|||
*/
|
||||
p->p_misc_flags &= ~MF_CONTEXT_SET;
|
||||
|
||||
#if defined(__i386__)
|
||||
assert(p->p_seg.p_cr3 != 0);
|
||||
#elif defined(__arm__)
|
||||
assert(p->p_seg.p_ttbr != 0);
|
||||
#endif
|
||||
#ifdef CONFIG_SMP
|
||||
if (p->p_misc_flags & MF_FLUSH_TLB) {
|
||||
if (tlb_must_refresh)
|
||||
|
|
|
@ -209,8 +209,10 @@ void system_init(void)
|
|||
|
||||
/* Device I/O. */
|
||||
map(SYS_IRQCTL, do_irqctl); /* interrupt control operations */
|
||||
#if defined(__i386__)
|
||||
map(SYS_DEVIO, do_devio); /* inb, inw, inl, outb, outw, outl */
|
||||
map(SYS_VDEVIO, do_vdevio); /* vector with devio requests */
|
||||
#endif
|
||||
|
||||
/* Memory management. */
|
||||
map(SYS_MEMSET, do_memset); /* write char to memory area */
|
||||
|
@ -255,11 +257,11 @@ void system_init(void)
|
|||
map(SYS_READBIOS, do_readbios); /* read from BIOS locations */
|
||||
map(SYS_IOPENABLE, do_iopenable); /* Enable I/O */
|
||||
map(SYS_SDEVIO, do_sdevio); /* phys_insb, _insw, _outsb, _outsw */
|
||||
#endif
|
||||
|
||||
/* Machine state switching. */
|
||||
map(SYS_SETMCONTEXT, do_setmcontext); /* set machine context */
|
||||
map(SYS_GETMCONTEXT, do_getmcontext); /* get machine context */
|
||||
#endif
|
||||
|
||||
/* Scheduling */
|
||||
map(SYS_SCHEDULE, do_schedule); /* reschedule a process */
|
||||
|
|
|
@ -15,8 +15,6 @@ SRCS+= \
|
|||
do_stime.c \
|
||||
do_vtimer.c \
|
||||
do_irqctl.c \
|
||||
do_devio.c \
|
||||
do_vdevio.c \
|
||||
do_copy.c \
|
||||
do_umap.c \
|
||||
do_umap_remote.c \
|
||||
|
@ -42,3 +40,9 @@ SRCS+= \
|
|||
do_schedctl.c \
|
||||
do_statectl.c
|
||||
|
||||
.if ${MACHINE_ARCH} == "i386"
|
||||
SRCS+= \
|
||||
do_devio.c \
|
||||
do_vdevio.c
|
||||
.endif
|
||||
|
||||
|
|
|
@ -71,7 +71,9 @@ int do_fork(struct proc * caller, message * m_ptr)
|
|||
rpc->p_user_time = 0; /* set all the accounting times to 0 */
|
||||
rpc->p_sys_time = 0;
|
||||
|
||||
#if defined(__i386__)
|
||||
rpc->p_reg.psw &= ~TRACEBIT; /* clear trace bit */
|
||||
#endif
|
||||
rpc->p_misc_flags &=
|
||||
~(MF_VIRT_TIMER | MF_PROF_TIMER | MF_SC_TRACE | MF_SPROF_SEEN);
|
||||
rpc->p_virt_left = 0; /* disable, clear the process-virtual timers */
|
||||
|
@ -116,8 +118,13 @@ int do_fork(struct proc * caller, message * m_ptr)
|
|||
RTS_UNSET(rpc, (RTS_SIGNALED | RTS_SIG_PENDING | RTS_P_STOP));
|
||||
(void) sigemptyset(&rpc->p_pending);
|
||||
|
||||
#if defined(__i386__)
|
||||
rpc->p_seg.p_cr3 = 0;
|
||||
rpc->p_seg.p_cr3_v = NULL;
|
||||
#elif defined(__arm__)
|
||||
rpc->p_seg.p_ttbr = 0;
|
||||
rpc->p_seg.p_ttbr_v = NULL;
|
||||
#endif
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
|
|
@ -34,9 +34,11 @@ int do_sigreturn(struct proc * caller, message * m_ptr)
|
|||
KERNEL, (vir_bytes) &sc, sizeof(struct sigcontext))) != OK)
|
||||
return r;
|
||||
|
||||
#if defined(__i386__)
|
||||
/* Restore user bits of psw from sc, maintain system bits from proc. */
|
||||
sc.sc_psw = (sc.sc_psw & X86_FLAGS_USER) |
|
||||
(rp->p_reg.psw & ~X86_FLAGS_USER);
|
||||
#endif
|
||||
|
||||
#if defined(__i386__)
|
||||
/* Don't panic kernel if user gave bad selectors. */
|
||||
|
|
|
@ -87,7 +87,9 @@ int do_trace(struct proc * caller, message * m_ptr)
|
|||
switch (tr_request) {
|
||||
case T_STOP: /* stop process */
|
||||
RTS_SET(rp, RTS_P_STOP);
|
||||
#if defined(__i386__)
|
||||
rp->p_reg.psw &= ~TRACEBIT; /* clear trace bit */
|
||||
#endif
|
||||
rp->p_misc_flags &= ~MF_SC_TRACE; /* clear syscall trace flag */
|
||||
return(OK);
|
||||
|
||||
|
@ -148,11 +150,13 @@ int do_trace(struct proc * caller, message * m_ptr)
|
|||
i == (int) &((struct proc *) 0)->p_reg.ss)
|
||||
return(EFAULT);
|
||||
#endif
|
||||
#if defined(__i386__)
|
||||
if (i == (int) &((struct proc *) 0)->p_reg.psw)
|
||||
/* only selected bits are changeable */
|
||||
SETPSW(rp, tr_data);
|
||||
else
|
||||
*(reg_t *) ((char *) &rp->p_reg + i) = (reg_t) tr_data;
|
||||
#endif
|
||||
m_ptr->CTL_DATA = 0;
|
||||
break;
|
||||
|
||||
|
@ -166,7 +170,9 @@ int do_trace(struct proc * caller, message * m_ptr)
|
|||
break;
|
||||
|
||||
case T_STEP: /* set trace bit */
|
||||
#if defined(__i386__)
|
||||
rp->p_reg.psw |= TRACEBIT;
|
||||
#endif
|
||||
RTS_UNSET(rp, RTS_P_STOP);
|
||||
m_ptr->CTL_DATA = 0;
|
||||
break;
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
/**========================================================================* */
|
||||
/* IPC assembly routines * */
|
||||
/**========================================================================* */
|
||||
ENTRY(_send)
|
||||
ENTRY(_send_orig)
|
||||
push {fp}
|
||||
mov fp, sp
|
||||
mov r2, r1 /* r2 = msg ptr */
|
||||
|
@ -15,7 +15,7 @@ ENTRY(_send)
|
|||
pop {fp}
|
||||
bx lr
|
||||
|
||||
ENTRY(_receive)
|
||||
ENTRY(_receive_orig)
|
||||
push {fp}
|
||||
mov fp, sp
|
||||
push {r2} /* save status ptr */
|
||||
|
@ -29,7 +29,7 @@ ENTRY(_receive)
|
|||
pop {fp}
|
||||
bx lr
|
||||
|
||||
ENTRY(_sendrec)
|
||||
ENTRY(_sendrec_orig)
|
||||
push {fp}
|
||||
mov fp, sp
|
||||
mov r2, r1 /* r2 = msg ptr */
|
||||
|
@ -55,7 +55,7 @@ ENTRY(_minix_kernel_info_struct)
|
|||
pop {fp}
|
||||
bx lr
|
||||
|
||||
ENTRY(_notify)
|
||||
ENTRY(_notify_orig)
|
||||
push {fp}
|
||||
mov fp, sp
|
||||
mov r1, r0 /* r1 = src_dest */
|
||||
|
@ -65,7 +65,7 @@ ENTRY(_notify)
|
|||
pop {fp}
|
||||
bx lr
|
||||
|
||||
ENTRY(_sendnb)
|
||||
ENTRY(_sendnb_orig)
|
||||
push {fp}
|
||||
mov fp, sp
|
||||
mov r2, r1 /* r2 = msg ptr */
|
||||
|
@ -77,7 +77,7 @@ ENTRY(_sendnb)
|
|||
bx lr
|
||||
|
||||
|
||||
ENTRY(_do_kernel_call)
|
||||
ENTRY(_do_kernel_call_orig)
|
||||
/* r0 already holds msg ptr */
|
||||
mov r3, #KERVEC /* r3 determines the SVC type */
|
||||
svc #0 /* trap to kernel */
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#include <minix/ipcconst.h>
|
||||
#include <machine/asm.h>
|
||||
|
||||
ENTRY(_senda)
|
||||
ENTRY(_senda_orig)
|
||||
push {fp}
|
||||
mov fp, sp
|
||||
mov r2, r0 /* r2 = table */
|
||||
|
|
5
servers/vm/arch/arm/Makefile.inc
Normal file
5
servers/vm/arch/arm/Makefile.inc
Normal file
|
@ -0,0 +1,5 @@
|
|||
.include <bsd.own.mk>
|
||||
|
||||
#Arch-specific sources
|
||||
.PATH: ${.CURDIR}/arch/${MACHINE_ARCH}
|
||||
SRCS+= pagetable.c #util.S
|
12
servers/vm/arch/arm/memory.h
Normal file
12
servers/vm/arch/arm/memory.h
Normal file
|
@ -0,0 +1,12 @@
|
|||
#include <machine/vm.h>
|
||||
|
||||
/* And what is the highest addressable piece of memory, when in paged
|
||||
* mode?
|
||||
*/
|
||||
#define VM_DATATOP kernel_boot_info.user_end
|
||||
#define VM_STACKTOP kernel_boot_info.user_sp
|
||||
|
||||
#define SLAB_PAGESIZE ARM_PAGE_SIZE
|
||||
#define VM_PAGE_SIZE ARM_PAGE_SIZE
|
||||
|
||||
#define CLICKSPERPAGE (ARM_PAGE_SIZE/CLICK_SIZE)
|
14
servers/vm/arch/arm/pagefaults.h
Normal file
14
servers/vm/arch/arm/pagefaults.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
|
||||
#ifndef _PAGEFAULTS_H
|
||||
#define _PAGEFAULTS_H 1
|
||||
|
||||
#include <machine/vm.h>
|
||||
|
||||
#define PFERR_PROT(e) ((ARM_VM_PFE_FS(e) == ARM_VM_PFE_L1PERM) \
|
||||
|| (ARM_VM_PFE_FS(e) == ARM_VM_PFE_L2PERM))
|
||||
#define PFERR_NOPAGE(e) (!PFERR_PROT(e))
|
||||
#define PFERR_WRITE(e) ((e) & ARM_VM_PFE_W)
|
||||
#define PFERR_READ(e) (!((e) & ARM_VM_PFE_W))
|
||||
|
||||
#endif
|
||||
|
1261
servers/vm/arch/arm/pagetable.c
Normal file
1261
servers/vm/arch/arm/pagetable.c
Normal file
File diff suppressed because it is too large
Load diff
51
servers/vm/arch/arm/pagetable.h
Normal file
51
servers/vm/arch/arm/pagetable.h
Normal file
|
@ -0,0 +1,51 @@
|
|||
|
||||
#ifndef _PAGETABLE_H
|
||||
#define _PAGETABLE_H 1
|
||||
|
||||
#include <stdint.h>
|
||||
#include <machine/vm.h>
|
||||
|
||||
#include "vm.h"
|
||||
|
||||
/* An ARM pagetable. */
|
||||
typedef struct {
|
||||
/* Directory entries in VM addr space - root of page table. */
|
||||
u32_t *pt_dir; /* 16KB aligned (ARM_VM_DIR_ENTRIES) */
|
||||
u32_t pt_dir_phys; /* physical address of pt_dir */
|
||||
|
||||
/* Pointers to page tables in VM address space. */
|
||||
u32_t *pt_pt[ARM_VM_DIR_ENTRIES];
|
||||
|
||||
/* When looking for a hole in virtual address space, start
|
||||
* looking here. This is in linear addresses, i.e.,
|
||||
* not as the process sees it but the position in the page
|
||||
* page table. This is just a hint.
|
||||
*/
|
||||
u32_t pt_virtop;
|
||||
} pt_t;
|
||||
|
||||
/* Mapping flags. */
|
||||
#define PTF_WRITE ARM_VM_PTE_RW
|
||||
#define PTF_READ ARM_VM_PTE_RO
|
||||
#define PTF_PRESENT ARM_VM_PTE_PRESENT
|
||||
#define PTF_SUPER ARM_VM_PTE_SUPER
|
||||
#define PTF_USER ARM_VM_PTE_USER
|
||||
#define PTF_NOCACHE ARM_VM_PTE_DEVICE
|
||||
#define PTF_CACHEWB ARM_VM_PTE_WB
|
||||
#define PTF_CACHEWT ARM_VM_PTE_WT
|
||||
#define PTF_SHARE ARM_VM_PTE_SHAREABLE
|
||||
|
||||
/* For arch-specific PT routines to check if no bits outside
|
||||
* the regular flags are set.
|
||||
*/
|
||||
#define PTF_ALLFLAGS (PTF_READ|PTF_WRITE|PTF_PRESENT|PTF_SUPER|PTF_USER|PTF_NOCACHE|PTF_CACHEWB|PTF_CACHEWT|PTF_SHARE)
|
||||
|
||||
#if SANITYCHECKS
|
||||
#define PT_SANE(p) { pt_sanitycheck((p), __FILE__, __LINE__); }
|
||||
#else
|
||||
#define PT_SANE(p)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -96,6 +96,7 @@ int pt_writemap(struct vmproc * vmp, pt_t *pt, vir_bytes v, phys_bytes
|
|||
int pt_checkrange(pt_t *pt, vir_bytes v, size_t bytes, int write);
|
||||
int pt_bind(pt_t *pt, struct vmproc *who);
|
||||
void *vm_allocpage(phys_bytes *p, int cat);
|
||||
void *vm_allocpagedir(phys_bytes *p);
|
||||
void pt_cycle(void);
|
||||
int pt_mapkernel(pt_t *pt);
|
||||
void vm_pagelock(void *vir, int lockflag);
|
||||
|
|
Loading…
Reference in a new issue