@@ -32,6 +32,7 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
3232 uint32_t tmp ;
3333 int n ;
3434 uint32_t offset , length , color ;
35+ uint32_t start_num , number , otp_row ;
3536
3637 /*
3738 * Copy the current state of the framebuffer config; we will update
@@ -322,6 +323,89 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
322323 0 );
323324 resplen = VCHI_BUSADDR_SIZE ;
324325 break ;
326+
327+ /* Customer OTP */
328+
329+ case RPI_FWREQ_GET_CUSTOMER_OTP :
330+ start_num = ldl_le_phys (& s -> dma_as , value + 12 );
331+ number = ldl_le_phys (& s -> dma_as , value + 16 );
332+
333+ resplen = 8 + 4 * number ;
334+
335+ for (n = start_num ; n < start_num + number &&
336+ n < BCM2835_OTP_CUSTOMER_OTP_LEN ; n ++ ) {
337+ otp_row = bcm2835_otp_get_row (s -> otp ,
338+ BCM2835_OTP_CUSTOMER_OTP + n );
339+ stl_le_phys (& s -> dma_as ,
340+ value + 20 + ((n - start_num ) << 2 ), otp_row );
341+ }
342+ break ;
343+ case RPI_FWREQ_SET_CUSTOMER_OTP :
344+ start_num = ldl_le_phys (& s -> dma_as , value + 12 );
345+ number = ldl_le_phys (& s -> dma_as , value + 16 );
346+
347+ resplen = 4 ;
348+
349+ /* Magic numbers to permanently lock customer OTP */
350+ if (start_num == BCM2835_OTP_LOCK_NUM1 &&
351+ number == BCM2835_OTP_LOCK_NUM2 ) {
352+ bcm2835_otp_set_row (s -> otp ,
353+ BCM2835_OTP_ROW_32 ,
354+ BCM2835_OTP_ROW_32_LOCK );
355+ break ;
356+ }
357+
358+ /* If row 32 has the lock bit, don't allow further writes */
359+ if (bcm2835_otp_get_row (s -> otp , BCM2835_OTP_ROW_32 ) &
360+ BCM2835_OTP_ROW_32_LOCK ) {
361+ break ;
362+ }
363+
364+ for (n = start_num ; n < start_num + number &&
365+ n < BCM2835_OTP_CUSTOMER_OTP_LEN ; n ++ ) {
366+ otp_row = ldl_le_phys (& s -> dma_as ,
367+ value + 20 + ((n - start_num ) << 2 ));
368+ bcm2835_otp_set_row (s -> otp ,
369+ BCM2835_OTP_CUSTOMER_OTP + n , otp_row );
370+ }
371+ break ;
372+
373+ /* Device-specific private key */
374+
375+ case RPI_FWREQ_GET_PRIVATE_KEY :
376+ start_num = ldl_le_phys (& s -> dma_as , value + 12 );
377+ number = ldl_le_phys (& s -> dma_as , value + 16 );
378+
379+ resplen = 8 + 4 * number ;
380+
381+ for (n = start_num ; n < start_num + number &&
382+ n < BCM2835_OTP_PRIVATE_KEY_LEN ; n ++ ) {
383+ otp_row = bcm2835_otp_get_row (s -> otp ,
384+ BCM2835_OTP_PRIVATE_KEY + n );
385+ stl_le_phys (& s -> dma_as ,
386+ value + 20 + ((n - start_num ) << 2 ), otp_row );
387+ }
388+ break ;
389+ case RPI_FWREQ_SET_PRIVATE_KEY :
390+ start_num = ldl_le_phys (& s -> dma_as , value + 12 );
391+ number = ldl_le_phys (& s -> dma_as , value + 16 );
392+
393+ resplen = 4 ;
394+
395+ /* If row 32 has the lock bit, don't allow further writes */
396+ if (bcm2835_otp_get_row (s -> otp , BCM2835_OTP_ROW_32 ) &
397+ BCM2835_OTP_ROW_32_LOCK ) {
398+ break ;
399+ }
400+
401+ for (n = start_num ; n < start_num + number &&
402+ n < BCM2835_OTP_PRIVATE_KEY_LEN ; n ++ ) {
403+ otp_row = ldl_le_phys (& s -> dma_as ,
404+ value + 20 + ((n - start_num ) << 2 ));
405+ bcm2835_otp_set_row (s -> otp ,
406+ BCM2835_OTP_PRIVATE_KEY + n , otp_row );
407+ }
408+ break ;
325409 default :
326410 qemu_log_mask (LOG_UNIMP ,
327411 "bcm2835_property: unhandled tag 0x%08x\n" , tag );
@@ -449,6 +533,9 @@ static void bcm2835_property_realize(DeviceState *dev, Error **errp)
449533 s -> dma_mr = MEMORY_REGION (obj );
450534 address_space_init (& s -> dma_as , s -> dma_mr , TYPE_BCM2835_PROPERTY "-memory" );
451535
536+ obj = object_property_get_link (OBJECT (dev ), "otp" , & error_abort );
537+ s -> otp = BCM2835_OTP (obj );
538+
452539 /* TODO: connect to MAC address of USB NIC device, once we emulate it */
453540 qemu_macaddr_default_if_unset (& s -> macaddr );
454541
0 commit comments