* [Qemu-devel] [Bug 1809546] [NEW] Writing a byte to a pl011 SFR overwrites the whole SFR
@ 2018-12-22 15:08 Daniels Umanovskis
2018-12-22 15:08 ` [Qemu-devel] [Bug 1809546] " Daniels Umanovskis
` (4 more replies)
0 siblings, 5 replies; 6+ messages in thread
From: Daniels Umanovskis @ 2018-12-22 15:08 UTC (permalink / raw)
To: qemu-devel
Public bug reported:
The bug is present in QEMU 2.8.1 and, if my analysis is correct, also on
master.
I first noticed that a PL011 UART driver, which is fine on real
hardware, fails to enable the RX interrupt in the IMSC register when
running in QEMU. However, the problem only comes up if the code is
compiled without optimizations. I think I've narrowed it down to a
minimal example that will exhibit the problem if run as a bare-metal
application.
Given:
pl011_addr: .word 0x10009000
The following snippet will be problematic:
ldr r3, pl011_addr
ldrb r2, [r3, #0x38] // IMSC
mov r2, #0
orr r2, r2, #0x10 // R2 == 0x10
strb r2, [r3, #0x38] // Whole word reads correctly after this
ldrb r2, [r3, #0x39]
mov r2, #0
strb r2, [r3, #0x39] // Problem here! Overwrites offset 0x38 as well
After the first strb instruction, which writes to 0x10009038, everything
is fine. It can be seen in the QEMU monitor:
(qemu) xp 0x10009038
0000000010009038: 0x00000010
After the second strb instruction, the write to 0x10009039 clears the
entire word:
(qemu) xp 0x10009038
0000000010009038: 0x00000000
QEMU command-line, using the vexpress-a9 which has the PL011 at
0x10009000:
qemu-system-arm -S -M vexpress-a9 -m 32M -no-reboot -nographic -monitor
telnet:127.0.0.1:1234,server,nowait -kernel pl011-sfr.bin -gdb tcp::2159
-serial mon:stdio
Compiling the original C code with optimizations makes the driver work.
It compiles down to assembly that only does a single write:
ldr r3, pl011_addr
mov r2, #0x10
str r2, [r3, #0x38]
Attached is the an assembly file, and linkscript, that shows the
problem, and also includes the working code.
I haven't debugged inside of QEMU itself but it seems to me that the
problem is in pl011_write in pl011.c - the functions looks at which
offset is being written, and then writes the entire SFR that offset
falls under, which means that changing a single byte will change the
whole SFR.
** Affects: qemu
Importance: Undecided
Status: New
** Attachment added: "startup.s"
https://bugs.launchpad.net/bugs/1809546/+attachment/5224336/+files/startup.s
--
You received this bug notification because you are a member of qemu-
devel-ml, which is subscribed to QEMU.
https://bugs.launchpad.net/bugs/1809546
Title:
Writing a byte to a pl011 SFR overwrites the whole SFR
Status in QEMU:
New
Bug description:
The bug is present in QEMU 2.8.1 and, if my analysis is correct, also
on master.
I first noticed that a PL011 UART driver, which is fine on real
hardware, fails to enable the RX interrupt in the IMSC register when
running in QEMU. However, the problem only comes up if the code is
compiled without optimizations. I think I've narrowed it down to a
minimal example that will exhibit the problem if run as a bare-metal
application.
Given:
pl011_addr: .word 0x10009000
The following snippet will be problematic:
ldr r3, pl011_addr
ldrb r2, [r3, #0x38] // IMSC
mov r2, #0
orr r2, r2, #0x10 // R2 == 0x10
strb r2, [r3, #0x38] // Whole word reads correctly after this
ldrb r2, [r3, #0x39]
mov r2, #0
strb r2, [r3, #0x39] // Problem here! Overwrites offset 0x38 as well
After the first strb instruction, which writes to 0x10009038,
everything is fine. It can be seen in the QEMU monitor:
(qemu) xp 0x10009038
0000000010009038: 0x00000010
After the second strb instruction, the write to 0x10009039 clears the
entire word:
(qemu) xp 0x10009038
0000000010009038: 0x00000000
QEMU command-line, using the vexpress-a9 which has the PL011 at
0x10009000:
qemu-system-arm -S -M vexpress-a9 -m 32M -no-reboot -nographic
-monitor telnet:127.0.0.1:1234,server,nowait -kernel pl011-sfr.bin
-gdb tcp::2159 -serial mon:stdio
Compiling the original C code with optimizations makes the driver
work. It compiles down to assembly that only does a single write:
ldr r3, pl011_addr
mov r2, #0x10
str r2, [r3, #0x38]
Attached is the an assembly file, and linkscript, that shows the
problem, and also includes the working code.
I haven't debugged inside of QEMU itself but it seems to me that the
problem is in pl011_write in pl011.c - the functions looks at which
offset is being written, and then writes the entire SFR that offset
falls under, which means that changing a single byte will change the
whole SFR.
To manage notifications about this bug go to:
https://bugs.launchpad.net/qemu/+bug/1809546/+subscriptions
^ permalink raw reply [flat|nested] 6+ messages in thread
* [Qemu-devel] [Bug 1809546] Re: Writing a byte to a pl011 SFR overwrites the whole SFR
2018-12-22 15:08 [Qemu-devel] [Bug 1809546] [NEW] Writing a byte to a pl011 SFR overwrites the whole SFR Daniels Umanovskis
@ 2018-12-22 15:08 ` Daniels Umanovskis
2019-01-04 14:32 ` Peter Maydell
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Daniels Umanovskis @ 2018-12-22 15:08 UTC (permalink / raw)
To: qemu-devel
Adding the link script.
** Attachment added: "linkscript.ld"
https://bugs.launchpad.net/qemu/+bug/1809546/+attachment/5224337/+files/linkscript.ld
--
You received this bug notification because you are a member of qemu-
devel-ml, which is subscribed to QEMU.
https://bugs.launchpad.net/bugs/1809546
Title:
Writing a byte to a pl011 SFR overwrites the whole SFR
Status in QEMU:
New
Bug description:
The bug is present in QEMU 2.8.1 and, if my analysis is correct, also
on master.
I first noticed that a PL011 UART driver, which is fine on real
hardware, fails to enable the RX interrupt in the IMSC register when
running in QEMU. However, the problem only comes up if the code is
compiled without optimizations. I think I've narrowed it down to a
minimal example that will exhibit the problem if run as a bare-metal
application.
Given:
pl011_addr: .word 0x10009000
The following snippet will be problematic:
ldr r3, pl011_addr
ldrb r2, [r3, #0x38] // IMSC
mov r2, #0
orr r2, r2, #0x10 // R2 == 0x10
strb r2, [r3, #0x38] // Whole word reads correctly after this
ldrb r2, [r3, #0x39]
mov r2, #0
strb r2, [r3, #0x39] // Problem here! Overwrites offset 0x38 as well
After the first strb instruction, which writes to 0x10009038,
everything is fine. It can be seen in the QEMU monitor:
(qemu) xp 0x10009038
0000000010009038: 0x00000010
After the second strb instruction, the write to 0x10009039 clears the
entire word:
(qemu) xp 0x10009038
0000000010009038: 0x00000000
QEMU command-line, using the vexpress-a9 which has the PL011 at
0x10009000:
qemu-system-arm -S -M vexpress-a9 -m 32M -no-reboot -nographic
-monitor telnet:127.0.0.1:1234,server,nowait -kernel pl011-sfr.bin
-gdb tcp::2159 -serial mon:stdio
Compiling the original C code with optimizations makes the driver
work. It compiles down to assembly that only does a single write:
ldr r3, pl011_addr
mov r2, #0x10
str r2, [r3, #0x38]
Attached is the an assembly file, and linkscript, that shows the
problem, and also includes the working code.
I haven't debugged inside of QEMU itself but it seems to me that the
problem is in pl011_write in pl011.c - the functions looks at which
offset is being written, and then writes the entire SFR that offset
falls under, which means that changing a single byte will change the
whole SFR.
To manage notifications about this bug go to:
https://bugs.launchpad.net/qemu/+bug/1809546/+subscriptions
^ permalink raw reply [flat|nested] 6+ messages in thread
* [Qemu-devel] [Bug 1809546] Re: Writing a byte to a pl011 SFR overwrites the whole SFR
2018-12-22 15:08 [Qemu-devel] [Bug 1809546] [NEW] Writing a byte to a pl011 SFR overwrites the whole SFR Daniels Umanovskis
2018-12-22 15:08 ` [Qemu-devel] [Bug 1809546] " Daniels Umanovskis
@ 2019-01-04 14:32 ` Peter Maydell
2019-01-04 16:29 ` Daniels Umanovskis
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Peter Maydell @ 2019-01-04 14:32 UTC (permalink / raw)
To: qemu-devel
Yes, our PL011 implementation assumes that you only ever access the
32-bit registers with full width 32-bit word reads and writes. Don't try
to do byte accesses to them. The PL011 data sheet doesn't specifically
say that partial-width accesses to registers are permitted, so I think
that trying to access offset 0x39 falls under the general note in
section 3.1 that attempting to access reserved or unused address
locations can result in unpredictable behaviour.
You need to make sure you write your C code in a manner which enforces
that accesses to device registers are done as single 32-bit accesses,
and the compiler does not silently break them down into multiple reads
and writes, or you will be in for a lot of pain trying to figure out
what is going on if the compiler ever does it with registers that are
write-to-clear or similar behaviour. Linux, for instance, does this by
having readl() and writel() functions that end up doing inline asm of
ldr/str instructions.
--
You received this bug notification because you are a member of qemu-
devel-ml, which is subscribed to QEMU.
https://bugs.launchpad.net/bugs/1809546
Title:
Writing a byte to a pl011 SFR overwrites the whole SFR
Status in QEMU:
New
Bug description:
The bug is present in QEMU 2.8.1 and, if my analysis is correct, also
on master.
I first noticed that a PL011 UART driver, which is fine on real
hardware, fails to enable the RX interrupt in the IMSC register when
running in QEMU. However, the problem only comes up if the code is
compiled without optimizations. I think I've narrowed it down to a
minimal example that will exhibit the problem if run as a bare-metal
application.
Given:
pl011_addr: .word 0x10009000
The following snippet will be problematic:
ldr r3, pl011_addr
ldrb r2, [r3, #0x38] // IMSC
mov r2, #0
orr r2, r2, #0x10 // R2 == 0x10
strb r2, [r3, #0x38] // Whole word reads correctly after this
ldrb r2, [r3, #0x39]
mov r2, #0
strb r2, [r3, #0x39] // Problem here! Overwrites offset 0x38 as well
After the first strb instruction, which writes to 0x10009038,
everything is fine. It can be seen in the QEMU monitor:
(qemu) xp 0x10009038
0000000010009038: 0x00000010
After the second strb instruction, the write to 0x10009039 clears the
entire word:
(qemu) xp 0x10009038
0000000010009038: 0x00000000
QEMU command-line, using the vexpress-a9 which has the PL011 at
0x10009000:
qemu-system-arm -S -M vexpress-a9 -m 32M -no-reboot -nographic
-monitor telnet:127.0.0.1:1234,server,nowait -kernel pl011-sfr.bin
-gdb tcp::2159 -serial mon:stdio
Compiling the original C code with optimizations makes the driver
work. It compiles down to assembly that only does a single write:
ldr r3, pl011_addr
mov r2, #0x10
str r2, [r3, #0x38]
Attached is the an assembly file, and linkscript, that shows the
problem, and also includes the working code.
I haven't debugged inside of QEMU itself but it seems to me that the
problem is in pl011_write in pl011.c - the functions looks at which
offset is being written, and then writes the entire SFR that offset
falls under, which means that changing a single byte will change the
whole SFR.
To manage notifications about this bug go to:
https://bugs.launchpad.net/qemu/+bug/1809546/+subscriptions
^ permalink raw reply [flat|nested] 6+ messages in thread
* [Qemu-devel] [Bug 1809546] Re: Writing a byte to a pl011 SFR overwrites the whole SFR
2018-12-22 15:08 [Qemu-devel] [Bug 1809546] [NEW] Writing a byte to a pl011 SFR overwrites the whole SFR Daniels Umanovskis
2018-12-22 15:08 ` [Qemu-devel] [Bug 1809546] " Daniels Umanovskis
2019-01-04 14:32 ` Peter Maydell
@ 2019-01-04 16:29 ` Daniels Umanovskis
2021-05-05 17:44 ` Thomas Huth
2021-07-05 4:17 ` Launchpad Bug Tracker
4 siblings, 0 replies; 6+ messages in thread
From: Daniels Umanovskis @ 2019-01-04 16:29 UTC (permalink / raw)
To: qemu-devel
Thanks for the response.
I don't think section 3.1 applies to 8-bit accesses. That is
specifically about reserved locations, and neither offset 0x38 nor 0x39
are reserved, so I think it's a matter of whether 32-bit access is
required or not.
>From what I usually see in ARM documentation, 32-bit access is
explicitly mentioned when required. For the PL011, it's mentioned for
the UARTPeriphID_n registers, for instance. In many other cases access
size depends on the implementation and the corresponding memory mapping
of that implementation.
I understand that *in practice* you should ensure single-access writes
unless doing otherwise is explicitly allowed. However, in cases like the
PL011 it seems ambiguous whether that is actually required, so it seems
like the best choice would be to explicitly document it for the QEMU
implementation. That would save some guesswork.
--
You received this bug notification because you are a member of qemu-
devel-ml, which is subscribed to QEMU.
https://bugs.launchpad.net/bugs/1809546
Title:
Writing a byte to a pl011 SFR overwrites the whole SFR
Status in QEMU:
New
Bug description:
The bug is present in QEMU 2.8.1 and, if my analysis is correct, also
on master.
I first noticed that a PL011 UART driver, which is fine on real
hardware, fails to enable the RX interrupt in the IMSC register when
running in QEMU. However, the problem only comes up if the code is
compiled without optimizations. I think I've narrowed it down to a
minimal example that will exhibit the problem if run as a bare-metal
application.
Given:
pl011_addr: .word 0x10009000
The following snippet will be problematic:
ldr r3, pl011_addr
ldrb r2, [r3, #0x38] // IMSC
mov r2, #0
orr r2, r2, #0x10 // R2 == 0x10
strb r2, [r3, #0x38] // Whole word reads correctly after this
ldrb r2, [r3, #0x39]
mov r2, #0
strb r2, [r3, #0x39] // Problem here! Overwrites offset 0x38 as well
After the first strb instruction, which writes to 0x10009038,
everything is fine. It can be seen in the QEMU monitor:
(qemu) xp 0x10009038
0000000010009038: 0x00000010
After the second strb instruction, the write to 0x10009039 clears the
entire word:
(qemu) xp 0x10009038
0000000010009038: 0x00000000
QEMU command-line, using the vexpress-a9 which has the PL011 at
0x10009000:
qemu-system-arm -S -M vexpress-a9 -m 32M -no-reboot -nographic
-monitor telnet:127.0.0.1:1234,server,nowait -kernel pl011-sfr.bin
-gdb tcp::2159 -serial mon:stdio
Compiling the original C code with optimizations makes the driver
work. It compiles down to assembly that only does a single write:
ldr r3, pl011_addr
mov r2, #0x10
str r2, [r3, #0x38]
Attached is the an assembly file, and linkscript, that shows the
problem, and also includes the working code.
I haven't debugged inside of QEMU itself but it seems to me that the
problem is in pl011_write in pl011.c - the functions looks at which
offset is being written, and then writes the entire SFR that offset
falls under, which means that changing a single byte will change the
whole SFR.
To manage notifications about this bug go to:
https://bugs.launchpad.net/qemu/+bug/1809546/+subscriptions
^ permalink raw reply [flat|nested] 6+ messages in thread
* [Bug 1809546] Re: Writing a byte to a pl011 SFR overwrites the whole SFR
2018-12-22 15:08 [Qemu-devel] [Bug 1809546] [NEW] Writing a byte to a pl011 SFR overwrites the whole SFR Daniels Umanovskis
` (2 preceding siblings ...)
2019-01-04 16:29 ` Daniels Umanovskis
@ 2021-05-05 17:44 ` Thomas Huth
2021-07-05 4:17 ` Launchpad Bug Tracker
4 siblings, 0 replies; 6+ messages in thread
From: Thomas Huth @ 2021-05-05 17:44 UTC (permalink / raw)
To: qemu-devel
The QEMU project is currently considering to move its bug tracking to
another system. For this we need to know which bugs are still valid
and which could be closed already. Thus we are setting older bugs to
"Incomplete" now.
If you still think this bug report here is valid, then please switch
the state back to "New" within the next 60 days, otherwise this report
will be marked as "Expired". Or please mark it as "Fix Released" if
the problem has been solved with a newer version of QEMU already.
Thank you and sorry for the inconvenience.
** Changed in: qemu
Status: New => Incomplete
--
You received this bug notification because you are a member of qemu-
devel-ml, which is subscribed to QEMU.
https://bugs.launchpad.net/bugs/1809546
Title:
Writing a byte to a pl011 SFR overwrites the whole SFR
Status in QEMU:
Incomplete
Bug description:
The bug is present in QEMU 2.8.1 and, if my analysis is correct, also
on master.
I first noticed that a PL011 UART driver, which is fine on real
hardware, fails to enable the RX interrupt in the IMSC register when
running in QEMU. However, the problem only comes up if the code is
compiled without optimizations. I think I've narrowed it down to a
minimal example that will exhibit the problem if run as a bare-metal
application.
Given:
pl011_addr: .word 0x10009000
The following snippet will be problematic:
ldr r3, pl011_addr
ldrb r2, [r3, #0x38] // IMSC
mov r2, #0
orr r2, r2, #0x10 // R2 == 0x10
strb r2, [r3, #0x38] // Whole word reads correctly after this
ldrb r2, [r3, #0x39]
mov r2, #0
strb r2, [r3, #0x39] // Problem here! Overwrites offset 0x38 as well
After the first strb instruction, which writes to 0x10009038,
everything is fine. It can be seen in the QEMU monitor:
(qemu) xp 0x10009038
0000000010009038: 0x00000010
After the second strb instruction, the write to 0x10009039 clears the
entire word:
(qemu) xp 0x10009038
0000000010009038: 0x00000000
QEMU command-line, using the vexpress-a9 which has the PL011 at
0x10009000:
qemu-system-arm -S -M vexpress-a9 -m 32M -no-reboot -nographic
-monitor telnet:127.0.0.1:1234,server,nowait -kernel pl011-sfr.bin
-gdb tcp::2159 -serial mon:stdio
Compiling the original C code with optimizations makes the driver
work. It compiles down to assembly that only does a single write:
ldr r3, pl011_addr
mov r2, #0x10
str r2, [r3, #0x38]
Attached is the an assembly file, and linkscript, that shows the
problem, and also includes the working code.
I haven't debugged inside of QEMU itself but it seems to me that the
problem is in pl011_write in pl011.c - the functions looks at which
offset is being written, and then writes the entire SFR that offset
falls under, which means that changing a single byte will change the
whole SFR.
To manage notifications about this bug go to:
https://bugs.launchpad.net/qemu/+bug/1809546/+subscriptions
^ permalink raw reply [flat|nested] 6+ messages in thread
* [Bug 1809546] Re: Writing a byte to a pl011 SFR overwrites the whole SFR
2018-12-22 15:08 [Qemu-devel] [Bug 1809546] [NEW] Writing a byte to a pl011 SFR overwrites the whole SFR Daniels Umanovskis
` (3 preceding siblings ...)
2021-05-05 17:44 ` Thomas Huth
@ 2021-07-05 4:17 ` Launchpad Bug Tracker
4 siblings, 0 replies; 6+ messages in thread
From: Launchpad Bug Tracker @ 2021-07-05 4:17 UTC (permalink / raw)
To: qemu-devel
[Expired for QEMU because there has been no activity for 60 days.]
** Changed in: qemu
Status: Incomplete => Expired
--
You received this bug notification because you are a member of qemu-
devel-ml, which is subscribed to QEMU.
https://bugs.launchpad.net/bugs/1809546
Title:
Writing a byte to a pl011 SFR overwrites the whole SFR
Status in QEMU:
Expired
Bug description:
The bug is present in QEMU 2.8.1 and, if my analysis is correct, also
on master.
I first noticed that a PL011 UART driver, which is fine on real
hardware, fails to enable the RX interrupt in the IMSC register when
running in QEMU. However, the problem only comes up if the code is
compiled without optimizations. I think I've narrowed it down to a
minimal example that will exhibit the problem if run as a bare-metal
application.
Given:
pl011_addr: .word 0x10009000
The following snippet will be problematic:
ldr r3, pl011_addr
ldrb r2, [r3, #0x38] // IMSC
mov r2, #0
orr r2, r2, #0x10 // R2 == 0x10
strb r2, [r3, #0x38] // Whole word reads correctly after this
ldrb r2, [r3, #0x39]
mov r2, #0
strb r2, [r3, #0x39] // Problem here! Overwrites offset 0x38 as well
After the first strb instruction, which writes to 0x10009038,
everything is fine. It can be seen in the QEMU monitor:
(qemu) xp 0x10009038
0000000010009038: 0x00000010
After the second strb instruction, the write to 0x10009039 clears the
entire word:
(qemu) xp 0x10009038
0000000010009038: 0x00000000
QEMU command-line, using the vexpress-a9 which has the PL011 at
0x10009000:
qemu-system-arm -S -M vexpress-a9 -m 32M -no-reboot -nographic
-monitor telnet:127.0.0.1:1234,server,nowait -kernel pl011-sfr.bin
-gdb tcp::2159 -serial mon:stdio
Compiling the original C code with optimizations makes the driver
work. It compiles down to assembly that only does a single write:
ldr r3, pl011_addr
mov r2, #0x10
str r2, [r3, #0x38]
Attached is the an assembly file, and linkscript, that shows the
problem, and also includes the working code.
I haven't debugged inside of QEMU itself but it seems to me that the
problem is in pl011_write in pl011.c - the functions looks at which
offset is being written, and then writes the entire SFR that offset
falls under, which means that changing a single byte will change the
whole SFR.
To manage notifications about this bug go to:
https://bugs.launchpad.net/qemu/+bug/1809546/+subscriptions
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2021-07-05 4:32 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-12-22 15:08 [Qemu-devel] [Bug 1809546] [NEW] Writing a byte to a pl011 SFR overwrites the whole SFR Daniels Umanovskis
2018-12-22 15:08 ` [Qemu-devel] [Bug 1809546] " Daniels Umanovskis
2019-01-04 14:32 ` Peter Maydell
2019-01-04 16:29 ` Daniels Umanovskis
2021-05-05 17:44 ` Thomas Huth
2021-07-05 4:17 ` Launchpad Bug Tracker
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.