aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/s390/include/asm/ipl.h27
-rw-r--r--arch/s390/kernel/ipl.c134
2 files changed, 161 insertions, 0 deletions
diff --git a/arch/s390/include/asm/ipl.h b/arch/s390/include/asm/ipl.h
index 878f6fd5f2e7..bf62af49af06 100644
--- a/arch/s390/include/asm/ipl.h
+++ b/arch/s390/include/asm/ipl.h
@@ -81,6 +81,33 @@ extern struct ipl_info ipl_info;
81extern void setup_ipl(void); 81extern void setup_ipl(void);
82extern void set_os_info_reipl_block(void); 82extern void set_os_info_reipl_block(void);
83 83
84struct ipl_report {
85 struct ipl_parameter_block *ipib;
86 struct list_head components;
87 struct list_head certificates;
88 size_t size;
89};
90
91struct ipl_report_component {
92 struct list_head list;
93 struct ipl_rb_component_entry entry;
94};
95
96struct ipl_report_certificate {
97 struct list_head list;
98 struct ipl_rb_certificate_entry entry;
99 void *key;
100};
101
102struct kexec_buf;
103struct ipl_report *ipl_report_init(struct ipl_parameter_block *ipib);
104void *ipl_report_finish(struct ipl_report *report);
105int ipl_report_free(struct ipl_report *report);
106int ipl_report_add_component(struct ipl_report *report, struct kexec_buf *kbuf,
107 unsigned char flags, unsigned short cert);
108int ipl_report_add_certificate(struct ipl_report *report, void *key,
109 unsigned long addr, unsigned long len);
110
84/* 111/*
85 * DIAG 308 support 112 * DIAG 308 support
86 */ 113 */
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c
index 0567de4005b4..6f2bb64cf70e 100644
--- a/arch/s390/kernel/ipl.c
+++ b/arch/s390/kernel/ipl.c
@@ -1705,3 +1705,137 @@ void s390_reset_system(void)
1705 __ctl_clear_bit(0, 28); 1705 __ctl_clear_bit(0, 28);
1706 diag308_reset(); 1706 diag308_reset();
1707} 1707}
1708
1709#ifdef CONFIG_KEXEC_FILE
1710
1711int ipl_report_add_component(struct ipl_report *report, struct kexec_buf *kbuf,
1712 unsigned char flags, unsigned short cert)
1713{
1714 struct ipl_report_component *comp;
1715
1716 comp = vzalloc(sizeof(*comp));
1717 if (!comp)
1718 return -ENOMEM;
1719 list_add_tail(&comp->list, &report->components);
1720
1721 comp->entry.addr = kbuf->mem;
1722 comp->entry.len = kbuf->memsz;
1723 comp->entry.flags = flags;
1724 comp->entry.certificate_index = cert;
1725
1726 report->size += sizeof(comp->entry);
1727
1728 return 0;
1729}
1730
1731int ipl_report_add_certificate(struct ipl_report *report, void *key,
1732 unsigned long addr, unsigned long len)
1733{
1734 struct ipl_report_certificate *cert;
1735
1736 cert = vzalloc(sizeof(*cert));
1737 if (!cert)
1738 return -ENOMEM;
1739 list_add_tail(&cert->list, &report->certificates);
1740
1741 cert->entry.addr = addr;
1742 cert->entry.len = len;
1743 cert->key = key;
1744
1745 report->size += sizeof(cert->entry);
1746 report->size += cert->entry.len;
1747
1748 return 0;
1749}
1750
1751struct ipl_report *ipl_report_init(struct ipl_parameter_block *ipib)
1752{
1753 struct ipl_report *report;
1754
1755 report = vzalloc(sizeof(*report));
1756 if (!report)
1757 return ERR_PTR(-ENOMEM);
1758
1759 report->ipib = ipib;
1760 INIT_LIST_HEAD(&report->components);
1761 INIT_LIST_HEAD(&report->certificates);
1762
1763 report->size = ALIGN(ipib->hdr.len, 8);
1764 report->size += sizeof(struct ipl_rl_hdr);
1765 report->size += sizeof(struct ipl_rb_components);
1766 report->size += sizeof(struct ipl_rb_certificates);
1767
1768 return report;
1769}
1770
1771void *ipl_report_finish(struct ipl_report *report)
1772{
1773 struct ipl_report_certificate *cert;
1774 struct ipl_report_component *comp;
1775 struct ipl_rb_certificates *certs;
1776 struct ipl_parameter_block *ipib;
1777 struct ipl_rb_components *comps;
1778 struct ipl_rl_hdr *rl_hdr;
1779 void *buf, *ptr;
1780
1781 buf = vzalloc(report->size);
1782 if (!buf)
1783 return ERR_PTR(-ENOMEM);
1784 ptr = buf;
1785
1786 memcpy(ptr, report->ipib, report->ipib->hdr.len);
1787 ipib = ptr;
1788 if (ipl_secure_flag)
1789 ipib->hdr.flags |= IPL_PL_FLAG_SIPL;
1790 ipib->hdr.flags |= IPL_PL_FLAG_IPLSR;
1791 ptr += report->ipib->hdr.len;
1792 ptr = PTR_ALIGN(ptr, 8);
1793
1794 rl_hdr = ptr;
1795 ptr += sizeof(*rl_hdr);
1796
1797 comps = ptr;
1798 comps->rbt = IPL_RBT_COMPONENTS;
1799 ptr += sizeof(*comps);
1800 list_for_each_entry(comp, &report->components, list) {
1801 memcpy(ptr, &comp->entry, sizeof(comp->entry));
1802 ptr += sizeof(comp->entry);
1803 }
1804 comps->len = ptr - (void *)comps;
1805
1806 certs = ptr;
1807 certs->rbt = IPL_RBT_CERTIFICATES;
1808 ptr += sizeof(*certs);
1809 list_for_each_entry(cert, &report->certificates, list) {
1810 memcpy(ptr, &cert->entry, sizeof(cert->entry));
1811 ptr += sizeof(cert->entry);
1812 }
1813 certs->len = ptr - (void *)certs;
1814 rl_hdr->len = ptr - (void *)rl_hdr;
1815
1816 list_for_each_entry(cert, &report->certificates, list) {
1817 memcpy(ptr, cert->key, cert->entry.len);
1818 ptr += cert->entry.len;
1819 }
1820
1821 BUG_ON(ptr > buf + report->size);
1822 return buf;
1823}
1824
1825int ipl_report_free(struct ipl_report *report)
1826{
1827 struct ipl_report_component *comp, *ncomp;
1828 struct ipl_report_certificate *cert, *ncert;
1829
1830 list_for_each_entry_safe(comp, ncomp, &report->components, list)
1831 vfree(comp);
1832
1833 list_for_each_entry_safe(cert, ncert, &report->certificates, list)
1834 vfree(cert);
1835
1836 vfree(report);
1837
1838 return 0;
1839}
1840
1841#endif