enum riscv_priv_spec_class class;
unsigned major, minor, revision;
obj_attribute *attr;
- size_t buf_size;
- char *buf;
/* Find the corresponding priv spec class. */
if (riscv_get_priv_spec_class (s, &class))
minor = (unsigned) attr[Tag_RISCV_priv_spec_minor].i;
revision = (unsigned) attr[Tag_RISCV_priv_spec_revision].i;
- /* The priv attributes setting 0.0.0 is meaningless. We should have set
- the default_priv_spec by md_parse_option and riscv_after_parse_args,
- so just skip the following setting. */
- if (major == 0 && minor == 0 && revision == 0)
- return 1;
-
- buf_size = riscv_estimate_digit (major)
- + 1 /* '.' */
- + riscv_estimate_digit (minor)
- + 1; /* string terminator */
- if (revision != 0)
+ if (riscv_get_priv_spec_class_from_numbers (major,
+ minor,
+ revision,
+ &class))
{
- buf_size += 1 /* '.' */
- + riscv_estimate_digit (revision);
- buf = xmalloc (buf_size);
- snprintf (buf, buf_size, "%d.%d.%d", major, minor, revision);
- }
- else
- {
- buf = xmalloc (buf_size);
- snprintf (buf, buf_size, "%d.%d", major, minor);
- }
+ /* The priv attributes setting 0.0.0 is meaningless. We should have set
+ the default_priv_spec by md_parse_option and riscv_after_parse_args,
+ so just skip the following setting. */
+ if (class == PRIV_SPEC_CLASS_NONE)
+ return 1;
- if (riscv_get_priv_spec_class (buf, &class))
- {
default_priv_spec = class;
- free (buf);
return 1;
}
/* Still can not find the priv spec class. */
- as_bad (_("Unknown default privilege spec `%d.%d.%d' set by "
+ as_bad (_("Unknown default privilege spec `%d.%d.%d' set by "
"privilege attributes"), major, minor, revision);
- free (buf);
return 0;
}
/* Indicate ELF attributes are explictly set. */
static bfd_boolean explicit_attr = FALSE;
-/* Indicate CSR are explictly used. */
-static bfd_boolean explicit_csr = FALSE;
+/* Indicate CSR or priv instructions are explictly used. */
+static bfd_boolean explicit_priv_attr = FALSE;
/* Macros for encoding relaxation state for RVC branches and far jumps. */
#define RELAX_BRANCH_ENCODE(uncond, rvc, length) \
pre_entry->next = entry;
}
-/* Check wether the CSR is valid according to the ISA. */
+/* Return the suitable CSR address after checking the ISA dependency and
+ priv spec versions. */
-static void
-riscv_csr_class_check (const char *s,
- enum riscv_csr_class csr_class)
+static unsigned int
+riscv_csr_address (const char *csr_name,
+ struct riscv_csr_extra *entry)
{
+ struct riscv_csr_extra *saved_entry = entry;
+ enum riscv_csr_class csr_class = entry->csr_class;
+ bfd_boolean need_check_version = TRUE;
bfd_boolean result = TRUE;
- /* Don't check the ISA dependency when -mcsr-check isn't set. */
- if (!riscv_opts.csr_check)
- return;
-
switch (csr_class)
{
case CSR_CLASS_I:
result = riscv_subset_supports ("i");
break;
+ case CSR_CLASS_I_32:
+ result = (xlen == 32 && riscv_subset_supports ("i"));
+ break;
case CSR_CLASS_F:
result = riscv_subset_supports ("f");
+ need_check_version = FALSE;
break;
- case CSR_CLASS_I_32:
- result = (xlen == 32 && riscv_subset_supports ("i"));
+ case CSR_CLASS_DEBUG:
+ need_check_version = FALSE;
break;
default:
as_bad (_("internal: bad RISC-V CSR class (0x%x)"), csr_class);
}
- if (!result)
- as_warn (_("Invalid CSR `%s' for the current ISA"), s);
-}
-
-/* Check and find the CSR address according to the privilege spec version. */
-
-static void
-riscv_csr_version_check (const char *csr_name,
- struct riscv_csr_extra **entryP)
-{
- struct riscv_csr_extra *entry = *entryP;
+ /* Don't report the ISA conflict when -mcsr-check isn't set. */
+ if (riscv_opts.csr_check && !result)
+ as_warn (_("Invalid CSR `%s' for the current ISA"), csr_name);
while (entry != NULL)
{
- if (default_priv_spec >= entry->define_version
- && default_priv_spec < entry->abort_version)
+ if (!need_check_version
+ || (default_priv_spec >= entry->define_version
+ && default_priv_spec < entry->abort_version))
{
/* Find the suitable CSR according to the specific version. */
- *entryP = entry;
- return;
+ return entry->address;
}
entry = entry->next;
}
as_warn (_("Invalid CSR `%s' for the privilege spec `%s'"),
csr_name, priv_name);
}
+
+ return saved_entry->address;
}
/* Once the CSR is defined, including the old privilege spec, then we call
will regard it as a "Unknown CSR" and report error. If user use number
to set the CSR, but over the range (> 0xfff), then assembler will report
"Improper CSR" error for it. */
- riscv_csr_class_check (s, r->csr_class);
- riscv_csr_version_check (s, &r);
-
- return r->address;
+ return riscv_csr_address (s, r);
}
static unsigned int
return TRUE;
}
+/* Return True if it is a privileged instruction. Otherwise, return FALSE.
+
+ uret is actually a N-ext instruction. So it is better to regard it as
+ an user instruction rather than the priv instruction.
+
+ hret is used to return from traps in H-mode. H-mode is removed since
+ the v1.10 priv spec, but probably be added in the new hypervisor spec.
+ Therefore, hret should be controlled by the hypervisor spec rather than
+ priv spec in the future.
+
+ dret is defined in the debug spec, so it should be checked in the future,
+ too. */
+
+static bfd_boolean
+riscv_is_priv_insn (insn_t insn)
+{
+ return (((insn ^ MATCH_SRET) & MASK_SRET) == 0
+ || ((insn ^ MATCH_MRET) & MASK_MRET) == 0
+ || ((insn ^ MATCH_SFENCE_VMA) & MASK_SFENCE_VMA) == 0
+ || ((insn ^ MATCH_WFI) & MASK_WFI) == 0
+ /* The sfence.vm is dropped in the v1.10 priv specs, but we still need to
+ check it here to keep the compatible. Maybe we should issue warning
+ if sfence.vm is used, but the priv spec newer than v1.10 is chosen.
+ We already have a similar check for CSR, but not yet for instructions.
+ It would be good if we could check the spec versions both for CSR and
+ instructions, but not here. */
+ || ((insn ^ MATCH_SFENCE_VM) & MASK_SFENCE_VM) == 0);
+}
+
/* This routine assembles an instruction into its binary format. As a
side effect, it sets the global variable imm_reloc to the type of
relocation to do if one of the operands is an address expression. */
&& !riscv_opts.rvc)
break;
+ if (riscv_is_priv_insn (ip->insn_opcode))
+ explicit_priv_attr = TRUE;
+
/* Check if we write a read-only CSR by the CSR
instruction. */
if (insn_with_csr
case 'E': /* Control register. */
insn_with_csr = TRUE;
- explicit_csr = TRUE;
+ explicit_priv_attr = TRUE;
if (reg_lookup (&s, RCLASS_CSR, ®no))
INSERT_OPERAND (CSR, *ip, regno);
else
&& !riscv_set_default_priv_spec (NULL))
return;
- /* If we already have set elf priv attributes, then generate them.
- Otherwise, don't generate them when no CSR are used. */
- if (!explicit_csr)
+ /* If we already have set elf priv attributes, then no need to do anything,
+ assembler will generate them according to what you set. Otherwise, don't
+ generate or update them when no CSR and priv instructions are used.
+ Generate the priv attributes according to default_priv_spec, which can be
+ set by -mpriv-spec and --with-priv-spec, and be updated by the original
+ priv attribute sets. */
+ if (!explicit_priv_attr)
return;
/* Re-write priv attributes by default_priv_spec. */