From: Tony Wu <tung7970@gmail.com>
To: ralf@linux-mips.org, macro@linux-mips.org,
Steven.Hill@imgtec.com, david.daney@cavium.com,
linux-mips@linux-mips.org
Subject: [PATCH v4 3/3] MIPS: microMIPS: Refactor get_frame_info support
Date: Mon, 27 May 2013 20:47:15 +0800 [thread overview]
Message-ID: <20130527124715.GC32322@hades> (raw)
In-Reply-To: <20130527124421.GA32322@hades>
Current get_frame_info implementation works on word boundary, this
can lead to alignment and endian issues in microMIPS mode,
due to:
1. microMIPS instructions are sequence of halfwords
2. microMIPS instructions can be one or two halfwords
3. microMIPS instructions are placed in 32-bit memory element,
in endian-dependent order.
Example:
insn1 = one halfword => word1, hword[0]
insn2 = two halfwords => word1, hword[1], word2, hword[0]
insn3 = one halfword => word2, hword[1]
Big Endian
hword[0] hword[1] hword[0] hword[1]
+-------------+-------------+-------------+-------------+
| insn1 | insn2 | insn2' | insn3 |
+-------------+-------------+-------------+-------------+
31 word1 0 31 word2 0
Little Endian
hword[1] hword[0] hword[1] hword[0]
+-------------+-------------+-------------+-------------+
| insn2 | insn1 | insn3 | insn2' |
+-------------+-------------+-------------+-------------+
31 word1 0 31 word2 0
This patch refactors microMIPS get_frame_info by implementing
fetch_instruction() to fetch words on word boundary, and
mmips_fetch_halfword() to assemble one or two halfwords into
microMIPS instructions for further processing.
This patch also fixes sibling call handling and schedule_mfi
initialization for microMIPS.
Signed-off-by: Tony Wu <tung7970@gmail.com>
Cc: Maciej W. Rozycki <macro@linux-mips.org>
Cc: David Daney <david.daney@cavium.com>
Cc: Steven J. Hill <Steven.Hill@imgtec.com>
---
arch/mips/kernel/process.c | 341 +++++++++++++++++++++++++++-----------------
1 file changed, 211 insertions(+), 130 deletions(-)
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index c6a041d..5c1a960 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -211,124 +211,201 @@ struct mips_frame_info {
int pc_offset;
};
-#define J_TARGET(pc,target) \
- (((unsigned long)(pc) & 0xf0000000) | ((target) << 2))
-
static inline int is_ra_save_ins(union mips_instruction *ip)
{
-#ifdef CONFIG_CPU_MICROMIPS
- union mips_instruction mmi;
-
- /*
- * swsp ra,offset
- * swm16 reglist,offset(sp)
- * swm32 reglist,offset(sp)
- * sw32 ra,offset(sp)
- * jradiussp - NOT SUPPORTED
- *
- * microMIPS is way more fun...
- */
- if (mm_insn_16bit(ip->halfword[0])) {
- mmi.word = (ip->halfword[0] << 16);
- return ((mmi.mm16_r5_format.opcode == mm_swsp16_op &&
- mmi.mm16_r5_format.rt == 31) ||
- (mmi.mm16_m_format.opcode == mm_pool16c_op &&
- mmi.mm16_m_format.func == mm_swm16_op));
- }
- else {
- mmi.halfword[0] = ip->halfword[1];
- mmi.halfword[1] = ip->halfword[0];
- return ((mmi.mm_m_format.opcode == mm_pool32b_op &&
- mmi.mm_m_format.rd > 9 &&
- mmi.mm_m_format.base == 29 &&
- mmi.mm_m_format.func == mm_swm32_func) ||
- (mmi.i_format.opcode == mm_sw32_op &&
- mmi.i_format.rs == 29 &&
- mmi.i_format.rt == 31));
+ if (kernel_uses_mmips) {
+ /*
+ * swsp ra,offset
+ * swm16 reglist,offset(sp)
+ * swm32 reglist,offset(sp)
+ * sw32 ra,offset(sp)
+ *
+ * microMIPS is way more fun...
+ */
+ return ((ip->mm16_r5_format.opcode == mm_swsp16_op &&
+ ip->mm16_r5_format.rt == 31) ||
+ (ip->mm16_m_format.opcode == mm_pool16c_op &&
+ ip->mm16_m_format.func == mm_swm16_op) ||
+ /* two-halfword instructions */
+ (ip->mm_m_format.opcode == mm_pool32b_op &&
+ ip->mm_m_format.rd >= 16 &&
+ ip->mm_m_format.base == 29 &&
+ ip->mm_m_format.func == mm_swm32_func) ||
+ (ip->mm_i_format.opcode == mm_sw32_op &&
+ ip->mm_i_format.rs == 29 &&
+ ip->mm_i_format.rt == 31));
+ } else {
+ /* sw / sd $ra, offset($sp) */
+ return (ip->i_format.opcode == sw_op ||
+ ip->i_format.opcode == sd_op) &&
+ ip->i_format.rs == 29 &&
+ ip->i_format.rt == 31;
}
-#else
- /* sw / sd $ra, offset($sp) */
- return (ip->i_format.opcode == sw_op || ip->i_format.opcode == sd_op) &&
- ip->i_format.rs == 29 &&
- ip->i_format.rt == 31;
-#endif
}
static inline int is_jump_ins(union mips_instruction *ip)
{
-#ifdef CONFIG_CPU_MICROMIPS
- /*
- * jr16,jrc,jalr16,jalr16
- * jal
- * jalr/jr,jalr.hb/jr.hb,jalrs,jalrs.hb
- * jraddiusp - NOT SUPPORTED
- *
- * microMIPS is kind of more fun...
- */
- union mips_instruction mmi;
-
- mmi.word = (ip->halfword[0] << 16);
-
- if ((mmi.mm16_r5_format.opcode == mm_pool16c_op &&
- (mmi.mm16_r5_format.rt & mm_jr16_op) == mm_jr16_op) ||
- ip->j_format.opcode == mm_jal32_op)
- return 1;
- if (ip->r_format.opcode != mm_pool32a_op ||
- ip->r_format.func != mm_pool32axf_op)
- return 0;
- return (((ip->u_format.uimmediate >> 6) & mm_jalr_op) == mm_jalr_op);
-#else
- if (ip->j_format.opcode == j_op)
- return 1;
- if (ip->j_format.opcode == jal_op)
- return 1;
- if (ip->r_format.opcode != spec_op)
- return 0;
- return ip->r_format.func == jalr_op || ip->r_format.func == jr_op;
-#endif
+ if (kernel_uses_mmips) {
+ /*
+ * jr16,jrc,jalr16,jalr16
+ * jal
+ * jalr/jr,jalr.hb/jr.hb,jalrs,jalrs.hb
+ * jraddiusp
+ *
+ * microMIPS is kind of more fun...
+ */
+ return ((ip->mm16_r5_format.opcode == mm_pool16c_op &&
+ ((ip->mm16_r5_format.rt & ~0x3) == mm_jr16_op ||
+ ip->mm16_r5_format.rt == mm_jraddiusp_op)) ||
+ /* two-halfword instructions */
+ ip->j_format.opcode == mm_jal32_op ||
+ ip->j_format.opcode == mm_jals32_op ||
+ ip->j_format.opcode == mm_j32_op ||
+ (ip->r_format.opcode == mm_pool32a_op &&
+ ip->r_format.func == mm_pool32axf_op &&
+ ((ip->u_format.uimmediate >> 6) & ~0x140) ==
+ mm_jalr_op));
+ } else {
+ return (ip->j_format.opcode == j_op ||
+ ip->j_format.opcode == jal_op ||
+ (ip->r_format.opcode == spec_op &&
+ (ip->r_format.func == jalr_op ||
+ ip->r_format.func == jr_op)));
+ }
}
static inline int is_sp_move_ins(union mips_instruction *ip)
{
-#ifdef CONFIG_CPU_MICROMIPS
- /*
- * addiusp -imm
- * addius5 sp,-imm
- * addiu32 sp,sp,-imm
- * jradiussp - NOT SUPPORTED
- *
- * microMIPS is not more fun...
- */
- if (mm_insn_16bit(ip->halfword[0])) {
- union mips_instruction mmi;
-
- mmi.word = (ip->halfword[0] << 16);
- return ((mmi.mm16_r3_format.opcode == mm_pool16d_op &&
- mmi.mm16_r3_format.simmediate && mm_addiusp_func) ||
- (mmi.mm16_r5_format.opcode == mm_pool16d_op &&
- mmi.mm16_r5_format.rt == 29));
+ if (kernel_uses_mmips) {
+ /*
+ * addiusp -imm
+ * addius5 sp,-imm
+ * addiu32 sp,sp,-imm
+ *
+ * microMIPS is not more fun...
+ */
+ return ((ip->mm16_r5_format.opcode == mm_pool16d_op &&
+ (ip->mm16_r5_format.simmediate & mm_addiusp_func ||
+ ip->mm16_r5_format.rt == 29)) ||
+ /* two-halfword instructions */
+ (ip->mm_i_format.opcode == mm_addiu32_op &&
+ ip->mm_i_format.rt == 29 &&
+ ip->mm_i_format.rs == 29));
+ } else {
+ /* addiu/daddiu sp,sp,-imm */
+ return (ip->i_format.rs == 29 &&
+ ip->i_format.rt == 29 &&
+ (ip->i_format.opcode == addiu_op ||
+ ip->i_format.opcode == daddiu_op));
}
- return (ip->mm_i_format.opcode == mm_addiu32_op &&
- ip->mm_i_format.rt == 29 && ip->mm_i_format.rs == 29);
-#else
- /* addiu/daddiu sp,sp,-imm */
- if (ip->i_format.rs != 29 || ip->i_format.rt != 29)
- return 0;
- if (ip->i_format.opcode == addiu_op || ip->i_format.opcode == daddiu_op)
- return 1;
-#endif
return 0;
}
+/*
+ * A few fun facts on microMIPS (MIPS32)
+ *
+ * 1. microMIPS instructions are sequence of halfwords
+ * 2. microMIPS instructions may contain one to two halfwords
+ * 3. microMIPS instructions are placed in 32-bit memory element,
+ * in endian-dependent order.
+ *
+ * Example:
+ * insn1 = one halfword => word1, hword[0]
+ * insn2 = two halfwords => word1, hword[1], word2, hword[0]
+ * insn3 = one halfword => word2, hword[1]
+ *
+ * Big Endian
+ * hword[0] hword[1] hword[0] hword[1]
+ * +-------------+-------------+-------------+-------------+
+ * | insn1 | insn2 | insn2' | insn3 |
+ * +-------------+-------------+-------------+-------------+
+ * 31 word1 0 31 word2 0
+ *
+ * Little Endian
+ * hword[1] hword[0] hword[1] hword[0]
+ * +-------------+-------------+-------------+-------------+
+ * | insn2 | insn1 | insn3 | insn2' |
+ * +-------------+-------------+-------------+-------------+
+ * 31 word1 0 31 word2 0
+ *
+ * mmips_fetch_halfword does the followings:
+ *
+ * 1. fetch word from word-aligned address
+ * 2. access the fetched word using halfword (defeat endian issue)
+ * 3. assemble microMIPS instruction with one or two halfwords
+ */
+static void mmips_fetch_halfword(union mips_instruction **ip,
+ unsigned short *this_halfword,
+ unsigned short *prev_halfword)
+{
+ if (*prev_halfword) {
+ *this_halfword = *prev_halfword;
+ *prev_halfword = 0;
+ } else {
+ /* advance pointer to next word */
+ *this_halfword = (*ip)->halfword[0];
+ *prev_halfword = (*ip)->halfword[1];
+ *ip += 1;
+ }
+}
+
+static void fetch_instruction(union mips_instruction **ip,
+ union mips_instruction *mi,
+ unsigned short *prev_halfword)
+{
+ if (kernel_uses_mmips) {
+ /* fetch the first microMIPS instruction */
+ mmips_fetch_halfword(ip, &mi->halfword[0], prev_halfword);
+
+ /* fetch the second half if it is a 32bit one */
+ if (mm_insn_16bit(mi->halfword[0]))
+ mi->halfword[1] = 0;
+ else
+ mmips_fetch_halfword(ip, &mi->halfword[1],
+ prev_halfword);
+ } else {
+ /* do simple assignment for mips32 mode */
+ *mi = **ip;
+ *ip += 1;
+ }
+}
+
+static int get_frame_size(union mips_instruction *ip)
+{
+ unsigned short tmp;
+ int size = 0;
+
+ if (kernel_uses_mmips &&
+ mm_insn_16bit(ip->halfword[0])) {
+ /*
+ * addiusp -imm
+ * addius5 sp,-imm
+ */
+ if (ip->halfword[0] & mm_addiusp_func) {
+ tmp = (((ip->halfword[0] >> 1) & 0x1ff) << 2);
+ size = -(signed short)(tmp |
+ ((tmp & 0x100) ? 0xfe00 : 0));
+ } else {
+ tmp = (ip->halfword[0] >> 1);
+ size = -(signed short)(tmp & 0xf);
+ }
+ } else {
+ /*
+ * addiu32 sp,sp,-imm
+ * addiu/daddiu sp,sp,-imm
+ */
+ size = - ip->i_format.simmediate;
+ }
+
+ return size;
+}
+
static int get_frame_info(struct mips_frame_info *info)
{
-#ifdef CONFIG_CPU_MICROMIPS
- union mips_instruction *ip = (void *) (((char *) info->func) - 1);
-#else
union mips_instruction *ip = info->func;
-#endif
+ union mips_instruction inst, *max_ip;
unsigned max_insns = info->func_size / sizeof(union mips_instruction);
- unsigned i;
+ unsigned short halfword = 0;
info->pc_offset = -1;
info->frame_size = 0;
@@ -340,37 +417,25 @@ static int get_frame_info(struct mips_frame_info *info)
max_insns = 128U; /* unknown function size */
max_insns = min(128U, max_insns);
- for (i = 0; i < max_insns; i++, ip++) {
+ if (kernel_uses_mmips) {
+ /* align start address to word boundary, lose mode bit. */
+ ip = (union mips_instruction *)((unsigned long)ip & ~0x3);
+ }
+ max_ip = ip + max_insns * sizeof(union mips_instruction);
- if (is_jump_ins(ip))
+ while (ip < max_ip) {
+ fetch_instruction(&ip, &inst, &halfword);
+
+ if (is_jump_ins(&inst))
break;
if (!info->frame_size) {
- if (is_sp_move_ins(ip))
- {
-#ifdef CONFIG_CPU_MICROMIPS
- if (mm_insn_16bit(ip->halfword[0]))
- {
- unsigned short tmp;
-
- if (ip->halfword[0] & mm_addiusp_func)
- {
- tmp = (((ip->halfword[0] >> 1) & 0x1ff) << 2);
- info->frame_size = -(signed short)(tmp | ((tmp & 0x100) ? 0xfe00 : 0));
- } else {
- tmp = (ip->halfword[0] >> 1);
- info->frame_size = -(signed short)(tmp & 0xf);
- }
- ip = (void *) &ip->halfword[1];
- ip--;
- } else
-#endif
- info->frame_size = - ip->i_format.simmediate;
- }
+ if (is_sp_move_ins(&inst))
+ info->frame_size = get_frame_size(&inst);
continue;
}
- if (info->pc_offset == -1 && is_ra_save_ins(ip)) {
+ if (info->pc_offset == -1 && is_ra_save_ins(&inst)) {
info->pc_offset =
- ip->i_format.simmediate / sizeof(long);
+ inst.i_format.simmediate / sizeof(long);
break;
}
}
@@ -390,20 +455,36 @@ static unsigned long get___schedule_addr(void)
{
return kallsyms_lookup_name("__schedule");
}
-#else
+#else /* CONFIG_KALLSYMS */
static unsigned long get___schedule_addr(void)
{
union mips_instruction *ip = (void *)schedule;
+ union mips_instruction inst;
+ union mips_instruction *max_ip;
int max_insns = 8;
- int i;
+ unsigned short halfword = 0;
- for (i = 0; i < max_insns; i++, ip++) {
- if (ip->j_format.opcode == j_op)
- return J_TARGET(ip, ip->j_format.target);
+ if (kernel_uses_mmips) {
+ /* align start address to word boundary, lose mode bit */
+ ip = (union mips_instruction *)((unsigned long)ip & ~0x3);
+ }
+ max_ip = ip + max_insns * sizeof(union mips_instruction);
+
+ while (ip < max_ip) {
+ fetch_instruction(&ip, &inst, &halfword);
+ if (kernel_uses_mmips) {
+ if (inst.j_format.opcode == mm_j32_op)
+ return (((unsigned long)(ip+1) & 0xf8000000) |
+ (inst.j_format.target << 1));
+ } else {
+ if (inst.j_format.opcode == j_op)
+ return (((unsigned long)(ip) & 0xf0000000) |
+ (inst.j_format.target << 2));
+ }
}
return 0;
}
-#endif
+#endif /* !CONFIG_KALLSYMS */
static int __init frame_info_init(void)
{
--
1.7.10.2 (Apple Git-33)
next prev parent reply other threads:[~2013-05-27 12:47 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-05-27 12:44 [PATCH v4 1/3] MIPS: microMIPS: Fix POOL16C minor opcode enum Tony Wu
2013-05-27 12:45 ` [PATCH v4 2/3] MIPS: microMIPS: Add kernel_uses_mmips in cpu-features.h Tony Wu
2013-05-27 14:34 ` Sergei Shtylyov
2013-06-19 21:56 ` Steven J. Hill
2013-06-19 21:56 ` Steven J. Hill
2013-06-20 9:50 ` Tony Wu
2013-05-27 12:47 ` Tony Wu [this message]
2013-06-19 21:53 ` [PATCH v4 1/3] MIPS: microMIPS: Fix POOL16C minor opcode enum Steven J. Hill
2013-06-19 21:53 ` Steven J. Hill
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20130527124715.GC32322@hades \
--to=tung7970@gmail.com \
--cc=Steven.Hill@imgtec.com \
--cc=david.daney@cavium.com \
--cc=linux-mips@linux-mips.org \
--cc=macro@linux-mips.org \
--cc=ralf@linux-mips.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.