!133 fix CVE-2020-12829 CVE-2020-15863 and CVE-2020-16092

From: @yorifang
Reviewed-by: @zhanghailiang_lucky
Signed-off-by: @zhanghailiang_lucky
This commit is contained in:
openeuler-ci-bot 2020-09-28 21:08:39 +08:00 committed by Gitee
commit d6857d428f
8 changed files with 806 additions and 1 deletions

View File

@ -0,0 +1,40 @@
From 596e7e8908b742f727d02ec9ab747116573f67e0 Mon Sep 17 00:00:00 2001
From: Mauro Matteo Cascella <mcascell@redhat.com>
Date: Sat, 1 Aug 2020 18:42:38 +0200
Subject: [PATCH] hw/net/net_tx_pkt: fix assertion failure in
net_tx_pkt_add_raw_fragment()
An assertion failure issue was found in the code that processes network packets
while adding data fragments into the packet context. It could be abused by a
malicious guest to abort the QEMU process on the host. This patch replaces the
affected assert() with a conditional statement, returning false if the current
data fragment exceeds max_raw_frags.
Reported-by: Alexander Bulekov <alxndr@bu.edu>
Reported-by: Ziming Zhang <ezrakiez@gmail.com>
Reviewed-by: Dmitry Fleytman <dmitry.fleytman@gmail.com>
Signed-off-by: Mauro Matteo Cascella <mcascell@redhat.com>
Signed-off-by: Jason Wang <jasowang@redhat.com>
---
hw/net/net_tx_pkt.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/hw/net/net_tx_pkt.c b/hw/net/net_tx_pkt.c
index 162f802dd7..54d4c3bbd0 100644
--- a/hw/net/net_tx_pkt.c
+++ b/hw/net/net_tx_pkt.c
@@ -379,7 +379,10 @@ bool net_tx_pkt_add_raw_fragment(struct NetTxPkt *pkt, hwaddr pa,
hwaddr mapped_len = 0;
struct iovec *ventry;
assert(pkt);
- assert(pkt->max_raw_frags > pkt->raw_frags);
+
+ if (pkt->raw_frags >= pkt->max_raw_frags) {
+ return false;
+ }
if (!len) {
return true;
--
2.23.0

View File

@ -0,0 +1,58 @@
From 2d18434c1ca66d68f80954be6828a3770176dab4 Mon Sep 17 00:00:00 2001
From: Mauro Matteo Cascella <mcascell@redhat.com>
Date: Fri, 10 Jul 2020 11:19:41 +0200
Subject: [PATCH] hw/net/xgmac: Fix buffer overflow in xgmac_enet_send()
A buffer overflow issue was reported by Mr. Ziming Zhang, CC'd here. It
occurs while sending an Ethernet frame due to missing break statements
and improper checking of the buffer size.
Reported-by: Ziming Zhang <ezrakiez@gmail.com>
Signed-off-by: Mauro Matteo Cascella <mcascell@redhat.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Jason Wang <jasowang@redhat.com>
---
hw/net/xgmac.c | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/hw/net/xgmac.c b/hw/net/xgmac.c
index f49df95b07..f496f7ed4c 100644
--- a/hw/net/xgmac.c
+++ b/hw/net/xgmac.c
@@ -217,21 +217,31 @@ static void xgmac_enet_send(XgmacState *s)
}
len = (bd.buffer1_size & 0xfff) + (bd.buffer2_size & 0xfff);
+ /*
+ * FIXME: these cases of malformed tx descriptors (bad sizes)
+ * should probably be reported back to the guest somehow
+ * rather than simply silently stopping processing, but we
+ * don't know what the hardware does in this situation.
+ * This will only happen for buggy guests anyway.
+ */
if ((bd.buffer1_size & 0xfff) > 2048) {
DEBUGF_BRK("qemu:%s:ERROR...ERROR...ERROR... -- "
"xgmac buffer 1 len on send > 2048 (0x%x)\n",
__func__, bd.buffer1_size & 0xfff);
+ break;
}
if ((bd.buffer2_size & 0xfff) != 0) {
DEBUGF_BRK("qemu:%s:ERROR...ERROR...ERROR... -- "
"xgmac buffer 2 len on send != 0 (0x%x)\n",
__func__, bd.buffer2_size & 0xfff);
+ break;
}
- if (len >= sizeof(frame)) {
+ if (frame_size + len >= sizeof(frame)) {
DEBUGF_BRK("qemu:%s: buffer overflow %d read into %zu "
- "buffer\n" , __func__, len, sizeof(frame));
+ "buffer\n" , __func__, frame_size + len, sizeof(frame));
DEBUGF_BRK("qemu:%s: buffer1.size=%d; buffer2.size=%d\n",
__func__, bd.buffer1_size, bd.buffer2_size);
+ break;
}
cpu_physical_memory_read(bd.buffer1_addr, ptr, len);
--
2.23.0

View File

@ -1,6 +1,6 @@
Name: qemu Name: qemu
Version: 4.1.0 Version: 4.1.0
Release: 25 Release: 26
Epoch: 2 Epoch: 2
Summary: QEMU is a generic and open source machine emulator and virtualizer Summary: QEMU is a generic and open source machine emulator and virtualizer
License: GPLv2 and BSD and MIT and CC-BY License: GPLv2 and BSD and MIT and CC-BY
@ -231,6 +231,13 @@ Patch0218: target-arm-ignore-evtstrm-and-cpuid-CPU-features.patch
Patch0219: Drop-bogus-IPv6-messages.patch Patch0219: Drop-bogus-IPv6-messages.patch
Patch0220: hw-sd-sdhci-Fix-DMA-Transfer-Block-Size-field.patch Patch0220: hw-sd-sdhci-Fix-DMA-Transfer-Block-Size-field.patch
Patch0221: hw-xhci-check-return-value-of-usb_packet_map.patch Patch0221: hw-xhci-check-return-value-of-usb_packet_map.patch
Patch0222: hw-net-xgmac-Fix-buffer-overflow-in-xgmac_enet_send.patch
Patch0223: hw-net-net_tx_pkt-fix-assertion-failure-in-net_tx_pk.patch
Patch0224: sm501-Convert-printf-abort-to-qemu_log_mask.patch
Patch0225: sm501-Shorten-long-variable-names-in-sm501_2d_operat.patch
Patch0226: sm501-Use-BIT-x-macro-to-shorten-constant.patch
Patch0227: sm501-Clean-up-local-variables-in-sm501_2d_operation.patch
Patch0228: sm501-Replace-hand-written-implementation-with-pixma.patch
BuildRequires: flex BuildRequires: flex
BuildRequires: bison BuildRequires: bison
@ -577,6 +584,15 @@ getent passwd qemu >/dev/null || \
%endif %endif
%changelog %changelog
* Mon Sep 28 2020 Huawei Technologies Co., Ltd <fangying1@huawei.com>
- sm501: Replace hand written implementation with pixman where possible
- sm501: Clean up local variables in sm501_2d_operation
- sm501: Use BIT(x) macro to shorten constant
- sm501: Shorten long variable names in sm501_2d_operation
- sm501: Convert printf + abort to qemu_log_mask
- hw/net/net_tx_pkt: fix assertion failure in net_tx_pkt_add_raw_fragment
- hw/net/xgmac: Fix buffer overflow in xgmac_enet_send()
* Fri Sep 18 2020 Huawei Technologies Co., Ltd <lijiajie11@huawei.com> * Fri Sep 18 2020 Huawei Technologies Co., Ltd <lijiajie11@huawei.com>
- hw-sd-sdhci-Fix-DMA-Transfer-Block-Size-field.patch - hw-sd-sdhci-Fix-DMA-Transfer-Block-Size-field.patch
- hw-xhci-check-return-value-of-usb_packet_map.patch - hw-xhci-check-return-value-of-usb_packet_map.patch

View File

@ -0,0 +1,95 @@
From 6186d3de416825e3a737dd3da31da475f50d66d0 Mon Sep 17 00:00:00 2001
From: BALATON Zoltan <balaton@eik.bme.hu>
Date: Thu, 21 May 2020 21:39:44 +0200
Subject: [PATCH] sm501: Clean up local variables in sm501_2d_operation
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Make variables local to the block they are used in to make it clearer
which operation they are needed for.
Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Message-id: ae59f8138afe7f6a5a4a82539d0f61496a906b06.1590089984.git.balaton@eik.bme.hu
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/display/sm501.c | 31 ++++++++++++++++---------------
1 file changed, 16 insertions(+), 15 deletions(-)
diff --git a/hw/display/sm501.c b/hw/display/sm501.c
index f3d11d0b23..98b3b97f7b 100644
--- a/hw/display/sm501.c
+++ b/hw/display/sm501.c
@@ -699,28 +699,19 @@ static inline void hwc_invalidate(SM501State *s, int crt)
static void sm501_2d_operation(SM501State *s)
{
- /* obtain operation parameters */
int cmd = (s->twoD_control >> 16) & 0x1F;
int rtl = s->twoD_control & BIT(27);
- int src_x = (s->twoD_source >> 16) & 0x01FFF;
- int src_y = s->twoD_source & 0xFFFF;
- int dst_x = (s->twoD_destination >> 16) & 0x01FFF;
- int dst_y = s->twoD_destination & 0xFFFF;
- int width = (s->twoD_dimension >> 16) & 0x1FFF;
- int height = s->twoD_dimension & 0xFFFF;
- uint32_t color = s->twoD_foreground;
int format = (s->twoD_stretch >> 20) & 0x3;
int rop_mode = (s->twoD_control >> 15) & 0x1; /* 1 for rop2, else rop3 */
/* 1 if rop2 source is the pattern, otherwise the source is the bitmap */
int rop2_source_is_pattern = (s->twoD_control >> 14) & 0x1;
int rop = s->twoD_control & 0xFF;
- uint32_t src_base = s->twoD_source_base & 0x03FFFFFF;
+ int dst_x = (s->twoD_destination >> 16) & 0x01FFF;
+ int dst_y = s->twoD_destination & 0xFFFF;
+ int width = (s->twoD_dimension >> 16) & 0x1FFF;
+ int height = s->twoD_dimension & 0xFFFF;
uint32_t dst_base = s->twoD_destination_base & 0x03FFFFFF;
-
- /* get frame buffer info */
- uint8_t *src = s->local_mem + src_base;
uint8_t *dst = s->local_mem + dst_base;
- int src_pitch = s->twoD_pitch & 0x1FFF;
int dst_pitch = (s->twoD_pitch >> 16) & 0x1FFF;
int crt = (s->dc_crt_control & SM501_DC_CRT_CONTROL_SEL) ? 1 : 0;
int fb_len = get_width(s, crt) * get_height(s, crt) * get_bpp(s, crt);
@@ -758,6 +749,13 @@ static void sm501_2d_operation(SM501State *s)
switch (cmd) {
case 0x00: /* copy area */
+ {
+ int src_x = (s->twoD_source >> 16) & 0x01FFF;
+ int src_y = s->twoD_source & 0xFFFF;
+ uint32_t src_base = s->twoD_source_base & 0x03FFFFFF;
+ uint8_t *src = s->local_mem + src_base;
+ int src_pitch = s->twoD_pitch & 0x1FFF;
+
#define COPY_AREA(_bpp, _pixel_type, rtl) { \
int y, x, index_d, index_s; \
for (y = 0; y < height; y++) { \
@@ -793,8 +791,11 @@ static void sm501_2d_operation(SM501State *s)
break;
}
break;
-
+ }
case 0x01: /* fill rectangle */
+ {
+ uint32_t color = s->twoD_foreground;
+
#define FILL_RECT(_bpp, _pixel_type) { \
int y, x; \
for (y = 0; y < height; y++) { \
@@ -819,7 +820,7 @@ static void sm501_2d_operation(SM501State *s)
break;
}
break;
-
+ }
default:
qemu_log_mask(LOG_UNIMP, "sm501: not implemented 2D operation: %d\n",
cmd);
--
2.23.0

View File

@ -0,0 +1,159 @@
From 428e3a78ddf1de3dfb914043d6a8668f73ef8bb3 Mon Sep 17 00:00:00 2001
From: BALATON Zoltan <balaton@eik.bme.hu>
Date: Thu, 21 May 2020 21:39:44 +0200
Subject: [PATCH] sm501: Convert printf + abort to qemu_log_mask
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Some places already use qemu_log_mask() to log unimplemented features
or errors but some others have printf() then abort(). Convert these to
qemu_log_mask() and avoid aborting to prevent guests to easily cause
denial of service.
Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Message-id: 305af87f59d81e92f2aaff09eb8a3603b8baa322.1590089984.git.balaton@eik.bme.hu
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/display/sm501.c | 57 ++++++++++++++++++++++------------------------
1 file changed, 27 insertions(+), 30 deletions(-)
diff --git a/hw/display/sm501.c b/hw/display/sm501.c
index 5918f59b2b..aa4b202a48 100644
--- a/hw/display/sm501.c
+++ b/hw/display/sm501.c
@@ -727,8 +727,8 @@ static void sm501_2d_operation(SM501State *s)
int fb_len = get_width(s, crt) * get_height(s, crt) * get_bpp(s, crt);
if (addressing != 0x0) {
- printf("%s: only XY addressing is supported.\n", __func__);
- abort();
+ qemu_log_mask(LOG_UNIMP, "sm501: only XY addressing is supported.\n");
+ return;
}
if (rop_mode == 0) {
@@ -754,8 +754,8 @@ static void sm501_2d_operation(SM501State *s)
if ((s->twoD_source_base & 0x08000000) ||
(s->twoD_destination_base & 0x08000000)) {
- printf("%s: only local memory is supported.\n", __func__);
- abort();
+ qemu_log_mask(LOG_UNIMP, "sm501: only local memory is supported.\n");
+ return;
}
switch (operation) {
@@ -823,9 +823,9 @@ static void sm501_2d_operation(SM501State *s)
break;
default:
- printf("non-implemented SM501 2D operation. %d\n", operation);
- abort();
- break;
+ qemu_log_mask(LOG_UNIMP, "sm501: not implemented 2D operation: %d\n",
+ operation);
+ return;
}
if (dst_base >= get_fb_addr(s, crt) &&
@@ -892,9 +892,8 @@ static uint64_t sm501_system_config_read(void *opaque, hwaddr addr,
break;
default:
- printf("sm501 system config : not implemented register read."
- " addr=%x\n", (int)addr);
- abort();
+ qemu_log_mask(LOG_UNIMP, "sm501: not implemented system config"
+ "register read. addr=%" HWADDR_PRIx "\n", addr);
}
return ret;
@@ -948,15 +947,15 @@ static void sm501_system_config_write(void *opaque, hwaddr addr,
break;
case SM501_ENDIAN_CONTROL:
if (value & 0x00000001) {
- printf("sm501 system config : big endian mode not implemented.\n");
- abort();
+ qemu_log_mask(LOG_UNIMP, "sm501: system config big endian mode not"
+ " implemented.\n");
}
break;
default:
- printf("sm501 system config : not implemented register write."
- " addr=%x, val=%x\n", (int)addr, (uint32_t)value);
- abort();
+ qemu_log_mask(LOG_UNIMP, "sm501: not implemented system config"
+ "register write. addr=%" HWADDR_PRIx
+ ", val=%" PRIx64 "\n", addr, value);
}
}
@@ -1207,9 +1206,8 @@ static uint64_t sm501_disp_ctrl_read(void *opaque, hwaddr addr,
break;
default:
- printf("sm501 disp ctrl : not implemented register read."
- " addr=%x\n", (int)addr);
- abort();
+ qemu_log_mask(LOG_UNIMP, "sm501: not implemented disp ctrl register "
+ "read. addr=%" HWADDR_PRIx "\n", addr);
}
return ret;
@@ -1345,9 +1343,9 @@ static void sm501_disp_ctrl_write(void *opaque, hwaddr addr,
break;
default:
- printf("sm501 disp ctrl : not implemented register write."
- " addr=%x, val=%x\n", (int)addr, (unsigned)value);
- abort();
+ qemu_log_mask(LOG_UNIMP, "sm501: not implemented disp ctrl register "
+ "write. addr=%" HWADDR_PRIx
+ ", val=%" PRIx64 "\n", addr, value);
}
}
@@ -1433,9 +1431,8 @@ static uint64_t sm501_2d_engine_read(void *opaque, hwaddr addr,
ret = 0; /* Should return interrupt status */
break;
default:
- printf("sm501 disp ctrl : not implemented register read."
- " addr=%x\n", (int)addr);
- abort();
+ qemu_log_mask(LOG_UNIMP, "sm501: not implemented disp ctrl register "
+ "read. addr=%" HWADDR_PRIx "\n", addr);
}
return ret;
@@ -1520,9 +1517,9 @@ static void sm501_2d_engine_write(void *opaque, hwaddr addr,
/* ignored, writing 0 should clear interrupt status */
break;
default:
- printf("sm501 2d engine : not implemented register write."
- " addr=%x, val=%x\n", (int)addr, (unsigned)value);
- abort();
+ qemu_log_mask(LOG_UNIMP, "sm501: not implemented 2d engine register "
+ "write. addr=%" HWADDR_PRIx
+ ", val=%" PRIx64 "\n", addr, value);
}
}
@@ -1670,9 +1667,9 @@ static void sm501_update_display(void *opaque)
draw_line = draw_line32_funcs[dst_depth_index];
break;
default:
- printf("sm501 update display : invalid control register value.\n");
- abort();
- break;
+ qemu_log_mask(LOG_GUEST_ERROR, "sm501: update display"
+ "invalid control register value.\n");
+ return;
}
/* set up to draw hardware cursor */
--
2.23.0

View File

@ -0,0 +1,261 @@
From bbbf2c2f4201eb84a5bcd07a92399fe166d682e9 Mon Sep 17 00:00:00 2001
From: BALATON Zoltan <balaton@eik.bme.hu>
Date: Thu, 21 May 2020 21:39:44 +0200
Subject: [PATCH] sm501: Replace hand written implementation with pixman where
possible
Besides being faster this should also prevent malicious guests to
abuse 2D engine to overwrite data or cause a crash.
Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu>
Message-id: 58666389b6cae256e4e972a32c05cf8aa51bffc0.1590089984.git.balaton@eik.bme.hu
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/display/sm501.c | 207 ++++++++++++++++++++++++++-------------------
1 file changed, 119 insertions(+), 88 deletions(-)
diff --git a/hw/display/sm501.c b/hw/display/sm501.c
index 98b3b97f7b..7dc4bb18b7 100644
--- a/hw/display/sm501.c
+++ b/hw/display/sm501.c
@@ -706,13 +706,12 @@ static void sm501_2d_operation(SM501State *s)
/* 1 if rop2 source is the pattern, otherwise the source is the bitmap */
int rop2_source_is_pattern = (s->twoD_control >> 14) & 0x1;
int rop = s->twoD_control & 0xFF;
- int dst_x = (s->twoD_destination >> 16) & 0x01FFF;
- int dst_y = s->twoD_destination & 0xFFFF;
- int width = (s->twoD_dimension >> 16) & 0x1FFF;
- int height = s->twoD_dimension & 0xFFFF;
+ unsigned int dst_x = (s->twoD_destination >> 16) & 0x01FFF;
+ unsigned int dst_y = s->twoD_destination & 0xFFFF;
+ unsigned int width = (s->twoD_dimension >> 16) & 0x1FFF;
+ unsigned int height = s->twoD_dimension & 0xFFFF;
uint32_t dst_base = s->twoD_destination_base & 0x03FFFFFF;
- uint8_t *dst = s->local_mem + dst_base;
- int dst_pitch = (s->twoD_pitch >> 16) & 0x1FFF;
+ unsigned int dst_pitch = (s->twoD_pitch >> 16) & 0x1FFF;
int crt = (s->dc_crt_control & SM501_DC_CRT_CONTROL_SEL) ? 1 : 0;
int fb_len = get_width(s, crt) * get_height(s, crt) * get_bpp(s, crt);
@@ -721,104 +720,136 @@ static void sm501_2d_operation(SM501State *s)
return;
}
- if (rop_mode == 0) {
- if (rop != 0xcc) {
- /* Anything other than plain copies are not supported */
- qemu_log_mask(LOG_UNIMP, "sm501: rop3 mode with rop %x is not "
- "supported.\n", rop);
- }
- } else {
- if (rop2_source_is_pattern && rop != 0x5) {
- /* For pattern source, we support only inverse dest */
- qemu_log_mask(LOG_UNIMP, "sm501: rop2 source being the pattern and "
- "rop %x is not supported.\n", rop);
- } else {
- if (rop != 0x5 && rop != 0xc) {
- /* Anything other than plain copies or inverse dest is not
- * supported */
- qemu_log_mask(LOG_UNIMP, "sm501: rop mode %x is not "
- "supported.\n", rop);
- }
- }
- }
-
if (s->twoD_source_base & BIT(27) || s->twoD_destination_base & BIT(27)) {
qemu_log_mask(LOG_UNIMP, "sm501: only local memory is supported.\n");
return;
}
+ if (!dst_pitch) {
+ qemu_log_mask(LOG_GUEST_ERROR, "sm501: Zero dest pitch.\n");
+ return;
+ }
+
+ if (!width || !height) {
+ qemu_log_mask(LOG_GUEST_ERROR, "sm501: Zero size 2D op.\n");
+ return;
+ }
+
+ if (rtl) {
+ dst_x -= width - 1;
+ dst_y -= height - 1;
+ }
+
+ if (dst_base >= get_local_mem_size(s) || dst_base +
+ (dst_x + width + (dst_y + height) * (dst_pitch + width)) *
+ (1 << format) >= get_local_mem_size(s)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "sm501: 2D op dest is outside vram.\n");
+ return;
+ }
+
switch (cmd) {
- case 0x00: /* copy area */
+ case 0: /* BitBlt */
{
- int src_x = (s->twoD_source >> 16) & 0x01FFF;
- int src_y = s->twoD_source & 0xFFFF;
+ unsigned int src_x = (s->twoD_source >> 16) & 0x01FFF;
+ unsigned int src_y = s->twoD_source & 0xFFFF;
uint32_t src_base = s->twoD_source_base & 0x03FFFFFF;
- uint8_t *src = s->local_mem + src_base;
- int src_pitch = s->twoD_pitch & 0x1FFF;
-
-#define COPY_AREA(_bpp, _pixel_type, rtl) { \
- int y, x, index_d, index_s; \
- for (y = 0; y < height; y++) { \
- for (x = 0; x < width; x++) { \
- _pixel_type val; \
- \
- if (rtl) { \
- index_s = ((src_y - y) * src_pitch + src_x - x) * _bpp; \
- index_d = ((dst_y - y) * dst_pitch + dst_x - x) * _bpp; \
- } else { \
- index_s = ((src_y + y) * src_pitch + src_x + x) * _bpp; \
- index_d = ((dst_y + y) * dst_pitch + dst_x + x) * _bpp; \
- } \
- if (rop_mode == 1 && rop == 5) { \
- /* Invert dest */ \
- val = ~*(_pixel_type *)&dst[index_d]; \
- } else { \
- val = *(_pixel_type *)&src[index_s]; \
- } \
- *(_pixel_type *)&dst[index_d] = val; \
- } \
- } \
- }
- switch (format) {
- case 0:
- COPY_AREA(1, uint8_t, rtl);
- break;
- case 1:
- COPY_AREA(2, uint16_t, rtl);
- break;
- case 2:
- COPY_AREA(4, uint32_t, rtl);
- break;
+ unsigned int src_pitch = s->twoD_pitch & 0x1FFF;
+
+ if (!src_pitch) {
+ qemu_log_mask(LOG_GUEST_ERROR, "sm501: Zero src pitch.\n");
+ return;
+ }
+
+ if (rtl) {
+ src_x -= width - 1;
+ src_y -= height - 1;
+ }
+
+ if (src_base >= get_local_mem_size(s) || src_base +
+ (src_x + width + (src_y + height) * (src_pitch + width)) *
+ (1 << format) >= get_local_mem_size(s)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "sm501: 2D op src is outside vram.\n");
+ return;
+ }
+
+ if ((rop_mode && rop == 0x5) || (!rop_mode && rop == 0x55)) {
+ /* Invert dest, is there a way to do this with pixman? */
+ unsigned int x, y, i;
+ uint8_t *d = s->local_mem + dst_base;
+
+ for (y = 0; y < height; y++) {
+ i = (dst_x + (dst_y + y) * dst_pitch) * (1 << format);
+ for (x = 0; x < width; x++, i += (1 << format)) {
+ switch (format) {
+ case 0:
+ d[i] = ~d[i];
+ break;
+ case 1:
+ *(uint16_t *)&d[i] = ~*(uint16_t *)&d[i];
+ break;
+ case 2:
+ *(uint32_t *)&d[i] = ~*(uint32_t *)&d[i];
+ break;
+ }
+ }
+ }
+ } else {
+ /* Do copy src for unimplemented ops, better than unpainted area */
+ if ((rop_mode && (rop != 0xc || rop2_source_is_pattern)) ||
+ (!rop_mode && rop != 0xcc)) {
+ qemu_log_mask(LOG_UNIMP,
+ "sm501: rop%d op %x%s not implemented\n",
+ (rop_mode ? 2 : 3), rop,
+ (rop2_source_is_pattern ?
+ " with pattern source" : ""));
+ }
+ /* Check for overlaps, this could be made more exact */
+ uint32_t sb, se, db, de;
+ sb = src_base + src_x + src_y * (width + src_pitch);
+ se = sb + width + height * (width + src_pitch);
+ db = dst_base + dst_x + dst_y * (width + dst_pitch);
+ de = db + width + height * (width + dst_pitch);
+ if (rtl && ((db >= sb && db <= se) || (de >= sb && de <= se))) {
+ /* regions may overlap: copy via temporary */
+ int llb = width * (1 << format);
+ int tmp_stride = DIV_ROUND_UP(llb, sizeof(uint32_t));
+ uint32_t *tmp = g_malloc(tmp_stride * sizeof(uint32_t) *
+ height);
+ pixman_blt((uint32_t *)&s->local_mem[src_base], tmp,
+ src_pitch * (1 << format) / sizeof(uint32_t),
+ tmp_stride, 8 * (1 << format), 8 * (1 << format),
+ src_x, src_y, 0, 0, width, height);
+ pixman_blt(tmp, (uint32_t *)&s->local_mem[dst_base],
+ tmp_stride,
+ dst_pitch * (1 << format) / sizeof(uint32_t),
+ 8 * (1 << format), 8 * (1 << format),
+ 0, 0, dst_x, dst_y, width, height);
+ g_free(tmp);
+ } else {
+ pixman_blt((uint32_t *)&s->local_mem[src_base],
+ (uint32_t *)&s->local_mem[dst_base],
+ src_pitch * (1 << format) / sizeof(uint32_t),
+ dst_pitch * (1 << format) / sizeof(uint32_t),
+ 8 * (1 << format), 8 * (1 << format),
+ src_x, src_y, dst_x, dst_y, width, height);
+ }
}
break;
}
- case 0x01: /* fill rectangle */
+ case 1: /* Rectangle Fill */
{
uint32_t color = s->twoD_foreground;
-#define FILL_RECT(_bpp, _pixel_type) { \
- int y, x; \
- for (y = 0; y < height; y++) { \
- for (x = 0; x < width; x++) { \
- int index = ((dst_y + y) * dst_pitch + dst_x + x) * _bpp; \
- *(_pixel_type *)&dst[index] = (_pixel_type)color; \
- } \
- } \
- }
-
- switch (format) {
- case 0:
- FILL_RECT(1, uint8_t);
- break;
- case 1:
- color = cpu_to_le16(color);
- FILL_RECT(2, uint16_t);
- break;
- case 2:
+ if (format == 2) {
color = cpu_to_le32(color);
- FILL_RECT(4, uint32_t);
- break;
+ } else if (format == 1) {
+ color = cpu_to_le16(color);
}
+
+ pixman_fill((uint32_t *)&s->local_mem[dst_base],
+ dst_pitch * (1 << format) / sizeof(uint32_t),
+ 8 * (1 << format), dst_x, dst_y, width, height, color);
break;
}
default:
--
2.23.0

View File

@ -0,0 +1,134 @@
From bc472e56b985db1de73a7ddab5ea8568d6e7f327 Mon Sep 17 00:00:00 2001
From: BALATON Zoltan <balaton@eik.bme.hu>
Date: Thu, 21 May 2020 21:39:44 +0200
Subject: [PATCH] sm501: Shorten long variable names in sm501_2d_operation
This increases readability and cleans up some confusing naming.
Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu>
Message-id: b9b67b94c46e945252a73c77dfd117132c63c4fb.1590089984.git.balaton@eik.bme.hu
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/display/sm501.c | 45 ++++++++++++++++++++++-----------------------
1 file changed, 22 insertions(+), 23 deletions(-)
diff --git a/hw/display/sm501.c b/hw/display/sm501.c
index aa4b202a48..51e7ccc39d 100644
--- a/hw/display/sm501.c
+++ b/hw/display/sm501.c
@@ -700,17 +700,16 @@ static inline void hwc_invalidate(SM501State *s, int crt)
static void sm501_2d_operation(SM501State *s)
{
/* obtain operation parameters */
- int operation = (s->twoD_control >> 16) & 0x1f;
+ int cmd = (s->twoD_control >> 16) & 0x1F;
int rtl = s->twoD_control & 0x8000000;
int src_x = (s->twoD_source >> 16) & 0x01FFF;
int src_y = s->twoD_source & 0xFFFF;
int dst_x = (s->twoD_destination >> 16) & 0x01FFF;
int dst_y = s->twoD_destination & 0xFFFF;
- int operation_width = (s->twoD_dimension >> 16) & 0x1FFF;
- int operation_height = s->twoD_dimension & 0xFFFF;
+ int width = (s->twoD_dimension >> 16) & 0x1FFF;
+ int height = s->twoD_dimension & 0xFFFF;
uint32_t color = s->twoD_foreground;
- int format_flags = (s->twoD_stretch >> 20) & 0x3;
- int addressing = (s->twoD_stretch >> 16) & 0xF;
+ int format = (s->twoD_stretch >> 20) & 0x3;
int rop_mode = (s->twoD_control >> 15) & 0x1; /* 1 for rop2, else rop3 */
/* 1 if rop2 source is the pattern, otherwise the source is the bitmap */
int rop2_source_is_pattern = (s->twoD_control >> 14) & 0x1;
@@ -721,12 +720,12 @@ static void sm501_2d_operation(SM501State *s)
/* get frame buffer info */
uint8_t *src = s->local_mem + src_base;
uint8_t *dst = s->local_mem + dst_base;
- int src_width = s->twoD_pitch & 0x1FFF;
- int dst_width = (s->twoD_pitch >> 16) & 0x1FFF;
+ int src_pitch = s->twoD_pitch & 0x1FFF;
+ int dst_pitch = (s->twoD_pitch >> 16) & 0x1FFF;
int crt = (s->dc_crt_control & SM501_DC_CRT_CONTROL_SEL) ? 1 : 0;
int fb_len = get_width(s, crt) * get_height(s, crt) * get_bpp(s, crt);
- if (addressing != 0x0) {
+ if ((s->twoD_stretch >> 16) & 0xF) {
qemu_log_mask(LOG_UNIMP, "sm501: only XY addressing is supported.\n");
return;
}
@@ -758,20 +757,20 @@ static void sm501_2d_operation(SM501State *s)
return;
}
- switch (operation) {
+ switch (cmd) {
case 0x00: /* copy area */
#define COPY_AREA(_bpp, _pixel_type, rtl) { \
int y, x, index_d, index_s; \
- for (y = 0; y < operation_height; y++) { \
- for (x = 0; x < operation_width; x++) { \
+ for (y = 0; y < height; y++) { \
+ for (x = 0; x < width; x++) { \
_pixel_type val; \
\
if (rtl) { \
- index_s = ((src_y - y) * src_width + src_x - x) * _bpp; \
- index_d = ((dst_y - y) * dst_width + dst_x - x) * _bpp; \
+ index_s = ((src_y - y) * src_pitch + src_x - x) * _bpp; \
+ index_d = ((dst_y - y) * dst_pitch + dst_x - x) * _bpp; \
} else { \
- index_s = ((src_y + y) * src_width + src_x + x) * _bpp; \
- index_d = ((dst_y + y) * dst_width + dst_x + x) * _bpp; \
+ index_s = ((src_y + y) * src_pitch + src_x + x) * _bpp; \
+ index_d = ((dst_y + y) * dst_pitch + dst_x + x) * _bpp; \
} \
if (rop_mode == 1 && rop == 5) { \
/* Invert dest */ \
@@ -783,7 +782,7 @@ static void sm501_2d_operation(SM501State *s)
} \
} \
}
- switch (format_flags) {
+ switch (format) {
case 0:
COPY_AREA(1, uint8_t, rtl);
break;
@@ -799,15 +798,15 @@ static void sm501_2d_operation(SM501State *s)
case 0x01: /* fill rectangle */
#define FILL_RECT(_bpp, _pixel_type) { \
int y, x; \
- for (y = 0; y < operation_height; y++) { \
- for (x = 0; x < operation_width; x++) { \
- int index = ((dst_y + y) * dst_width + dst_x + x) * _bpp; \
+ for (y = 0; y < height; y++) { \
+ for (x = 0; x < width; x++) { \
+ int index = ((dst_y + y) * dst_pitch + dst_x + x) * _bpp; \
*(_pixel_type *)&dst[index] = (_pixel_type)color; \
} \
} \
}
- switch (format_flags) {
+ switch (format) {
case 0:
FILL_RECT(1, uint8_t);
break;
@@ -824,14 +823,14 @@ static void sm501_2d_operation(SM501State *s)
default:
qemu_log_mask(LOG_UNIMP, "sm501: not implemented 2D operation: %d\n",
- operation);
+ cmd);
return;
}
if (dst_base >= get_fb_addr(s, crt) &&
dst_base <= get_fb_addr(s, crt) + fb_len) {
- int dst_len = MIN(fb_len, ((dst_y + operation_height - 1) * dst_width +
- dst_x + operation_width) * (1 << format_flags));
+ int dst_len = MIN(fb_len, ((dst_y + height - 1) * dst_pitch +
+ dst_x + width) * (1 << format));
if (dst_len) {
memory_region_set_dirty(&s->local_mem_region, dst_base, dst_len);
}
--
2.23.0

View File

@ -0,0 +1,42 @@
From 9f1e9012047639121eb275a4f8f5693d340e91f6 Mon Sep 17 00:00:00 2001
From: BALATON Zoltan <balaton@eik.bme.hu>
Date: Thu, 21 May 2020 21:39:44 +0200
Subject: [PATCH] sm501: Use BIT(x) macro to shorten constant
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Message-id: 124bf5de8d7cf503b32b377d0445029a76bfbd49.1590089984.git.balaton@eik.bme.hu
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/display/sm501.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/hw/display/sm501.c b/hw/display/sm501.c
index 51e7ccc39d..f3d11d0b23 100644
--- a/hw/display/sm501.c
+++ b/hw/display/sm501.c
@@ -701,7 +701,7 @@ static void sm501_2d_operation(SM501State *s)
{
/* obtain operation parameters */
int cmd = (s->twoD_control >> 16) & 0x1F;
- int rtl = s->twoD_control & 0x8000000;
+ int rtl = s->twoD_control & BIT(27);
int src_x = (s->twoD_source >> 16) & 0x01FFF;
int src_y = s->twoD_source & 0xFFFF;
int dst_x = (s->twoD_destination >> 16) & 0x01FFF;
@@ -751,8 +751,7 @@ static void sm501_2d_operation(SM501State *s)
}
}
- if ((s->twoD_source_base & 0x08000000) ||
- (s->twoD_destination_base & 0x08000000)) {
+ if (s->twoD_source_base & BIT(27) || s->twoD_destination_base & BIT(27)) {
qemu_log_mask(LOG_UNIMP, "sm501: only local memory is supported.\n");
return;
}
--
2.23.0