diff options
author | Matt Fleming <matt.fleming@intel.com> | 2014-03-27 18:10:39 -0400 |
---|---|---|
committer | Matt Fleming <matt.fleming@intel.com> | 2014-04-17 08:26:30 -0400 |
commit | 62fa6e69a436f662090f3996538adb9e568817f6 (patch) | |
tree | 445c95f20eb3ad3e35073e3612a58ba4feebbfa5 | |
parent | c625d1c203941fad755eb4eb729db1f65d6e9836 (diff) |
x86/efi: Delete most of the efi_call* macros
We really only need one phys and one virt function call, and then only
one assembly function to make firmware calls.
Since we are not using the C type system anyway, we're not really losing
much by deleting the macros apart from no longer having a check that
we are passing the correct number of parameters. The lack of duplicated
code seems like a worthwhile trade-off.
Cc: Ricardo Neri <ricardo.neri-calderon@linux.intel.com>
Cc: Borislav Petkov <bp@suse.de>
Signed-off-by: Matt Fleming <matt.fleming@intel.com>
-rw-r--r-- | arch/x86/boot/compressed/head_64.S | 2 | ||||
-rw-r--r-- | arch/x86/include/asm/efi.h | 74 | ||||
-rw-r--r-- | arch/x86/platform/efi/efi.c | 48 | ||||
-rw-r--r-- | arch/x86/platform/efi/efi_stub_64.S | 81 | ||||
-rw-r--r-- | arch/x86/platform/uv/bios_uv.c | 2 |
5 files changed, 35 insertions, 172 deletions
diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S index 0d558ee899ae..2884e0c3e8a5 100644 --- a/arch/x86/boot/compressed/head_64.S +++ b/arch/x86/boot/compressed/head_64.S | |||
@@ -452,7 +452,7 @@ efi32_config: | |||
452 | .global efi64_config | 452 | .global efi64_config |
453 | efi64_config: | 453 | efi64_config: |
454 | .fill 11,8,0 | 454 | .fill 11,8,0 |
455 | .quad efi_call6 | 455 | .quad efi_call |
456 | .byte 1 | 456 | .byte 1 |
457 | #endif /* CONFIG_EFI_STUB */ | 457 | #endif /* CONFIG_EFI_STUB */ |
458 | 458 | ||
diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h index 0869434eaf72..e3975597b289 100644 --- a/arch/x86/include/asm/efi.h +++ b/arch/x86/include/asm/efi.h | |||
@@ -27,16 +27,6 @@ | |||
27 | 27 | ||
28 | extern unsigned long asmlinkage efi_call_phys(void *, ...); | 28 | extern unsigned long asmlinkage efi_call_phys(void *, ...); |
29 | 29 | ||
30 | #define efi_call_phys0(f) efi_call_phys(f) | ||
31 | #define efi_call_phys1(f, a1) efi_call_phys(f, a1) | ||
32 | #define efi_call_phys2(f, a1, a2) efi_call_phys(f, a1, a2) | ||
33 | #define efi_call_phys3(f, a1, a2, a3) efi_call_phys(f, a1, a2, a3) | ||
34 | #define efi_call_phys4(f, a1, a2, a3, a4) \ | ||
35 | efi_call_phys(f, a1, a2, a3, a4) | ||
36 | #define efi_call_phys5(f, a1, a2, a3, a4, a5) \ | ||
37 | efi_call_phys(f, a1, a2, a3, a4, a5) | ||
38 | #define efi_call_phys6(f, a1, a2, a3, a4, a5, a6) \ | ||
39 | efi_call_phys(f, a1, a2, a3, a4, a5, a6) | ||
40 | /* | 30 | /* |
41 | * Wrap all the virtual calls in a way that forces the parameters on the stack. | 31 | * Wrap all the virtual calls in a way that forces the parameters on the stack. |
42 | */ | 32 | */ |
@@ -44,75 +34,27 @@ extern unsigned long asmlinkage efi_call_phys(void *, ...); | |||
44 | #define efi_call_virt(f, args...) \ | 34 | #define efi_call_virt(f, args...) \ |
45 | ((efi_##f##_t __attribute__((regparm(0)))*)efi.systab->runtime->f)(args) | 35 | ((efi_##f##_t __attribute__((regparm(0)))*)efi.systab->runtime->f)(args) |
46 | 36 | ||
47 | #define efi_call_virt0(f) efi_call_virt(f) | ||
48 | #define efi_call_virt1(f, a1) efi_call_virt(f, a1) | ||
49 | #define efi_call_virt2(f, a1, a2) efi_call_virt(f, a1, a2) | ||
50 | #define efi_call_virt3(f, a1, a2, a3) efi_call_virt(f, a1, a2, a3) | ||
51 | #define efi_call_virt4(f, a1, a2, a3, a4) \ | ||
52 | efi_call_virt(f, a1, a2, a3, a4) | ||
53 | #define efi_call_virt5(f, a1, a2, a3, a4, a5) \ | ||
54 | efi_call_virt(f, a1, a2, a3, a4, a5) | ||
55 | #define efi_call_virt6(f, a1, a2, a3, a4, a5, a6) \ | ||
56 | efi_call_virt(f, a1, a2, a3, a4, a5, a6) | ||
57 | |||
58 | #define efi_ioremap(addr, size, type, attr) ioremap_cache(addr, size) | 37 | #define efi_ioremap(addr, size, type, attr) ioremap_cache(addr, size) |
59 | 38 | ||
60 | #else /* !CONFIG_X86_32 */ | 39 | #else /* !CONFIG_X86_32 */ |
61 | 40 | ||
62 | extern u64 efi_call0(void *fp); | 41 | #define EFI_LOADER_SIGNATURE "EL64" |
63 | extern u64 efi_call1(void *fp, u64 arg1); | 42 | |
64 | extern u64 efi_call2(void *fp, u64 arg1, u64 arg2); | 43 | extern u64 asmlinkage efi_call(void *fp, ...); |
65 | extern u64 efi_call3(void *fp, u64 arg1, u64 arg2, u64 arg3); | 44 | |
66 | extern u64 efi_call4(void *fp, u64 arg1, u64 arg2, u64 arg3, u64 arg4); | 45 | #define efi_call_phys(f, args...) efi_call((f), args) |
67 | extern u64 efi_call5(void *fp, u64 arg1, u64 arg2, u64 arg3, | 46 | |
68 | u64 arg4, u64 arg5); | 47 | #define efi_call_virt(f, ...) \ |
69 | extern u64 efi_call6(void *fp, u64 arg1, u64 arg2, u64 arg3, | ||
70 | u64 arg4, u64 arg5, u64 arg6); | ||
71 | |||
72 | #define efi_call_phys0(f) \ | ||
73 | efi_call0((f)) | ||
74 | #define efi_call_phys1(f, a1) \ | ||
75 | efi_call1((f), (u64)(a1)) | ||
76 | #define efi_call_phys2(f, a1, a2) \ | ||
77 | efi_call2((f), (u64)(a1), (u64)(a2)) | ||
78 | #define efi_call_phys3(f, a1, a2, a3) \ | ||
79 | efi_call3((f), (u64)(a1), (u64)(a2), (u64)(a3)) | ||
80 | #define efi_call_phys4(f, a1, a2, a3, a4) \ | ||
81 | efi_call4((f), (u64)(a1), (u64)(a2), (u64)(a3), \ | ||
82 | (u64)(a4)) | ||
83 | #define efi_call_phys5(f, a1, a2, a3, a4, a5) \ | ||
84 | efi_call5((f), (u64)(a1), (u64)(a2), (u64)(a3), \ | ||
85 | (u64)(a4), (u64)(a5)) | ||
86 | #define efi_call_phys6(f, a1, a2, a3, a4, a5, a6) \ | ||
87 | efi_call6((f), (u64)(a1), (u64)(a2), (u64)(a3), \ | ||
88 | (u64)(a4), (u64)(a5), (u64)(a6)) | ||
89 | |||
90 | #define _efi_call_virtX(x, f, ...) \ | ||
91 | ({ \ | 48 | ({ \ |
92 | efi_status_t __s; \ | 49 | efi_status_t __s; \ |
93 | \ | 50 | \ |
94 | efi_sync_low_kernel_mappings(); \ | 51 | efi_sync_low_kernel_mappings(); \ |
95 | preempt_disable(); \ | 52 | preempt_disable(); \ |
96 | __s = efi_call##x((void *)efi.systab->runtime->f, __VA_ARGS__); \ | 53 | __s = efi_call((void *)efi.systab->runtime->f, __VA_ARGS__); \ |
97 | preempt_enable(); \ | 54 | preempt_enable(); \ |
98 | __s; \ | 55 | __s; \ |
99 | }) | 56 | }) |
100 | 57 | ||
101 | #define efi_call_virt0(f) \ | ||
102 | _efi_call_virtX(0, f) | ||
103 | #define efi_call_virt1(f, a1) \ | ||
104 | _efi_call_virtX(1, f, (u64)(a1)) | ||
105 | #define efi_call_virt2(f, a1, a2) \ | ||
106 | _efi_call_virtX(2, f, (u64)(a1), (u64)(a2)) | ||
107 | #define efi_call_virt3(f, a1, a2, a3) \ | ||
108 | _efi_call_virtX(3, f, (u64)(a1), (u64)(a2), (u64)(a3)) | ||
109 | #define efi_call_virt4(f, a1, a2, a3, a4) \ | ||
110 | _efi_call_virtX(4, f, (u64)(a1), (u64)(a2), (u64)(a3), (u64)(a4)) | ||
111 | #define efi_call_virt5(f, a1, a2, a3, a4, a5) \ | ||
112 | _efi_call_virtX(5, f, (u64)(a1), (u64)(a2), (u64)(a3), (u64)(a4), (u64)(a5)) | ||
113 | #define efi_call_virt6(f, a1, a2, a3, a4, a5, a6) \ | ||
114 | _efi_call_virtX(6, f, (u64)(a1), (u64)(a2), (u64)(a3), (u64)(a4), (u64)(a5), (u64)(a6)) | ||
115 | |||
116 | extern void __iomem *efi_ioremap(unsigned long addr, unsigned long size, | 58 | extern void __iomem *efi_ioremap(unsigned long addr, unsigned long size, |
117 | u32 type, u64 attribute); | 59 | u32 type, u64 attribute); |
118 | 60 | ||
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index 3781dd39e8bd..8f6531e8d32f 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c | |||
@@ -110,7 +110,7 @@ static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc) | |||
110 | efi_status_t status; | 110 | efi_status_t status; |
111 | 111 | ||
112 | spin_lock_irqsave(&rtc_lock, flags); | 112 | spin_lock_irqsave(&rtc_lock, flags); |
113 | status = efi_call_virt2(get_time, tm, tc); | 113 | status = efi_call_virt(get_time, tm, tc); |
114 | spin_unlock_irqrestore(&rtc_lock, flags); | 114 | spin_unlock_irqrestore(&rtc_lock, flags); |
115 | return status; | 115 | return status; |
116 | } | 116 | } |
@@ -121,7 +121,7 @@ static efi_status_t virt_efi_set_time(efi_time_t *tm) | |||
121 | efi_status_t status; | 121 | efi_status_t status; |
122 | 122 | ||
123 | spin_lock_irqsave(&rtc_lock, flags); | 123 | spin_lock_irqsave(&rtc_lock, flags); |
124 | status = efi_call_virt1(set_time, tm); | 124 | status = efi_call_virt(set_time, tm); |
125 | spin_unlock_irqrestore(&rtc_lock, flags); | 125 | spin_unlock_irqrestore(&rtc_lock, flags); |
126 | return status; | 126 | return status; |
127 | } | 127 | } |
@@ -134,8 +134,7 @@ static efi_status_t virt_efi_get_wakeup_time(efi_bool_t *enabled, | |||
134 | efi_status_t status; | 134 | efi_status_t status; |
135 | 135 | ||
136 | spin_lock_irqsave(&rtc_lock, flags); | 136 | spin_lock_irqsave(&rtc_lock, flags); |
137 | status = efi_call_virt3(get_wakeup_time, | 137 | status = efi_call_virt(get_wakeup_time, enabled, pending, tm); |
138 | enabled, pending, tm); | ||
139 | spin_unlock_irqrestore(&rtc_lock, flags); | 138 | spin_unlock_irqrestore(&rtc_lock, flags); |
140 | return status; | 139 | return status; |
141 | } | 140 | } |
@@ -146,8 +145,7 @@ static efi_status_t virt_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm) | |||
146 | efi_status_t status; | 145 | efi_status_t status; |
147 | 146 | ||
148 | spin_lock_irqsave(&rtc_lock, flags); | 147 | spin_lock_irqsave(&rtc_lock, flags); |
149 | status = efi_call_virt2(set_wakeup_time, | 148 | status = efi_call_virt(set_wakeup_time, enabled, tm); |
150 | enabled, tm); | ||
151 | spin_unlock_irqrestore(&rtc_lock, flags); | 149 | spin_unlock_irqrestore(&rtc_lock, flags); |
152 | return status; | 150 | return status; |
153 | } | 151 | } |
@@ -158,17 +156,17 @@ static efi_status_t virt_efi_get_variable(efi_char16_t *name, | |||
158 | unsigned long *data_size, | 156 | unsigned long *data_size, |
159 | void *data) | 157 | void *data) |
160 | { | 158 | { |
161 | return efi_call_virt5(get_variable, | 159 | return efi_call_virt(get_variable, |
162 | name, vendor, attr, | 160 | name, vendor, attr, |
163 | data_size, data); | 161 | data_size, data); |
164 | } | 162 | } |
165 | 163 | ||
166 | static efi_status_t virt_efi_get_next_variable(unsigned long *name_size, | 164 | static efi_status_t virt_efi_get_next_variable(unsigned long *name_size, |
167 | efi_char16_t *name, | 165 | efi_char16_t *name, |
168 | efi_guid_t *vendor) | 166 | efi_guid_t *vendor) |
169 | { | 167 | { |
170 | return efi_call_virt3(get_next_variable, | 168 | return efi_call_virt(get_next_variable, |
171 | name_size, name, vendor); | 169 | name_size, name, vendor); |
172 | } | 170 | } |
173 | 171 | ||
174 | static efi_status_t virt_efi_set_variable(efi_char16_t *name, | 172 | static efi_status_t virt_efi_set_variable(efi_char16_t *name, |
@@ -177,9 +175,9 @@ static efi_status_t virt_efi_set_variable(efi_char16_t *name, | |||
177 | unsigned long data_size, | 175 | unsigned long data_size, |
178 | void *data) | 176 | void *data) |
179 | { | 177 | { |
180 | return efi_call_virt5(set_variable, | 178 | return efi_call_virt(set_variable, |
181 | name, vendor, attr, | 179 | name, vendor, attr, |
182 | data_size, data); | 180 | data_size, data); |
183 | } | 181 | } |
184 | 182 | ||
185 | static efi_status_t virt_efi_query_variable_info(u32 attr, | 183 | static efi_status_t virt_efi_query_variable_info(u32 attr, |
@@ -190,13 +188,13 @@ static efi_status_t virt_efi_query_variable_info(u32 attr, | |||
190 | if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) | 188 | if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) |
191 | return EFI_UNSUPPORTED; | 189 | return EFI_UNSUPPORTED; |
192 | 190 | ||
193 | return efi_call_virt4(query_variable_info, attr, storage_space, | 191 | return efi_call_virt(query_variable_info, attr, storage_space, |
194 | remaining_space, max_variable_size); | 192 | remaining_space, max_variable_size); |
195 | } | 193 | } |
196 | 194 | ||
197 | static efi_status_t virt_efi_get_next_high_mono_count(u32 *count) | 195 | static efi_status_t virt_efi_get_next_high_mono_count(u32 *count) |
198 | { | 196 | { |
199 | return efi_call_virt1(get_next_high_mono_count, count); | 197 | return efi_call_virt(get_next_high_mono_count, count); |
200 | } | 198 | } |
201 | 199 | ||
202 | static void virt_efi_reset_system(int reset_type, | 200 | static void virt_efi_reset_system(int reset_type, |
@@ -204,8 +202,8 @@ static void virt_efi_reset_system(int reset_type, | |||
204 | unsigned long data_size, | 202 | unsigned long data_size, |
205 | efi_char16_t *data) | 203 | efi_char16_t *data) |
206 | { | 204 | { |
207 | efi_call_virt4(reset_system, reset_type, status, | 205 | efi_call_virt(reset_system, reset_type, status, |
208 | data_size, data); | 206 | data_size, data); |
209 | } | 207 | } |
210 | 208 | ||
211 | static efi_status_t virt_efi_update_capsule(efi_capsule_header_t **capsules, | 209 | static efi_status_t virt_efi_update_capsule(efi_capsule_header_t **capsules, |
@@ -215,7 +213,7 @@ static efi_status_t virt_efi_update_capsule(efi_capsule_header_t **capsules, | |||
215 | if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) | 213 | if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) |
216 | return EFI_UNSUPPORTED; | 214 | return EFI_UNSUPPORTED; |
217 | 215 | ||
218 | return efi_call_virt3(update_capsule, capsules, count, sg_list); | 216 | return efi_call_virt(update_capsule, capsules, count, sg_list); |
219 | } | 217 | } |
220 | 218 | ||
221 | static efi_status_t virt_efi_query_capsule_caps(efi_capsule_header_t **capsules, | 219 | static efi_status_t virt_efi_query_capsule_caps(efi_capsule_header_t **capsules, |
@@ -226,8 +224,8 @@ static efi_status_t virt_efi_query_capsule_caps(efi_capsule_header_t **capsules, | |||
226 | if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) | 224 | if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) |
227 | return EFI_UNSUPPORTED; | 225 | return EFI_UNSUPPORTED; |
228 | 226 | ||
229 | return efi_call_virt4(query_capsule_caps, capsules, count, max_size, | 227 | return efi_call_virt(query_capsule_caps, capsules, count, max_size, |
230 | reset_type); | 228 | reset_type); |
231 | } | 229 | } |
232 | 230 | ||
233 | static efi_status_t __init phys_efi_set_virtual_address_map( | 231 | static efi_status_t __init phys_efi_set_virtual_address_map( |
@@ -239,9 +237,9 @@ static efi_status_t __init phys_efi_set_virtual_address_map( | |||
239 | efi_status_t status; | 237 | efi_status_t status; |
240 | 238 | ||
241 | efi_call_phys_prelog(); | 239 | efi_call_phys_prelog(); |
242 | status = efi_call_phys4(efi_phys.set_virtual_address_map, | 240 | status = efi_call_phys(efi_phys.set_virtual_address_map, |
243 | memory_map_size, descriptor_size, | 241 | memory_map_size, descriptor_size, |
244 | descriptor_version, virtual_map); | 242 | descriptor_version, virtual_map); |
245 | efi_call_phys_epilog(); | 243 | efi_call_phys_epilog(); |
246 | return status; | 244 | return status; |
247 | } | 245 | } |
diff --git a/arch/x86/platform/efi/efi_stub_64.S b/arch/x86/platform/efi/efi_stub_64.S index e0984ef0374b..5fcda7272550 100644 --- a/arch/x86/platform/efi/efi_stub_64.S +++ b/arch/x86/platform/efi/efi_stub_64.S | |||
@@ -73,84 +73,7 @@ | |||
73 | 2: | 73 | 2: |
74 | .endm | 74 | .endm |
75 | 75 | ||
76 | ENTRY(efi_call0) | 76 | ENTRY(efi_call) |
77 | SAVE_XMM | ||
78 | subq $32, %rsp | ||
79 | SWITCH_PGT | ||
80 | call *%rdi | ||
81 | RESTORE_PGT | ||
82 | addq $32, %rsp | ||
83 | RESTORE_XMM | ||
84 | ret | ||
85 | ENDPROC(efi_call0) | ||
86 | |||
87 | ENTRY(efi_call1) | ||
88 | SAVE_XMM | ||
89 | subq $32, %rsp | ||
90 | mov %rsi, %rcx | ||
91 | SWITCH_PGT | ||
92 | call *%rdi | ||
93 | RESTORE_PGT | ||
94 | addq $32, %rsp | ||
95 | RESTORE_XMM | ||
96 | ret | ||
97 | ENDPROC(efi_call1) | ||
98 | |||
99 | ENTRY(efi_call2) | ||
100 | SAVE_XMM | ||
101 | subq $32, %rsp | ||
102 | mov %rsi, %rcx | ||
103 | SWITCH_PGT | ||
104 | call *%rdi | ||
105 | RESTORE_PGT | ||
106 | addq $32, %rsp | ||
107 | RESTORE_XMM | ||
108 | ret | ||
109 | ENDPROC(efi_call2) | ||
110 | |||
111 | ENTRY(efi_call3) | ||
112 | SAVE_XMM | ||
113 | subq $32, %rsp | ||
114 | mov %rcx, %r8 | ||
115 | mov %rsi, %rcx | ||
116 | SWITCH_PGT | ||
117 | call *%rdi | ||
118 | RESTORE_PGT | ||
119 | addq $32, %rsp | ||
120 | RESTORE_XMM | ||
121 | ret | ||
122 | ENDPROC(efi_call3) | ||
123 | |||
124 | ENTRY(efi_call4) | ||
125 | SAVE_XMM | ||
126 | subq $32, %rsp | ||
127 | mov %r8, %r9 | ||
128 | mov %rcx, %r8 | ||
129 | mov %rsi, %rcx | ||
130 | SWITCH_PGT | ||
131 | call *%rdi | ||
132 | RESTORE_PGT | ||
133 | addq $32, %rsp | ||
134 | RESTORE_XMM | ||
135 | ret | ||
136 | ENDPROC(efi_call4) | ||
137 | |||
138 | ENTRY(efi_call5) | ||
139 | SAVE_XMM | ||
140 | subq $48, %rsp | ||
141 | mov %r9, 32(%rsp) | ||
142 | mov %r8, %r9 | ||
143 | mov %rcx, %r8 | ||
144 | mov %rsi, %rcx | ||
145 | SWITCH_PGT | ||
146 | call *%rdi | ||
147 | RESTORE_PGT | ||
148 | addq $48, %rsp | ||
149 | RESTORE_XMM | ||
150 | ret | ||
151 | ENDPROC(efi_call5) | ||
152 | |||
153 | ENTRY(efi_call6) | ||
154 | SAVE_XMM | 77 | SAVE_XMM |
155 | mov (%rsp), %rax | 78 | mov (%rsp), %rax |
156 | mov 8(%rax), %rax | 79 | mov 8(%rax), %rax |
@@ -166,7 +89,7 @@ ENTRY(efi_call6) | |||
166 | addq $48, %rsp | 89 | addq $48, %rsp |
167 | RESTORE_XMM | 90 | RESTORE_XMM |
168 | ret | 91 | ret |
169 | ENDPROC(efi_call6) | 92 | ENDPROC(efi_call) |
170 | 93 | ||
171 | #ifdef CONFIG_EFI_MIXED | 94 | #ifdef CONFIG_EFI_MIXED |
172 | 95 | ||
diff --git a/arch/x86/platform/uv/bios_uv.c b/arch/x86/platform/uv/bios_uv.c index 766612137a62..1584cbed0dce 100644 --- a/arch/x86/platform/uv/bios_uv.c +++ b/arch/x86/platform/uv/bios_uv.c | |||
@@ -39,7 +39,7 @@ s64 uv_bios_call(enum uv_bios_cmd which, u64 a1, u64 a2, u64 a3, u64 a4, u64 a5) | |||
39 | */ | 39 | */ |
40 | return BIOS_STATUS_UNIMPLEMENTED; | 40 | return BIOS_STATUS_UNIMPLEMENTED; |
41 | 41 | ||
42 | ret = efi_call6((void *)__va(tab->function), (u64)which, | 42 | ret = efi_call((void *)__va(tab->function), (u64)which, |
43 | a1, a2, a3, a4, a5); | 43 | a1, a2, a3, a4, a5); |
44 | return ret; | 44 | return ret; |
45 | } | 45 | } |