22/* Copyright(c) 2022 Intel Corporation. */
33
44#include <linux/firmware.h>
5+ #include <linux/sizes.h>
56#include <asm/cpu.h>
67#include <asm/microcode.h>
78
@@ -26,6 +27,11 @@ union meta_data {
2627
2728#define IFS_HEADER_SIZE (sizeof(struct microcode_header_intel))
2829#define META_TYPE_IFS 1
30+ #define INVALIDATE_STRIDE 0x1UL
31+ #define IFS_GEN_STRIDE_AWARE 2
32+ #define AUTH_INTERRUPTED_ERROR 5
33+ #define IFS_AUTH_RETRY_CT 10
34+
2935static struct microcode_header_intel * ifs_header_ptr ; /* pointer to the ifs image header */
3036static u64 ifs_hash_ptr ; /* Address of ifs metadata (hash) */
3137static u64 ifs_test_image_ptr ; /* 256B aligned address of test pattern */
@@ -44,7 +50,10 @@ static const char * const scan_hash_status[] = {
4450static const char * const scan_authentication_status [] = {
4551 [0 ] = "No error reported" ,
4652 [1 ] = "Attempt to authenticate a chunk which is already marked as authentic" ,
47- [2 ] = "Chunk authentication error. The hash of chunk did not match expected value"
53+ [2 ] = "Chunk authentication error. The hash of chunk did not match expected value" ,
54+ [3 ] = "Reserved" ,
55+ [4 ] = "Chunk outside the current stride" ,
56+ [5 ] = "Authentication flow interrupted" ,
4857};
4958
5059#define MC_HEADER_META_TYPE_END (0)
@@ -154,6 +163,102 @@ static void copy_hashes_authenticate_chunks(struct work_struct *work)
154163 complete (& ifs_done );
155164}
156165
166+ static int get_num_chunks (int gen , union ifs_scan_hashes_status_gen2 status )
167+ {
168+ return gen >= IFS_GEN_STRIDE_AWARE ? status .chunks_in_stride : status .num_chunks ;
169+ }
170+
171+ static bool need_copy_scan_hashes (struct ifs_data * ifsd )
172+ {
173+ return !ifsd -> loaded ||
174+ ifsd -> generation < IFS_GEN_STRIDE_AWARE ||
175+ ifsd -> loaded_version != ifs_header_ptr -> rev ;
176+ }
177+
178+ static int copy_hashes_authenticate_chunks_gen2 (struct device * dev )
179+ {
180+ union ifs_scan_hashes_status_gen2 hashes_status ;
181+ union ifs_chunks_auth_status_gen2 chunk_status ;
182+ u32 err_code , valid_chunks , total_chunks ;
183+ int i , num_chunks , chunk_size ;
184+ union meta_data * ifs_meta ;
185+ int starting_chunk_nr ;
186+ struct ifs_data * ifsd ;
187+ u64 linear_addr , base ;
188+ u64 chunk_table [2 ];
189+ int retry_count ;
190+
191+ ifsd = ifs_get_data (dev );
192+
193+ if (need_copy_scan_hashes (ifsd )) {
194+ wrmsrl (MSR_COPY_SCAN_HASHES , ifs_hash_ptr );
195+ rdmsrl (MSR_SCAN_HASHES_STATUS , hashes_status .data );
196+
197+ /* enumerate the scan image information */
198+ chunk_size = hashes_status .chunk_size * SZ_1K ;
199+ err_code = hashes_status .error_code ;
200+
201+ num_chunks = get_num_chunks (ifsd -> generation , hashes_status );
202+
203+ if (!hashes_status .valid ) {
204+ hashcopy_err_message (dev , err_code );
205+ return - EIO ;
206+ }
207+ ifsd -> loaded_version = ifs_header_ptr -> rev ;
208+ ifsd -> chunk_size = chunk_size ;
209+ } else {
210+ num_chunks = ifsd -> valid_chunks ;
211+ chunk_size = ifsd -> chunk_size ;
212+ }
213+
214+ if (ifsd -> generation >= IFS_GEN_STRIDE_AWARE ) {
215+ wrmsrl (MSR_SAF_CTRL , INVALIDATE_STRIDE );
216+ rdmsrl (MSR_CHUNKS_AUTHENTICATION_STATUS , chunk_status .data );
217+ if (chunk_status .valid_chunks != 0 ) {
218+ dev_err (dev , "Couldn't invalidate installed stride - %d\n" ,
219+ chunk_status .valid_chunks );
220+ return - EIO ;
221+ }
222+ }
223+
224+ base = ifs_test_image_ptr ;
225+ ifs_meta = (union meta_data * )find_meta_data (ifs_header_ptr , META_TYPE_IFS );
226+ starting_chunk_nr = ifs_meta -> starting_chunk ;
227+
228+ /* scan data authentication and copy chunks to secured memory */
229+ for (i = 0 ; i < num_chunks ; i ++ ) {
230+ retry_count = IFS_AUTH_RETRY_CT ;
231+ linear_addr = base + i * chunk_size ;
232+
233+ chunk_table [0 ] = starting_chunk_nr + i ;
234+ chunk_table [1 ] = linear_addr ;
235+ do {
236+ wrmsrl (MSR_AUTHENTICATE_AND_COPY_CHUNK , (u64 )chunk_table );
237+ rdmsrl (MSR_CHUNKS_AUTHENTICATION_STATUS , chunk_status .data );
238+ err_code = chunk_status .error_code ;
239+ } while (err_code == AUTH_INTERRUPTED_ERROR && -- retry_count );
240+
241+ if (err_code ) {
242+ ifsd -> loading_error = true;
243+ auth_err_message (dev , err_code );
244+ return - EIO ;
245+ }
246+ }
247+
248+ valid_chunks = chunk_status .valid_chunks ;
249+ total_chunks = chunk_status .total_chunks ;
250+
251+ if (valid_chunks != total_chunks ) {
252+ ifsd -> loading_error = true;
253+ dev_err (dev , "Couldn't authenticate all the chunks. Authenticated %d total %d.\n" ,
254+ valid_chunks , total_chunks );
255+ return - EIO ;
256+ }
257+ ifsd -> valid_chunks = valid_chunks ;
258+
259+ return 0 ;
260+ }
261+
157262static int validate_ifs_metadata (struct device * dev )
158263{
159264 struct ifs_data * ifsd = ifs_get_data (dev );
@@ -206,7 +311,9 @@ static int scan_chunks_sanity_check(struct device *dev)
206311 return ret ;
207312
208313 ifsd -> loading_error = false;
209- ifsd -> loaded_version = ifs_header_ptr -> rev ;
314+
315+ if (ifsd -> generation > 0 )
316+ return copy_hashes_authenticate_chunks_gen2 (dev );
210317
211318 /* copy the scan hash and authenticate per package */
212319 cpus_read_lock ();
@@ -226,6 +333,7 @@ static int scan_chunks_sanity_check(struct device *dev)
226333 ifs_pkg_auth [curr_pkg ] = 1 ;
227334 }
228335 ret = 0 ;
336+ ifsd -> loaded_version = ifs_header_ptr -> rev ;
229337out :
230338 cpus_read_unlock ();
231339
0 commit comments