diff --git a/.ci/check-format.sh b/.ci/check-format.sh index fd0477dc..959100af 100755 --- a/.ci/check-format.sh +++ b/.ci/check-format.sh @@ -10,4 +10,4 @@ done < <(git ls-files '*.c' '*.cxx' '*.cpp' '*.h' '*.hpp') # Use clang-format dry-run mode with --Werror to fail on format violations # This eliminates the need for temporary files and manual diff comparisons -clang-format-18 -n --Werror "${SOURCES[@]}" +clang-format-20 -n --Werror "${SOURCES[@]}" diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a091bc22..b36afa68 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -140,13 +140,13 @@ jobs: uses: actions/cache@v4 with: path: /var/cache/apt/archives - key: ${{ runner.os }}-apt-clang-format-18 + key: ${{ runner.os }}-apt-clang-format-20 restore-keys: | ${{ runner.os }}-apt- - name: Install clang-format run: | sudo apt-get update - sudo apt-get install -q -y clang-format-18 + sudo apt-get install -q -y clang-format-20 shell: bash timeout-minutes: 5 - name: Setup reviewdog @@ -178,7 +178,7 @@ jobs: trap cleanup_files EXIT INT TERM # Apply clang-format in-place to generate diff - clang-format-18 -i "${SOURCES[@]}" + clang-format-20 -i "${SOURCES[@]}" # Generate diff and pipe to reviewdog # Note: reviewdog exit code doesn't affect cleanup due to trap diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3b090198..0936dff8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -44,7 +44,7 @@ However, participation requires adherence to fundamental ground rules: This variant should be considered the standard for all documentation efforts. For instance, opt for "initialize" over "initialise" and "color" rather than "colour". -Software requirement: [clang-format](https://clang.llvm.org/docs/ClangFormat.html) version 18 or later. +Software requirement: [clang-format](https://clang.llvm.org/docs/ClangFormat.html) version 20 or later. This repository consistently contains an up-to-date `.clang-format` file with rules that match the explained ones. For maintaining a uniform coding style, execute the command `clang-format -i *.{c,h}`. diff --git a/main.c b/main.c index 82e1433e..d11ba5a9 100644 --- a/main.c +++ b/main.c @@ -359,9 +359,9 @@ static inline sbi_ret_t handle_sbi_ecall_TIMER(hart_t *hart, int32_t fid) (((uint64_t) hart->x_regs[RV_R_A1]) << 32) | (uint64_t) (hart->x_regs[RV_R_A0]); hart->sip &= ~RV_INT_STI_BIT; - return (sbi_ret_t){SBI_SUCCESS, 0}; + return (sbi_ret_t) {SBI_SUCCESS, 0}; default: - return (sbi_ret_t){SBI_ERR_NOT_SUPPORTED, 0}; + return (sbi_ret_t) {SBI_ERR_NOT_SUPPORTED, 0}; } } @@ -373,9 +373,9 @@ static inline sbi_ret_t handle_sbi_ecall_RST(hart_t *hart, int32_t fid) fprintf(stderr, "system reset: type=%u, reason=%u\n", hart->x_regs[RV_R_A0], hart->x_regs[RV_R_A1]); data->stopped = true; - return (sbi_ret_t){SBI_SUCCESS, 0}; + return (sbi_ret_t) {SBI_SUCCESS, 0}; default: - return (sbi_ret_t){SBI_ERR_NOT_SUPPORTED, 0}; + return (sbi_ret_t) {SBI_ERR_NOT_SUPPORTED, 0}; } } @@ -395,13 +395,13 @@ static inline sbi_ret_t handle_sbi_ecall_HSM(hart_t *hart, int32_t fid) vm->hart[hartid]->x_regs[RV_R_A1] = opaque; vm->hart[hartid]->pc = start_addr; vm->hart[hartid]->s_mode = true; - return (sbi_ret_t){SBI_SUCCESS, 0}; + return (sbi_ret_t) {SBI_SUCCESS, 0}; case SBI_HSM__HART_STOP: hart->hsm_status = SBI_HSM_STATE_STOPPED; - return (sbi_ret_t){SBI_SUCCESS, 0}; + return (sbi_ret_t) {SBI_SUCCESS, 0}; case SBI_HSM__HART_GET_STATUS: hartid = hart->x_regs[RV_R_A0]; - return (sbi_ret_t){SBI_SUCCESS, vm->hart[hartid]->hsm_status}; + return (sbi_ret_t) {SBI_SUCCESS, vm->hart[hartid]->hsm_status}; case SBI_HSM__HART_SUSPEND: suspend_type = hart->x_regs[RV_R_A0]; resume_addr = hart->x_regs[RV_R_A1]; @@ -415,11 +415,11 @@ static inline sbi_ret_t handle_sbi_ecall_HSM(hart_t *hart, int32_t fid) hart->hsm_resume_pc = resume_addr; hart->hsm_resume_opaque = opaque; } - return (sbi_ret_t){SBI_SUCCESS, 0}; + return (sbi_ret_t) {SBI_SUCCESS, 0}; default: - return (sbi_ret_t){SBI_ERR_NOT_SUPPORTED, 0}; + return (sbi_ret_t) {SBI_ERR_NOT_SUPPORTED, 0}; } - return (sbi_ret_t){SBI_ERR_FAILED, 0}; + return (sbi_ret_t) {SBI_ERR_FAILED, 0}; } static inline sbi_ret_t handle_sbi_ecall_IPI(hart_t *hart, int32_t fid) @@ -438,10 +438,10 @@ static inline sbi_ret_t handle_sbi_ecall_IPI(hart_t *hart, int32_t fid) data->sswi.ssip[i] = hart_mask & 1; } - return (sbi_ret_t){SBI_SUCCESS, 0}; + return (sbi_ret_t) {SBI_SUCCESS, 0}; break; default: - return (sbi_ret_t){SBI_ERR_FAILED, 0}; + return (sbi_ret_t) {SBI_ERR_FAILED, 0}; } } @@ -458,7 +458,7 @@ static inline sbi_ret_t handle_sbi_ecall_RFENCE(hart_t *hart, int32_t fid) switch (fid) { case SBI_RFENCE__I: /* Instruction cache flush - ignored in interpreter mode */ - return (sbi_ret_t){SBI_SUCCESS, 0}; + return (sbi_ret_t) {SBI_SUCCESS, 0}; case SBI_RFENCE__VMA: case SBI_RFENCE__VMA_ASID: /* RFENCE.VMA and RFENCE.VMA.ASID both use the same parameters: @@ -484,15 +484,15 @@ static inline sbi_ret_t handle_sbi_ecall_RFENCE(hart_t *hart, int32_t fid) mmu_invalidate_range(hart->vm->hart[i], start_addr, size); } } - return (sbi_ret_t){SBI_SUCCESS, 0}; + return (sbi_ret_t) {SBI_SUCCESS, 0}; case SBI_RFENCE__GVMA_VMID: case SBI_RFENCE__GVMA: case SBI_RFENCE__VVMA_ASID: case SBI_RFENCE__VVMA: /* Hypervisor-related RFENCE operations - not implemented */ - return (sbi_ret_t){SBI_SUCCESS, 0}; + return (sbi_ret_t) {SBI_SUCCESS, 0}; default: - return (sbi_ret_t){SBI_ERR_FAILED, 0}; + return (sbi_ret_t) {SBI_ERR_FAILED, 0}; } } @@ -504,26 +504,26 @@ static inline sbi_ret_t handle_sbi_ecall_BASE(hart_t *hart, int32_t fid) { switch (fid) { case SBI_BASE__GET_SBI_IMPL_ID: - return (sbi_ret_t){SBI_SUCCESS, SBI_IMPL_ID}; + return (sbi_ret_t) {SBI_SUCCESS, SBI_IMPL_ID}; case SBI_BASE__GET_SBI_IMPL_VERSION: - return (sbi_ret_t){SBI_SUCCESS, SBI_IMPL_VERSION}; + return (sbi_ret_t) {SBI_SUCCESS, SBI_IMPL_VERSION}; case SBI_BASE__GET_MVENDORID: - return (sbi_ret_t){SBI_SUCCESS, RV_MVENDORID}; + return (sbi_ret_t) {SBI_SUCCESS, RV_MVENDORID}; case SBI_BASE__GET_MARCHID: - return (sbi_ret_t){SBI_SUCCESS, RV_MARCHID}; + return (sbi_ret_t) {SBI_SUCCESS, RV_MARCHID}; case SBI_BASE__GET_MIMPID: - return (sbi_ret_t){SBI_SUCCESS, RV_MIMPID}; + return (sbi_ret_t) {SBI_SUCCESS, RV_MIMPID}; case SBI_BASE__GET_SBI_SPEC_VERSION: - return (sbi_ret_t){SBI_SUCCESS, (2 << 24) | 0}; /* version 2.0 */ + return (sbi_ret_t) {SBI_SUCCESS, (2 << 24) | 0}; /* version 2.0 */ case SBI_BASE__PROBE_EXTENSION: { int32_t eid = (int32_t) hart->x_regs[RV_R_A0]; bool available = eid == SBI_EID_BASE || eid == SBI_EID_TIMER || eid == SBI_EID_RST || eid == SBI_EID_HSM || eid == SBI_EID_IPI || eid == SBI_EID_RFENCE; - return (sbi_ret_t){SBI_SUCCESS, available}; + return (sbi_ret_t) {SBI_SUCCESS, available}; } default: - return (sbi_ret_t){SBI_ERR_NOT_SUPPORTED, 0}; + return (sbi_ret_t) {SBI_ERR_NOT_SUPPORTED, 0}; } } @@ -553,7 +553,7 @@ static void handle_sbi_ecall(hart_t *hart) SBI_HANDLE(RFENCE); break; default: - ret = (sbi_ret_t){SBI_ERR_NOT_SUPPORTED, 0}; + ret = (sbi_ret_t) {SBI_ERR_NOT_SUPPORTED, 0}; } hart->x_regs[RV_R_A0] = (uint32_t) ret.error; hart->x_regs[RV_R_A1] = (uint32_t) ret.value; @@ -1249,7 +1249,7 @@ static int semu_run(emu_state_t *emu) #ifdef __APPLE__ /* macOS: use kqueue with EVFILT_TIMER */ if (kq >= 0 && pfd_count < poll_capacity && harts_active) { - pfds[pfd_count] = (struct pollfd){kq, POLLIN, 0}; + pfds[pfd_count] = (struct pollfd) {kq, POLLIN, 0}; timer_index = (int) pfd_count; pfd_count++; } @@ -1257,7 +1257,7 @@ static int semu_run(emu_state_t *emu) /* Linux: use timerfd */ if (wfi_timer_fd >= 0 && pfd_count < poll_capacity && harts_active) { - pfds[pfd_count] = (struct pollfd){wfi_timer_fd, POLLIN, 0}; + pfds[pfd_count] = (struct pollfd) {wfi_timer_fd, POLLIN, 0}; timer_index = (int) pfd_count; pfd_count++; } @@ -1279,7 +1279,7 @@ static int semu_run(emu_state_t *emu) (idle_harts == 0) || emu->uart.has_waiting_hart; if (emu->uart.in_fd >= 0 && pfd_count < poll_capacity && need_uart) { - pfds[pfd_count] = (struct pollfd){emu->uart.in_fd, POLLIN, 0}; + pfds[pfd_count] = (struct pollfd) {emu->uart.in_fd, POLLIN, 0}; pfd_count++; } @@ -1521,7 +1521,7 @@ static int semu_run_debug(emu_state_t *emu) emu->curr_cpuid = 0; if (!gdbstub_init(&gdbstub, &gdbstub_ops, - (arch_info_t){ + (arch_info_t) { .smp = vm->n_hart, .reg_num = 33, .target_desc = TARGET_RV32, diff --git a/virtio-snd.c b/virtio-snd.c index 9248fe46..90faf87a 100644 --- a/virtio-snd.c +++ b/virtio-snd.c @@ -345,111 +345,114 @@ typedef struct { */ static uint32_t flush_stream_id = 0; -#define VSND_TX_QUEUE_BODY(WRITE) \ - do { \ - /* A PCM I/O message uses at least 3 virtqueue descriptors to \ - * represent a PCM data of a period size. \ - * The first part contains one descriptor as follows: \ - * struct virtio_snd_pcm_xfer \ - * The second part contains one or more descriptors \ - * representing PCM frames. \ - * the last part contains one descriptor as follows: \ - * struct virtio_snd_pcm_status \ - */ \ - virtq_desc_queue_node_t *node; \ - struct list_head q; \ - INIT_LIST_HEAD(&q); \ - \ - /* Collect the descriptors */ \ - int cnt = 0; \ - for (;;) { \ - /* The size of the `struct virtq_desc` is 4 words */ \ - const uint32_t *desc = \ - &vsnd->ram[queue->QueueDesc + desc_idx * 4]; \ - \ - /* Retrieve the fields of current descriptor */ \ - node = (virtq_desc_queue_node_t *) malloc(sizeof(*node)); \ - node->vq_desc.addr = desc[0]; \ - node->vq_desc.len = desc[2]; \ - node->vq_desc.flags = desc[3]; \ - list_push(&node->q, &q); \ - desc_idx = desc[3] >> 16; /* vq_desc[desc_cnt].next */ \ - \ - cnt++; \ - \ - /* Leave the loop if next-flag is not set */ \ - if (!(desc[3] & VIRTIO_DESC_F_NEXT)) \ - break; \ - } \ - \ - int idx = 0; \ - uint32_t stream_id = 0; /* Explicitly set the stream_id */ \ - uintptr_t base = (uintptr_t) vsnd->ram; \ - uint32_t ret_len = 0; \ - uint8_t bad_msg_err = 0; \ - list_for_each_entry (node, &q, q) { \ - uint32_t addr = node->vq_desc.addr; \ - uint32_t len = node->vq_desc.len; \ - if (idx == 0) { /* the first descriptor */ \ - const virtio_snd_pcm_xfer_t *request = \ - (virtio_snd_pcm_xfer_t *) (base + addr); \ - stream_id = request->stream_id; \ - IIF(WRITE) \ - (/* enqueue frames */ \ - bad_msg_err = stream_id >= VSND_DEV_CNT_MAX ? 1 : 0; \ - , /* flush queue */ \ - bad_msg_err = stream_id != flush_stream_id \ - ? 1 \ - : 0; /* select only stream_id 0 */ \ - ) goto early_continue; \ - } else if (idx == cnt - 1) { /* the last descriptor */ \ - IIF(WRITE) \ - ( /* enqueue frames */ \ - , /* flush queue */ \ - if (bad_msg_err == 1) { \ - fprintf(stderr, "ignore flush stream_id %" PRIu32 "\n", \ - stream_id); \ - goto early_continue; \ - } fprintf(stderr, "flush stream_id %" PRIu32 "\n", \ - stream_id);) virtio_snd_pcm_status_t *response = \ - (virtio_snd_pcm_status_t *) (base + addr); \ - response->status = \ - bad_msg_err ? VIRTIO_SND_S_IO_ERR : VIRTIO_SND_S_OK; \ - response->latency_bytes = ret_len; \ - *plen = sizeof(*response); \ - goto early_continue; \ - } \ - \ - IIF(WRITE) \ - (/* enqueue frames */ \ - void *payload = (void *) (base + addr); if (bad_msg_err == 0) \ - __virtio_snd_frame_enqueue(payload, len, stream_id); \ - , /* flush queue */ \ - (void) stream_id; \ - /* Suppress unused variable warning. */) ret_len += len; \ - \ - early_continue: \ - idx++; \ - } \ - \ - if (bad_msg_err != 0) \ - goto finally; \ - IIF(WRITE) \ - (/* enque frames */ \ - virtio_snd_prop_t *props = &vsnd_props[stream_id]; \ - props->lock.buf_ev_notify++; \ - pthread_cond_signal(&props->lock.readable);, /* flush queue */ \ - ) \ - \ - /* Tear down the descriptor list and free space. */ \ - virtq_desc_queue_node_t *tmp = NULL; \ - list_for_each_entry_safe (node, tmp, &q, q) { \ - list_del(&node->q); \ - free(node); \ - } \ - \ - finally: \ - return 0; \ +#define VSND_TX_QUEUE_BODY(WRITE) \ + do { \ + /* A PCM I/O message uses at least 3 virtqueue descriptors to \ + * represent a PCM data of a period size. \ + * The first part contains one descriptor as follows: \ + * struct virtio_snd_pcm_xfer \ + * The second part contains one or more descriptors \ + * representing PCM frames. \ + * the last part contains one descriptor as follows: \ + * struct virtio_snd_pcm_status \ + */ \ + virtq_desc_queue_node_t *node; \ + struct list_head q; \ + INIT_LIST_HEAD(&q); \ + \ + /* Collect the descriptors */ \ + int cnt = 0; \ + for (;;) { \ + /* The size of the `struct virtq_desc` is 4 words */ \ + const uint32_t *desc = \ + &vsnd->ram[queue->QueueDesc + desc_idx * 4]; \ + \ + /* Retrieve the fields of current descriptor */ \ + node = (virtq_desc_queue_node_t *) malloc(sizeof(*node)); \ + node->vq_desc.addr = desc[0]; \ + node->vq_desc.len = desc[2]; \ + node->vq_desc.flags = desc[3]; \ + list_push(&node->q, &q); \ + desc_idx = desc[3] >> 16; /* vq_desc[desc_cnt].next */ \ + \ + cnt++; \ + \ + /* Leave the loop if next-flag is not set */ \ + if (!(desc[3] & VIRTIO_DESC_F_NEXT)) \ + break; \ + } \ + \ + int idx = 0; \ + uint32_t stream_id = 0; /* Explicitly set the stream_id */ \ + uintptr_t base = (uintptr_t) vsnd->ram; \ + uint32_t ret_len = 0; \ + uint8_t bad_msg_err = 0; \ + list_for_each_entry (node, &q, q) { \ + uint32_t addr = node->vq_desc.addr; \ + uint32_t len = node->vq_desc.len; \ + if (idx == 0) { /* the first descriptor */ \ + const virtio_snd_pcm_xfer_t *request = \ + (virtio_snd_pcm_xfer_t *) (base + addr); \ + stream_id = request->stream_id; \ + IIF(WRITE)(/* enqueue frames */ \ + bad_msg_err = \ + stream_id >= VSND_DEV_CNT_MAX ? 1 : 0; \ + , /* flush queue */ \ + bad_msg_err = \ + stream_id != flush_stream_id \ + ? 1 \ + : 0; /* select only stream_id 0 */ \ + ) goto early_continue; \ + } else if (idx == cnt - 1) { /* the last descriptor */ \ + IIF(WRITE)( /* enqueue frames */ \ + , /* flush queue */ \ + if (bad_msg_err == 1) { \ + fprintf(stderr, \ + "ignore flush stream_id %" PRIu32 "\n", \ + stream_id); \ + goto early_continue; \ + } fprintf(stderr, "flush stream_id %" PRIu32 "\n", \ + stream_id);) \ + virtio_snd_pcm_status_t *response = \ + (virtio_snd_pcm_status_t *) (base + addr); \ + response->status = \ + bad_msg_err ? VIRTIO_SND_S_IO_ERR : VIRTIO_SND_S_OK; \ + response->latency_bytes = ret_len; \ + *plen = sizeof(*response); \ + goto early_continue; \ + } \ + \ + IIF(WRITE)(/* enqueue frames */ \ + void *payload = (void *) (base + addr); \ + if (bad_msg_err == 0) __virtio_snd_frame_enqueue( \ + payload, len, stream_id); \ + , /* flush queue */ \ + (void) stream_id; \ + /* Suppress unused variable warning. */) ret_len += \ + len; \ + \ + early_continue: \ + idx++; \ + } \ + \ + if (bad_msg_err != 0) \ + goto finally; \ + IIF(WRITE)(/* enque frames */ \ + virtio_snd_prop_t *props = &vsnd_props[stream_id]; \ + props->lock.buf_ev_notify++; \ + pthread_cond_signal(&props->lock.readable); \ + , /* flush queue */ \ + ) \ + \ + /* Tear down the descriptor list and free space. */ \ + virtq_desc_queue_node_t *tmp = NULL; \ + list_for_each_entry_safe (node, tmp, &q, q) { \ + list_del(&node->q); \ + free(node); \ + } \ + \ + finally: \ + return 0; \ } while (0) static int virtio_snd_tx_desc_handler(virtio_snd_state_t *vsnd,