diff options
author | Christian Borntraeger | 2014-06-18 14:16:45 +0200 |
---|---|---|
committer | Cornelia Huck | 2014-06-23 14:03:31 +0200 |
commit | 962982329029acb6651f81b47cb401e593bb62df (patch) | |
tree | 66a73474911ffafac83a666f89735ec0efd2714b /pc-bios | |
parent | pc-bios/s390-ccw: virtio_load_direct() can't load max number of sectors (diff) | |
download | qemu-962982329029acb6651f81b47cb401e593bb62df.tar.gz qemu-962982329029acb6651f81b47cb401e593bb62df.tar.xz qemu-962982329029acb6651f81b47cb401e593bb62df.zip |
pc-bios/s390-ccw: do a subsystem reset before running the guest
The loader BIOS has already activated several devices. Let's do a
subsystem reset before jumping into the guest. As there is no direct
way of doing so, we use diagnose 308 to bring the system in a
defined state. This is similar to what kdump on s390 uses. We have
to define a small trampoline function that restores the low bytes
to whatever the bootmap has written there.
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: Jens Freimann <jfrei@linux.vnet.ibm.com>
Reviewed-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Diffstat (limited to 'pc-bios')
-rw-r--r-- | pc-bios/s390-ccw/bootmap.c | 55 |
1 files changed, 47 insertions, 8 deletions
diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c index 53a460df84..c07553ba2a 100644 --- a/pc-bios/s390-ccw/bootmap.c +++ b/pc-bios/s390-ccw/bootmap.c @@ -58,6 +58,52 @@ struct mbr { /* Scratch space */ static uint8_t sec[SECTOR_SIZE] __attribute__((__aligned__(SECTOR_SIZE))); +typedef struct ResetInfo { + uint32_t ipl_mask; + uint32_t ipl_addr; + uint32_t ipl_continue; +} ResetInfo; + +ResetInfo save; + +static void jump_to_IPL_2(void) +{ + ResetInfo *current = 0; + + void (*ipl)(void) = (void *) (uint64_t) current->ipl_continue; + debug_print_addr("set IPL addr to", ipl); + + /* Ensure the guest output starts fresh */ + sclp_print("\n"); + + *current = save; + ipl(); /* should not return */ +} + +static void jump_to_IPL_code(uint64_t address) +{ + /* + * The IPL PSW is at address 0. We also must not overwrite the + * content of non-BIOS memory after we loaded the guest, so we + * save the original content and restore it in jump_to_IPL_2. + */ + ResetInfo *current = 0; + + save = *current; + current->ipl_addr = (uint32_t) (uint64_t) &jump_to_IPL_2; + current->ipl_continue = address & 0x7fffffff; + + /* + * HACK ALERT. + * We use the load normal reset to keep r15 unchanged. jump_to_IPL_2 + * can then use r15 as its stack pointer. + */ + asm volatile("lghi 1,1\n\t" + "diag 1,1,0x308\n\t" + : : : "1", "memory"); + virtio_panic("\n! IPL returns !\n"); +} + /* Check for ZIPL magic. Returns 0 if not matched. */ static int zipl_magic(uint8_t *ptr) { @@ -123,7 +169,6 @@ static int zipl_run(struct scsi_blockptr *pte) { struct component_header *header; struct component_entry *entry; - void (*ipl)(void); uint8_t tmp_sec[SECTOR_SIZE]; virtio_read(pte->blockno, tmp_sec); @@ -157,14 +202,8 @@ static int zipl_run(struct scsi_blockptr *pte) goto fail; } - /* Ensure the guest output starts fresh */ - sclp_print("\n"); - - /* And run the OS! */ - ipl = (void*)(entry->load_address & 0x7fffffff); - debug_print_addr("set IPL addr to", ipl); /* should not return */ - ipl(); + jump_to_IPL_code(entry->load_address); return 0; |