The virtio-net receive buffers are filled asynchronously, so we should make sure to properly shut down the virtio-net device before we jump into the loaded kernel. Otherwise an incoming packet could destroy memory of the OS kernel if it did not re-initialize the virtio-net device fast enough yet.
Signed-off-by: Thomas Huth <th...@redhat.com> --- pc-bios/s390-ccw/netmain.c | 1 + pc-bios/s390-ccw/virtio-net.c | 8 ++++++++ pc-bios/s390-ccw/virtio.c | 19 ++++++++++++++----- pc-bios/s390-ccw/virtio.h | 3 +++ 4 files changed, 26 insertions(+), 5 deletions(-) diff --git a/pc-bios/s390-ccw/netmain.c b/pc-bios/s390-ccw/netmain.c index ebdc440..e11ed4e 100644 --- a/pc-bios/s390-ccw/netmain.c +++ b/pc-bios/s390-ccw/netmain.c @@ -273,6 +273,7 @@ static void net_uninit(filename_ip_t *fn_ip) if (ip_version == 4) { dhcp_send_release(fn_ip->fd); } + virtio_net_uninit(); } void panic(const char *string) diff --git a/pc-bios/s390-ccw/virtio-net.c b/pc-bios/s390-ccw/virtio-net.c index ff7f4da..339fe53 100644 --- a/pc-bios/s390-ccw/virtio-net.c +++ b/pc-bios/s390-ccw/virtio-net.c @@ -67,6 +67,14 @@ int virtio_net_init(void *mac_addr) return 0; } +void virtio_net_uninit(void) +{ + VDev *vdev = virtio_get_device(); + + virtio_status_set(vdev, VIRTIO_CONFIG_S_FAILED); + virtio_reset_dev(vdev); +} + int send(int fd, const void *buf, int len, int flags) { VirtioNetHdr tx_hdr; diff --git a/pc-bios/s390-ccw/virtio.c b/pc-bios/s390-ccw/virtio.c index cdb66f4..1d15b03 100644 --- a/pc-bios/s390-ccw/virtio.c +++ b/pc-bios/s390-ccw/virtio.c @@ -248,10 +248,21 @@ int virtio_run(VDev *vdev, int vqid, VirtioCmd *cmd) return 0; } +void virtio_status_set(VDev *vdev, uint8_t status) +{ + IPL_assert( + run_ccw(vdev, CCW_CMD_WRITE_STATUS, &status, sizeof(status)) == 0, + "Could not write status to host"); +} + +void virtio_reset_dev(VDev *vdev) +{ + run_ccw(vdev, CCW_CMD_VDEV_RESET, NULL, 0); +} + void virtio_setup_ccw(VDev *vdev) { int i, rc, cfg_size = 0; - unsigned char status = VIRTIO_CONFIG_S_DRIVER_OK; struct VirtioFeatureDesc { uint32_t features; uint8_t index; @@ -263,7 +274,7 @@ void virtio_setup_ccw(VDev *vdev) vdev->config.blk.blk_size = 0; /* mark "illegal" - setup started... */ vdev->guessed_disk_nature = VIRTIO_GDN_NONE; - run_ccw(vdev, CCW_CMD_VDEV_RESET, NULL, 0); + virtio_reset_dev(vdev); switch (vdev->senseid.cu_model) { case VIRTIO_ID_NET: @@ -320,9 +331,7 @@ void virtio_setup_ccw(VDev *vdev) IPL_assert(run_ccw(vdev, CCW_CMD_SET_VQ, &info, sizeof(info)) == 0, "Cannot set VQ info"); } - IPL_assert( - run_ccw(vdev, CCW_CMD_WRITE_STATUS, &status, sizeof(status)) == 0, - "Could not write status to host"); + virtio_status_set(vdev, VIRTIO_CONFIG_S_DRIVER_OK); } bool virtio_is_supported(SubChannelId schid) diff --git a/pc-bios/s390-ccw/virtio.h b/pc-bios/s390-ccw/virtio.h index 19fceb6..c2479be 100644 --- a/pc-bios/s390-ccw/virtio.h +++ b/pc-bios/s390-ccw/virtio.h @@ -277,8 +277,11 @@ void vring_send_buf(VRing *vr, void *p, int len, int flags); int vr_poll(VRing *vr); int vring_wait_reply(void); int virtio_run(VDev *vdev, int vqid, VirtioCmd *cmd); +void virtio_status_set(VDev *vdev, uint8_t status); +void virtio_reset_dev(VDev *vdev); void virtio_setup_ccw(VDev *vdev); int virtio_net_init(void *mac_addr); +void virtio_net_uninit(void); #endif /* VIRTIO_H */ -- 1.8.3.1