From: ljsebald <ljs...@us...> - 2025-04-24 02:27:38
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "A pseudo Operating System for the Dreamcast.". The branch, master has been updated via 35931a498b667b91024dd826b7141a1ad05cb4fa (commit) via c9ecb53a4a48a4cb0bc4b65d4364b206af14c861 (commit) via b47567c783166c31d0ddaeb1add4ef76600a6406 (commit) via 1ef5090fbe0b1693faf7cd3e63bbd8bb1235c0d6 (commit) via 9509e5c055aaaaee87041e868f3217a8d4070c12 (commit) via d71b4fba22234d2322f77930307f99cd746f0eb7 (commit) via 274d7ae48835cf72c3aa43d7f31fb417a67bd688 (commit) from f6485596cf4bfe263ddea4f975f9041bd78095ff (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 35931a498b667b91024dd826b7141a1ad05cb4fa Merge: b47567c7 c9ecb53a Author: Lawrence Sebald <ljs...@us...> Date: Thu Apr 17 01:18:07 2025 -0400 Merge pull request #970 from DC-SWAT/g1ata_fix_prot_cleanup g1ata: Fixed DMA protection and cleanup. commit c9ecb53a4a48a4cb0bc4b65d4364b206af14c861 Author: DC-SWAT <sw...@21...> Date: Thu Apr 17 08:21:50 2025 +0700 g1ata: Fixed DMA protection and cleanup. - Fixed DMA protection register memory area. - Introduced constants for maximum sector counts (LBA28 and LBA48). - Refactored sector count handling in various functions to use these constants. - Improved DMA chaining logic and error handling in the DMA IRQ handler. - Updated type usage for sector counts to size_t for better compatibility. - Using macros instead of hardcoded values. commit b47567c783166c31d0ddaeb1add4ef76600a6406 Merge: 9509e5c0 1ef5090f Author: Lawrence Sebald <ljs...@us...> Date: Wed Apr 16 15:21:53 2025 -0400 Merge pull request #969 from pcercuei/libc-fix-thrd-join Fix potential NULL pointer dereference in thrd_join(). commit 1ef5090fbe0b1693faf7cd3e63bbd8bb1235c0d6 Author: Paul Cercueil <pa...@cr...> Date: Tue Apr 15 13:10:09 2025 +0200 libc: Fix thrd_join() thrd_join() did not handle the case where the second parameter passed is NULL, which is permitted by the standard. Signed-off-by: Paul Cercueil <pa...@cr...> commit 9509e5c055aaaaee87041e868f3217a8d4070c12 Author: QuzarDC <qu...@co...> Date: Sat Apr 12 18:22:37 2025 -0400 Use new __array_size macro. Replace instances of build-time array size counting with the new macro. Cleaned up one to use more appropriate types. commit d71b4fba22234d2322f77930307f99cd746f0eb7 Author: QuzarDC <qu...@co...> Date: Sat Apr 12 15:38:26 2025 -0400 Add build_assert and array_size macros. The `__array_size` macro is already being hand-rolled multiple times in the codebase. This should provide a more robust version of it. `__build_assert` should also be quite useful and backs param checking in `__array_size`. commit 274d7ae48835cf72c3aa43d7f31fb417a67bd688 Author: QuzarDC <qu...@co...> Date: Sat Apr 12 15:09:26 2025 -0400 Clean up doxygen for cdefs.h Split out the doxygen group for the defines that are for compiler attributes vs language defines. ----------------------------------------------------------------------- Summary of changes: include/kos/cdefs.h | 113 ++++++++++++++++++--- include/kos/dbgio.h | 2 +- kernel/arch/dreamcast/hardware/g1ata.c | 99 ++++++++++-------- kernel/arch/dreamcast/hardware/maple/keyboard.c | 2 +- kernel/arch/dreamcast/hardware/maple/maple_utils.c | 6 +- kernel/arch/dreamcast/kernel/init.c | 2 +- kernel/debug/dbgio.c | 4 +- kernel/libc/c11/thrd_join.c | 4 +- 8 files changed, 169 insertions(+), 63 deletions(-) diff --git a/include/kos/cdefs.h b/include/kos/cdefs.h index f042b524..22ff1e16 100644 --- a/include/kos/cdefs.h +++ b/include/kos/cdefs.h @@ -9,12 +9,12 @@ */ /** \file kos/cdefs.h - \brief Definitions for builtin attributes and compiler directives - \ingroup system_macros + \brief Various common macros used throughout the codebase + \ingroup system - This file contains definitions of various __attribute__ directives in - shorter forms for use in programs. These typically aid in optimizations - or provide the compiler with extra information about a symbol. + This file contains various convenience macros. Mostly compiler + __attribute__ directives, as well as other language defines, and + useful language extensions. \author Megan Potter \author Lawrence Sebald @@ -26,19 +26,21 @@ #include <sys/cdefs.h> -/** \defgroup system_macros Macros - \brief Various common macros used throughout the codebase - \ingroup system - - @{ -*/ - /* Check GCC version */ #if __GNUC__ <= 3 # warning Your GCC is too old. This will probably not work right. #endif -/* Special function/variable attributes */ +/** \defgroup system_attributes + \brief Definitions for builtin attributes and compiler directives + \ingroup system + + This group contains definitions of various __attribute__ directives in + shorter forms for use in programs. These typically aid in optimizations + or provide the compiler with extra information about a symbol. + + @{ +*/ #ifndef __noreturn /** \brief Identify a function that will never return. */ @@ -169,6 +171,18 @@ #define __no_inline __attribute__((__noinline__)) #endif +/** @} */ + +/** \defgroup system_compat + \brief Definitions for language features + \ingroup system + + This group contains definitions to help retain some older language + backwards compatibility for external software linking into KOS. + + @{ +*/ + /* GCC macros for special cases */ /* #if __GNUC__ == */ @@ -192,4 +206,77 @@ /** @} */ +/** \defgroup system_helpers + \brief General useful language macros + \ingroup system + + This group contains definitions to help give robust solutions + to common code patterns. + + @{ +*/ + +/** \brief Assert a build-time dependency. + + Your compiler will fail if the condition isn't true, or can't be evaluated + by the compiler. This can only be used within a function. + + Example: + #include <stddef.h> + ... + static char *foo_to_char(struct foo *foo) + { + // This code needs string to be at start of foo. + __build_assert(offsetof(struct foo, string) == 0); + return (char *)foo; + } + + \param cond The compile-time condition which must be true. + + \sa __build_assert_or_zero + */ +#define __build_assert(cond) \ + do { (void) sizeof(char [1 - 2*!(cond)]); } while(0) + +/** \brief Assert a build-time dependency. + + Your compiler will fail if the condition isn't true, or can't be evaluated + by the compiler. This can be used in an expression: its value is "0". + + Example: + #define foo_to_char(foo) \ + ((char *)(foo) \ + + __build_assert_or_zero(offsetof(struct foo, string) == 0)) + + \param cond The compile-time condition which must be true. + + \sa __build_assert + */ +#define __build_assert_or_zero(cond) \ + (sizeof(char [1 - 2*!(cond)]) - 1) + +/** \brief Get the number of elements in a visible array. + + This does not work on pointers, or arrays declared as [], or + function parameters. With correct compiler support, such usage + will cause a build error (\see __build_assert). + + \param arr The array whose size you want. + + */ +#define __array_size(arr) (sizeof(arr) / sizeof((arr)[0]) + _array_size_chk(arr)) + +/* Helper for __array_size's type check */ +#if HAVE_BUILTIN_TYPES_COMPATIBLE_P && HAVE_TYPEOF +/* Two gcc extensions. + * &a[0] degrades to a pointer: a different type from an array */ +#define _array_size_chk(arr) \ + __build_assert_or_zero(!__builtin_types_compatible_p(typeof(arr), \ + typeof(&(arr)[0]))) +#else +#define _array_size_chk(arr) 0 +#endif + +/** @} */ + #endif /* __KOS_CDEFS_H */ diff --git a/include/kos/dbgio.h b/include/kos/dbgio.h index ffdcb5f0..4210f2e4 100644 --- a/include/kos/dbgio.h +++ b/include/kos/dbgio.h @@ -107,7 +107,7 @@ typedef struct dbgio_handler { /** \cond */ /* These two should be initialized in arch. */ extern dbgio_handler_t * dbgio_handlers[]; -extern int dbgio_handler_cnt; +extern const size_t dbgio_handler_cnt; /* This is defined by the shared code, in case there's no valid handler. */ extern dbgio_handler_t dbgio_null; diff --git a/kernel/arch/dreamcast/hardware/g1ata.c b/kernel/arch/dreamcast/hardware/g1ata.c index 83b72b7f..54894c5d 100644 --- a/kernel/arch/dreamcast/hardware/g1ata.c +++ b/kernel/arch/dreamcast/hardware/g1ata.c @@ -150,6 +150,9 @@ typedef struct ata_devdata { #define ATA_TRANSFER_WDMA(x) 0x20 | ((x) & 0x07) #define ATA_TRANSFER_UDMA(x) 0x40 | ((x) & 0x07) +#define ATA_MAX_SECTORS_LBA28 256 +#define ATA_MAX_SECTORS_LBA48 65536 + /* Access timing data. */ #define G1_ACCESS_WDMA_MODE2 0x00001001 #define G1_ACCESS_PIO_DEFAULT 0x00000222 @@ -194,7 +197,7 @@ extern mutex_t _g1_ata_mutex; do {} while(!(IN8(G1_ATA_ALTSTATUS) & G1_ATA_SR_DRDY)) static inline int use_lba28(uint64_t sector, size_t count) { - return ((sector + count) < 0x0FFFFFFF) && (count <= 256); + return ((sector + count) < 0x0FFFFFFF) && (count <= ATA_MAX_SECTORS_LBA28); } #define CAN_USE_LBA48() ((device.command_sets & (1 << 26))) @@ -218,7 +221,7 @@ inline int g1_ata_mutex_unlock(void) { return mutex_unlock(&_g1_ata_mutex); } -static void g1_ata_set_sector_and_count(uint64_t sector, uint32_t count, int lba28) { +static void g1_ata_set_sector_and_count(uint64_t sector, size_t count, int lba28) { if(!lba28) { OUT8(G1_ATA_SECTOR_COUNT, (uint8_t)(count >> 8)); OUT8(G1_ATA_LBA_LOW, (uint8_t)((sector >> 24) & 0xFF)); @@ -235,24 +238,50 @@ static void g1_ata_set_sector_and_count(uint64_t sector, uint32_t count, int lba OUT8(G1_ATA_LBA_HIGH, (uint8_t)((sector >> 16) & 0xFF)); } +static void g1_dma_done(void) { + /* Signal the calling thread to continue, if it is blocking. */ + if(dma_blocking) { + sem_signal(&dma_done); + thd_schedule(1, 0); + dma_blocking = 0; + } + + dma_in_progress = 0; + + /* Make sure to select the GD-ROM drive back. */ + g1_ata_select_device(G1_ATA_MASTER); + mutex_unlock_as_thread(&_g1_ata_mutex, dma_thd); +} + static void g1_dma_irq_hnd(uint32 code, void *data) { int can_lba48 = CAN_USE_LBA48(); - unsigned int nb_sectors; + size_t nb_sectors; + uint8_t status; /* XXXX: Probably should look at the code to make sure it isn't an error. */ (void)code; (void)data; - if(dma_in_progress && !can_lba48 && dma_nb_sectors > 256) { - dma_sector += 256; - dma_nb_sectors -= 256; - nb_sectors = dma_nb_sectors <= 256 ? dma_nb_sectors : 256; + if(dma_in_progress && !can_lba48 && dma_nb_sectors > ATA_MAX_SECTORS_LBA28) { + dma_sector += ATA_MAX_SECTORS_LBA28; + dma_nb_sectors -= ATA_MAX_SECTORS_LBA28; + nb_sectors = dma_nb_sectors <= ATA_MAX_SECTORS_LBA28 ? dma_nb_sectors : ATA_MAX_SECTORS_LBA28; + + /* Make sure to acknowledge the IRQ before continuing */ + status = IN8(G1_ATA_STATUS_REG); + + /* If there is an error, stop the DMA chain. */ + if(status & (G1_ATA_SR_ERR | G1_ATA_SR_DF)) { + dbglog(DBG_ERROR, "g1_dma_irq_hnd: Error detected in DMA chain, aborting\n"); + g1_dma_done(); + return; + } /* Set the DMA parameters for the next transfer. */ g1_ata_select_device(G1_ATA_SLAVE | G1_ATA_LBA_MODE | ((dma_sector >> 24) & 0x0F)); g1_ata_set_sector_and_count(dma_sector, nb_sectors, 1); - OUT32(G1_ATA_DMA_ADDRESS, IN32(G1_ATA_DMA_ADDRESS) + 256 * 512); + OUT32(G1_ATA_DMA_ADDRESS, IN32(G1_ATA_DMA_ADDRESS) + ATA_MAX_SECTORS_LBA28 * 512); OUT32(G1_ATA_DMA_LENGTH, nb_sectors * 512); if(dma_cmd == ATA_CMD_WRITE_DMA) @@ -267,18 +296,7 @@ static void g1_dma_irq_hnd(uint32 code, void *data) { OUT32(G1_ATA_DMA_STATUS, 1); } else if(dma_in_progress) { - /* Signal the calling thread to continue, if it is blocking. */ - if(dma_blocking) { - sem_signal(&dma_done); - thd_schedule(1, 0); - dma_blocking = 0; - } - - dma_in_progress = 0; - - /* Make sure to select the GD-ROM drive back. */ - g1_ata_select_device(G1_ATA_MASTER); - mutex_unlock_as_thread(&_g1_ata_mutex, dma_thd); + g1_dma_done(); } } @@ -382,7 +400,7 @@ int g1_ata_read_chs(uint16_t c, uint8_t h, uint8_t s, size_t count, void *buf) { int rv = 0; unsigned int i, j; - uint16_t nsects; + size_t nsects; uint16_t word; uint8_t *ptr = (uint8_t *)buf; @@ -400,14 +418,14 @@ int g1_ata_read_chs(uint16_t c, uint8_t h, uint8_t s, size_t count, g1_ata_wait_bsydrq(); while(count) { - nsects = count > 256 ? 256 : (uint16_t)count; + nsects = count > ATA_MAX_SECTORS_LBA28 ? ATA_MAX_SECTORS_LBA28 : count; count -= nsects; g1_ata_select_device(G1_ATA_SLAVE | (h & 0x0F)); /* Write out the number of sectors we want as well as the cylinder and sector. */ - OUT8(G1_ATA_SECTOR_COUNT, nsects); + OUT8(G1_ATA_SECTOR_COUNT, (uint8_t)nsects); OUT8(G1_ATA_CHS_SECTOR, s); OUT8(G1_ATA_CHS_CYL_LOW, (uint8_t)((c >> 0) & 0xFF)); OUT8(G1_ATA_CHS_CYL_HIGH, (uint8_t)((c >> 8) & 0xFF)); @@ -463,7 +481,7 @@ int g1_ata_write_chs(uint16_t c, uint8_t h, uint8_t s, size_t count, const void *buf) { int rv = 0; unsigned int i, j; - uint16_t nsects; + size_t nsects; uint16_t word; uint8_t *ptr = (uint8_t *)buf; @@ -481,14 +499,14 @@ int g1_ata_write_chs(uint16_t c, uint8_t h, uint8_t s, size_t count, g1_ata_wait_bsydrq(); while(count) { - nsects = count > 256 ? 256 : (uint16_t)count; + nsects = count > ATA_MAX_SECTORS_LBA28 ? ATA_MAX_SECTORS_LBA28 : count; count -= nsects; g1_ata_select_device(G1_ATA_SLAVE | (h & 0x0F)); /* Write out the number of sectors we want as well as the cylinder and sector. */ - OUT8(G1_ATA_SECTOR_COUNT, nsects); + OUT8(G1_ATA_SECTOR_COUNT, (uint8_t)nsects); OUT8(G1_ATA_CHS_SECTOR, s); OUT8(G1_ATA_CHS_CYL_LOW, (uint8_t)((c >> 0) & 0xFF)); OUT8(G1_ATA_CHS_CYL_HIGH, (uint8_t)((c >> 8) & 0xFF)); @@ -538,10 +556,11 @@ int g1_ata_write_chs(uint16_t c, uint8_t h, uint8_t s, size_t count, int g1_ata_read_lba(uint64_t sector, size_t count, void *buf) { int rv = 0; unsigned int i, j; - uint16_t nsects; + size_t nsects; uint16_t word; uint8_t *ptr = (uint8_t *)buf; int lba28, cmd; + const size_t max_sectors = CAN_USE_LBA48() ? ATA_MAX_SECTORS_LBA48 : ATA_MAX_SECTORS_LBA28; /* Make sure that we've been initialized and there's a disk attached. */ if(!devices) { @@ -569,11 +588,11 @@ int g1_ata_read_lba(uint64_t sector, size_t count, void *buf) { g1_ata_wait_bsydrq(); while(count) { - nsects = count > 256 ? 256 : (uint16_t)count; + nsects = count > max_sectors ? max_sectors : count; count -= nsects; /* Which mode are we using: LBA28 or LBA48? */ - lba28 = (sector + nsects) <= 0x0FFFFFFF; + lba28 = use_lba28(sector, nsects); if(lba28) { g1_ata_select_device(G1_ATA_SLAVE | G1_ATA_LBA_MODE | ((sector >> 24) & 0x0F)); @@ -656,7 +675,7 @@ int g1_ata_read_lba_dma(uint64_t sector, size_t count, void *buf, } /* Chaining isn't done yet, so make sure we don't need to. */ - if(count > 65536) { + if(count > ATA_MAX_SECTORS_LBA48) { errno = EOVERFLOW; return -1; } @@ -712,8 +731,8 @@ int g1_ata_read_lba_dma(uint64_t sector, size_t count, void *buf, dma_sector = sector; irq_restore(old); - if(!can_lba48 && count > 256) - count = 256; + if(!can_lba48 && count > ATA_MAX_SECTORS_LBA28) + count = ATA_MAX_SECTORS_LBA28; /* Wait for the device to signal it is ready. */ g1_ata_wait_bsydrq(); @@ -739,11 +758,11 @@ int g1_ata_read_lba_dma(uint64_t sector, size_t count, void *buf, int g1_ata_write_lba(uint64_t sector, size_t count, const void *buf) { unsigned int i, j; - uint32_t nsects; + size_t nsects; uint16_t word; uint8_t *ptr = (uint8_t *)buf; int cmd, lba28; - const size_t max_sectors = CAN_USE_LBA48() ? 65536 : 256; + const size_t max_sectors = CAN_USE_LBA48() ? ATA_MAX_SECTORS_LBA48 : ATA_MAX_SECTORS_LBA28; /* Make sure that we've been initialized and there's a disk attached. */ if(!devices) { @@ -775,7 +794,7 @@ int g1_ata_write_lba(uint64_t sector, size_t count, const void *buf) { count -= nsects; /* Which mode are we using: LBA28 or LBA48? */ - lba28 = (sector + nsects) <= 0x0FFFFFFF; + lba28 = use_lba28(sector, nsects); if(lba28) { g1_ata_select_device(G1_ATA_SLAVE | G1_ATA_LBA_MODE | ((sector >> 24) & 0x0F)); @@ -847,7 +866,7 @@ int g1_ata_write_lba_dma(uint64_t sector, size_t count, const void *buf, } /* Make sure we don't exceed maximum sector count */ - if(count > 65536) { + if(count > ATA_MAX_SECTORS_LBA48) { errno = EOVERFLOW; return -1; } @@ -912,8 +931,8 @@ int g1_ata_write_lba_dma(uint64_t sector, size_t count, const void *buf, g1_ata_select_device(G1_ATA_SLAVE | G1_ATA_LBA_MODE | ((sector >> 24) & 0x0F)); cmd = ATA_CMD_WRITE_DMA; - if(count > 256) { - count = 256; + if(count > ATA_MAX_SECTORS_LBA28) { + count = ATA_MAX_SECTORS_LBA28; } } else { @@ -944,7 +963,7 @@ int g1_ata_flush(void) { timer_spin_sleep(1); /* Flush the disk's write cache to make sure everything gets written out. */ - if(device.max_lba > 0x0FFFFFFF) + if(CAN_USE_LBA48()) OUT8(G1_ATA_COMMAND_REG, ATA_CMD_FLUSH_CACHE_EXT); else OUT8(G1_ATA_COMMAND_REG, ATA_CMD_FLUSH_CACHE); @@ -1092,7 +1111,7 @@ static int g1_ata_scan(void) { if(!g1_ata_set_transfer_mode(ATA_TRANSFER_WDMA(2))) { OUT32(G1_ATA_DMA_RACCESS_WAIT, G1_ACCESS_WDMA_MODE2); OUT32(G1_ATA_DMA_WACCESS_WAIT, G1_ACCESS_WDMA_MODE2); - OUT32(G1_ATA_DMA_PROTECTION, G1_DMA_UNLOCK_ALLMEM); + OUT32(G1_ATA_DMA_PROTECTION | MEM_AREA_P2_BASE, G1_DMA_UNLOCK_ALLMEM); } else { device.wdma_modes = 0; diff --git a/kernel/arch/dreamcast/hardware/maple/keyboard.c b/kernel/arch/dreamcast/hardware/maple/keyboard.c index c4dc8663..9fd1b22c 100644 --- a/kernel/arch/dreamcast/hardware/maple/keyboard.c +++ b/kernel/arch/dreamcast/hardware/maple/keyboard.c @@ -80,7 +80,7 @@ typedef struct kbd_keymap { } kbd_keymap_internal_t; /* Built-in keymaps. */ -#define KBD_NUM_KEYMAPS (sizeof(keymaps) / sizeof(keymaps[0])) +#define KBD_NUM_KEYMAPS __array_size(keymaps) static const kbd_keymap_internal_t keymaps[] = { { /* Japanese keyboard */ diff --git a/kernel/arch/dreamcast/hardware/maple/maple_utils.c b/kernel/arch/dreamcast/hardware/maple/maple_utils.c index 5b455e12..c12db5c6 100644 --- a/kernel/arch/dreamcast/hardware/maple/maple_utils.c +++ b/kernel/arch/dreamcast/hardware/maple/maple_utils.c @@ -93,7 +93,6 @@ static const char *maple_cap_names[] = { "Mouse", "JumpPack" }; -#define maple_cap_name_cnt (sizeof(maple_cap_names)/sizeof(char *)) /* Print the capabilities of a given driver to dbglog; NOT THREAD SAFE */ static char caps_buffer[64]; @@ -102,7 +101,7 @@ const char * maple_pcaps(uint32 functions) { for(o = 0, i = 0; i < 32; i++) { if(functions & (0x80000000 >> i)) { - if(i > maple_cap_name_cnt || maple_cap_names[i] == NULL) { + if(i > __array_size(maple_cap_names) || maple_cap_names[i] == NULL) { sprintf(caps_buffer + o, "UNKNOWN(%08x), ", (0x80000000 >> i)); o += strlen(caps_buffer + o); } @@ -133,13 +132,12 @@ static const char *maple_resp_names[] = { "OK", "DATATRF" }; -#define maple_resp_name_cnt ((int)(sizeof(maple_resp_names)/sizeof(char *))) /* Return a string representing the maple response code */ const char * maple_perror(int response) { response += 5; - if(response < 0 || response >= maple_resp_name_cnt) + if(response < 0 || (size_t)response >= __array_size(maple_resp_names)) return "UNKNOWN"; else return maple_resp_names[response]; diff --git a/kernel/arch/dreamcast/kernel/init.c b/kernel/arch/dreamcast/kernel/init.c index dae62a55..01841aec 100644 --- a/kernel/arch/dreamcast/kernel/init.c +++ b/kernel/arch/dreamcast/kernel/init.c @@ -53,7 +53,7 @@ dbgio_handler_t * dbgio_handlers[] = { &dbgio_null, &dbgio_fb }; -int dbgio_handler_cnt = sizeof(dbgio_handlers) / sizeof(dbgio_handler_t *); +const size_t dbgio_handler_cnt = __array_size(dbgio_handlers); void arch_init_net_dcload_ip(void) { union { diff --git a/kernel/debug/dbgio.c b/kernel/debug/dbgio.c index a7ecb9f8..1c79034c 100644 --- a/kernel/debug/dbgio.c +++ b/kernel/debug/dbgio.c @@ -25,7 +25,7 @@ static dbgio_handler_t * dbgio = NULL; int dbgio_dev_select(const char * name) { - int i; ...<truncated>... hooks/post-receive -- A pseudo Operating System for the Dreamcast. |