Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
9baa4bb9
Commit
9baa4bb9
authored
Nov 21, 2002
by
Rusty Russell
Committed by
Paul Mackerras
Nov 21, 2002
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
PPC32: In-kernel module linker for PPC.
parent
fdea9fc9
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
308 additions
and
22 deletions
+308
-22
arch/ppc/kernel/Makefile
arch/ppc/kernel/Makefile
+1
-1
arch/ppc/kernel/misc.S
arch/ppc/kernel/misc.S
+3
-3
arch/ppc/kernel/module.c
arch/ppc/kernel/module.c
+260
-0
arch/ppc/mm/extable.c
arch/ppc/mm/extable.c
+15
-10
include/asm-ppc/module.h
include/asm-ppc/module.h
+29
-8
No files found.
arch/ppc/kernel/Makefile
View file @
9baa4bb9
...
@@ -25,7 +25,7 @@ obj-y := entry.o traps.o irq.o idle.o time.o misc.o \
...
@@ -25,7 +25,7 @@ obj-y := entry.o traps.o irq.o idle.o time.o misc.o \
cputable.o ppc_htab.o
cputable.o ppc_htab.o
obj-$(CONFIG_6xx)
+=
l2cr.o ppc6xx_idle.o
obj-$(CONFIG_6xx)
+=
l2cr.o ppc6xx_idle.o
obj-$(CONFIG_ALL_PPC)
+=
ppc6xx_idle.o
obj-$(CONFIG_ALL_PPC)
+=
ppc6xx_idle.o
obj-$(CONFIG_MODULES)
+=
ppc_ksyms.o
obj-$(CONFIG_MODULES)
+=
module.o
ppc_ksyms.o
obj-$(CONFIG_PCI)
+=
pci.o
obj-$(CONFIG_PCI)
+=
pci.o
ifneq
($(CONFIG_PPC_ISERIES),y)
ifneq
($(CONFIG_PPC_ISERIES),y)
obj-$(CONFIG_PCI)
+=
pci-dma.o
obj-$(CONFIG_PCI)
+=
pci-dma.o
...
...
arch/ppc/kernel/misc.S
View file @
9baa4bb9
...
@@ -1182,10 +1182,10 @@ _GLOBAL(sys_call_table)
...
@@ -1182,10 +1182,10 @@ _GLOBAL(sys_call_table)
.
long
sys_adjtimex
.
long
sys_adjtimex
.
long
sys_mprotect
/*
125
*/
.
long
sys_mprotect
/*
125
*/
.
long
sys_sigprocmask
.
long
sys_sigprocmask
.
long
sys_
create_module
.
long
sys_
ni_syscall
/*
old
sys_create_module
*/
.
long
sys_init_module
.
long
sys_init_module
.
long
sys_delete_module
.
long
sys_delete_module
.
long
sys_
get_kernel_syms
/*
130
*/
.
long
sys_
ni_syscall
/*
old
sys_get_kernel_syms
*/
/*
130
*/
.
long
sys_quotactl
.
long
sys_quotactl
.
long
sys_getpgid
.
long
sys_getpgid
.
long
sys_fchdir
.
long
sys_fchdir
...
@@ -1221,7 +1221,7 @@ _GLOBAL(sys_call_table)
...
@@ -1221,7 +1221,7 @@ _GLOBAL(sys_call_table)
.
long
sys_mremap
.
long
sys_mremap
.
long
sys_setresuid
.
long
sys_setresuid
.
long
sys_getresuid
/*
165
*/
.
long
sys_getresuid
/*
165
*/
.
long
sys_
query_module
.
long
sys_
ni_syscall
/*
old
sys_query_module
*/
.
long
sys_poll
.
long
sys_poll
.
long
sys_nfsservctl
.
long
sys_nfsservctl
.
long
sys_setresgid
.
long
sys_setresgid
...
...
arch/ppc/kernel/module.c
0 → 100644
View file @
9baa4bb9
/* Kernel module help for PPC.
Copyright (C) 2001 Rusty Russell.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/module.h>
#include <linux/elf.h>
#include <linux/vmalloc.h>
#include <linux/fs.h>
#include <linux/string.h>
#include <linux/kernel.h>
#if 0
#define DEBUGP printk
#else
#define DEBUGP(fmt , ...)
#endif
void
*
module_alloc
(
unsigned
long
size
)
{
if
(
size
==
0
)
return
NULL
;
return
vmalloc
(
size
);
}
/* Free memory returned from module_alloc */
void
module_free
(
struct
module
*
mod
,
void
*
module_region
)
{
vfree
(
module_region
);
/* FIXME: If module_region == mod->init_region, trim exception
table entries. */
}
/* Count how many different relocations (different symbol, different
addend) */
static
unsigned
int
count_relocs
(
const
Elf32_Rela
*
rela
,
unsigned
int
num
)
{
unsigned
int
i
,
j
,
ret
=
0
;
/* Sure, this is order(n^2), but it's usually short, and not
time critical */
for
(
i
=
0
;
i
<
num
;
i
++
)
{
for
(
j
=
0
;
j
<
i
;
j
++
)
{
/* If this addend appeared before, it's
already been counted */
if
(
ELF32_R_SYM
(
rela
[
i
].
r_info
)
==
ELF32_R_SYM
(
rela
[
j
].
r_info
)
&&
rela
[
i
].
r_addend
==
rela
[
j
].
r_addend
)
break
;
}
if
(
j
==
i
)
ret
++
;
}
return
ret
;
}
/* Get the potential trampolines size required of the init and
non-init sections */
static
unsigned
long
get_plt_size
(
const
Elf32_Ehdr
*
hdr
,
const
Elf32_Shdr
*
sechdrs
,
const
char
*
secstrings
,
int
is_init
)
{
unsigned
long
ret
=
0
;
unsigned
i
;
/* Everything marked ALLOC (this includes the exported
symbols) */
for
(
i
=
1
;
i
<
hdr
->
e_shnum
;
i
++
)
{
/* If it's called *.init*, and we're not init, we're
not interested */
if
((
strstr
(
secstrings
+
sechdrs
[
i
].
sh_name
,
".init"
)
!=
0
)
!=
is_init
)
continue
;
if
(
sechdrs
[
i
].
sh_type
==
SHT_RELA
)
{
DEBUGP
(
"Found relocations in section %u
\n
"
,
i
);
DEBUGP
(
"Ptr: %p. Number: %u
\n
"
,
(
void
*
)
hdr
+
sechdrs
[
i
].
sh_offset
,
sechdrs
[
i
].
sh_size
/
sizeof
(
Elf32_Rela
));
ret
+=
count_relocs
((
void
*
)
hdr
+
sechdrs
[
i
].
sh_offset
,
sechdrs
[
i
].
sh_size
/
sizeof
(
Elf32_Rela
))
*
sizeof
(
struct
ppc_plt_entry
);
}
}
return
ret
;
}
long
module_core_size
(
const
Elf32_Ehdr
*
hdr
,
const
Elf32_Shdr
*
sechdrs
,
const
char
*
secstrings
,
struct
module
*
module
)
{
module
->
arch
.
core_plt_offset
=
module
->
core_size
;
return
module
->
core_size
+
get_plt_size
(
hdr
,
sechdrs
,
secstrings
,
0
);
}
long
module_init_size
(
const
Elf32_Ehdr
*
hdr
,
const
Elf32_Shdr
*
sechdrs
,
const
char
*
secstrings
,
struct
module
*
module
)
{
module
->
arch
.
init_plt_offset
=
module
->
init_size
;
return
module
->
init_size
+
get_plt_size
(
hdr
,
sechdrs
,
secstrings
,
1
);
}
int
apply_relocate
(
Elf32_Shdr
*
sechdrs
,
const
char
*
strtab
,
unsigned
int
symindex
,
unsigned
int
relsec
,
struct
module
*
module
)
{
printk
(
KERN_ERR
"%s: Non-ADD RELOCATION unsupported
\n
"
,
module
->
name
);
return
-
ENOEXEC
;
}
static
inline
int
entry_matches
(
struct
ppc_plt_entry
*
entry
,
Elf32_Addr
val
)
{
if
(
entry
->
jump
[
0
]
==
0x3d600000
+
((
val
+
0x8000
)
>>
16
)
&&
entry
->
jump
[
1
]
==
0x396b0000
+
(
val
&
0xffff
))
return
1
;
return
0
;
}
/* Set up a trampoline in the PLT to bounce us to the distant function */
static
uint32_t
do_plt_call
(
void
*
location
,
Elf32_Addr
val
,
struct
module
*
mod
)
{
struct
ppc_plt_entry
*
entry
;
DEBUGP
(
"Doing plt for %u
\n
"
,
(
unsigned
int
)
location
);
/* Init, or core PLT? */
if
(
location
>=
mod
->
module_core
&&
location
<
mod
->
module_core
+
mod
->
arch
.
core_plt_offset
)
entry
=
mod
->
module_core
+
mod
->
arch
.
core_plt_offset
;
else
entry
=
mod
->
module_init
+
mod
->
arch
.
init_plt_offset
;
/* Find this entry, or if that fails, the next avail. entry */
while
(
entry
->
jump
[
0
])
{
if
(
entry_matches
(
entry
,
val
))
return
(
uint32_t
)
entry
;
entry
++
;
}
/* Stolen from Paul Mackerras as well... */
entry
->
jump
[
0
]
=
0x3d600000
+
((
val
+
0x8000
)
>>
16
);
/* lis r11,sym@ha */
entry
->
jump
[
1
]
=
0x396b0000
+
(
val
&
0xffff
);
/* addi r11,r11,sym@l*/
entry
->
jump
[
2
]
=
0x7d6903a6
;
/* mtctr r11 */
entry
->
jump
[
3
]
=
0x4e800420
;
/* bctr */
return
(
uint32_t
)
entry
;
}
int
apply_relocate_add
(
Elf32_Shdr
*
sechdrs
,
const
char
*
strtab
,
unsigned
int
symindex
,
unsigned
int
relsec
,
struct
module
*
module
)
{
unsigned
int
i
;
Elf32_Rela
*
rela
=
(
void
*
)
sechdrs
[
relsec
].
sh_offset
;
Elf32_Sym
*
sym
;
uint32_t
*
location
;
uint32_t
value
;
DEBUGP
(
"Applying ADD relocate section %u to %u
\n
"
,
relsec
,
sechdrs
[
relsec
].
sh_info
);
for
(
i
=
0
;
i
<
sechdrs
[
relsec
].
sh_size
/
sizeof
(
*
rela
);
i
++
)
{
/* This is where to make the change */
location
=
(
void
*
)
sechdrs
[
sechdrs
[
relsec
].
sh_info
].
sh_offset
+
rela
[
i
].
r_offset
;
/* This is the symbol it is referring to */
sym
=
(
Elf32_Sym
*
)
sechdrs
[
symindex
].
sh_offset
+
ELF32_R_SYM
(
rela
[
i
].
r_info
);
if
(
!
sym
->
st_value
)
{
printk
(
KERN_WARNING
"%s: Unknown symbol %s
\n
"
,
module
->
name
,
strtab
+
sym
->
st_name
);
return
-
ENOENT
;
}
/* `Everything is relative'. */
value
=
sym
->
st_value
+
rela
[
i
].
r_addend
;
switch
(
ELF32_R_TYPE
(
rela
[
i
].
r_info
))
{
case
R_PPC_ADDR32
:
/* Simply set it */
*
(
uint32_t
*
)
location
=
value
;
break
;
case
R_PPC_ADDR16_LO
:
/* Low half of the symbol */
*
(
uint16_t
*
)
location
=
value
;
break
;
case
R_PPC_ADDR16_HA
:
/* Sign-adjusted lower 16 bits: PPC ELF ABI says:
(((x >> 16) + ((x & 0x8000) ? 1 : 0))) & 0xFFFF.
This is the same, only sane.
*/
*
(
uint16_t
*
)
location
=
(
value
+
0x8000
)
>>
16
;
break
;
case
R_PPC_REL24
:
if
((
int
)(
value
-
(
uint32_t
)
location
)
<
-
0x02000000
||
(
int
)(
value
-
(
uint32_t
)
location
)
>=
0x02000000
)
value
=
do_plt_call
(
location
,
value
,
module
);
/* Only replace bits 2 through 26 */
DEBUGP
(
"REL24 value = %08X. location = %08X
\n
"
,
value
,
(
uint32_t
)
location
);
DEBUGP
(
"Location before: %08X.
\n
"
,
*
(
uint32_t
*
)
location
);
*
(
uint32_t
*
)
location
=
(
*
(
uint32_t
*
)
location
&
~
0x03fffffc
)
|
((
value
-
(
uint32_t
)
location
)
&
0x03fffffc
);
DEBUGP
(
"Location after: %08X.
\n
"
,
*
(
uint32_t
*
)
location
);
DEBUGP
(
"ie. jump to %08X+%08X = %08X
\n
"
,
*
(
uint32_t
*
)
location
&
0x03fffffc
,
(
uint32_t
)
location
,
(
*
(
uint32_t
*
)
location
&
0x03fffffc
)
+
(
uint32_t
)
location
);
break
;
case
R_PPC_REL32
:
/* 32-bit relative jump. */
*
(
uint32_t
*
)
location
=
value
-
(
uint32_t
)
location
;
break
;
default:
printk
(
"%s: unknown ADD relocation: %u
\n
"
,
module
->
name
,
ELF32_R_TYPE
(
rela
[
i
].
r_info
));
return
-
ENOEXEC
;
}
}
return
0
;
}
/* FIXME: Sort exception table --RR */
int
module_finalize
(
const
Elf_Ehdr
*
hdr
,
const
Elf_Shdr
*
sechdrs
,
struct
module
*
me
)
{
return
0
;
}
arch/ppc/mm/extable.c
View file @
9baa4bb9
...
@@ -70,24 +70,29 @@ search_one_table(const struct exception_table_entry *first,
...
@@ -70,24 +70,29 @@ search_one_table(const struct exception_table_entry *first,
unsigned
long
unsigned
long
search_exception_table
(
unsigned
long
addr
)
search_exception_table
(
unsigned
long
addr
)
{
{
unsigned
long
ret
;
unsigned
long
ret
=
0
;
#ifndef CONFIG_MODULES
#ifndef CONFIG_MODULES
/* There is only the kernel to search. */
/* There is only the kernel to search. */
ret
=
search_one_table
(
__start___ex_table
,
__stop___ex_table
-
1
,
addr
);
ret
=
search_one_table
(
__start___ex_table
,
__stop___ex_table
-
1
,
addr
);
if
(
ret
)
return
ret
;
#else
#else
/* The kernel is the last "module" -- no need to treat it special. */
unsigned
long
flags
;
struct
module
*
mp
;
struct
list_head
*
i
;
for
(
mp
=
module_list
;
mp
!=
NULL
;
mp
=
mp
->
next
)
{
if
(
mp
->
ex_table_start
==
NULL
)
/* The kernel is the last "module" -- no need to treat it special. */
spin_lock_irqsave
(
&
modlist_lock
,
flags
);
list_for_each
(
i
,
&
extables
)
{
struct
exception_table
*
ex
=
list_entry
(
i
,
struct
exception_table
,
list
);
if
(
ex
->
num_entries
==
0
)
continue
;
continue
;
ret
=
search_one_table
(
mp
->
ex_table_start
,
ret
=
search_one_table
(
ex
->
entry
,
mp
->
ex_table_end
-
1
,
addr
);
ex
->
entry
+
ex
->
num_entries
-
1
,
addr
);
if
(
ret
)
if
(
ret
)
return
ret
;
break
;
}
}
spin_unlock_irqrestore
(
&
modlist_lock
,
flags
);
#endif
#endif
return
0
;
return
ret
;
}
}
include/asm-ppc/module.h
View file @
9baa4bb9
#ifndef _ASM_PPC_MODULE_H
#ifndef _ASM_PPC_MODULE_H
#define _ASM_PPC_MODULE_H
#define _ASM_PPC_MODULE_H
/*
/* Module stuff for PPC. (C) 2001 Rusty Russell */
* This file contains the PPC architecture specific module code.
*/
/* Thanks to Paul M for explaining this.
#define module_map(x) vmalloc(x)
PPC can only do rel jumps += 32MB, and often the kernel and other
#define module_unmap(x) vfree(x)
modules are furthur away than this. So, we jump to a table of
#define module_arch_init(x) (0)
trampolines attached to the module (the Procedure Linkage Table)
#define arch_init_modules(x) do { } while (0)
whenever that happens.
*/
struct
ppc_plt_entry
{
/* 16 byte jump instruction sequence (4 instructions) */
unsigned
int
jump
[
4
];
};
struct
mod_arch_specific
{
/* How much of the core is actually taken up with core (then
we know the rest is for the PLT */
unsigned
int
core_plt_offset
;
/* Same for init */
unsigned
int
init_plt_offset
;
};
#define Elf_Shdr Elf32_Shdr
#define Elf_Sym Elf32_Sym
#define Elf_Ehdr Elf32_Ehdr
#endif
/* _ASM_PPC_MODULE_H */
#endif
/* _ASM_PPC_MODULE_H */
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment