On Wed, Jan 8, 2025 at 12:28 PM Sam Price <thesampr...@gmail.com> wrote:
I made the changes, and added documentation.
https://gitlab.com/thesamprice/qemu/-/compare/master...loader?from_project_id=11167699
I left it as [PREFIX]<RegNumber>
I can switch this to just RegNumber if desired.
I am still struggling with the email format sorry.
---
docs/system/generic-loader.rst | 98 ++++++++++++++++++++++++++++++++
hw/core/generic-loader.c | 46 +++++++++++----
include/hw/core/generic-loader.h | 7 +++
3 files changed, 139 insertions(+), 12 deletions(-)
diff --git a/docs/system/generic-loader.rst b/docs/system/generic-loader.rst
index 4f9fb005f1..71d4aaa097 100644
--- a/docs/system/generic-loader.rst
+++ b/docs/system/generic-loader.rst
@@ -117,4 +117,102 @@ future the internal state 'set_pc' (which exists
in the generic loader
now) should be exposed to the user so that they can choose if the PC
is set or not.
+Loading Data into Registers
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The `loader` device allows the initialization of CPU registers from the command
+line. This feature is particularly useful for setting up the processor state
+before starting an executable. By configuring registers prior to execution, the
+`loader` can mimic the state that a bootloader would leave the processor in
+before transferring control to an ELF file or another executable.
This isn't really true though. A bootloader generally will set more
than the GP registers. A boot loader will configure devices and
perhaps initalise memory.
+
+The syntax for loading data into registers is as follows::
+
+ -device loader,reg=<reg>,data=<data>,data-len=<data-len>
+
+**Parameters:**
+
+``<reg>``
+ The target register to set. Format must pass the following regex
+ ``[a-zA-Z]+[0-9]+``. The numeric part corresponds to the processor's GDB \
+ register index. For general-purpose registers, this is typically the
+ number in the register's name (e.g., ``r5`` translates to ``5``).
+ Special-purpose registers have specific IDs defined in their processor's
+ `gdbstub.c` file. Note that these IDs vary between processors.
+
+``<data>``
+ The value to load into the specified register. The data must not exceed 8
+ bytes in size.
Why 8 bytes?
+
+``<data-len>``
+ The length of the data in bytes. This parameter is mandatory when using
+ the ``data`` argument.
Do we need data-len? Why not just use the register size
+
+**Examples:**
+
+Set a general-purpose register
+""""""""""""""""""""""""""""""
+
+To set register ``r5`` to ``0xc0001000`` (4 bytes) on CPU 0::
+
+ -device loader,reg=r5,data=0xc0001000,data-len=4
+
+Set a special register
+""""""""""""""""""""""
+
+To set the Program Counter (PC, register ``32``) to ``0x80000000`` on CPU 0::
+
+ -device loader,reg=pc32,data=0x80000000,data-len=4
+
+You must look in your processor's `gdbstub.c` file to special register to index
+mappings.
That isn't really helpful for users, but I don't have a better idea
+
+**Special Registers:**
+
+Special registers are defined in the processor's ``gdbstub.c`` file
with numeric IDs.
+Examples from the MicroBlaze processor at one point looked like. include::
+
+ enum {
+ GDB_PC = 32 + 0,
+ GDB_MSR = 32 + 1,
+ GDB_EAR = 32 + 2,
+ GDB_ESR = 32 + 3,
+ GDB_FSR = 32 + 4,
+ GDB_BTR = 32 + 5,
+ GDB_PVR0 = 32 + 6,
+ GDB_PVR11 = 32 + 17,
+ GDB_EDR = 32 + 18,
+ GDB_SLR = 32 + 25,
+ GDB_SHR = 32 + 26,
+ };
+
+For example, to set the Machine State Register (``GDB_MSR``) on a MicroBlaze
+processor::
+
+ -device loader,reg=MSR33,data=0x00000001,data-len=4
+
+**Register Loading Notes:**
+
+1. **Processor-Specific IDs**:
+ The numeric IDs for registers vary between processors. Always refer to the
+ `gdbstub.c` file for the target processor to identify the correct register
+ mappings.
+
+2. **Pre-Execution State**:
+ This capability is ideal for initializing a simulated environment to match
+ the state expected by an ELF file. For example, you can configure stack
+ pointers, machine state registers, and program counters to prepare the
+ processor to run a bootstrapped application.
+
+3. **Validation**:
+ Register numbers are validated by the `gdb_write_register` function. Ensure
+ the specified register is supported by the target architecture.
+
+4. **Endianess**:
+ The `data` value is written using the processor's native endian format.
+
+By using the `loader` device to initialize registers, you can simulate
+realistic execution environments, enabling detailed testing and debugging
+of embedded software, including bootloaders interactions and operating
+system kernels.
diff --git a/hw/core/generic-loader.c b/hw/core/generic-loader.c
index ea8628b892..9408ecd150 100644
--- a/hw/core/generic-loader.c
+++ b/hw/core/generic-loader.c
@@ -55,6 +55,14 @@ static void generic_loader_reset(void *opaque)
}
}
+ if(s->reg.name) {
+ CPUClass *cc = CPU_GET_CLASS(s->cpu);
+ int bytes_written = cc->gdb_write_register(s->cpu, (uint8_t*)
&s->reg.value, s->reg.num);
+ if(bytes_written != s->reg.data_len) {
+ printf("Error setting register %d to value %lX expected to write %d,
but wrote %d\n", s->reg.num, s->reg.value, s->reg.data_len,
bytes_written);
The line wrapping is muddled up here. Can you please send it with git
send-email. Do some sends against yourself to make sure it works.
You mentioned gmail in an earlier thread I think, did you follow the
instructions:
https://git-scm.com/docs/git-send-email#_use_gmail_as_the_smtp_server
Alistair