On Sat, Mar 13, 2010 at 12:34:17PM +0800, Wu Zhangjin wrote:
> - /* reboot via jumping to boot base address */
> + /* reboot via jumping to boot base address
> + *
> + * ".set noat" and ".set at" are used to ensure the address not break
> + * by the -mfix-loongson2f-jump option provided by binutils 2.20.1 (or
> + * higher version) which try to change the jumping address to "addr &
> + * 0xcfffffff" via the at($1) register, this is totally wrong for
> + * 0xbfc00000 (LOONGSON_BOOT_BASE).
> + */
> + __asm__ __volatile__(".set noat\n");
> ((void (*)(void))ioremap_nocache(LOONGSON_BOOT_BASE, 4)) ();
> + __asm__ __volatile__(".set at\n");
Ouch. This is fragile and totally puts the kernels fate at the mercy of
gcc and the ioremap_nocache() implementation. GCC might emit a .set noat
at any time. Something like
void loongson_restart(char *command)
{
void (*func)(void);
/* do preparation for reboot */
mach_prepare_reboot();
/* reboot via jumping to boot base address */
func = (void *) ioremap_nocache(LOONGSON_BOOT_BASE, 4);
__asm__ __volatile__(
" .set noat \n"
" jr %[func] \n"
" .set at \n"
: /* No outputs */
: [func] "r" (func));
}
should be safe against -mfix-loongson2f-jump I think.
The workaround in http://sourceware.org/ml/binutils/2009-11/msg00387.html
will also cause problems calling functions with bits 28..29 set, that is
in the ranges 0x81000000..0xbffffff and 0xd0000000..0xffffffff. The
first range is not much of a problem as only the kernel proper resides
there and the kernel load address is manually selected in the Makefile.
The 2nd range might be used for under certain circumstances.
Ralf
|