1313#define pr_fmt (fmt ) "microcode: " fmt
1414#include <linux/earlycpio.h>
1515#include <linux/firmware.h>
16+ #include <linux/pci_ids.h>
1617#include <linux/uaccess.h>
1718#include <linux/initrd.h>
1819#include <linux/kernel.h>
@@ -41,8 +42,31 @@ static const char ucode_path[] = "kernel/x86/microcode/GenuineIntel.bin";
4142
4243#define MBOX_CONTROL_OFFSET 0x0
4344#define MBOX_STATUS_OFFSET 0x4
45+ #define MBOX_WRDATA_OFFSET 0x8
46+ #define MBOX_RDDATA_OFFSET 0xc
4447
4548#define MASK_MBOX_CTRL_ABORT BIT(0)
49+ #define MASK_MBOX_CTRL_GO BIT(31)
50+
51+ #define MASK_MBOX_STATUS_ERROR BIT(2)
52+ #define MASK_MBOX_STATUS_READY BIT(31)
53+
54+ #define MASK_MBOX_RESP_SUCCESS BIT(0)
55+ #define MASK_MBOX_RESP_PROGRESS BIT(1)
56+ #define MASK_MBOX_RESP_ERROR BIT(2)
57+
58+ #define MBOX_CMD_LOAD 0x3
59+ #define MBOX_OBJ_STAGING 0xb
60+ #define MBOX_HEADER (size ) ((PCI_VENDOR_ID_INTEL) | \
61+ (MBOX_OBJ_STAGING << 16) | \
62+ ((u64)((size) / sizeof(u32)) << 32))
63+
64+ /* The size of each mailbox header */
65+ #define MBOX_HEADER_SIZE sizeof(u64)
66+ /* The size of staging hardware response */
67+ #define MBOX_RESPONSE_SIZE sizeof(u64)
68+
69+ #define MBOX_XACTION_TIMEOUT_MS (10 * MSEC_PER_SEC)
4670
4771/* Current microcode patch used in early patching on the APs. */
4872static struct microcode_intel * ucode_patch_va __read_mostly ;
@@ -327,6 +351,49 @@ static __init struct microcode_intel *scan_microcode(void *data, size_t size,
327351 return size ? NULL : patch ;
328352}
329353
354+ static inline u32 read_mbox_dword (void __iomem * mmio_base )
355+ {
356+ u32 dword = readl (mmio_base + MBOX_RDDATA_OFFSET );
357+
358+ /* Acknowledge read completion to the staging hardware */
359+ writel (0 , mmio_base + MBOX_RDDATA_OFFSET );
360+ return dword ;
361+ }
362+
363+ static inline void write_mbox_dword (void __iomem * mmio_base , u32 dword )
364+ {
365+ writel (dword , mmio_base + MBOX_WRDATA_OFFSET );
366+ }
367+
368+ static inline u64 read_mbox_header (void __iomem * mmio_base )
369+ {
370+ u32 high , low ;
371+
372+ low = read_mbox_dword (mmio_base );
373+ high = read_mbox_dword (mmio_base );
374+
375+ return ((u64 )high << 32 ) | low ;
376+ }
377+
378+ static inline void write_mbox_header (void __iomem * mmio_base , u64 value )
379+ {
380+ write_mbox_dword (mmio_base , value );
381+ write_mbox_dword (mmio_base , value >> 32 );
382+ }
383+
384+ static void write_mbox_data (void __iomem * mmio_base , u32 * chunk , unsigned int chunk_bytes )
385+ {
386+ int i ;
387+
388+ /*
389+ * The MMIO space is mapped as Uncached (UC). Each write arrives
390+ * at the device as an individual transaction in program order.
391+ * The device can then reassemble the sequence accordingly.
392+ */
393+ for (i = 0 ; i < chunk_bytes / sizeof (u32 ); i ++ )
394+ write_mbox_dword (mmio_base , chunk [i ]);
395+ }
396+
330397/*
331398 * Prepare for a new microcode transfer: reset hardware and record the
332399 * image size.
@@ -377,24 +444,83 @@ static bool can_send_next_chunk(struct staging_state *ss, int *err)
377444 return true;
378445}
379446
447+ /*
448+ * The hardware indicates completion by returning a sentinel end offset.
449+ */
450+ static inline bool is_end_offset (u32 offset )
451+ {
452+ return offset == UINT_MAX ;
453+ }
454+
380455/*
381456 * Determine whether staging is complete: either the hardware signaled
382457 * the end offset, or no more transactions are permitted (retry limit
383458 * reached).
384459 */
385460static inline bool staging_is_complete (struct staging_state * ss , int * err )
386461{
387- return (ss -> offset == UINT_MAX ) || !can_send_next_chunk (ss , err );
462+ return is_end_offset (ss -> offset ) || !can_send_next_chunk (ss , err );
463+ }
464+
465+ /*
466+ * Wait for the hardware to complete a transaction.
467+ * Return 0 on success, or an error code on failure.
468+ */
469+ static int wait_for_transaction (struct staging_state * ss )
470+ {
471+ u32 timeout , status ;
472+
473+ /* Allow time for hardware to complete the operation: */
474+ for (timeout = 0 ; timeout < MBOX_XACTION_TIMEOUT_MS ; timeout ++ ) {
475+ msleep (1 );
476+
477+ status = readl (ss -> mmio_base + MBOX_STATUS_OFFSET );
478+ /* Break out early if the hardware is ready: */
479+ if (status & MASK_MBOX_STATUS_READY )
480+ break ;
481+ }
482+
483+ /* Check for explicit error response */
484+ if (status & MASK_MBOX_STATUS_ERROR )
485+ return - EIO ;
486+
487+ /*
488+ * Hardware has neither responded to the action nor signaled any
489+ * error. Treat this as a timeout.
490+ */
491+ if (!(status & MASK_MBOX_STATUS_READY ))
492+ return - ETIMEDOUT ;
493+
494+ return 0 ;
388495}
389496
390497/*
391498 * Transmit a chunk of the microcode image to the hardware.
392499 * Return 0 on success, or an error code on failure.
393500 */
394- static int send_data_chunk (struct staging_state * ss , void * ucode_ptr __maybe_unused )
501+ static int send_data_chunk (struct staging_state * ss , void * ucode_ptr )
395502{
396- pr_debug_once ("Staging mailbox loading code needs to be implemented.\n" );
397- return - EPROTONOSUPPORT ;
503+ u32 * src_chunk = ucode_ptr + ss -> offset ;
504+ u16 mbox_size ;
505+
506+ /*
507+ * Write a 'request' mailbox object in this order:
508+ * 1. Mailbox header includes total size
509+ * 2. Command header specifies the load operation
510+ * 3. Data section contains a microcode chunk
511+ *
512+ * Thus, the mailbox size is two headers plus the chunk size.
513+ */
514+ mbox_size = MBOX_HEADER_SIZE * 2 + ss -> chunk_size ;
515+ write_mbox_header (ss -> mmio_base , MBOX_HEADER (mbox_size ));
516+ write_mbox_header (ss -> mmio_base , MBOX_CMD_LOAD );
517+ write_mbox_data (ss -> mmio_base , src_chunk , ss -> chunk_size );
518+ ss -> bytes_sent += ss -> chunk_size ;
519+
520+ /* Notify the hardware that the mailbox is ready for processing. */
521+ writel (MASK_MBOX_CTRL_GO , ss -> mmio_base + MBOX_CONTROL_OFFSET );
522+
523+ return wait_for_transaction (ss );
398524}
399525
400526/*
@@ -403,8 +529,42 @@ static int send_data_chunk(struct staging_state *ss, void *ucode_ptr __maybe_unu
403529 */
404530static int fetch_next_offset (struct staging_state * ss )
405531{
406- pr_debug_once ("Staging mailbox response handling code needs to be implemented.\n" );
407- return - EPROTONOSUPPORT ;
532+ const u64 expected_header = MBOX_HEADER (MBOX_HEADER_SIZE + MBOX_RESPONSE_SIZE );
533+ u32 offset , status ;
534+ u64 header ;
535+
536+ /*
537+ * The 'response' mailbox returns three fields, in order:
538+ * 1. Header
539+ * 2. Next offset in the microcode image
540+ * 3. Status flags
541+ */
542+ header = read_mbox_header (ss -> mmio_base );
543+ offset = read_mbox_dword (ss -> mmio_base );
544+ status = read_mbox_dword (ss -> mmio_base );
545+
546+ /* All valid responses must start with the expected header. */
547+ if (header != expected_header ) {
548+ pr_err_once ("staging: invalid response header (0x%llx)\n" , header );
549+ return - EBADR ;
550+ }
551+
552+ /*
553+ * Verify the offset: If not at the end marker, it must not
554+ * exceed the microcode image length.
555+ */
556+ if (!is_end_offset (offset ) && offset > ss -> ucode_len ) {
557+ pr_err_once ("staging: invalid offset (%u) past the image end (%u)\n" ,
558+ offset , ss -> ucode_len );
559+ return - EINVAL ;
560+ }
561+
562+ /* Hardware may report errors explicitly in the status field */
563+ if (status & MASK_MBOX_RESP_ERROR )
564+ return - EPROTO ;
565+
566+ ss -> offset = offset ;
567+ return 0 ;
408568}
409569
410570/*
0 commit comments