^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * OS info memory interface
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright IBM Corp. 2012
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Author(s): Michael Holzheu <holzheu@linux.vnet.ibm.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #define KMSG_COMPONENT "os_info"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/crash_dump.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <asm/checksum.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <asm/lowcore.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <asm/os_info.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * OS info structure has to be page aligned
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) static struct os_info os_info __page_aligned_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) * Compute checksum over OS info structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) u32 os_info_csum(struct os_info *os_info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) int size = sizeof(*os_info) - offsetof(struct os_info, version_major);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) return (__force u32)csum_partial(&os_info->version_major, size, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) * Add crashkernel info to OS info and update checksum
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) void os_info_crashkernel_add(unsigned long base, unsigned long size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) os_info.crashkernel_addr = (u64)(unsigned long)base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) os_info.crashkernel_size = (u64)(unsigned long)size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) os_info.csum = os_info_csum(&os_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) * Add OS info entry and update checksum
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) void os_info_entry_add(int nr, void *ptr, u64 size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) os_info.entry[nr].addr = (u64)(unsigned long)ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) os_info.entry[nr].size = size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) os_info.entry[nr].csum = (__force u32)csum_partial(ptr, size, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) os_info.csum = os_info_csum(&os_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) * Initialize OS info struture and set lowcore pointer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) void __init os_info_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) void *ptr = &os_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) os_info.version_major = OS_INFO_VERSION_MAJOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) os_info.version_minor = OS_INFO_VERSION_MINOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) os_info.magic = OS_INFO_MAGIC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) os_info.csum = os_info_csum(&os_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) mem_assign_absolute(S390_lowcore.os_info, (unsigned long) ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) #ifdef CONFIG_CRASH_DUMP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) static struct os_info *os_info_old;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) * Allocate and copy OS info entry from oldmem
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) static void os_info_old_alloc(int nr, int align)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) unsigned long addr, size = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) char *buf, *buf_align, *msg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) u32 csum;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) addr = os_info_old->entry[nr].addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) if (!addr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) msg = "not available";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) size = os_info_old->entry[nr].size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) buf = kmalloc(size + align - 1, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) if (!buf) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) msg = "alloc failed";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) buf_align = PTR_ALIGN(buf, align);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) if (copy_oldmem_kernel(buf_align, (void *) addr, size)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) msg = "copy failed";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) goto fail_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) csum = (__force u32)csum_partial(buf_align, size, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) if (csum != os_info_old->entry[nr].csum) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) msg = "checksum failed";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) goto fail_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) os_info_old->entry[nr].addr = (u64)(unsigned long)buf_align;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) msg = "copied";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) fail_free:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) kfree(buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) fail:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) os_info_old->entry[nr].addr = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) pr_info("entry %i: %s (addr=0x%lx size=%lu)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) nr, msg, addr, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) * Initialize os info and os info entries from oldmem
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) static void os_info_old_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) static int os_info_init;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) unsigned long addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) if (os_info_init)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) if (!OLDMEM_BASE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) if (copy_oldmem_kernel(&addr, &S390_lowcore.os_info, sizeof(addr)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) if (addr == 0 || addr % PAGE_SIZE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) os_info_old = kzalloc(sizeof(*os_info_old), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) if (!os_info_old)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) if (copy_oldmem_kernel(os_info_old, (void *) addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) sizeof(*os_info_old)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) goto fail_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) if (os_info_old->magic != OS_INFO_MAGIC)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) goto fail_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) if (os_info_old->csum != os_info_csum(os_info_old))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) goto fail_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) if (os_info_old->version_major > OS_INFO_VERSION_MAJOR)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) goto fail_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) os_info_old_alloc(OS_INFO_VMCOREINFO, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) os_info_old_alloc(OS_INFO_REIPL_BLOCK, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) pr_info("crashkernel: addr=0x%lx size=%lu\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) (unsigned long) os_info_old->crashkernel_addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) (unsigned long) os_info_old->crashkernel_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) os_info_init = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) fail_free:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) kfree(os_info_old);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) fail:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) os_info_init = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) os_info_old = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) * Return pointer to os infor entry and its size
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) void *os_info_old_entry(int nr, unsigned long *size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) os_info_old_init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) if (!os_info_old)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) if (!os_info_old->entry[nr].addr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) *size = (unsigned long) os_info_old->entry[nr].size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) return (void *)(unsigned long)os_info_old->entry[nr].addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) #endif