| 1 | /* |
| 2 | * S390 guest code used in migration tests |
| 3 | * |
| 4 | * Copyright 2018 Thomas Huth, Red Hat Inc. |
| 5 | * |
| 6 | * This code is free software; you can redistribute it and/or modify it |
| 7 | * under the terms of the GNU General Public License as published by the |
| 8 | * Free Software Foundation; either version 2 of the License, or (at your |
| 9 | * option) any later version. |
| 10 | */ |
| 11 | |
| 12 | /* for sclp.h */ |
| 13 | #define LOADPARM_LEN 8 |
| 14 | typedef unsigned int uint32_t; |
| 15 | typedef unsigned short uint16_t; |
| 16 | typedef unsigned char uint8_t; |
| 17 | |
| 18 | #include <sclp.h> |
| 19 | |
| 20 | #define START_ADDRESS (1024 * 1024) |
| 21 | #define END_ADDRESS (100 * 1024 * 1024) |
| 22 | |
| 23 | /* at pc-bios/s390-ccw/start.S */ |
| 24 | |
| 25 | void __attribute__((weak)) consume_sclp_int(void) |
| 26 | { |
| 27 | } |
| 28 | |
| 29 | static char _sccb[4096] __attribute__((__aligned__(4096))); |
| 30 | char stack[0x8000] __attribute__((aligned(4096))); |
| 31 | |
| 32 | static void sclp_service_call(unsigned int command) |
| 33 | { |
| 34 | int cc; |
| 35 | |
| 36 | asm volatile( |
| 37 | " .insn rre,0xb2200000,%1,%2\n" /* servc %1,%2 */ |
| 38 | " ipm %0\n" |
| 39 | " srl %0,28" |
| 40 | : "=&d" (cc) : "d" (command), "a" (__pa(_sccb)) |
| 41 | : "cc", "memory"); |
| 42 | consume_sclp_int(); |
| 43 | } |
| 44 | |
| 45 | static void sclp_setup(void) |
| 46 | { |
| 47 | WriteEventMask *sccb = (void *)_sccb; |
| 48 | |
| 49 | sccb->h.length = sizeof(WriteEventMask); |
| 50 | |
| 51 | sccb->mask_length = sizeof(unsigned int); |
| 52 | sccb->cp_receive_mask = 0; |
| 53 | sccb->cp_send_mask = SCLP_EVENT_MASK_MSG_ASCII; |
| 54 | |
| 55 | sclp_service_call(SCLP_CMD_WRITE_EVENT_MASK); |
| 56 | } |
| 57 | |
| 58 | static void putc(const char c) |
| 59 | { |
| 60 | WriteEventData *sccb = (void *)_sccb; |
| 61 | int len = 1; |
| 62 | |
| 63 | sccb->data[0] = c; |
| 64 | |
| 65 | sccb->h.length = sizeof(WriteEventData) + len; |
| 66 | sccb->h.function_code = SCLP_FC_NORMAL_WRITE; |
| 67 | |
| 68 | sccb->ebh.length = sizeof(EventBufferHeader) + len; |
| 69 | sccb->ebh.type = SCLP_EVENT_ASCII_CONSOLE_DATA; |
| 70 | sccb->ebh.flags = 0; |
| 71 | |
| 72 | sclp_service_call(SCLP_CMD_WRITE_EVENT_DATA); |
| 73 | } |
| 74 | |
| 75 | void main(void) |
| 76 | { |
| 77 | unsigned long addr; |
| 78 | |
| 79 | sclp_setup(); |
| 80 | putc('A'); |
| 81 | |
| 82 | /* |
| 83 | * Make sure all of the pages have consistent contents before incrementing |
| 84 | * the first byte below. |
| 85 | */ |
| 86 | for (addr = START_ADDRESS; addr < END_ADDRESS; addr += 4096) { |
| 87 | *(volatile char *)addr = 0; |
| 88 | } |
| 89 | |
| 90 | while (1) { |
| 91 | for (addr = START_ADDRESS; addr < END_ADDRESS; addr += 4096) { |
| 92 | *(volatile char *)addr += 1; /* Change pages */ |
| 93 | } |
| 94 | putc('B'); |
| 95 | } |
| 96 | } |