Cc'ing Alex/Pierrick

On 31/1/25 01:27, Alistair Francis wrote:
On Fri, Jan 10, 2025 at 3:33 PM Sam Price <thesampr...@gmail.com> wrote:

Yes that is true a boot loader will do more than just set registers.
Ill rework the text a bit on the next update.
In my case i need to set the r5 register that specifies the memory
location to the device tree.

Should that be done in the machine instead? It seems tricky to expect
users to set this register

I also use the device loader to load in a elf file to ram, and the
device-loader to load in the device tree to the location specified by
the r5 register

I could add a gdb call that would return an array of string mappings
to integers.
If the machine doesn't implement the function/  leaves it as null
pointer then you wouldn't get the cli support.
Not sure where you would document all the machine register names /
numbers at though.
This might be too much though?

We probably don't need to document the register names

Alistair

I left the door somewhat open on this via the NAME_NUMBER format.

There was some checking logic where if data is supplied then it forces
a check for data-len.
I could relax that check if you supply the reg.name field.

I am unsure how to determine the machine register size.
I assumed the max register size on any machine would be 8 bytes, this
might be wrong.
the gdb call seems to just pass in the full 8 bytes, but I didn't dig
into it for all machines.

Ill look at this a bit more and try to configure the git email.
I also need to set up a docker container to build /test latest.
I have been building / testing on an old ubuntu machine.
(To test this I need to run it on qemu-xilinx).
My workplace has us on ubuntu 20.

So it might be a while before I have another version up.

Thanks,
Sam

On Thu, Jan 9, 2025 at 7:34 PM Alistair Francis <alistai...@gmail.com> wrote:

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



--
Sincerely,

Sam Price



Reply via email to