sh: Tidy up the sh bios VBR handling.
This moves the VBR handling out of the main trap handling code and in to the sh-bios helper code. A couple of accessors are added in order to permit other kernel code to get at the VBR value for state save/restore paths. Signed-off-by: Paul Mundt <lethal@linux-sh.org>
This commit is contained in:
@@ -1,13 +1,13 @@
|
|||||||
#ifndef __ASM_SH_BIOS_H
|
#ifndef __ASM_SH_BIOS_H
|
||||||
#define __ASM_SH_BIOS_H
|
#define __ASM_SH_BIOS_H
|
||||||
|
|
||||||
|
#ifdef CONFIG_SH_STANDARD_BIOS
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2000 Greg Banks, Mitch Davis
|
* Copyright (C) 2000 Greg Banks, Mitch Davis
|
||||||
* C API to interface to the standard LinuxSH BIOS
|
* C API to interface to the standard LinuxSH BIOS
|
||||||
* usually from within the early stages of kernel boot.
|
* usually from within the early stages of kernel boot.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
extern void sh_bios_console_write(const char *buf, unsigned int len);
|
extern void sh_bios_console_write(const char *buf, unsigned int len);
|
||||||
extern void sh_bios_char_out(char ch);
|
extern void sh_bios_char_out(char ch);
|
||||||
extern void sh_bios_gdb_detach(void);
|
extern void sh_bios_gdb_detach(void);
|
||||||
@@ -15,4 +15,14 @@ extern void sh_bios_gdb_detach(void);
|
|||||||
extern void sh_bios_get_node_addr(unsigned char *node_addr);
|
extern void sh_bios_get_node_addr(unsigned char *node_addr);
|
||||||
extern void sh_bios_shutdown(unsigned int how);
|
extern void sh_bios_shutdown(unsigned int how);
|
||||||
|
|
||||||
|
extern void sh_bios_vbr_init(void);
|
||||||
|
extern void sh_bios_vbr_reload(void);
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static inline void sh_bios_vbr_init(void) { }
|
||||||
|
static inline void sh_bios_vbr_reload(void) { }
|
||||||
|
|
||||||
|
#endif /* CONFIG_SH_STANDARD_BIOS */
|
||||||
|
|
||||||
#endif /* __ASM_SH_BIOS_H */
|
#endif /* __ASM_SH_BIOS_H */
|
||||||
|
@@ -21,6 +21,7 @@
|
|||||||
#include <asm/mmu_context.h>
|
#include <asm/mmu_context.h>
|
||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
#include <asm/cacheflush.h>
|
#include <asm/cacheflush.h>
|
||||||
|
#include <asm/sh_bios.h>
|
||||||
|
|
||||||
typedef void (*relocate_new_kernel_t)(unsigned long indirection_page,
|
typedef void (*relocate_new_kernel_t)(unsigned long indirection_page,
|
||||||
unsigned long reboot_code_buffer,
|
unsigned long reboot_code_buffer,
|
||||||
@@ -28,7 +29,6 @@ typedef void (*relocate_new_kernel_t)(unsigned long indirection_page,
|
|||||||
|
|
||||||
extern const unsigned char relocate_new_kernel[];
|
extern const unsigned char relocate_new_kernel[];
|
||||||
extern const unsigned int relocate_new_kernel_size;
|
extern const unsigned int relocate_new_kernel_size;
|
||||||
extern void *gdb_vbr_vector;
|
|
||||||
extern void *vbr_base;
|
extern void *vbr_base;
|
||||||
|
|
||||||
void machine_shutdown(void)
|
void machine_shutdown(void)
|
||||||
@@ -117,11 +117,7 @@ void machine_kexec(struct kimage *image)
|
|||||||
kexec_info(image);
|
kexec_info(image);
|
||||||
flush_cache_all();
|
flush_cache_all();
|
||||||
|
|
||||||
#if defined(CONFIG_SH_STANDARD_BIOS)
|
sh_bios_vbr_reload();
|
||||||
asm volatile("ldc %0, vbr" :
|
|
||||||
: "r" (((unsigned long) gdb_vbr_vector) - 0x100)
|
|
||||||
: "memory");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* now call it */
|
/* now call it */
|
||||||
rnk = (relocate_new_kernel_t) reboot_code_buffer;
|
rnk = (relocate_new_kernel_t) reboot_code_buffer;
|
||||||
|
@@ -55,3 +55,40 @@ void sh_bios_shutdown(unsigned int how)
|
|||||||
{
|
{
|
||||||
sh_bios_call(BIOS_CALL_SHUTDOWN, how, 0, 0, 0);
|
sh_bios_call(BIOS_CALL_SHUTDOWN, how, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void *gdb_vbr_vector = NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read the old value of the VBR register to initialise the vector
|
||||||
|
* through which debug and BIOS traps are delegated by the Linux trap
|
||||||
|
* handler.
|
||||||
|
*/
|
||||||
|
void sh_bios_vbr_init(void)
|
||||||
|
{
|
||||||
|
unsigned long vbr;
|
||||||
|
|
||||||
|
if (unlikely(gdb_vbr_vector))
|
||||||
|
return;
|
||||||
|
|
||||||
|
__asm__ __volatile__ ("stc vbr, %0" : "=r" (vbr));
|
||||||
|
|
||||||
|
gdb_vbr_vector = (void *)(vbr + 0x100);
|
||||||
|
printk(KERN_NOTICE "Setting GDB trap vector to %p\n", gdb_vbr_vector);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sh_bios_vbr_reload - Re-load the system VBR from the BIOS vector.
|
||||||
|
*
|
||||||
|
* This can be used by save/restore code to reinitialize the system VBR
|
||||||
|
* from the fixed BIOS VBR. A no-op if no BIOS VBR is known.
|
||||||
|
*/
|
||||||
|
void sh_bios_vbr_reload(void)
|
||||||
|
{
|
||||||
|
if (gdb_vbr_vector)
|
||||||
|
__asm__ __volatile__ (
|
||||||
|
"ldc %0, vbr"
|
||||||
|
:
|
||||||
|
: "r" (((unsigned long) gdb_vbr_vector) - 0x100)
|
||||||
|
: "memory"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@@ -31,6 +31,7 @@
|
|||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
#include <asm/fpu.h>
|
#include <asm/fpu.h>
|
||||||
#include <asm/kprobes.h>
|
#include <asm/kprobes.h>
|
||||||
|
#include <asm/sh_bios.h>
|
||||||
|
|
||||||
#ifdef CONFIG_CPU_SH2
|
#ifdef CONFIG_CPU_SH2
|
||||||
# define TRAP_RESERVED_INST 4
|
# define TRAP_RESERVED_INST 4
|
||||||
@@ -876,35 +877,10 @@ asmlinkage void do_exception_error(unsigned long r4, unsigned long r5,
|
|||||||
die_if_kernel("exception", regs, ex);
|
die_if_kernel("exception", regs, ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(CONFIG_SH_STANDARD_BIOS)
|
|
||||||
void *gdb_vbr_vector;
|
|
||||||
|
|
||||||
static inline void __init gdb_vbr_init(void)
|
|
||||||
{
|
|
||||||
register unsigned long vbr;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Read the old value of the VBR register to initialise
|
|
||||||
* the vector through which debug and BIOS traps are
|
|
||||||
* delegated by the Linux trap handler.
|
|
||||||
*/
|
|
||||||
asm volatile("stc vbr, %0" : "=r" (vbr));
|
|
||||||
|
|
||||||
gdb_vbr_vector = (void *)(vbr + 0x100);
|
|
||||||
printk("Setting GDB trap vector to 0x%08lx\n",
|
|
||||||
(unsigned long)gdb_vbr_vector);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void __cpuinit per_cpu_trap_init(void)
|
void __cpuinit per_cpu_trap_init(void)
|
||||||
{
|
{
|
||||||
extern void *vbr_base;
|
extern void *vbr_base;
|
||||||
|
|
||||||
#ifdef CONFIG_SH_STANDARD_BIOS
|
|
||||||
if (raw_smp_processor_id() == 0)
|
|
||||||
gdb_vbr_init();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* NOTE: The VBR value should be at P1
|
/* NOTE: The VBR value should be at P1
|
||||||
(or P2, virtural "fixed" address space).
|
(or P2, virtural "fixed" address space).
|
||||||
It's definitely should not in physical address. */
|
It's definitely should not in physical address. */
|
||||||
@@ -959,6 +935,9 @@ void __init trap_init(void)
|
|||||||
set_exception_table_vec(TRAP_UBC, break_point_trap);
|
set_exception_table_vec(TRAP_UBC, break_point_trap);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Save off the BIOS VBR, if there is one */
|
||||||
|
sh_bios_vbr_init();
|
||||||
|
|
||||||
/* Setup VBR for boot cpu */
|
/* Setup VBR for boot cpu */
|
||||||
per_cpu_trap_init();
|
per_cpu_trap_init();
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user