* Fixed a bug regarding storing/restoring FPSCR in the interrupt
code. The stack pointer was not adjusted, hence we were overwriting the previous register value. But it looks like I missed to check in the arch_cpu.h with the iframe structure including the floating point registers anyway. * Backported the ELF PPC relocation code from the boot loader to the kernel. * Fixed the PPC version of arch_thread_switch_kstack_and_call(). Apparently the signature had changed, but the assembly implementation was not adjusted accordingly. * sc prints more registers now (LR, CR, CTR, XER,...). * Fixed several occurences of not-working fault handlers. Apparently the compiler realized, that the "error" label was never jumped to (by the code it knew), and optimized the respective code away. Now we use a trick to make it think the error label might actually be jumped to. I wonder whether the x86 version has the same problem when being compiled with GCC4. * Adopted the x86 page fault handling interrupt code. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@15933 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -22,6 +22,7 @@ struct iframe {
|
|||||||
uint32 cr;
|
uint32 cr;
|
||||||
uint32 xer;
|
uint32 xer;
|
||||||
uint32 ctr;
|
uint32 ctr;
|
||||||
|
uint32 fpscr;
|
||||||
uint32 r31;
|
uint32 r31;
|
||||||
uint32 r30;
|
uint32 r30;
|
||||||
uint32 r29;
|
uint32 r29;
|
||||||
@@ -54,6 +55,38 @@ struct iframe {
|
|||||||
uint32 r2;
|
uint32 r2;
|
||||||
uint32 r1;
|
uint32 r1;
|
||||||
uint32 r0;
|
uint32 r0;
|
||||||
|
double f31;
|
||||||
|
double f30;
|
||||||
|
double f29;
|
||||||
|
double f28;
|
||||||
|
double f27;
|
||||||
|
double f26;
|
||||||
|
double f25;
|
||||||
|
double f24;
|
||||||
|
double f23;
|
||||||
|
double f22;
|
||||||
|
double f21;
|
||||||
|
double f20;
|
||||||
|
double f19;
|
||||||
|
double f18;
|
||||||
|
double f17;
|
||||||
|
double f16;
|
||||||
|
double f15;
|
||||||
|
double f14;
|
||||||
|
double f13;
|
||||||
|
double f12;
|
||||||
|
double f11;
|
||||||
|
double f10;
|
||||||
|
double f9;
|
||||||
|
double f8;
|
||||||
|
double f7;
|
||||||
|
double f6;
|
||||||
|
double f5;
|
||||||
|
double f4;
|
||||||
|
double f3;
|
||||||
|
double f2;
|
||||||
|
double f1;
|
||||||
|
double f0;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum machine_state {
|
enum machine_state {
|
||||||
@@ -113,6 +146,9 @@ int64 __ppc_get_time_base(void);
|
|||||||
|
|
||||||
extern void ppc_context_switch(void **_oldStackPointer, void *newStackPointer);
|
extern void ppc_context_switch(void **_oldStackPointer, void *newStackPointer);
|
||||||
|
|
||||||
|
extern bool ppc_set_fault_handler(addr_t *handlerLocation, addr_t handler)
|
||||||
|
__attribute__((noinline));
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -305,9 +305,9 @@ FUNCTION(ppc_context_switch):
|
|||||||
blr
|
blr
|
||||||
|
|
||||||
|
|
||||||
// void arch_thread_switch_kstack_and_call(addr_t new_kstack,
|
// void ppc_switch_stack_and_call(addr_t newKstack,
|
||||||
// void (*func)(void *), void *arg)
|
// void (*func)(void *), void *arg)
|
||||||
FUNCTION(arch_thread_switch_kstack_and_call):
|
FUNCTION(ppc_switch_stack_and_call):
|
||||||
mr %r1, %r3 // set the new stack pointer
|
mr %r1, %r3 // set the new stack pointer
|
||||||
mtctr %r4 // move the target function into CTR
|
mtctr %r4 // move the target function into CTR
|
||||||
mr %r3, %r5 // move the arg to this func to the new arg
|
mr %r3, %r5 // move the arg to this func to the new arg
|
||||||
|
|||||||
@@ -146,21 +146,23 @@ arch_cpu_user_TLB_invalidate(void)
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
arch_cpu_user_memcpy(void *to, const void *from, size_t size, addr_t *fault_handler)
|
arch_cpu_user_memcpy(void *to, const void *from, size_t size,
|
||||||
|
addr_t *faultHandler)
|
||||||
{
|
{
|
||||||
char *tmp = (char *)to;
|
char *tmp = (char *)to;
|
||||||
char *s = (char *)from;
|
char *s = (char *)from;
|
||||||
|
|
||||||
*fault_handler = (addr_t)&&error;
|
if (ppc_set_fault_handler(faultHandler, (addr_t)&&error))
|
||||||
|
goto error;
|
||||||
|
|
||||||
while (size--)
|
while (size--)
|
||||||
*tmp++ = *s++;
|
*tmp++ = *s++;
|
||||||
|
|
||||||
*fault_handler = 0;
|
*faultHandler = 0;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
*fault_handler = 0;
|
*faultHandler = 0;
|
||||||
return B_BAD_ADDRESS;
|
return B_BAD_ADDRESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,7 +182,8 @@ arch_cpu_user_strlcpy(char *to, const char *from, size_t size, addr_t *faultHand
|
|||||||
{
|
{
|
||||||
int from_length = 0;
|
int from_length = 0;
|
||||||
|
|
||||||
*faultHandler = (addr_t)&&error;
|
if (ppc_set_fault_handler(faultHandler, (addr_t)&&error))
|
||||||
|
goto error;
|
||||||
|
|
||||||
if (size > 0) {
|
if (size > 0) {
|
||||||
to[--size] = '\0';
|
to[--size] = '\0';
|
||||||
@@ -204,20 +207,21 @@ error:
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
arch_cpu_user_memset(void *s, char c, size_t count, addr_t *fault_handler)
|
arch_cpu_user_memset(void *s, char c, size_t count, addr_t *faultHandler)
|
||||||
{
|
{
|
||||||
char *xs = (char *)s;
|
char *xs = (char *)s;
|
||||||
|
|
||||||
*fault_handler = (addr_t)&&error;
|
if (ppc_set_fault_handler(faultHandler, (addr_t)&&error))
|
||||||
|
goto error;
|
||||||
|
|
||||||
while (count--)
|
while (count--)
|
||||||
*xs++ = c;
|
*xs++ = c;
|
||||||
|
|
||||||
*fault_handler = 0;
|
*faultHandler = 0;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
*fault_handler = 0;
|
*faultHandler = 0;
|
||||||
return B_BAD_ADDRESS;
|
return B_BAD_ADDRESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -235,3 +239,23 @@ arch_cpu_idle(void)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// The purpose of this function is to trick the compiler. When setting the
|
||||||
|
// page_handler to a label that is obviously (to the compiler) never used,
|
||||||
|
// it may reorganize the control flow, so that the labeled part is optimized
|
||||||
|
// away.
|
||||||
|
// By invoking the function like this
|
||||||
|
//
|
||||||
|
// if (ppc_set_fault_handler(faultHandler, (addr_t)&&error))
|
||||||
|
// goto error;
|
||||||
|
//
|
||||||
|
// the compiler has to keep the labeled code, since it can't guess the return
|
||||||
|
// value of this (non-inlinable) function. At least in my tests it worked that
|
||||||
|
// way, and I hope it will continue to work like this in the future.
|
||||||
|
//
|
||||||
|
bool
|
||||||
|
ppc_set_fault_handler(addr_t *handlerLocation, addr_t handler)
|
||||||
|
{
|
||||||
|
*handlerLocation = handler;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,10 +1,16 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2003-2005, Axel D�fler, [email protected]. All rights reserved.
|
* Copyright 2003-2006, Haiku Inc. All rights reserved.
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Axel Dörfler <[email protected]>
|
||||||
|
* Ingo Weinhold <[email protected]>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include <arch/debug.h>
|
#include <arch/debug.h>
|
||||||
|
|
||||||
|
#include <arch_cpu.h>
|
||||||
#include <debug.h>
|
#include <debug.h>
|
||||||
#include <elf.h>
|
#include <elf.h>
|
||||||
#include <kernel.h>
|
#include <kernel.h>
|
||||||
@@ -61,8 +67,10 @@ get_next_frame(addr_t framePointer, addr_t *next, addr_t *ip)
|
|||||||
struct thread *thread = thread_get_current_thread();
|
struct thread *thread = thread_get_current_thread();
|
||||||
|
|
||||||
// set fault handler, so that we can safely access user stacks
|
// set fault handler, so that we can safely access user stacks
|
||||||
if (thread)
|
if (thread) {
|
||||||
thread->fault_handler = (addr_t)&&error;
|
if (ppc_set_fault_handler(&thread->fault_handler, (addr_t)&&error))
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
*ip = ((struct stack_frame *)framePointer)->return_address;
|
*ip = ((struct stack_frame *)framePointer)->return_address;
|
||||||
*next = (addr_t)((struct stack_frame *)framePointer)->previous;
|
*next = (addr_t)((struct stack_frame *)framePointer)->previous;
|
||||||
@@ -209,13 +217,11 @@ return 0;
|
|||||||
frame->r24, frame->r25, frame->r26, frame->r27);
|
frame->r24, frame->r25, frame->r26, frame->r27);
|
||||||
kprintf(" r28 0x%08lx r29 0x%08lx r30 0x%08lx r31 0x%08lx\n",
|
kprintf(" r28 0x%08lx r29 0x%08lx r30 0x%08lx r31 0x%08lx\n",
|
||||||
frame->r28, frame->r29, frame->r30, frame->r31);
|
frame->r28, frame->r29, frame->r30, frame->r31);
|
||||||
kprintf(" srr0 0x%08lx srr1 0x%08lx", frame->srr0, frame->srr1);
|
kprintf(" lr 0x%08lx cr 0x%08lx xer 0x%08lx ctr 0x%08lx\n",
|
||||||
// TODO: Look up the bit in srr1!
|
frame->lr, frame->cr, frame->xer, frame->ctr);
|
||||||
// if ((frame->error_code & 0x4) != 0) {
|
kprintf("fpscr 0x%08lx\n", frame->fpscr);
|
||||||
// // from user space
|
kprintf(" srr0 0x%08lx srr1 0x%08lx dar 0x%08lx dsisr 0x%08lx\n",
|
||||||
// kprintf("user esp 0x%lx", frame->user_esp);
|
frame->srr0, frame->srr1, frame->dar, frame->dsisr);
|
||||||
// }
|
|
||||||
kprintf("\n");
|
|
||||||
kprintf(" vector: 0x%lx\n", frame->vector);
|
kprintf(" vector: 0x%lx\n", frame->vector);
|
||||||
|
|
||||||
print_stack_frame(thread, frame->srr0, framePointer, frame->r1);
|
print_stack_frame(thread, frame->srr0, framePointer, frame->r1);
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
/*
|
/*
|
||||||
** Copyright 2002, Travis Geiselbrecht. All rights reserved.
|
* Copyright 2005, Ingo Weinhold <[email protected]>.
|
||||||
** Distributed under the terms of the NewOS License.
|
* All rights reserved. Distributed under the terms of the MIT License.
|
||||||
*/
|
*
|
||||||
|
*
|
||||||
|
* Copyright 2002, Travis Geiselbrecht. All rights reserved.
|
||||||
|
* Distributed under the terms of the NewOS License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include <KernelExport.h>
|
#include <KernelExport.h>
|
||||||
@@ -22,6 +26,85 @@ arch_elf_relocate_rel(struct elf_image_info *image, const char *sym_prepend,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
write_word32(addr_t P, Elf32_Word value)
|
||||||
|
{
|
||||||
|
*(Elf32_Word*)P = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
write_word30(addr_t P, Elf32_Word value)
|
||||||
|
{
|
||||||
|
// bits 0:29
|
||||||
|
*(Elf32_Word*)P = (*(Elf32_Word*)P & 0x3) | (value << 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
write_low24_check(addr_t P, Elf32_Word value)
|
||||||
|
{
|
||||||
|
// bits 6:29
|
||||||
|
if ((value & 0x3f000000) && (~value & 0x3f800000))
|
||||||
|
return false;
|
||||||
|
*(Elf32_Word*)P = (*(Elf32_Word*)P & 0xfc000003)
|
||||||
|
| ((value & 0x00ffffff) << 2);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
write_low14_check(addr_t P, Elf32_Word value)
|
||||||
|
{
|
||||||
|
// bits 16:29
|
||||||
|
if ((value & 0x3fffc000) && (~value & 0x3fffe000))
|
||||||
|
return false;
|
||||||
|
*(Elf32_Word*)P = (*(Elf32_Word*)P & 0xffff0003)
|
||||||
|
| ((value & 0x00003fff) << 2);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
write_half16(addr_t P, Elf32_Word value)
|
||||||
|
{
|
||||||
|
// bits 16:29
|
||||||
|
*(Elf32_Half*)P = (Elf32_Half)value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
write_half16_check(addr_t P, Elf32_Word value)
|
||||||
|
{
|
||||||
|
// bits 16:29
|
||||||
|
if ((value & 0xffff0000) && (~value & 0xffff8000))
|
||||||
|
return false;
|
||||||
|
*(Elf32_Half*)P = (Elf32_Half)value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline Elf32_Word
|
||||||
|
lo(Elf32_Word value)
|
||||||
|
{
|
||||||
|
return (value & 0xffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline Elf32_Word
|
||||||
|
hi(Elf32_Word value)
|
||||||
|
{
|
||||||
|
return ((value >> 16) & 0xffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline Elf32_Word
|
||||||
|
ha(Elf32_Word value)
|
||||||
|
{
|
||||||
|
return (((value >> 16) + (value & 0x8000 ? 1 : 0)) & 0xffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
arch_elf_relocate_rela(struct elf_image_info *image, const char *sym_prepend,
|
arch_elf_relocate_rela(struct elf_image_info *image, const char *sym_prepend,
|
||||||
struct elf_image_info *resolve_image, struct Elf32_Rela *rel, int rel_len)
|
struct elf_image_info *resolve_image, struct Elf32_Rela *rel, int rel_len)
|
||||||
@@ -29,77 +112,274 @@ arch_elf_relocate_rela(struct elf_image_info *image, const char *sym_prepend,
|
|||||||
int i;
|
int i;
|
||||||
struct Elf32_Sym *sym;
|
struct Elf32_Sym *sym;
|
||||||
int vlErr;
|
int vlErr;
|
||||||
addr_t S = 0;
|
addr_t S = 0; // symbol address
|
||||||
addr_t final_val;
|
addr_t R = 0; // section relative symbol address
|
||||||
|
|
||||||
#define P ((addr_t)(image->text_region.delta + rel[i].r_offset))
|
addr_t G = 0; // GOT address
|
||||||
#define A ((addr_t)rel[i].r_addend)
|
addr_t L = 0; // PLT address
|
||||||
#define B (image->text_region.delta)
|
|
||||||
|
#define P ((addr_t)(image->text_region.delta + rel[i].r_offset))
|
||||||
|
#define A ((addr_t)rel[i].r_addend)
|
||||||
|
#define B (image->text_region.delta)
|
||||||
|
|
||||||
|
// TODO: Get the GOT address!
|
||||||
|
#define REQUIRE_GOT \
|
||||||
|
if (G == 0) { \
|
||||||
|
dprintf("arch_elf_relocate_rela(): Failed to get GOT address!\n"); \
|
||||||
|
return B_ERROR; \
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Get the PLT address!
|
||||||
|
#define REQUIRE_PLT \
|
||||||
|
if (L == 0) { \
|
||||||
|
dprintf("arch_elf_relocate_rela(): Failed to get PLT address!\n"); \
|
||||||
|
return B_ERROR; \
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i * (int)sizeof(struct Elf32_Rela) < rel_len; i++) {
|
for (i = 0; i * (int)sizeof(struct Elf32_Rela) < rel_len; i++) {
|
||||||
#if CHATTY
|
#if CHATTY
|
||||||
dprintf("looking at rel type %d, offset 0x%x, sym 0x%x, addend 0x%x\n",
|
dprintf("looking at rel type %d, offset 0x%lx, sym 0x%lx, addend 0x%lx\n",
|
||||||
ELF32_R_TYPE(rel[i].r_info), rel[i].r_offset, ELF32_R_SYM(rel[i].r_info), rel[i].r_addend);
|
ELF32_R_TYPE(rel[i].r_info), rel[i].r_offset, ELF32_R_SYM(rel[i].r_info), rel[i].r_addend);
|
||||||
#endif
|
#endif
|
||||||
switch (ELF32_R_TYPE(rel[i].r_info)) {
|
switch (ELF32_R_TYPE(rel[i].r_info)) {
|
||||||
|
case R_PPC_SECTOFF:
|
||||||
|
case R_PPC_SECTOFF_LO:
|
||||||
|
case R_PPC_SECTOFF_HI:
|
||||||
|
case R_PPC_SECTOFF_HA:
|
||||||
|
dprintf("arch_elf_relocate_rela(): Getting section relative "
|
||||||
|
"symbol addresses not yet supported!\n");
|
||||||
|
return B_ERROR;
|
||||||
|
|
||||||
case R_PPC_ADDR32:
|
case R_PPC_ADDR32:
|
||||||
case R_PPC_ADDR24:
|
case R_PPC_ADDR24:
|
||||||
case R_PPC_ADDR16:
|
case R_PPC_ADDR16:
|
||||||
case R_PPC_ADDR16_LO:
|
case R_PPC_ADDR16_LO:
|
||||||
case R_PPC_ADDR16_HI:
|
case R_PPC_ADDR16_HI:
|
||||||
case R_PPC_ADDR16_HA:
|
case R_PPC_ADDR16_HA:
|
||||||
|
case R_PPC_ADDR14:
|
||||||
|
case R_PPC_ADDR14_BRTAKEN:
|
||||||
|
case R_PPC_ADDR14_BRNTAKEN:
|
||||||
case R_PPC_REL24:
|
case R_PPC_REL24:
|
||||||
|
case R_PPC_REL14:
|
||||||
|
case R_PPC_REL14_BRTAKEN:
|
||||||
|
case R_PPC_REL14_BRNTAKEN:
|
||||||
|
case R_PPC_GLOB_DAT:
|
||||||
|
case R_PPC_UADDR32:
|
||||||
|
case R_PPC_UADDR16:
|
||||||
|
case R_PPC_REL32:
|
||||||
|
case R_PPC_SDAREL16:
|
||||||
|
case R_PPC_ADDR30:
|
||||||
|
case R_PPC_JMP_SLOT:
|
||||||
sym = SYMBOL(image, ELF32_R_SYM(rel[i].r_info));
|
sym = SYMBOL(image, ELF32_R_SYM(rel[i].r_info));
|
||||||
|
|
||||||
vlErr = elf_resolve_symbol(image, sym, resolve_image, sym_prepend, &S);
|
vlErr = elf_resolve_symbol(image, sym, resolve_image,
|
||||||
if (vlErr<0)
|
sym_prepend, &S);
|
||||||
|
if (vlErr < 0) {
|
||||||
|
dprintf("arch_elf_relocate_rela(): Failed to relocate "
|
||||||
|
"entry index %d, rel type %d, offset 0x%lx, sym 0x%lx, "
|
||||||
|
"addend 0x%lx\n", i, ELF32_R_TYPE(rel[i].r_info),
|
||||||
|
rel[i].r_offset, ELF32_R_SYM(rel[i].r_info),
|
||||||
|
rel[i].r_addend);
|
||||||
return vlErr;
|
return vlErr;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (ELF32_R_TYPE(rel[i].r_info)) {
|
switch (ELF32_R_TYPE(rel[i].r_info)) {
|
||||||
case R_PPC_NONE:
|
case R_PPC_NONE:
|
||||||
continue;
|
break;
|
||||||
|
|
||||||
|
case R_PPC_COPY:
|
||||||
|
// TODO: Implement!
|
||||||
|
dprintf("arch_elf_relocate_rela(): R_PPC_COPY not yet "
|
||||||
|
"supported!\n");
|
||||||
|
return B_ERROR;
|
||||||
|
|
||||||
case R_PPC_ADDR32:
|
case R_PPC_ADDR32:
|
||||||
final_val = S + A;
|
case R_PPC_GLOB_DAT:
|
||||||
|
case R_PPC_UADDR32:
|
||||||
|
write_word32(P, S + A);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case R_PPC_ADDR24:
|
||||||
|
if (write_low24_check(P, (S + A) >> 2))
|
||||||
|
break;
|
||||||
|
dprintf("R_PPC_ADDR24 overflow\n");
|
||||||
|
return B_BAD_DATA;
|
||||||
|
|
||||||
case R_PPC_ADDR16:
|
case R_PPC_ADDR16:
|
||||||
*(Elf32_Half*)P = S;
|
case R_PPC_UADDR16:
|
||||||
continue;
|
if (write_half16_check(P, S + A))
|
||||||
|
break;
|
||||||
|
dprintf("R_PPC_ADDR16 overflow\n");
|
||||||
|
return B_BAD_DATA;
|
||||||
|
|
||||||
case R_PPC_ADDR16_LO:
|
case R_PPC_ADDR16_LO:
|
||||||
*(Elf32_Half*)P = S & 0xffff;
|
write_half16(P, lo(S + A));
|
||||||
continue;
|
|
||||||
|
|
||||||
case R_PPC_ADDR16_HI:
|
|
||||||
*(Elf32_Half*)P = (S >> 16) & 0xffff;
|
|
||||||
continue;
|
|
||||||
|
|
||||||
case R_PPC_ADDR16_HA:
|
|
||||||
*(Elf32_Half*)P = ((S >> 16) + ((S & 0x8000) ? 1 : 0)) & 0xFFFF;
|
|
||||||
continue;
|
|
||||||
|
|
||||||
case R_PPC_REL24:
|
|
||||||
final_val = (*(Elf32_Word *)P & 0xff000003) | ((S + A - P) & 0x3fffffc);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case R_PPC_ADDR16_HI:
|
||||||
|
write_half16(P, hi(S + A));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case R_PPC_ADDR16_HA:
|
||||||
|
write_half16(P, ha(S + A));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case R_PPC_ADDR14:
|
||||||
|
case R_PPC_ADDR14_BRTAKEN:
|
||||||
|
case R_PPC_ADDR14_BRNTAKEN:
|
||||||
|
if (write_low14_check(P, (S + A) >> 2))
|
||||||
|
break;
|
||||||
|
dprintf("R_PPC_ADDR14 overflow\n");
|
||||||
|
return B_BAD_DATA;
|
||||||
|
|
||||||
|
case R_PPC_REL24:
|
||||||
|
if (write_low24_check(P, (S + A - P) >> 2))
|
||||||
|
break;
|
||||||
|
dprintf("R_PPC_REL24 overflow: 0x%lx\n", (S + A - P) >> 2);
|
||||||
|
return B_BAD_DATA;
|
||||||
|
|
||||||
|
case R_PPC_REL14:
|
||||||
|
case R_PPC_REL14_BRTAKEN:
|
||||||
|
case R_PPC_REL14_BRNTAKEN:
|
||||||
|
if (write_low14_check(P, (S + A - P) >> 2))
|
||||||
|
break;
|
||||||
|
dprintf("R_PPC_REL14 overflow\n");
|
||||||
|
return B_BAD_DATA;
|
||||||
|
|
||||||
|
case R_PPC_GOT16:
|
||||||
|
REQUIRE_GOT;
|
||||||
|
if (write_half16_check(P, G + A))
|
||||||
|
break;
|
||||||
|
dprintf("R_PPC_GOT16 overflow\n");
|
||||||
|
return B_BAD_DATA;
|
||||||
|
|
||||||
|
case R_PPC_GOT16_LO:
|
||||||
|
REQUIRE_GOT;
|
||||||
|
write_half16(P, lo(G + A));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case R_PPC_GOT16_HI:
|
||||||
|
REQUIRE_GOT;
|
||||||
|
write_half16(P, hi(G + A));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case R_PPC_GOT16_HA:
|
||||||
|
REQUIRE_GOT;
|
||||||
|
write_half16(P, ha(G + A));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case R_PPC_JMP_SLOT:
|
||||||
|
{
|
||||||
|
// If the relative offset is small enough, we fabricate a
|
||||||
|
// relative branch instruction ("b <addr>").
|
||||||
|
addr_t jumpOffset = S - P;
|
||||||
|
if ((jumpOffset & 0xfc000000) != 0
|
||||||
|
&& (~jumpOffset & 0xfe000000) != 0) {
|
||||||
|
// Offset > 24 bit.
|
||||||
|
// TODO: Implement!
|
||||||
|
// See System V PPC ABI supplement, p. 5-6!
|
||||||
|
dprintf("arch_elf_relocate_rela(): R_PPC_JMP_SLOT: "
|
||||||
|
"Offsets > 24 bit currently not supported!\n");
|
||||||
|
dprintf("jumpOffset: %p\n", (void*)jumpOffset);
|
||||||
|
return B_ERROR;
|
||||||
|
} else {
|
||||||
|
// Offset <= 24 bit
|
||||||
|
// 0:5 opcode (= 18), 6:29 address, 30 AA, 31 LK
|
||||||
|
// "b" instruction: opcode = 18, AA = 0, LK = 0
|
||||||
|
// address: 24 high-order bits of 26 bit offset
|
||||||
|
*(uint32*)P = 0x48000000 | ((jumpOffset) & 0x03fffffc);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case R_PPC_RELATIVE:
|
case R_PPC_RELATIVE:
|
||||||
final_val = B + A;
|
write_word32(P, B + A);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case R_PPC_LOCAL24PC:
|
||||||
|
// TODO: Implement!
|
||||||
|
// low24*
|
||||||
|
// if (write_low24_check(P, ?)
|
||||||
|
// break;
|
||||||
|
// return B_BAD_DATA;
|
||||||
|
dprintf("arch_elf_relocate_rela(): R_PPC_LOCAL24PC not yet "
|
||||||
|
"supported!\n");
|
||||||
|
return B_ERROR;
|
||||||
|
|
||||||
|
case R_PPC_REL32:
|
||||||
|
write_word32(P, S + A - P);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case R_PPC_PLTREL24:
|
||||||
|
REQUIRE_PLT;
|
||||||
|
if (write_low24_check(P, (L + A - P) >> 2))
|
||||||
|
break;
|
||||||
|
dprintf("R_PPC_PLTREL24 overflow\n");
|
||||||
|
return B_BAD_DATA;
|
||||||
|
|
||||||
|
case R_PPC_PLT32:
|
||||||
|
REQUIRE_PLT;
|
||||||
|
write_word32(P, L + A);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case R_PPC_PLTREL32:
|
||||||
|
REQUIRE_PLT;
|
||||||
|
write_word32(P, L + A - P);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case R_PPC_PLT16_LO:
|
||||||
|
REQUIRE_PLT;
|
||||||
|
write_half16(P, lo(L + A));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case R_PPC_PLT16_HI:
|
||||||
|
REQUIRE_PLT;
|
||||||
|
write_half16(P, hi(L + A));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case R_PPC_PLT16_HA:
|
||||||
|
write_half16(P, ha(L + A));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case R_PPC_SDAREL16:
|
||||||
|
// TODO: Implement!
|
||||||
|
// if (write_half16_check(P, S + A - _SDA_BASE_))
|
||||||
|
// break;
|
||||||
|
// return B_BAD_DATA;
|
||||||
|
dprintf("arch_elf_relocate_rela(): R_PPC_SDAREL16 not yet "
|
||||||
|
"supported!\n");
|
||||||
|
return B_ERROR;
|
||||||
|
|
||||||
|
case R_PPC_SECTOFF:
|
||||||
|
if (write_half16_check(P, R + A))
|
||||||
|
break;
|
||||||
|
dprintf("R_PPC_SECTOFF overflow\n");
|
||||||
|
return B_BAD_DATA;
|
||||||
|
|
||||||
|
case R_PPC_SECTOFF_LO:
|
||||||
|
write_half16(P, lo(R + A));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case R_PPC_SECTOFF_HI:
|
||||||
|
write_half16(P, hi(R + A));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case R_PPC_SECTOFF_HA:
|
||||||
|
write_half16(P, ha(R + A));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case R_PPC_ADDR30:
|
||||||
|
write_word30(P, (S + A - P) >> 2);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
dprintf("arch_elf_relocate_rela: unhandled relocation type %d\n", ELF32_R_TYPE(rel[i].r_info));
|
dprintf("arch_elf_relocate_rela: unhandled relocation type %d\n", ELF32_R_TYPE(rel[i].r_info));
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
#if CHATTY
|
|
||||||
dprintf("going to put 0x%x at 0x%x\n", final_val, P);
|
|
||||||
#endif
|
|
||||||
*(addr_t *)P = final_val;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return B_NO_ERROR;
|
return B_NO_ERROR;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -316,7 +316,7 @@ __save_regs:
|
|||||||
|
|
||||||
/* save some of the other regs */
|
/* save some of the other regs */
|
||||||
mffs %f0
|
mffs %f0
|
||||||
stfs %f0, -4(%r1) /* push FPSCR */
|
stfsu %f0, -4(%r1) /* push FPSCR */
|
||||||
mfctr %r0
|
mfctr %r0
|
||||||
stwu %r0, -4(%r1) /* push CTR */
|
stwu %r0, -4(%r1) /* push CTR */
|
||||||
mfxer %r0
|
mfxer %r0
|
||||||
@@ -359,7 +359,7 @@ __restore_regs_and_rfi:
|
|||||||
mtxer %r0
|
mtxer %r0
|
||||||
lwzu %r0, 4(%r1) /* CTR */
|
lwzu %r0, 4(%r1) /* CTR */
|
||||||
mtctr %r0
|
mtctr %r0
|
||||||
lfs %f0, 4(%r1) /* FPSCR */
|
lfsu %f0, 4(%r1) /* FPSCR */
|
||||||
mtfsf 0xff, %f0
|
mtfsf 0xff, %f0
|
||||||
|
|
||||||
lwzu %r31, 4(%r1)
|
lwzu %r31, 4(%r1)
|
||||||
|
|||||||
@@ -106,6 +106,37 @@ ppc_exception_entry(int vector, struct iframe *iframe)
|
|||||||
case 0x300: // DSI
|
case 0x300: // DSI
|
||||||
case 0x400: // ISI
|
case 0x400: // ISI
|
||||||
{
|
{
|
||||||
|
bool kernelDebugger = debug_debugger_running();
|
||||||
|
|
||||||
|
if (kernelDebugger) {
|
||||||
|
// if this thread has a fault handler, we're allowed to be here
|
||||||
|
struct thread *thread = thread_get_current_thread();
|
||||||
|
if (thread && thread->fault_handler != NULL) {
|
||||||
|
iframe->srr0 = thread->fault_handler;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise, not really
|
||||||
|
panic("page fault in debugger without fault handler! Touching "
|
||||||
|
"address %p from ip %p\n", (void *)iframe->dar,
|
||||||
|
(void *)iframe->srr0);
|
||||||
|
break;
|
||||||
|
} else if ((iframe->srr1 & MSR_EXCEPTIONS_ENABLED) == 0) {
|
||||||
|
// if the interrupts were disabled, and we are not running the
|
||||||
|
// kernel startup the page fault was not allowed to happen and
|
||||||
|
// we must panic
|
||||||
|
panic("page fault, but interrupts were disabled. Touching "
|
||||||
|
"address %p from ip %p\n", (void *)iframe->dar,
|
||||||
|
(void *)iframe->srr0);
|
||||||
|
break;
|
||||||
|
} else if (thread != NULL && thread->page_faults_allowed < 1) {
|
||||||
|
panic("page fault not allowed at this place. Touching address "
|
||||||
|
"%p from ip %p\n", (void *)iframe->dar,
|
||||||
|
(void *)iframe->srr0);
|
||||||
|
}
|
||||||
|
|
||||||
|
enable_interrupts();
|
||||||
|
|
||||||
addr_t newip;
|
addr_t newip;
|
||||||
|
|
||||||
ret = vm_page_fault(iframe->dar, iframe->srr0,
|
ret = vm_page_fault(iframe->dar, iframe->srr0,
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
#include <arch_thread.h>
|
#include <arch_thread.h>
|
||||||
|
|
||||||
#include <arch_cpu.h>
|
#include <arch_cpu.h>
|
||||||
|
#include <arch/thread.h>
|
||||||
#include <boot/stage2.h>
|
#include <boot/stage2.h>
|
||||||
#include <kernel.h>
|
#include <kernel.h>
|
||||||
#include <thread.h>
|
#include <thread.h>
|
||||||
@@ -25,9 +26,13 @@
|
|||||||
// a new thread structure.
|
// a new thread structure.
|
||||||
static struct arch_thread sInitialState;
|
static struct arch_thread sInitialState;
|
||||||
|
|
||||||
// Helper functions for thread creation, defined in arch_asm.S.
|
// Helper function for thread creation, defined in arch_asm.S.
|
||||||
extern void ppc_kernel_thread_root();
|
extern void ppc_kernel_thread_root();
|
||||||
|
|
||||||
|
extern void ppc_switch_stack_and_call(addr_t newKstack, void (*func)(void *),
|
||||||
|
void *arg);
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
ppc_push_iframe(struct iframe_stack *stack, struct iframe *frame)
|
ppc_push_iframe(struct iframe_stack *stack, struct iframe *frame)
|
||||||
{
|
{
|
||||||
@@ -162,6 +167,14 @@ arch_thread_init_tls(struct thread *thread)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
arch_thread_switch_kstack_and_call(struct thread *t, addr_t newKstack,
|
||||||
|
void (*func)(void *), void *arg)
|
||||||
|
{
|
||||||
|
ppc_switch_stack_and_call(newKstack, func, arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
arch_thread_context_switch(struct thread *t_from, struct thread *t_to)
|
arch_thread_context_switch(struct thread *t_from, struct thread *t_to)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user