qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] RFC: Why does target/m68k RTE insn. use gen_exception


From: Lucien Murray-Pitts
Subject: Re: [Qemu-devel] RFC: Why does target/m68k RTE insn. use gen_exception
Date: Sun, 30 Jun 2019 01:36:21 +0900
User-agent: Mutt/1.12.0 (2019-05-25)

On Sat, Jun 29, 2019 at 12:15:44PM +0200, Richard Henderson wrote:
> On 6/28/19 5:50 PM, Lucien Murray-Pitts wrote:
> >  op_helper.c
> >    static void m68k_interrupt_all(CPUM68KState *env, int is_hw)
> >    ...
> >      if (cs->exception_index == EXCP_ACCESS) {
> >       ...
> >       do_stack_frame(env, &sp, 7, oldsr, 0, retaddr /*LMP: BROKEN - needs 
> > PC NEXT*/);
> > 
> > Actually according to the MC68000 manuals the "return address" (the PC 
> > saved on
> > the stack) can be upto 5 instructions later due to prefetch. So some pc_next
> > would best be used here.
> 
> The way I read it from the 68040 manual, it's "the pc of the instruction
> executing at the time the fault was detected".  Well, we did in fact detect 
> the
> fault at "retaddr", so that seems to be the right answer.  The fact that real
> hardware has a different pipeline and detects the fault later seems 
> immaterial,
> and largely irrelevant, since the programmer wasn't given any guarantees for
> what sort of value appears in that slot.
> 

I was reading the 68000/68020, and based on your suggestion now the 68060 manual
The 68000 is pretty rough, but I agree you could expect it to more likely be the
next or even upto 5 or so instructions away.

MC68000UM.pdf, 5.4.1 Bus Error Operation
  ....the following information is placed on the supervisor stack:
    1. Status register
    2. Program counter (two words, which may be up to five words past the
       instruction being executed)
....
MC68000UM.pdf, 6.3.9.1 BUS ERROR.
  ...value saved for the program counter is advanced 2–10 bytes beyond the
  address of the first word of the instruction that made the reference causing
  the bus error. If the bus error occurred during the fetch of the next
  instruction, the saved program counter has a value in the vicinity of the
  current instruction, even if the current instruction is a branch, a jump, or
  a return instruction ...

MC68020UM.pdf, 6.1.2 Bus Error Exception
  The saved PC value is the logical address of the instruction that was
  executing at the time the fault was detected. This is not necessarily the
  instruction that initiated the bus cycle since the processor overlaps
  execution of instructions
  (See 6.4 Bus Fault REcovery and 6.3.11 Return From Exception)
  
MC68060UM.pdf, 8.4.4.1 Program Counter (PC).
On read access faults, the PC points to the instruction that caused the
access error. This instruction is restarted when an RTE is executed, hence,
the read cycle is re-executed. On read access errors on the second or later
of misaligned reads, the read cycles that are successful prior to the access
error are re-executed since the processor uses a restart model for recovery
from exceptions.

So it would seem the m68k was rather rough, but with the introduction
of MMUs the 68010 and beyond handle it differently.  68010/20 have
pipeline stage retries, and 68060 just returns to retry the instruction.

In my case I think the original firmware expects to return after the
faulting instruction, and the retry of the bus io is to be ignored
(this is a memory map probe routine).

So I think it would take significant work to fake the pipeline retry
in the RTE instruction - so I will hack somethign into the memory region
so it passes the second time the instruciton is exected.

What are your thoughts?


> > I am triggering this from inside my device by doing the following, since 
> > that memory address
> > should dynamically cause a bus error (I hope this is the right way to do it)
> >    cpuclass->do_unassigned_access( s->cpu, /*addr*/0x0, /*is_write*/1, 
> > /*is_exec*/0, opaque, /*size*/4);
> 
> 
> For a device to raise a bus error, it should return MEMTX_ERROR (or 
> something).
>  This eventually reaches cpu_transaction_failed, which has all of the data 
> that
> you seem to be missing above.
> 

I was originally using this but it wasnt doing anything, now that you recommend 
it I see why -
thank you for your help.

qemu/accel/tcg/cputlb.c
   ...
   r = memory_region_dispatch_read(mr, mr_offset,
                                    &val, size, iotlbentry->attrs);
    if (r != MEMTX_OK) {
        hwaddr physaddr = mr_offset +
            section->offset_within_address_space -
            section->offset_within_region;

        cpu_transaction_failed(cpu, physaddr, addr, size, access_type,
                               mmu_idx, iotlbentry->attrs, r, retaddr);
    }
    ...

As you say this call directly flows through to CPUClass->transaction_failed
( as found in the struct for CPUClass in qemu/include/qom/cpu.h )

However for the m68k the do_transaction_failed function pointer field
has not been implemented.

I implemented it in a rudamentary fashion copying from already existing
m68k_cpu_unassigned_access.  I really dont know if this is the right way.

  void m68k_cpu_transaction_failed(CPUState *cs, hwaddr physaddr, vaddr addr,
                                  unsigned size, MMUAccessType access_type,
                                  int mmu_idx, MemTxAttrs attrs,
                                  MemTxResult response, uintptr_t retaddr)
  {
      cs->exception_index = EXCP_ACCESS;
      cpu_loop_exit(cs);
  }

Then I reverted my device to the "mem with attributes" io with a return of
MEMTX_ERROR and found that the behavior during single-step were the same as
before.

I end up ISR+1 instruction stepped in.

I will have to dig more.  See some other peoples implementation and methods.

If you have time I would appreciate your input, I am still very hazy on how
the complete interaction, sepcially with gdb happens.

Cheers,
Luc








reply via email to

[Prev in Thread] Current Thread [Next in Thread]