diff options
author | Sebastian Ott <sebott@linux.vnet.ibm.com> | 2013-04-16 08:16:14 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2013-04-17 08:07:37 -0400 |
commit | f0bacb7fc4f7defb15a6575d92f8ea4342f8f09e (patch) | |
tree | f8e029110696a0cb846357a2b1e267015ec37e62 /arch/s390 | |
parent | b2a9e87d2ce8fb2d0ce08ee49168805975c622da (diff) |
s390/pci: add exception table to load/store instructions
Don't let pci_load and friends crash the kernel when called with
e.g. an invalid offset. Return -ENXIO instead.
Reviewed-by: Gerald Schaefer <gerald.schaefer@de.ibm.com>
Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch/s390')
-rw-r--r-- | arch/s390/include/asm/pci_io.h | 2 | ||||
-rw-r--r-- | arch/s390/pci/pci_insn.c | 52 |
2 files changed, 30 insertions, 24 deletions
diff --git a/arch/s390/include/asm/pci_io.h b/arch/s390/include/asm/pci_io.h index a312c7e5a71e..0e0bec9a3fb7 100644 --- a/arch/s390/include/asm/pci_io.h +++ b/arch/s390/include/asm/pci_io.h | |||
@@ -89,7 +89,7 @@ static inline int zpci_write_single(u64 req, const u64 *data, u64 offset, u8 len | |||
89 | static inline int zpci_read_single(u64 req, u64 *dst, u64 offset, u8 len) | 89 | static inline int zpci_read_single(u64 req, u64 *dst, u64 offset, u8 len) |
90 | { | 90 | { |
91 | u64 data; | 91 | u64 data; |
92 | u8 cc; | 92 | int cc; |
93 | 93 | ||
94 | cc = s390pci_load(&data, req, offset); | 94 | cc = s390pci_load(&data, req, offset); |
95 | switch (len) { | 95 | switch (len) { |
diff --git a/arch/s390/pci/pci_insn.c b/arch/s390/pci/pci_insn.c index d9b573bf4eb7..4bc32f368f7d 100644 --- a/arch/s390/pci/pci_insn.c +++ b/arch/s390/pci/pci_insn.c | |||
@@ -8,6 +8,7 @@ | |||
8 | #include <linux/errno.h> | 8 | #include <linux/errno.h> |
9 | #include <linux/delay.h> | 9 | #include <linux/delay.h> |
10 | #include <asm/pci_insn.h> | 10 | #include <asm/pci_insn.h> |
11 | #include <asm/processor.h> | ||
11 | 12 | ||
12 | #define ZPCI_INSN_BUSY_DELAY 1 /* 1 microsecond */ | 13 | #define ZPCI_INSN_BUSY_DELAY 1 /* 1 microsecond */ |
13 | 14 | ||
@@ -85,18 +86,20 @@ void set_irq_ctrl(u16 ctl, char *unused, u8 isc) | |||
85 | } | 86 | } |
86 | 87 | ||
87 | /* PCI Load */ | 88 | /* PCI Load */ |
88 | static inline u8 __pcilg(u64 *data, u64 req, u64 offset, u8 *status) | 89 | static inline int __pcilg(u64 *data, u64 req, u64 offset, u8 *status) |
89 | { | 90 | { |
90 | register u64 __req asm("2") = req; | 91 | register u64 __req asm("2") = req; |
91 | register u64 __offset asm("3") = offset; | 92 | register u64 __offset asm("3") = offset; |
93 | int cc = -ENXIO; | ||
92 | u64 __data; | 94 | u64 __data; |
93 | u8 cc; | ||
94 | 95 | ||
95 | asm volatile ( | 96 | asm volatile ( |
96 | " .insn rre,0xb9d20000,%[data],%[req]\n" | 97 | " .insn rre,0xb9d20000,%[data],%[req]\n" |
97 | " ipm %[cc]\n" | 98 | "0: ipm %[cc]\n" |
98 | " srl %[cc],28\n" | 99 | " srl %[cc],28\n" |
99 | : [cc] "=d" (cc), [data] "=d" (__data), [req] "+d" (__req) | 100 | "1:\n" |
101 | EX_TABLE(0b, 1b) | ||
102 | : [cc] "+d" (cc), [data] "=d" (__data), [req] "+d" (__req) | ||
100 | : "d" (__offset) | 103 | : "d" (__offset) |
101 | : "cc"); | 104 | : "cc"); |
102 | *status = __req >> 24 & 0xff; | 105 | *status = __req >> 24 & 0xff; |
@@ -106,7 +109,8 @@ static inline u8 __pcilg(u64 *data, u64 req, u64 offset, u8 *status) | |||
106 | 109 | ||
107 | int s390pci_load(u64 *data, u64 req, u64 offset) | 110 | int s390pci_load(u64 *data, u64 req, u64 offset) |
108 | { | 111 | { |
109 | u8 cc, status; | 112 | u8 status; |
113 | int cc; | ||
110 | 114 | ||
111 | do { | 115 | do { |
112 | cc = __pcilg(data, req, offset, &status); | 116 | cc = __pcilg(data, req, offset, &status); |
@@ -114,29 +118,27 @@ int s390pci_load(u64 *data, u64 req, u64 offset) | |||
114 | udelay(ZPCI_INSN_BUSY_DELAY); | 118 | udelay(ZPCI_INSN_BUSY_DELAY); |
115 | } while (cc == 2); | 119 | } while (cc == 2); |
116 | 120 | ||
117 | if (cc) { | 121 | if (cc) |
118 | printk_once(KERN_ERR "%s: error cc: %d status: %d req: %Lx offset: %Lx\n", | 122 | printk_once(KERN_ERR "%s: error cc: %d status: %d req: %Lx offset: %Lx\n", |
119 | __func__, cc, status, req, offset); | 123 | __func__, cc, status, req, offset); |
120 | /* TODO: on IO errors set data to 0xff... | 124 | return (cc > 0) ? -EIO : cc; |
121 | * here or in users of pcilg (le conversion)? | ||
122 | */ | ||
123 | } | ||
124 | return (cc) ? -EIO : 0; | ||
125 | } | 125 | } |
126 | EXPORT_SYMBOL_GPL(s390pci_load); | 126 | EXPORT_SYMBOL_GPL(s390pci_load); |
127 | 127 | ||
128 | /* PCI Store */ | 128 | /* PCI Store */ |
129 | static inline u8 __pcistg(u64 data, u64 req, u64 offset, u8 *status) | 129 | static inline int __pcistg(u64 data, u64 req, u64 offset, u8 *status) |
130 | { | 130 | { |
131 | register u64 __req asm("2") = req; | 131 | register u64 __req asm("2") = req; |
132 | register u64 __offset asm("3") = offset; | 132 | register u64 __offset asm("3") = offset; |
133 | u8 cc; | 133 | int cc = -ENXIO; |
134 | 134 | ||
135 | asm volatile ( | 135 | asm volatile ( |
136 | " .insn rre,0xb9d00000,%[data],%[req]\n" | 136 | " .insn rre,0xb9d00000,%[data],%[req]\n" |
137 | " ipm %[cc]\n" | 137 | "0: ipm %[cc]\n" |
138 | " srl %[cc],28\n" | 138 | " srl %[cc],28\n" |
139 | : [cc] "=d" (cc), [req] "+d" (__req) | 139 | "1:\n" |
140 | EX_TABLE(0b, 1b) | ||
141 | : [cc] "+d" (cc), [req] "+d" (__req) | ||
140 | : "d" (__offset), [data] "d" (data) | 142 | : "d" (__offset), [data] "d" (data) |
141 | : "cc"); | 143 | : "cc"); |
142 | *status = __req >> 24 & 0xff; | 144 | *status = __req >> 24 & 0xff; |
@@ -145,7 +147,8 @@ static inline u8 __pcistg(u64 data, u64 req, u64 offset, u8 *status) | |||
145 | 147 | ||
146 | int s390pci_store(u64 data, u64 req, u64 offset) | 148 | int s390pci_store(u64 data, u64 req, u64 offset) |
147 | { | 149 | { |
148 | u8 cc, status; | 150 | u8 status; |
151 | int cc; | ||
149 | 152 | ||
150 | do { | 153 | do { |
151 | cc = __pcistg(data, req, offset, &status); | 154 | cc = __pcistg(data, req, offset, &status); |
@@ -156,20 +159,22 @@ int s390pci_store(u64 data, u64 req, u64 offset) | |||
156 | if (cc) | 159 | if (cc) |
157 | printk_once(KERN_ERR "%s: error cc: %d status: %d req: %Lx offset: %Lx\n", | 160 | printk_once(KERN_ERR "%s: error cc: %d status: %d req: %Lx offset: %Lx\n", |
158 | __func__, cc, status, req, offset); | 161 | __func__, cc, status, req, offset); |
159 | return (cc) ? -EIO : 0; | 162 | return (cc > 0) ? -EIO : cc; |
160 | } | 163 | } |
161 | EXPORT_SYMBOL_GPL(s390pci_store); | 164 | EXPORT_SYMBOL_GPL(s390pci_store); |
162 | 165 | ||
163 | /* PCI Store Block */ | 166 | /* PCI Store Block */ |
164 | static inline u8 __pcistb(const u64 *data, u64 req, u64 offset, u8 *status) | 167 | static inline int __pcistb(const u64 *data, u64 req, u64 offset, u8 *status) |
165 | { | 168 | { |
166 | u8 cc; | 169 | int cc = -ENXIO; |
167 | 170 | ||
168 | asm volatile ( | 171 | asm volatile ( |
169 | " .insn rsy,0xeb00000000d0,%[req],%[offset],%[data]\n" | 172 | " .insn rsy,0xeb00000000d0,%[req],%[offset],%[data]\n" |
170 | " ipm %[cc]\n" | 173 | "0: ipm %[cc]\n" |
171 | " srl %[cc],28\n" | 174 | " srl %[cc],28\n" |
172 | : [cc] "=d" (cc), [req] "+d" (req) | 175 | "1:\n" |
176 | EX_TABLE(0b, 1b) | ||
177 | : [cc] "+d" (cc), [req] "+d" (req) | ||
173 | : [offset] "d" (offset), [data] "Q" (*data) | 178 | : [offset] "d" (offset), [data] "Q" (*data) |
174 | : "cc"); | 179 | : "cc"); |
175 | *status = req >> 24 & 0xff; | 180 | *status = req >> 24 & 0xff; |
@@ -178,7 +183,8 @@ static inline u8 __pcistb(const u64 *data, u64 req, u64 offset, u8 *status) | |||
178 | 183 | ||
179 | int s390pci_store_block(const u64 *data, u64 req, u64 offset) | 184 | int s390pci_store_block(const u64 *data, u64 req, u64 offset) |
180 | { | 185 | { |
181 | u8 cc, status; | 186 | u8 status; |
187 | int cc; | ||
182 | 188 | ||
183 | do { | 189 | do { |
184 | cc = __pcistb(data, req, offset, &status); | 190 | cc = __pcistb(data, req, offset, &status); |
@@ -189,6 +195,6 @@ int s390pci_store_block(const u64 *data, u64 req, u64 offset) | |||
189 | if (cc) | 195 | if (cc) |
190 | printk_once(KERN_ERR "%s: error cc: %d status: %d req: %Lx offset: %Lx\n", | 196 | printk_once(KERN_ERR "%s: error cc: %d status: %d req: %Lx offset: %Lx\n", |
191 | __func__, cc, status, req, offset); | 197 | __func__, cc, status, req, offset); |
192 | return (cc) ? -EIO : 0; | 198 | return (cc > 0) ? -EIO : cc; |
193 | } | 199 | } |
194 | EXPORT_SYMBOL_GPL(s390pci_store_block); | 200 | EXPORT_SYMBOL_GPL(s390pci_store_block); |