Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 105 additions & 0 deletions .ci/boot-linux.sh
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ function ASSERT

cleanup

# To test RTC clock
HOST_UTC_YEAR=$(LC_ALL=C date -u +%Y)

ENABLE_VBLK=1
VBLK_IMG=build/disk.img
[ -f "${VBLK_IMG}" ] || ENABLE_VBLK=0
Expand All @@ -33,10 +36,93 @@ OPTS_BASE+=" -i build/linux-image/rootfs.cpio"
TEST_OPTIONS=("base (${OPTS_BASE})")
EXPECT_CMDS=('
expect "buildroot login:" { send "root\n" } timeout { exit 1 }
expect "# " { send "dmesg | grep rtc\n" } timeout { exit 2 }
Copy link

@cubic-dev-ai cubic-dev-ai bot Sep 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Misleading exit code: use exit 3 for command timeout to match "Fail to run commands" message.

Prompt for AI agents
Address the following comment on .ci/boot-linux.sh at line 39:

<comment>Misleading exit code: use exit 3 for command timeout to match &quot;Fail to run commands&quot; message.</comment>

<file context>
@@ -33,10 +36,93 @@ OPTS_BASE+=&quot; -i build/linux-image/rootfs.cpio&quot;
 TEST_OPTIONS=(&quot;base (${OPTS_BASE})&quot;)
 EXPECT_CMDS=(&#39;
     expect &quot;buildroot login:&quot; { send &quot;root\n&quot; } timeout { exit 1 }
+    expect &quot;# &quot; { send &quot;dmesg | grep rtc\n&quot; } timeout { exit 2 }
+    expect &quot;rtc0&quot; { } timeout { exit 3 }
+    expect &quot;# &quot; { send &quot;date -u +%Y\n&quot; } timeout { exit 2 }
</file context>
Fix with Cubic

expect "rtc0" { } timeout { exit 3 }
expect "# " { send "date -u +%Y\n" } timeout { exit 2 }
expect "${HOST_UTC_YEAR}" { } timeout { exit 3 }
expect "# " { send "uname -a\n" } timeout { exit 2 }
expect "riscv32 GNU/Linux" { send "\x01"; send "x" } timeout { exit 3 }
')

# RTC alarm and settime tests
TEST_OPTIONS+=("${OPTS_BASE}")
EXPECT_CMDS+=('
expect "buildroot login:" { send "root\n" } timeout { exit 1 }
expect "# " { send "dmesg | grep rtc\n" } timeout { exit 2 }
expect "rtc0" { } timeout { exit 3 }
expect "# " { send "date -u +%Y\n" } timeout { exit 2 }
expect "${HOST_UTC_YEAR}" { } timeout { exit 3 }
expect "# " { send "uname -a\n" } timeout { exit 2 }
expect "riscv32 GNU/Linux" { } timeout { exit 3 }
expect "# " { send "rtc_alarm\n" } timeout { exit 3 }
expect "alarm_IRQ : no" { } timeout { exit 3 }
expect "alarm_IRQ : yes" { } timeout { exit 3 }
expect "alarm_IRQ : no" { } timeout { exit 3 }
expect "# " { send "\x01"; send "x" } timeout { exit 3 }
')
year1=1980
year2=2030
TEST_OPTIONS+=("${OPTS_BASE}")
EXPECT_CMDS+=('
expect "buildroot login:" { send "root\n" } timeout { exit 1 }
expect "# " { send "dmesg | grep rtc\n" } timeout { exit 2 }
expect "rtc0" { } timeout { exit 3 }
expect "# " { send "date -u +%Y\n" } timeout { exit 2 }
expect "${HOST_UTC_YEAR}" { } timeout { exit 3 }
expect "# " { send "uname -a\n" } timeout { exit 2 }
expect "riscv32 GNU/Linux" { } timeout { exit 3 }
expect "# " { send "rtc_settime ${year1}\n" } timeout { exit 3 }
expect "rtc_date : ${year1}-01-01" { } timeout { exit 3 }
expect "# " { send "\x01"; send "x" } timeout { exit 3 }
')
TEST_OPTIONS+=("${OPTS_BASE}")
EXPECT_CMDS+=('
expect "buildroot login:" { send "root\n" } timeout { exit 1 }
expect "# " { send "dmesg | grep rtc\n" } timeout { exit 2 }
expect "rtc0" { } timeout { exit 3 }
expect "# " { send "date -u +%Y\n" } timeout { exit 2 }
expect "${HOST_UTC_YEAR}" { } timeout { exit 3 }
expect "# " { send "uname -a\n" } timeout { exit 2 }
expect "riscv32 GNU/Linux" { } timeout { exit 3 }
expect "# " { send "rtc_settime ${year2}\n" } timeout { exit 3 }
expect "rtc_date : ${year2}-01-01" { } timeout { exit 3 }
expect "# " { send "\x01"; send "x" } timeout { exit 3 }
')
TEST_OPTIONS+=("${OPTS_BASE}")
EXPECT_CMDS+=('
expect "buildroot login:" { send "root\n" } timeout { exit 1 }
expect "# " { send "dmesg | grep rtc\n" } timeout { exit 2 }
expect "rtc0" { } timeout { exit 3 }
expect "# " { send "date -u +%Y\n" } timeout { exit 2 }
expect "${HOST_UTC_YEAR}" { } timeout { exit 3 }
expect "# " { send "uname -a\n" } timeout { exit 2 }
expect "riscv32 GNU/Linux" { } timeout { exit 3 }
expect "# " { send "rtc_settime ${year1}\n" } timeout { exit 3 }
expect "rtc_date : ${year1}-01-01" { } timeout { exit 3 }
expect "# " { send "rtc_alarm\n" } timeout { exit 3 }
expect "alarm_IRQ : no" { } timeout { exit 3 }
expect "alarm_IRQ : yes" { } timeout { exit 3 }
expect "alarm_IRQ : no" { } timeout { exit 3 }
expect "# " { send "\x01"; send "x" } timeout { exit 3 }
')
TEST_OPTIONS+=("${OPTS_BASE}")
EXPECT_CMDS+=('
expect "buildroot login:" { send "root\n" } timeout { exit 1 }
expect "# " { send "dmesg | grep rtc\n" } timeout { exit 2 }
expect "rtc0" { } timeout { exit 3 }
expect "# " { send "date -u +%Y\n" } timeout { exit 2 }
expect "${HOST_UTC_YEAR}" { } timeout { exit 3 }
expect "# " { send "uname -a\n" } timeout { exit 2 }
expect "riscv32 GNU/Linux" { } timeout { exit 3 }
expect "# " { send "rtc_settime ${year2}\n" } timeout { exit 3 }
expect "rtc_date : ${year2}-01-01" { } timeout { exit 3 }
expect "# " { send "rtc_alarm\n" } timeout { exit 3 }
expect "alarm_IRQ : no" { } timeout { exit 3 }
expect "alarm_IRQ : yes" { } timeout { exit 3 }
expect "alarm_IRQ : no" { } timeout { exit 3 }
expect "# " { send "\x01"; send "x" } timeout { exit 3 }
')

COLOR_G='\e[32;01m' # Green
COLOR_R='\e[31;01m' # Red
COLOR_Y='\e[33;01m' # Yellow
Expand All @@ -54,6 +140,10 @@ if [ "${ENABLE_VBLK}" -eq "1" ]; then
TEST_OPTIONS+=("${OPTS_BASE} -x vblk:${VBLK_IMG},readonly")
EXPECT_CMDS+=('
expect "buildroot login:" { send "root\n" } timeout { exit 1 }
expect "# " { send "dmesg | grep rtc\n" } timeout { exit 2 }
expect "rtc0" { } timeout { exit 3 }
expect "# " { send "date -u +%Y\n" } timeout { exit 2 }
expect "${HOST_UTC_YEAR}" { } timeout { exit 3 }
expect "# " { send "uname -a\n" } timeout { exit 2 }
expect "riscv32 GNU/Linux" { send "mkdir mnt && mount /dev/vda mnt\n" } timeout { exit 3 }
expect "# " { send "echo rv32emu > mnt/emu.txt\n" } timeout { exit 3 }
Expand All @@ -65,6 +155,10 @@ if [ "${ENABLE_VBLK}" -eq "1" ]; then
TEST_OPTIONS+=("${OPTS_BASE} -x vblk:${VBLK_IMG},readonly -x vblk:${BLK_DEV},readonly")
EXPECT_CMDS+=('
expect "buildroot login:" { send "root\n" } timeout { exit 1 }
expect "# " { send "dmesg | grep rtc\n" } timeout { exit 2 }
expect "rtc0" { } timeout { exit 3 }
expect "# " { send "date -u +%Y\n" } timeout { exit 2 }
expect "${HOST_UTC_YEAR}" { } timeout { exit 3 }
expect "# " { send "uname -a\n" } timeout { exit 2 }
expect "riscv32 GNU/Linux" { send "mkdir mnt && mount /dev/vda mnt\n" } timeout { exit 3 }
expect "# " { send "echo rv32emu > mnt/emu.txt\n" } timeout { exit 3 }
Expand All @@ -79,6 +173,10 @@ if [ "${ENABLE_VBLK}" -eq "1" ]; then
TEST_OPTIONS+=("${OPTS_BASE} -x vblk:${VBLK_IMG}")
VBLK_EXPECT_CMDS='
expect "buildroot login:" { send "root\n" } timeout { exit 1 }
expect "# " { send "dmesg | grep rtc\n" } timeout { exit 2 }
expect "rtc0" { } timeout { exit 3 }
expect "# " { send "date -u +%Y\n" } timeout { exit 2 }
expect "${HOST_UTC_YEAR}" { } timeout { exit 3 }
expect "# " { send "uname -a\n" } timeout { exit 2 }
expect "riscv32 GNU/Linux" { send "mkdir mnt && mount /dev/vda mnt\n" } timeout { exit 3 }
expect "# " { send "echo rv32emu > mnt/emu.txt\n" } timeout { exit 3 }
Expand All @@ -96,6 +194,10 @@ if [ "${ENABLE_VBLK}" -eq "1" ]; then
TEST_OPTIONS+=("${OPTS_BASE} -x vblk:${VBLK_IMG} -x vblk:${BLK_DEV}")
VBLK_EXPECT_CMDS='
expect "buildroot login:" { send "root\n" } timeout { exit 1 }
expect "# " { send "dmesg | grep rtc\n" } timeout { exit 2 }
expect "rtc0" { } timeout { exit 3 }
expect "# " { send "date -u +%Y\n" } timeout { exit 2 }
expect "${HOST_UTC_YEAR}" { } timeout { exit 3 }
expect "# " { send "uname -a\n" } timeout { exit 2 }
expect "riscv32 GNU/Linux" { send "mkdir mnt && mount /dev/vda mnt\n" } timeout { exit 3 }
expect "# " { send "echo rv32emu > mnt/emu.txt\n" } timeout { exit 3 }
Expand All @@ -121,6 +223,9 @@ for i in "${!TEST_OPTIONS[@]}"; do
RUN_LINUX="build/rv32emu ${OPTS}"

ASSERT expect <<- DONE
set HOST_UTC_YEAR ${HOST_UTC_YEAR}
set year1 ${year1}
set year2 ${year2}
set timeout ${TIMEOUT}
spawn ${RUN_LINUX}
${EXPECT_CMDS[$i]}
Expand Down
5 changes: 5 additions & 0 deletions assets/system/configs/buildroot.config
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,8 @@ BR2_TARGET_ROOTFS_CPIO_NONE=y
BR2_PACKAGE_BUSYBOX_CONFIG="busybox.config"
BR2_PACKAGE_COREMARK=y
BR2_PACKAGE_DHRYSTONE=y
BR2_PACKAGE_UTIL_LINUX=y
BR2_PACKAGE_UTIL_LINUX_HWCLOCK=y

BR2_PACKAGE_RTC_ALARM=y
Copy link

@cubic-dev-ai cubic-dev-ai bot Sep 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unknown Buildroot symbol BR2_PACKAGE_RTC_ALARM is enabled but no package definition exists in the repo; this will be ignored by Kconfig or break reproducibility. Disable or add proper Buildroot package metadata.

Prompt for AI agents
Address the following comment on assets/system/configs/buildroot.config at line 51:

<comment>Unknown Buildroot symbol BR2_PACKAGE_RTC_ALARM is enabled but no package definition exists in the repo; this will be ignored by Kconfig or break reproducibility. Disable or add proper Buildroot package metadata.</comment>

<file context>
@@ -45,3 +45,8 @@ BR2_TARGET_ROOTFS_CPIO_NONE=y
+BR2_PACKAGE_UTIL_LINUX=y
+BR2_PACKAGE_UTIL_LINUX_HWCLOCK=y
+
+BR2_PACKAGE_RTC_ALARM=y
+BR2_PACKAGE_RTC_SETTIME=y
</file context>
Suggested change
BR2_PACKAGE_RTC_ALARM=y
# BR2_PACKAGE_RTC_ALARM is not set
Fix with Cubic

BR2_PACKAGE_RTC_SETTIME=y
Copy link

@cubic-dev-ai cubic-dev-ai bot Sep 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unknown Buildroot symbol BR2_PACKAGE_RTC_SETTIME is enabled but no package definition exists in the repo; this will be ignored by Kconfig or break reproducibility. Disable or add proper Buildroot package metadata.

Prompt for AI agents
Address the following comment on assets/system/configs/buildroot.config at line 52:

<comment>Unknown Buildroot symbol BR2_PACKAGE_RTC_SETTIME is enabled but no package definition exists in the repo; this will be ignored by Kconfig or break reproducibility. Disable or add proper Buildroot package metadata.</comment>

<file context>
@@ -45,3 +45,8 @@ BR2_TARGET_ROOTFS_CPIO_NONE=y
+BR2_PACKAGE_UTIL_LINUX_HWCLOCK=y
+
+BR2_PACKAGE_RTC_ALARM=y
+BR2_PACKAGE_RTC_SETTIME=y
</file context>
Suggested change
BR2_PACKAGE_RTC_SETTIME=y
# BR2_PACKAGE_RTC_SETTIME is not set
Fix with Cubic

61 changes: 60 additions & 1 deletion assets/system/configs/linux.config
Original file line number Diff line number Diff line change
Expand Up @@ -1026,7 +1026,66 @@ CONFIG_USB_OHCI_LITTLE_ENDIAN=y
# CONFIG_ACCESSIBILITY is not set
# CONFIG_INFINIBAND is not set
CONFIG_EDAC_SUPPORT=y
# CONFIG_RTC_CLASS is not set

CONFIG_RTC_LIB=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_HCTOSYS=y
CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
# CONFIG_RTC_SYSTOHC is not set
# CONFIG_RTC_DEBUG is not set
# CONFIG_RTC_NVMEM is not set

#
# RTC interfaces
#
CONFIG_RTC_INTF_SYSFS=y
CONFIG_RTC_INTF_PROC=y
CONFIG_RTC_INTF_DEV=y
# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
# CONFIG_RTC_DRV_TEST is not set

#
# I2C RTC drivers
#

#
# SPI RTC drivers
#

#
# SPI and I2C RTC drivers
#

#
# Platform RTC drivers
#
# CONFIG_RTC_DRV_DS1286 is not set
# CONFIG_RTC_DRV_DS1511 is not set
# CONFIG_RTC_DRV_DS1553 is not set
# CONFIG_RTC_DRV_DS1685_FAMILY is not set
# CONFIG_RTC_DRV_DS1742 is not set
# CONFIG_RTC_DRV_DS2404 is not set
# CONFIG_RTC_DRV_STK17TA8 is not set
# CONFIG_RTC_DRV_M48T86 is not set
# CONFIG_RTC_DRV_M48T35 is not set
# CONFIG_RTC_DRV_M48T59 is not set
# CONFIG_RTC_DRV_MSM6242 is not set
# CONFIG_RTC_DRV_BQ4802 is not set
# CONFIG_RTC_DRV_RP5C01 is not set
# CONFIG_RTC_DRV_V3020 is not set
# CONFIG_RTC_DRV_ZYNQMP is not set

#
# on-CPU RTC drivers
#
# CONFIG_RTC_DRV_CADENCE is not set
# CONFIG_RTC_DRV_FTRTC010 is not set
# CONFIG_RTC_DRV_R7301 is not set

#
# HID Sensor RTC drivers
#
CONFIG_RTC_DRV_GOLDFISH=y
# CONFIG_DMADEVICES is not set

#
Expand Down
2 changes: 1 addition & 1 deletion src/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@

#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))

#define MASK(n) (~((~0U << (n))))
#define MASK(n) (~((~0UL << (n))))
Copy link

@cubic-dev-ai cubic-dev-ai bot Sep 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left shift can be undefined when n >= bit-width of unsigned long; guard against out-of-range shift to avoid UB.

Prompt for AI agents
Address the following comment on src/common.h at line 32:

<comment>Left shift can be undefined when n &gt;= bit-width of unsigned long; guard against out-of-range shift to avoid UB.</comment>

<file context>
@@ -29,7 +29,7 @@
 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
 
-#define MASK(n) (~((~0U &lt;&lt; (n))))
+#define MASK(n) (~((~0UL &lt;&lt; (n))))
 
 #if defined(_MSC_VER)
</file context>
Suggested change
#define MASK(n) (~((~0UL << (n))))
#define MASK(n) ((n) >= (sizeof(unsigned long) * 8) ? ~0UL : ((1UL << (n)) - 1UL))
Fix with Cubic


#if defined(_MSC_VER)
#include <intrin.h>
Expand Down
13 changes: 10 additions & 3 deletions src/devices/minimal.dts
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,21 @@
clock-frequency = <5000000>; /* the baudrate divisor is ignored */
};

rtc0: rtc@4100000 {
compatible = "google,goldfish-rtc";
reg = <0x4100000 0x1000>;
interrupts = <2>;
interrupt-parent = <&plic0>;
};

/*
* Virtio block example subnode
* The actual subnode are generated dynamically depends on the CLI -x vblk option
*/
/*blk0: virtio@4100000 {
/*blk0: virtio@4200000 {
compatible = "virtio,mmio";
reg = <0x4100000 0x200>;
interrupts = <2>;
reg = <0x4200000 0x200>;
interrupts = <3>;
};*/
};
};
120 changes: 120 additions & 0 deletions src/devices/rtc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/*
* rv32emu is freely redistributable under the MIT License. See the file
* "LICENSE" for information on usage and redistribution of this file.
*/

#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>

#include "rtc.h"

static uint64_t now_nsec;

uint64_t get_now_nsec(rtc_t *rtc)
{
/* TODO:
* - detects timezone and use the correct UTC offset
* - a new CLI option should be added to main.c to let user to select
* [UTC] or [UTC + offset](localtime) time. E.g., -x rtc:utc or -x
* rtc:localtime
*/
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
return (uint64_t) (ts.tv_sec * 1e9) + ts.tv_nsec + rtc->clock_offset;
}

uint32_t rtc_read(rtc_t *rtc, uint32_t addr)
{
uint32_t rtc_read_val = 0;

switch (addr) {
case RTC_TIME_LOW:
now_nsec = get_now_nsec(rtc);
rtc->time_low = (uint32_t) (now_nsec & MASK(32));
rtc_read_val = rtc->time_low;
break;
case RTC_TIME_HIGH:
/* reuse the now_nsec when reading RTC_TIME_LOW */
rtc->time_high = (uint32_t) (now_nsec >> 32);
rtc_read_val = rtc->time_high;
break;
case RTC_ALARM_LOW:
rtc_read_val = rtc->alarm_low;
break;
case RTC_ALARM_HIGH:
rtc_read_val = rtc->alarm_high;
break;
case RTC_ALARM_STATUS:
rtc_read_val = rtc->alarm_status;
break;
default:
rv_log_error("Unsupported RTC read operation, 0x%x", addr);
break;
}

return rtc_read_val;
}

void rtc_write(rtc_t *rtc, uint32_t addr, uint32_t value)
{
switch (addr) {
case RTC_TIME_LOW:
now_nsec = get_now_nsec(rtc);
rtc->clock_offset += (uint64_t) (value) - (now_nsec & MASK(32));
break;
case RTC_TIME_HIGH:
/* reuse the now_nsec when writing RTC_TIME_LOW */
rtc->clock_offset += ((uint64_t) (value) << 32) -
(now_nsec & ((uint64_t) (MASK(32)) << 32));
break;
case RTC_ALARM_LOW:
rtc->alarm_low = value;
break;
case RTC_ALARM_HIGH:
rtc->alarm_high = value;
break;
case RTC_IRQ_ENABLED:
rtc->irq_enabled = value;
break;
case RTC_CLEAR_ALARM:
rtc->clear_alarm = value;
break;
case RTC_CLEAR_INTERRUPT:
rtc->clear_interrupt = value;
rtc->interrupt_status = 0;
break;
default:
rv_log_error("Unsupported RTC write operation, 0x%x", addr);
break;
}
return;
}

rtc_t *rtc_new()
{
rtc_t *rtc = calloc(1, sizeof(rtc_t));
assert(rtc);

/*
* The rtc->time_low/high values can be updated through the RTC_SET_TIME
* ioctl operation. Therefore, they should be initialized to match the
* host OS time during initialization.
*/
now_nsec = get_now_nsec(rtc);
rtc->time_low = (uint32_t) (now_nsec & MASK(32));
rtc->time_high = (uint32_t) (now_nsec >> 32);

return rtc;
}

void rtc_delete(rtc_t *rtc)
{
free(rtc);
}
Loading
Loading