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