aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndy Shevchenko <andriy.shevchenko@linux.intel.com>2018-05-15 13:32:02 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2018-05-17 06:47:21 -0400
commit63dcc7090137a893322432e156d66be3ce104615 (patch)
tree600312eeea6325c486b706b846ffa62b0c0e3a7f
parent67b8d5c7081221efa252e111cd52532ec6d4266f (diff)
device property: Get rid of union aliasing
Commit 318a19718261 (device property: refactor built-in properties support) went way too far and brought a union aliasing. Partially revert it here to get rid of union aliasing. Note, all Apple properties are considered as u8 arrays. To get a value of any of them the caller must use device_property_read_u8_array(). What's union aliasing? ~~~~~~~~~~~~~~~~~~~~~~ The C99 standard in section 6.2.5 paragraph 20 defines union type as "an overlapping nonempty set of member objects". It also states in section 6.7.2.1 paragraph 14 that "the value of at most one of the members can be stored in a union object at any time'. Union aliasing is a type punning mechanism using union members to store as one type and read back as another. Why it's not good? ~~~~~~~~~~~~~~~~~~ Section 6.2.6.1 paragraph 6 says that a union object may not be a trap representation, although its member objects may be. Meanwhile annex J.1 says that "the value of a union member other than the last one stored into" is unspecified [removed in C11]. In TC3, a footnote is added which specifies that accessing a member of a union other than the last one stored causes "the object representation" to be re-interpreted in the new type and specifically refers to this as "type punning". This conflicts to some degree with Annex J.1. While it's working in Linux with GCC, the use of union members to do type punning is not clear area in the C standard and might lead to unspecified behaviour. More information is available in this [1] blog post. [1]: https://davmac.wordpress.com/2010/02/26/c99-revisited/ Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r--drivers/base/property.c104
-rw-r--r--drivers/firmware/efi/apple-properties.c8
-rw-r--r--include/linux/property.h52
3 files changed, 117 insertions, 47 deletions
diff --git a/drivers/base/property.c b/drivers/base/property.c
index 8f205f6461ed..240ab5230ff6 100644
--- a/drivers/base/property.c
+++ b/drivers/base/property.c
@@ -56,6 +56,72 @@ pset_prop_get(const struct property_set *pset, const char *name)
56 return NULL; 56 return NULL;
57} 57}
58 58
59static const void *property_get_pointer(const struct property_entry *prop)
60{
61 switch (prop->type) {
62 case DEV_PROP_U8:
63 if (prop->is_array)
64 return prop->pointer.u8_data;
65 return &prop->value.u8_data;
66 case DEV_PROP_U16:
67 if (prop->is_array)
68 return prop->pointer.u16_data;
69 return &prop->value.u16_data;
70 case DEV_PROP_U32:
71 if (prop->is_array)
72 return prop->pointer.u32_data;
73 return &prop->value.u32_data;
74 case DEV_PROP_U64:
75 if (prop->is_array)
76 return prop->pointer.u64_data;
77 return &prop->value.u64_data;
78 case DEV_PROP_STRING:
79 if (prop->is_array)
80 return prop->pointer.str;
81 return &prop->value.str;
82 default:
83 return NULL;
84 }
85}
86
87static void property_set_pointer(struct property_entry *prop, const void *pointer)
88{
89 switch (prop->type) {
90 case DEV_PROP_U8:
91 if (prop->is_array)
92 prop->pointer.u8_data = pointer;
93 else
94 prop->value.u8_data = *((u8 *)pointer);
95 break;
96 case DEV_PROP_U16:
97 if (prop->is_array)
98 prop->pointer.u16_data = pointer;
99 else
100 prop->value.u16_data = *((u16 *)pointer);
101 break;
102 case DEV_PROP_U32:
103 if (prop->is_array)
104 prop->pointer.u32_data = pointer;
105 else
106 prop->value.u32_data = *((u32 *)pointer);
107 break;
108 case DEV_PROP_U64:
109 if (prop->is_array)
110 prop->pointer.u64_data = pointer;
111 else
112 prop->value.u64_data = *((u64 *)pointer);
113 break;
114 case DEV_PROP_STRING:
115 if (prop->is_array)
116 prop->pointer.str = pointer;
117 else
118 prop->value.str = pointer;
119 break;
120 default:
121 break;
122 }
123}
124
59static const void *pset_prop_find(const struct property_set *pset, 125static const void *pset_prop_find(const struct property_set *pset,
60 const char *propname, size_t length) 126 const char *propname, size_t length)
61{ 127{
@@ -65,10 +131,7 @@ static const void *pset_prop_find(const struct property_set *pset,
65 prop = pset_prop_get(pset, propname); 131 prop = pset_prop_get(pset, propname);
66 if (!prop) 132 if (!prop)
67 return ERR_PTR(-EINVAL); 133 return ERR_PTR(-EINVAL);
68 if (prop->is_array) 134 pointer = property_get_pointer(prop);
69 pointer = prop->pointer.raw_data;
70 else
71 pointer = &prop->value.raw_data;
72 if (!pointer) 135 if (!pointer)
73 return ERR_PTR(-ENODATA); 136 return ERR_PTR(-ENODATA);
74 if (length > prop->length) 137 if (length > prop->length)
@@ -698,16 +761,17 @@ EXPORT_SYMBOL_GPL(fwnode_property_get_reference_args);
698 761
699static void property_entry_free_data(const struct property_entry *p) 762static void property_entry_free_data(const struct property_entry *p)
700{ 763{
764 const void *pointer = property_get_pointer(p);
701 size_t i, nval; 765 size_t i, nval;
702 766
703 if (p->is_array) { 767 if (p->is_array) {
704 if (p->is_string && p->pointer.str) { 768 if (p->type == DEV_PROP_STRING && p->pointer.str) {
705 nval = p->length / sizeof(const char *); 769 nval = p->length / sizeof(const char *);
706 for (i = 0; i < nval; i++) 770 for (i = 0; i < nval; i++)
707 kfree(p->pointer.str[i]); 771 kfree(p->pointer.str[i]);
708 } 772 }
709 kfree(p->pointer.raw_data); 773 kfree(pointer);
710 } else if (p->is_string) { 774 } else if (p->type == DEV_PROP_STRING) {
711 kfree(p->value.str); 775 kfree(p->value.str);
712 } 776 }
713 kfree(p->name); 777 kfree(p->name);
@@ -716,7 +780,7 @@ static void property_entry_free_data(const struct property_entry *p)
716static int property_copy_string_array(struct property_entry *dst, 780static int property_copy_string_array(struct property_entry *dst,
717 const struct property_entry *src) 781 const struct property_entry *src)
718{ 782{
719 char **d; 783 const char **d;
720 size_t nval = src->length / sizeof(*d); 784 size_t nval = src->length / sizeof(*d);
721 int i; 785 int i;
722 786
@@ -734,40 +798,44 @@ static int property_copy_string_array(struct property_entry *dst,
734 } 798 }
735 } 799 }
736 800
737 dst->pointer.raw_data = d; 801 dst->pointer.str = d;
738 return 0; 802 return 0;
739} 803}
740 804
741static int property_entry_copy_data(struct property_entry *dst, 805static int property_entry_copy_data(struct property_entry *dst,
742 const struct property_entry *src) 806 const struct property_entry *src)
743{ 807{
808 const void *pointer = property_get_pointer(src);
809 const void *new;
744 int error; 810 int error;
745 811
746 if (src->is_array) { 812 if (src->is_array) {
747 if (!src->length) 813 if (!src->length)
748 return -ENODATA; 814 return -ENODATA;
749 815
750 if (src->is_string) { 816 if (src->type == DEV_PROP_STRING) {
751 error = property_copy_string_array(dst, src); 817 error = property_copy_string_array(dst, src);
752 if (error) 818 if (error)
753 return error; 819 return error;
820 new = dst->pointer.str;
754 } else { 821 } else {
755 dst->pointer.raw_data = kmemdup(src->pointer.raw_data, 822 new = kmemdup(pointer, src->length, GFP_KERNEL);
756 src->length, GFP_KERNEL); 823 if (!new)
757 if (!dst->pointer.raw_data)
758 return -ENOMEM; 824 return -ENOMEM;
759 } 825 }
760 } else if (src->is_string) { 826 } else if (src->type == DEV_PROP_STRING) {
761 dst->value.str = kstrdup(src->value.str, GFP_KERNEL); 827 new = kstrdup(src->value.str, GFP_KERNEL);
762 if (!dst->value.str && src->value.str) 828 if (!new && src->value.str)
763 return -ENOMEM; 829 return -ENOMEM;
764 } else { 830 } else {
765 dst->value.raw_data = src->value.raw_data; 831 new = pointer;
766 } 832 }
767 833
768 dst->length = src->length; 834 dst->length = src->length;
769 dst->is_array = src->is_array; 835 dst->is_array = src->is_array;
770 dst->is_string = src->is_string; 836 dst->type = src->type;
837
838 property_set_pointer(dst, new);
771 839
772 dst->name = kstrdup(src->name, GFP_KERNEL); 840 dst->name = kstrdup(src->name, GFP_KERNEL);
773 if (!dst->name) 841 if (!dst->name)
diff --git a/drivers/firmware/efi/apple-properties.c b/drivers/firmware/efi/apple-properties.c
index adaa9a3714b9..60a95719ecb8 100644
--- a/drivers/firmware/efi/apple-properties.c
+++ b/drivers/firmware/efi/apple-properties.c
@@ -13,6 +13,9 @@
13 * 13 *
14 * You should have received a copy of the GNU General Public License 14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see <http://www.gnu.org/licenses/>. 15 * along with this program; if not, see <http://www.gnu.org/licenses/>.
16 *
17 * Note, all properties are considered as u8 arrays.
18 * To get a value of any of them the caller must use device_property_read_u8_array().
16 */ 19 */
17 20
18#define pr_fmt(fmt) "apple-properties: " fmt 21#define pr_fmt(fmt) "apple-properties: " fmt
@@ -96,12 +99,13 @@ static void __init unmarshal_key_value_pairs(struct dev_header *dev_header,
96 entry[i].name = key; 99 entry[i].name = key;
97 entry[i].length = val_len - sizeof(val_len); 100 entry[i].length = val_len - sizeof(val_len);
98 entry[i].is_array = !!entry[i].length; 101 entry[i].is_array = !!entry[i].length;
99 entry[i].pointer.raw_data = ptr + key_len + sizeof(val_len); 102 entry[i].type = DEV_PROP_U8;
103 entry[i].pointer.u8_data = ptr + key_len + sizeof(val_len);
100 104
101 if (dump_properties) { 105 if (dump_properties) {
102 dev_info(dev, "property: %s\n", entry[i].name); 106 dev_info(dev, "property: %s\n", entry[i].name);
103 print_hex_dump(KERN_INFO, pr_fmt(), DUMP_PREFIX_OFFSET, 107 print_hex_dump(KERN_INFO, pr_fmt(), DUMP_PREFIX_OFFSET,
104 16, 1, entry[i].pointer.raw_data, 108 16, 1, entry[i].pointer.u8_data,
105 entry[i].length, true); 109 entry[i].length, true);
106 } 110 }
107 111
diff --git a/include/linux/property.h b/include/linux/property.h
index 2eea4b310fc2..ac8a1ebc4c1b 100644
--- a/include/linux/property.h
+++ b/include/linux/property.h
@@ -178,7 +178,7 @@ static inline int fwnode_property_read_u64(const struct fwnode_handle *fwnode,
178 * @name: Name of the property. 178 * @name: Name of the property.
179 * @length: Length of data making up the value. 179 * @length: Length of data making up the value.
180 * @is_array: True when the property is an array. 180 * @is_array: True when the property is an array.
181 * @is_string: True when property is a string. 181 * @type: Type of the data in unions.
182 * @pointer: Pointer to the property (an array of items of the given type). 182 * @pointer: Pointer to the property (an array of items of the given type).
183 * @value: Value of the property (when it is a single item of the given type). 183 * @value: Value of the property (when it is a single item of the given type).
184 */ 184 */
@@ -186,10 +186,9 @@ struct property_entry {
186 const char *name; 186 const char *name;
187 size_t length; 187 size_t length;
188 bool is_array; 188 bool is_array;
189 bool is_string; 189 enum dev_prop_type type;
190 union { 190 union {
191 union { 191 union {
192 const void *raw_data;
193 const u8 *u8_data; 192 const u8 *u8_data;
194 const u16 *u16_data; 193 const u16 *u16_data;
195 const u32 *u32_data; 194 const u32 *u32_data;
@@ -197,7 +196,6 @@ struct property_entry {
197 const char * const *str; 196 const char * const *str;
198 } pointer; 197 } pointer;
199 union { 198 union {
200 unsigned long long raw_data;
201 u8 u8_data; 199 u8 u8_data;
202 u16 u16_data; 200 u16 u16_data;
203 u32 u32_data; 201 u32 u32_data;
@@ -213,55 +211,55 @@ struct property_entry {
213 * and structs. 211 * and structs.
214 */ 212 */
215 213
216#define PROPERTY_ENTRY_INTEGER_ARRAY(_name_, _type_, _val_) \ 214#define PROPERTY_ENTRY_INTEGER_ARRAY(_name_, _type_, _Type_, _val_) \
217(struct property_entry) { \ 215(struct property_entry) { \
218 .name = _name_, \ 216 .name = _name_, \
219 .length = ARRAY_SIZE(_val_) * sizeof(_type_), \ 217 .length = ARRAY_SIZE(_val_) * sizeof(_type_), \
220 .is_array = true, \ 218 .is_array = true, \
221 .is_string = false, \ 219 .type = DEV_PROP_##_Type_, \
222 { .pointer = { ._type_##_data = _val_ } }, \ 220 { .pointer = { ._type_##_data = _val_ } }, \
223} 221}
224 222
225#define PROPERTY_ENTRY_U8_ARRAY(_name_, _val_) \ 223#define PROPERTY_ENTRY_U8_ARRAY(_name_, _val_) \
226 PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u8, _val_) 224 PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u8, U8, _val_)
227#define PROPERTY_ENTRY_U16_ARRAY(_name_, _val_) \ 225#define PROPERTY_ENTRY_U16_ARRAY(_name_, _val_) \
228 PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u16, _val_) 226 PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u16, U16, _val_)
229#define PROPERTY_ENTRY_U32_ARRAY(_name_, _val_) \ 227#define PROPERTY_ENTRY_U32_ARRAY(_name_, _val_) \
230 PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u32, _val_) 228 PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u32, U32, _val_)
231#define PROPERTY_ENTRY_U64_ARRAY(_name_, _val_) \ 229#define PROPERTY_ENTRY_U64_ARRAY(_name_, _val_) \
232 PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u64, _val_) 230 PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u64, U64, _val_)
233 231
234#define PROPERTY_ENTRY_STRING_ARRAY(_name_, _val_) \ 232#define PROPERTY_ENTRY_STRING_ARRAY(_name_, _val_) \
235(struct property_entry) { \ 233(struct property_entry) { \
236 .name = _name_, \ 234 .name = _name_, \
237 .length = ARRAY_SIZE(_val_) * sizeof(const char *), \ 235 .length = ARRAY_SIZE(_val_) * sizeof(const char *), \
238 .is_array = true, \ 236 .is_array = true, \
239 .is_string = true, \ 237 .type = DEV_PROP_STRING, \
240 { .pointer = { .str = _val_ } }, \ 238 { .pointer = { .str = _val_ } }, \
241} 239}
242 240
243#define PROPERTY_ENTRY_INTEGER(_name_, _type_, _val_) \ 241#define PROPERTY_ENTRY_INTEGER(_name_, _type_, _Type_, _val_) \
244(struct property_entry) { \ 242(struct property_entry) { \
245 .name = _name_, \ 243 .name = _name_, \
246 .length = sizeof(_type_), \ 244 .length = sizeof(_type_), \
247 .is_string = false, \ 245 .type = DEV_PROP_##_Type_, \
248 { .value = { ._type_##_data = _val_ } }, \ 246 { .value = { ._type_##_data = _val_ } }, \
249} 247}
250 248
251#define PROPERTY_ENTRY_U8(_name_, _val_) \ 249#define PROPERTY_ENTRY_U8(_name_, _val_) \
252 PROPERTY_ENTRY_INTEGER(_name_, u8, _val_) 250 PROPERTY_ENTRY_INTEGER(_name_, u8, U8, _val_)
253#define PROPERTY_ENTRY_U16(_name_, _val_) \ 251#define PROPERTY_ENTRY_U16(_name_, _val_) \
254 PROPERTY_ENTRY_INTEGER(_name_, u16, _val_) 252 PROPERTY_ENTRY_INTEGER(_name_, u16, U16, _val_)
255#define PROPERTY_ENTRY_U32(_name_, _val_) \ 253#define PROPERTY_ENTRY_U32(_name_, _val_) \
256 PROPERTY_ENTRY_INTEGER(_name_, u32, _val_) 254 PROPERTY_ENTRY_INTEGER(_name_, u32, U32, _val_)
257#define PROPERTY_ENTRY_U64(_name_, _val_) \ 255#define PROPERTY_ENTRY_U64(_name_, _val_) \
258 PROPERTY_ENTRY_INTEGER(_name_, u64, _val_) 256 PROPERTY_ENTRY_INTEGER(_name_, u64, U64, _val_)
259 257
260#define PROPERTY_ENTRY_STRING(_name_, _val_) \ 258#define PROPERTY_ENTRY_STRING(_name_, _val_) \
261(struct property_entry) { \ 259(struct property_entry) { \
262 .name = _name_, \ 260 .name = _name_, \
263 .length = sizeof(_val_), \ 261 .length = sizeof(_val_), \
264 .is_string = true, \ 262 .type = DEV_PROP_STRING, \
265 { .value = { .str = _val_ } }, \ 263 { .value = { .str = _val_ } }, \
266} 264}
267 265