diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000000000000000000000000000000000000..667d62e8ff631c0aee828b2ef1a3e4dd2e71088d --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,9 @@ +{ + "files.associations": { + "lwp_arch.h": "c", + "cpuport.h": "c", + "rtdevice.h": "c", + "rtthread.h": "c", + "random": "c" + } +} \ No newline at end of file diff --git a/bsp/x86/.config b/bsp/x86/.config new file mode 100644 index 0000000000000000000000000000000000000000..935981c0f1d755b6de6e7f1d4ad7bb82c673867c --- /dev/null +++ b/bsp/x86/.config @@ -0,0 +1,595 @@ +# +# Automatically generated file; DO NOT EDIT. +# RT-Thread Project Configuration +# + +# +# RT-Thread Kernel +# +CONFIG_RT_NAME_MAX=20 +# CONFIG_RT_USING_ARCH_DATA_TYPE is not set +CONFIG_RT_USING_SMART=y +# CONFIG_RT_USING_SMP is not set +CONFIG_RT_ALIGN_SIZE=4 +# CONFIG_RT_THREAD_PRIORITY_8 is not set +CONFIG_RT_THREAD_PRIORITY_32=y +# CONFIG_RT_THREAD_PRIORITY_256 is not set +CONFIG_RT_THREAD_PRIORITY_MAX=32 +CONFIG_RT_TICK_PER_SECOND=100 +# CONFIG_RT_USING_OVERFLOW_CHECK is not set +CONFIG_RT_USING_HOOK=y +CONFIG_RT_USING_IDLE_HOOK=y +CONFIG_RT_IDLE_HOOK_LIST_SIZE=4 +CONFIG_IDLE_THREAD_STACK_SIZE=16384 +CONFIG_RT_USING_TIMER_SOFT=y +CONFIG_RT_TIMER_THREAD_PRIO=4 +CONFIG_RT_TIMER_THREAD_STACK_SIZE=16384 +CONFIG_RT_DEBUG=y +# CONFIG_RT_DEBUG_COLOR is not set +# CONFIG_RT_DEBUG_INIT_CONFIG is not set +# CONFIG_RT_DEBUG_THREAD_CONFIG is not set +# CONFIG_RT_DEBUG_SCHEDULER_CONFIG is not set +# CONFIG_RT_DEBUG_IPC_CONFIG is not set +# CONFIG_RT_DEBUG_TIMER_CONFIG is not set +# CONFIG_RT_DEBUG_IRQ_CONFIG is not set +# CONFIG_RT_DEBUG_MEM_CONFIG is not set +# CONFIG_RT_DEBUG_SLAB_CONFIG is not set +# CONFIG_RT_DEBUG_MEMHEAP_CONFIG is not set +# CONFIG_RT_DEBUG_MODULE_CONFIG is not set + +# +# Inter-Thread communication +# +CONFIG_RT_USING_SEMAPHORE=y +CONFIG_RT_USING_MUTEX=y +CONFIG_RT_USING_EVENT=y +CONFIG_RT_USING_MAILBOX=y +CONFIG_RT_USING_MESSAGEQUEUE=y +CONFIG_RT_USING_SIGNALS=y + +# +# Memory Management +# +CONFIG_RT_USING_MEMPOOL=y +# CONFIG_RT_USING_MEMHEAP is not set +# CONFIG_RT_USING_NOHEAP is not set +CONFIG_RT_USING_SMALL_MEM=y +# CONFIG_RT_USING_SLAB is not set +# CONFIG_RT_USING_MEMTRACE is not set +CONFIG_RT_USING_HEAP=y + +# +# Kernel Device Object +# +CONFIG_RT_USING_DEVICE=y +# CONFIG_RT_USING_DEVICE_OPS is not set +# CONFIG_RT_USING_INTERRUPT_INFO is not set +CONFIG_RT_USING_CONSOLE=y +CONFIG_RT_CONSOLEBUF_SIZE=256 +CONFIG_RT_CONSOLE_DEVICE_NAME="uart0" +CONFIG_RT_VER_NUM=0x50000 +CONFIG_RT_USING_CACHE=y +# CONFIG_RT_USING_CPU_FFS is not set +# CONFIG_ARCH_CPU_STACK_GROWS_UPWARD is not set +CONFIG_RT_USING_USERSPACE=y +CONFIG_KERNEL_VADDR_START=0x00000000 +CONFIG_PV_OFFSET=0 +CONFIG_ARCH_X86=y + +# +# RT-Thread Components +# +CONFIG_RT_USING_COMPONENTS_INIT=y +CONFIG_RT_USING_USER_MAIN=y +CONFIG_RT_MAIN_THREAD_STACK_SIZE=2048 +CONFIG_RT_MAIN_THREAD_PRIORITY=10 + +# +# C++ features +# +# CONFIG_RT_USING_CPLUSPLUS is not set + +# +# Command shell +# +CONFIG_RT_USING_FINSH=y +CONFIG_RT_USING_MSH=y +CONFIG_FINSH_THREAD_NAME="tshell" +CONFIG_FINSH_USING_HISTORY=y +CONFIG_FINSH_HISTORY_LINES=5 +CONFIG_FINSH_USING_SYMTAB=y +CONFIG_FINSH_USING_DESCRIPTION=y +# CONFIG_FINSH_ECHO_DISABLE_DEFAULT is not set +CONFIG_FINSH_THREAD_PRIORITY=20 +CONFIG_FINSH_THREAD_STACK_SIZE=4096 +CONFIG_FINSH_CMD_SIZE=80 +# CONFIG_FINSH_USING_AUTH is not set +CONFIG_FINSH_ARG_MAX=10 + +# +# Device virtual file system +# +CONFIG_RT_USING_DFS=y +CONFIG_DFS_USING_WORKDIR=y +CONFIG_DFS_FILESYSTEMS_MAX=3 +CONFIG_DFS_FILESYSTEM_TYPES_MAX=3 +CONFIG_DFS_FD_MAX=16 +# CONFIG_RT_USING_DFS_MNTTABLE is not set +CONFIG_RT_USING_DFS_ELMFAT=y + +# +# elm-chan's FatFs, Generic FAT Filesystem Module +# +CONFIG_RT_DFS_ELM_CODE_PAGE=437 +CONFIG_RT_DFS_ELM_WORD_ACCESS=y +# CONFIG_RT_DFS_ELM_USE_LFN_0 is not set +# CONFIG_RT_DFS_ELM_USE_LFN_1 is not set +# CONFIG_RT_DFS_ELM_USE_LFN_2 is not set +CONFIG_RT_DFS_ELM_USE_LFN_3=y +CONFIG_RT_DFS_ELM_USE_LFN=3 +CONFIG_RT_DFS_ELM_MAX_LFN=255 +CONFIG_RT_DFS_ELM_DRIVES=2 +CONFIG_RT_DFS_ELM_MAX_SECTOR_SIZE=512 +# CONFIG_RT_DFS_ELM_USE_ERASE is not set +CONFIG_RT_DFS_ELM_REENTRANT=y +CONFIG_RT_USING_DFS_DEVFS=y +CONFIG_RT_USING_DFS_ROMFS=y +# CONFIG_RT_USING_DFS_CROMFS is not set +# CONFIG_RT_USING_DFS_RAMFS is not set +# CONFIG_RT_USING_DFS_UFFS is not set +# CONFIG_RT_USING_DFS_JFFS2 is not set + +# +# Device Drivers +# +CONFIG_RT_USING_DEVICE_IPC=y +CONFIG_RT_PIPE_BUFSZ=512 +# CONFIG_RT_USING_SYSTEM_WORKQUEUE is not set +CONFIG_RT_USING_SERIAL=y +# CONFIG_RT_SERIAL_USING_DMA is not set +CONFIG_RT_SERIAL_RB_BUFSZ=64 +# CONFIG_RT_USING_CAN is not set +# CONFIG_RT_USING_HWTIMER is not set +# CONFIG_RT_USING_CPUTIME is not set +# CONFIG_RT_USING_I2C is not set +# CONFIG_RT_USING_PHY is not set +# CONFIG_RT_USING_PIN is not set +# CONFIG_RT_USING_ADC is not set +# CONFIG_RT_USING_DAC is not set +# CONFIG_RT_USING_NULL is not set +# CONFIG_RT_USING_ZERO is not set +# CONFIG_RT_USING_RANDOM is not set +# CONFIG_RT_USING_PWM is not set +# CONFIG_RT_USING_MTD_NOR is not set +# CONFIG_RT_USING_MTD_NAND is not set +# CONFIG_RT_USING_PM is not set +# CONFIG_RT_USING_RTC is not set +# CONFIG_RT_USING_SDIO is not set +# CONFIG_RT_USING_SPI is not set +# CONFIG_RT_USING_WDT is not set +# CONFIG_RT_USING_AUDIO is not set +# CONFIG_RT_USING_SENSOR is not set +# CONFIG_RT_USING_TOUCH is not set +# CONFIG_RT_USING_HWCRYPTO is not set +# CONFIG_RT_USING_PULSE_ENCODER is not set +# CONFIG_RT_USING_INPUT_CAPTURE is not set +# CONFIG_RT_USING_WIFI is not set + +# +# Using USB +# +# CONFIG_RT_USING_USB_HOST is not set +# CONFIG_RT_USING_USB_DEVICE is not set + +# +# POSIX layer and C standard library +# +CONFIG_RT_USING_LIBC=y +# CONFIG_RT_USING_NEWLIB is not set +CONFIG_RT_USING_MUSL=y +# CONFIG_RT_USING_PTHREADS is not set +CONFIG_RT_USING_POSIX=y +# CONFIG_RT_USING_POSIX_MMAP is not set +# CONFIG_RT_USING_POSIX_TERMIOS is not set +# CONFIG_RT_USING_POSIX_GETLINE is not set +# CONFIG_RT_USING_POSIX_AIO is not set +CONFIG_RT_USING_POSIX_CLOCKTIME=y +# CONFIG_RT_USING_MODULE is not set + +# +# Network +# + +# +# Socket abstraction layer +# +# CONFIG_RT_USING_SAL is not set + +# +# Network interface device +# +# CONFIG_RT_USING_NETDEV is not set + +# +# light weight TCP/IP stack +# +# CONFIG_RT_USING_LWIP is not set + +# +# AT commands +# +# CONFIG_RT_USING_AT is not set + +# +# VBUS(Virtual Software BUS) +# +# CONFIG_RT_USING_VBUS is not set + +# +# Utilities +# +# CONFIG_RT_USING_RYM is not set +# CONFIG_RT_USING_ULOG is not set +# CONFIG_RT_USING_UTEST is not set +# CONFIG_RT_USING_RT_LINK is not set +CONFIG_RT_USING_LWP=y +CONFIG_RT_LWP_MAX_NR=30 +CONFIG_LWP_TASK_STACK_SIZE=16384 +CONFIG_RT_CH_MSG_MAX_NR=1024 +CONFIG_RT_LWP_SHM_MAX_NR=64 +CONFIG_LWP_CONSOLE_INPUT_BUFFER_SIZE=1024 +CONFIG_LWP_TID_MAX_NR=64 +# CONFIG_LWP_UNIX98_PTY is not set + +# +# RT-Thread online packages +# + +# +# IoT - internet of things +# +# CONFIG_PKG_USING_LORAWAN_DRIVER is not set +# CONFIG_PKG_USING_PAHOMQTT is not set +# CONFIG_PKG_USING_UMQTT is not set +# CONFIG_PKG_USING_WEBCLIENT is not set +# CONFIG_PKG_USING_WEBNET is not set +# CONFIG_PKG_USING_MONGOOSE is not set +# CONFIG_PKG_USING_MYMQTT is not set +# CONFIG_PKG_USING_KAWAII_MQTT is not set +# CONFIG_PKG_USING_BC28_MQTT is not set +# CONFIG_PKG_USING_WEBTERMINAL is not set +# CONFIG_PKG_USING_CJSON is not set +# CONFIG_PKG_USING_JSMN is not set +# CONFIG_PKG_USING_LIBMODBUS is not set +# CONFIG_PKG_USING_FREEMODBUS is not set +# CONFIG_PKG_USING_LJSON is not set +# CONFIG_PKG_USING_EZXML is not set +# CONFIG_PKG_USING_NANOPB is not set + +# +# Wi-Fi +# + +# +# Marvell WiFi +# +# CONFIG_PKG_USING_WLANMARVELL is not set + +# +# Wiced WiFi +# +# CONFIG_PKG_USING_WLAN_WICED is not set +# CONFIG_PKG_USING_RW007 is not set +# CONFIG_PKG_USING_COAP is not set +# CONFIG_PKG_USING_NOPOLL is not set +# CONFIG_PKG_USING_NETUTILS is not set +# CONFIG_PKG_USING_CMUX is not set +# CONFIG_PKG_USING_PPP_DEVICE is not set +# CONFIG_PKG_USING_AT_DEVICE is not set +# CONFIG_PKG_USING_ATSRV_SOCKET is not set +# CONFIG_PKG_USING_WIZNET is not set + +# +# IoT Cloud +# +# CONFIG_PKG_USING_ONENET is not set +# CONFIG_PKG_USING_GAGENT_CLOUD is not set +# CONFIG_PKG_USING_ALI_IOTKIT is not set +# CONFIG_PKG_USING_AZURE is not set +# CONFIG_PKG_USING_TENCENT_IOT_EXPLORER is not set +# CONFIG_PKG_USING_JIOT-C-SDK is not set +# CONFIG_PKG_USING_UCLOUD_IOT_SDK is not set +# CONFIG_PKG_USING_JOYLINK is not set +# CONFIG_PKG_USING_NIMBLE is not set +# CONFIG_PKG_USING_OTA_DOWNLOADER is not set +# CONFIG_PKG_USING_IPMSG is not set +# CONFIG_PKG_USING_LSSDP is not set +# CONFIG_PKG_USING_AIRKISS_OPEN is not set +# CONFIG_PKG_USING_LIBRWS is not set +# CONFIG_PKG_USING_TCPSERVER is not set +# CONFIG_PKG_USING_PROTOBUF_C is not set +# CONFIG_PKG_USING_DLT645 is not set +# CONFIG_PKG_USING_QXWZ is not set +# CONFIG_PKG_USING_SMTP_CLIENT is not set +# CONFIG_PKG_USING_ABUP_FOTA is not set +# CONFIG_PKG_USING_LIBCURL2RTT is not set +# CONFIG_PKG_USING_CAPNP is not set +# CONFIG_PKG_USING_RT_CJSON_TOOLS is not set +# CONFIG_PKG_USING_AGILE_TELNET is not set +# CONFIG_PKG_USING_NMEALIB is not set +# CONFIG_PKG_USING_AGILE_JSMN is not set +# CONFIG_PKG_USING_PDULIB is not set +# CONFIG_PKG_USING_BTSTACK is not set +# CONFIG_PKG_USING_LORAWAN_ED_STACK is not set +# CONFIG_PKG_USING_WAYZ_IOTKIT is not set +# CONFIG_PKG_USING_MAVLINK is not set +# CONFIG_PKG_USING_RAPIDJSON is not set +# CONFIG_PKG_USING_BSAL is not set +# CONFIG_PKG_USING_AGILE_MODBUS is not set +# CONFIG_PKG_USING_AGILE_FTP is not set +# CONFIG_PKG_USING_EMBEDDEDPROTO is not set + +# +# security packages +# +# CONFIG_PKG_USING_MBEDTLS is not set +# CONFIG_PKG_USING_libsodium is not set +# CONFIG_PKG_USING_TINYCRYPT is not set +# CONFIG_PKG_USING_TFM is not set +# CONFIG_PKG_USING_YD_CRYPTO is not set + +# +# language packages +# +# CONFIG_PKG_USING_LUA is not set +# CONFIG_PKG_USING_JERRYSCRIPT is not set +# CONFIG_PKG_USING_MICROPYTHON is not set + +# +# multimedia packages +# +# CONFIG_PKG_USING_OPENMV is not set +# CONFIG_PKG_USING_MUPDF is not set +# CONFIG_PKG_USING_STEMWIN is not set +# CONFIG_PKG_USING_WAVPLAYER is not set +# CONFIG_PKG_USING_TJPGD is not set +# CONFIG_PKG_USING_PDFGEN is not set +# CONFIG_PKG_USING_HELIX is not set +# CONFIG_PKG_USING_AZUREGUIX is not set +# CONFIG_PKG_USING_TOUCHGFX2RTT is not set +# CONFIG_PKG_USING_NUEMWIN is not set +# CONFIG_PKG_USING_MP3PLAYER is not set +# CONFIG_PKG_USING_TINYJPEG is not set + +# +# tools packages +# +# CONFIG_PKG_USING_CMBACKTRACE is not set +# CONFIG_PKG_USING_EASYFLASH is not set +# CONFIG_PKG_USING_EASYLOGGER is not set +# CONFIG_PKG_USING_SYSTEMVIEW is not set +# CONFIG_PKG_USING_SEGGER_RTT is not set +# CONFIG_PKG_USING_RDB is not set +# CONFIG_PKG_USING_QRCODE is not set +# CONFIG_PKG_USING_ULOG_EASYFLASH is not set +# CONFIG_PKG_USING_ULOG_FILE is not set +# CONFIG_PKG_USING_LOGMGR is not set +# CONFIG_PKG_USING_ADBD is not set +# CONFIG_PKG_USING_COREMARK is not set +# CONFIG_PKG_USING_DHRYSTONE is not set +# CONFIG_PKG_USING_MEMORYPERF is not set +# CONFIG_PKG_USING_NR_MICRO_SHELL is not set +# CONFIG_PKG_USING_CHINESE_FONT_LIBRARY is not set +# CONFIG_PKG_USING_LUNAR_CALENDAR is not set +# CONFIG_PKG_USING_BS8116A is not set +# CONFIG_PKG_USING_GPS_RMC is not set +# CONFIG_PKG_USING_URLENCODE is not set +# CONFIG_PKG_USING_UMCN is not set +# CONFIG_PKG_USING_LWRB2RTT is not set +# CONFIG_PKG_USING_CPU_USAGE is not set +# CONFIG_PKG_USING_GBK2UTF8 is not set +# CONFIG_PKG_USING_VCONSOLE is not set +# CONFIG_PKG_USING_KDB is not set +# CONFIG_PKG_USING_WAMR is not set +# CONFIG_PKG_USING_MICRO_XRCE_DDS_CLIENT is not set +# CONFIG_PKG_USING_LWLOG is not set +# CONFIG_PKG_USING_ANV_TRACE is not set +# CONFIG_PKG_USING_ANV_MEMLEAK is not set +# CONFIG_PKG_USING_ANV_TESTSUIT is not set +# CONFIG_PKG_USING_ANV_BENCH is not set +# CONFIG_PKG_USING_DEVMEM is not set +# CONFIG_PKG_USING_REGEX is not set +# CONFIG_PKG_USING_MEM_SANDBOX is not set +# CONFIG_PKG_USING_SOLAR_TERMS is not set +# CONFIG_PKG_USING_GAN_ZHI is not set + +# +# system packages +# + +# +# acceleration: Assembly language or algorithmic acceleration packages +# +# CONFIG_PKG_USING_RT_MEMCPY_CM is not set +# CONFIG_PKG_USING_QFPLIB_M0_FULL is not set +# CONFIG_PKG_USING_QFPLIB_M0_TINY is not set +# CONFIG_PKG_USING_QFPLIB_M3 is not set + +# +# Micrium: Micrium software products porting for RT-Thread +# +# CONFIG_PKG_USING_UCOSIII_WRAPPER is not set +# CONFIG_PKG_USING_UCOSII_WRAPPER is not set +# CONFIG_PKG_USING_UC_CRC is not set +# CONFIG_PKG_USING_UC_CLK is not set +# CONFIG_PKG_USING_UC_COMMON is not set +# CONFIG_PKG_USING_UC_MODBUS is not set +# CONFIG_PKG_USING_GUIENGINE is not set +# CONFIG_PKG_USING_CAIRO is not set +# CONFIG_PKG_USING_PIXMAN is not set +# CONFIG_PKG_USING_PARTITION is not set +# CONFIG_PKG_USING_FAL is not set +# CONFIG_PKG_USING_FLASHDB is not set +# CONFIG_PKG_USING_SQLITE is not set +# CONFIG_PKG_USING_RTI is not set +# CONFIG_PKG_USING_LITTLEVGL2RTT is not set +# CONFIG_PKG_USING_CMSIS is not set +# CONFIG_PKG_USING_DFS_YAFFS is not set +# CONFIG_PKG_USING_LITTLEFS is not set +# CONFIG_PKG_USING_DFS_JFFS2 is not set +# CONFIG_PKG_USING_DFS_UFFS is not set +# CONFIG_PKG_USING_LWEXT4 is not set +# CONFIG_PKG_USING_THREAD_POOL is not set +# CONFIG_PKG_USING_ROBOTS is not set +# CONFIG_PKG_USING_EV is not set +# CONFIG_PKG_USING_SYSWATCH is not set +# CONFIG_PKG_USING_SYS_LOAD_MONITOR is not set +# CONFIG_PKG_USING_PLCCORE is not set +# CONFIG_PKG_USING_RAMDISK is not set +# CONFIG_PKG_USING_MININI is not set +# CONFIG_PKG_USING_QBOOT is not set +# CONFIG_PKG_USING_PPOOL is not set +# CONFIG_PKG_USING_OPENAMP is not set +# CONFIG_PKG_USING_RT_KPRINTF_THREADSAFE is not set +# CONFIG_PKG_USING_LPM is not set +# CONFIG_PKG_USING_TLSF is not set +# CONFIG_PKG_USING_EVENT_RECORDER is not set + +# +# peripheral libraries and drivers +# +# CONFIG_PKG_USING_SENSORS_DRIVERS is not set +# CONFIG_PKG_USING_REALTEK_AMEBA is not set +# CONFIG_PKG_USING_SHT2X is not set +# CONFIG_PKG_USING_SHT3X is not set +# CONFIG_PKG_USING_AS7341 is not set +# CONFIG_PKG_USING_STM32_SDIO is not set +# CONFIG_PKG_USING_ICM20608 is not set +# CONFIG_PKG_USING_U8G2 is not set +# CONFIG_PKG_USING_BUTTON is not set +# CONFIG_PKG_USING_PCF8574 is not set +# CONFIG_PKG_USING_SX12XX is not set +# CONFIG_PKG_USING_SIGNAL_LED is not set +# CONFIG_PKG_USING_LEDBLINK is not set +# CONFIG_PKG_USING_LITTLED is not set +# CONFIG_PKG_USING_LKDGUI is not set +# CONFIG_PKG_USING_NRF5X_SDK is not set +# CONFIG_PKG_USING_NRFX is not set +# CONFIG_PKG_USING_WM_LIBRARIES is not set +# CONFIG_PKG_USING_KENDRYTE_SDK is not set +# CONFIG_PKG_USING_INFRARED is not set +# CONFIG_PKG_USING_AGILE_BUTTON is not set +# CONFIG_PKG_USING_AGILE_LED is not set +# CONFIG_PKG_USING_AT24CXX is not set +# CONFIG_PKG_USING_MOTIONDRIVER2RTT is not set +# CONFIG_PKG_USING_AD7746 is not set +# CONFIG_PKG_USING_PCA9685 is not set +# CONFIG_PKG_USING_I2C_TOOLS is not set +# CONFIG_PKG_USING_NRF24L01 is not set +# CONFIG_PKG_USING_TOUCH_DRIVERS is not set +# CONFIG_PKG_USING_MAX17048 is not set +# CONFIG_PKG_USING_RPLIDAR is not set +# CONFIG_PKG_USING_AS608 is not set +# CONFIG_PKG_USING_RC522 is not set +# CONFIG_PKG_USING_WS2812B is not set +# CONFIG_PKG_USING_EMBARC_BSP is not set +# CONFIG_PKG_USING_EXTERN_RTC_DRIVERS is not set +# CONFIG_PKG_USING_MULTI_RTIMER is not set +# CONFIG_PKG_USING_MAX7219 is not set +# CONFIG_PKG_USING_BEEP is not set +# CONFIG_PKG_USING_EASYBLINK is not set +# CONFIG_PKG_USING_PMS_SERIES is not set +# CONFIG_PKG_USING_CAN_YMODEM is not set +# CONFIG_PKG_USING_LORA_RADIO_DRIVER is not set +# CONFIG_PKG_USING_QLED is not set +# CONFIG_PKG_USING_PAJ7620 is not set +# CONFIG_PKG_USING_AGILE_CONSOLE is not set +# CONFIG_PKG_USING_LD3320 is not set +# CONFIG_PKG_USING_WK2124 is not set +# CONFIG_PKG_USING_LY68L6400 is not set +# CONFIG_PKG_USING_DM9051 is not set +# CONFIG_PKG_USING_SSD1306 is not set +# CONFIG_PKG_USING_QKEY is not set +# CONFIG_PKG_USING_RS485 is not set +# CONFIG_PKG_USING_NES is not set +# CONFIG_PKG_USING_VIRTUAL_SENSOR is not set +# CONFIG_PKG_USING_VDEVICE is not set +# CONFIG_PKG_USING_SGM706 is not set +# CONFIG_PKG_USING_STM32WB55_SDK is not set +# CONFIG_PKG_USING_RDA58XX is not set +# CONFIG_PKG_USING_LIBNFC is not set +# CONFIG_PKG_USING_MFOC is not set +# CONFIG_PKG_USING_TMC51XX is not set +# CONFIG_PKG_USING_TCA9534 is not set +# CONFIG_PKG_USING_KOBUKI is not set +# CONFIG_PKG_USING_ROSSERIAL is not set +# CONFIG_PKG_USING_MICRO_ROS is not set + +# +# AI packages +# +# CONFIG_PKG_USING_LIBANN is not set +# CONFIG_PKG_USING_NNOM is not set +# CONFIG_PKG_USING_ONNX_BACKEND is not set +# CONFIG_PKG_USING_ONNX_PARSER is not set +# CONFIG_PKG_USING_TENSORFLOWLITEMICRO is not set +# CONFIG_PKG_USING_ELAPACK is not set +# CONFIG_PKG_USING_ULAPACK is not set +# CONFIG_PKG_USING_QUEST is not set +# CONFIG_PKG_USING_NAXOS is not set + +# +# miscellaneous packages +# +# CONFIG_PKG_USING_LIBCSV is not set +# CONFIG_PKG_USING_OPTPARSE is not set +# CONFIG_PKG_USING_FASTLZ is not set +# CONFIG_PKG_USING_MINILZO is not set +# CONFIG_PKG_USING_QUICKLZ is not set +# CONFIG_PKG_USING_LZMA is not set +# CONFIG_PKG_USING_MULTIBUTTON is not set +# CONFIG_PKG_USING_FLEXIBLE_BUTTON is not set +# CONFIG_PKG_USING_CANFESTIVAL is not set +# CONFIG_PKG_USING_ZLIB is not set +# CONFIG_PKG_USING_MINIZIP is not set +# CONFIG_PKG_USING_DSTR is not set +# CONFIG_PKG_USING_TINYFRAME is not set +# CONFIG_PKG_USING_KENDRYTE_DEMO is not set +# CONFIG_PKG_USING_DIGITALCTRL is not set +# CONFIG_PKG_USING_UPACKER is not set +# CONFIG_PKG_USING_UPARAM is not set + +# +# samples: kernel and components samples +# +# CONFIG_PKG_USING_KERNEL_SAMPLES is not set +# CONFIG_PKG_USING_FILESYSTEM_SAMPLES is not set +# CONFIG_PKG_USING_NETWORK_SAMPLES is not set +# CONFIG_PKG_USING_PERIPHERAL_SAMPLES is not set +# CONFIG_PKG_USING_HELLO is not set +# CONFIG_PKG_USING_VI is not set +# CONFIG_PKG_USING_KI is not set +# CONFIG_PKG_USING_ARMv7M_DWT is not set +# CONFIG_PKG_USING_VT100 is not set +# CONFIG_PKG_USING_UKAL is not set +# CONFIG_PKG_USING_CRCLIB is not set + +# +# entertainment: terminal games and other interesting software packages +# +# CONFIG_PKG_USING_THREES is not set +# CONFIG_PKG_USING_2048 is not set +# CONFIG_PKG_USING_SNAKE is not set +# CONFIG_PKG_USING_TETRIS is not set +# CONFIG_PKG_USING_DONUT is not set +# CONFIG_PKG_USING_ACLOCK is not set +# CONFIG_PKG_USING_LWGPS is not set +# CONFIG_PKG_USING_STATE_MACHINE is not set +# CONFIG_PKG_USING_MCURSES is not set +# CONFIG_PKG_USING_COWSAY is not set +CONFIG_BOARD_x86=y +CONFIG_BSP_USING_DIRECT_UART=y +CONFIG_BSP_DRV_UART=y +CONFIG_RT_USING_UART0=y +# CONFIG_RT_USING_UART1 is not set +CONFIG_BSP_DRV_AHCI=y diff --git a/bsp/x86/.gitignore b/bsp/x86/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..108b9aba15717c648c3940e8eadc51e8910a1239 --- /dev/null +++ b/bsp/x86/.gitignore @@ -0,0 +1,31 @@ +*.pyc +*.map +*.dblite +*.elf +*.bin +*.hex +*.axf +*.exe +*.pdb +*.idb +*.ilk +*.old +build +Debug +documentation/html +packages/ +*~ +*.o +*.obj +*.out +*.bak +*.dep +*.lib +*.i +*.d +*.iso +# grub efi +*.efi + +grub-2.04 +*.img \ No newline at end of file diff --git a/bsp/x86/Kconfig b/bsp/x86/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..995027fcd0047a29b7782c81c07486e3af373097 --- /dev/null +++ b/bsp/x86/Kconfig @@ -0,0 +1,34 @@ +mainmenu "RT-Thread Project Configuration" + +config BSP_DIR + string + option env="BSP_ROOT" + default "." + +config RTT_DIR + string + option env="RTT_ROOT" + default "../.." + +config PKGS_DIR + string + option env="PKGS_ROOT" + default "packages" + +source "$RTT_DIR/Kconfig" +source "$PKGS_DIR/Kconfig" + +config BOARD_x86 + bool + select ARCH_X86 + select RT_USING_COMPONENTS_INIT + select RT_USING_USER_MAIN + select RT_USING_CACHE + select BSP_USING_UART + default y + +config RT_USING_USERSPACE + bool + default y + +source "$BSP_DIR/drivers/Kconfig" diff --git a/bsp/x86/Makefile b/bsp/x86/Makefile index eb4654193b5100b8550a5bd399908da140cb04a7..559e4cd3a4842ecdfa022cd4f82fa126f9126dfc 100644 --- a/bsp/x86/Makefile +++ b/bsp/x86/Makefile @@ -1,46 +1,64 @@ +# tools +GRUB_DIR := grub-2.04 +OS_NAME := rtthread +QEMU := qemu-system-i386 +GDB := gdb +TRUNC := truncate +MCOPY := mcopy +RM := rm -CC = gcc -O0 -m32 -fno-builtin -fno-stack-protector -nostdinc -nostdlib -LD = ld -melf_i386 -nostdlib +# file name +DISK0 := disk0.img +DISK1 := disk1.img +SZ_DISK0 := 64M +SZ_DISK1 := 64M +MKFS := mkfs.fat +ROM_DIR := ../../../userapps/root -all: rtthread rtsym exe dll floppy.img - @mkdir -p tmp - @sudo mount -t vfat floppy.img tmp -o loop - @sudo cp -fv rtthread.elf tmp/boot/oskernel - @sudo rm tmp/bin/* -fr - @sudo cp out/*.mo tmp/bin/ -fv - @sudo umount tmp +RTTHREAD_ELF:= rtthread.elf -rtthread: - @scons +# config graphic window ? (y/n) +QEMU_WINDOW ?= n -rtsym: - @./src/extract.sh ./rtthread-ia32.map ./src/rt_thread_sym.h +# qemu args +QEMU_ARGS := -m 256m \ + -rtc base=localtime \ + -boot d \ + -cdrom $(OS_NAME).iso + +ifeq ($(QEMU_WINDOW),y) + QEMU_ARGS += -serial stdio +else + QEMU_ARGS += -nographic +endif -obj: - mkdir -p obj +QEMU_ARGS +=-drive id=disk0,file=$(DISK0),format=raw,if=none \ + -drive id=disk1,file=$(DISK1),format=raw,if=none \ + -device ahci,id=ahci \ + -device ide-hd,drive=disk0,bus=ahci.0 \ + -device ide-hd,drive=disk1,bus=ahci.1 -out: - mkdir -p out +all: makeiso makedisk -dll: obj out - $(CC) -c -fPIC -Isrc src/hello.c -o out/hello.o - $(CC) -s -Wl,-shared,-melf_i386,--entry=main -o out/hello.mo out/hello.o +makeiso: $(RTTHREAD_ELF) + @$(MAKE) -s -C $(GRUB_DIR) KERNEL=$(RTTHREAD_ELF) OS_NAME=$(OS_NAME) -disasm: obj out - $(CC) -shared -S -fPIC -Isrc src/hello.c -o obj/hello.s - cat obj/hello.s - objdump --disassemble out/hello.mo +makedisk: + $(TRUNC) --size $(SZ_DISK0) $(DISK0) + $(TRUNC) --size $(SZ_DISK1) $(DISK1) + $(MKFS) -F32 $(DISK0) + -$(MCOPY) -i $(DISK0) $(ROM_DIR)/bin/*.elf :: -exe: obj out +run: makedisk makeiso + $(QEMU) $(QEMU_ARGS) +qemudbg: + $(QEMU) -S -gdb tcp::10001,ipv4 $(QEMU_ARGS) -clean: - scons -c clean - rm -fr build rtthread* out obj - -floppy.img: - wget https://github.com/bajdcc/tinix/raw/master/floppy.img +# 连接gdb server: target remote localhost:10001 +gdb: + $(GDB) $(RTTHREAD_ELF) -# https://en.wikibooks.org/wiki/QEMU/Devices/Network -run: - qemu-system-i386 -fda floppy.img -boot a -m 64M -serial stdio -net nic,model=ne2k_pci +clean: + @$(MAKE) -s -C $(GRUB_DIR) clean + -$(RM) -f *.img *.map *.bin *.elf \ No newline at end of file diff --git a/bsp/x86/README.md b/bsp/x86/README.md new file mode 100644 index 0000000000000000000000000000000000000000..431afbe343dc91da7b81a19dc02e8b5aae558f41 --- /dev/null +++ b/bsp/x86/README.md @@ -0,0 +1,24 @@ +# RT-Smart x86 +This bsp os used to run RT-Smart on PC/Server or others environment. + +## Get GRUB2 +If you want to run RT-Smart x86, you must download GRUB2 to build a iso image with rtthread.elf. + +```shell +# 1. download +git clone https://gitee.com/hzc1998/grub2for-rt-smartx86 +# 2. unzip +unzip grub2for-rt-smartx86/grub-2.04-for-rt-smartx86.zip +# 3. remove hub +rm -rf grub2for-rt-smartx86 +``` + +## Get Qemu for i386 +```shell +sudo apt install qemu-system-i386 +``` + +## Run in Qemu +```shell +make run +``` \ No newline at end of file diff --git a/bsp/x86/SConscript b/bsp/x86/SConscript index fe0ae941ae9a759ae478de901caec1c961e56af8..c7ef7659ecea92b1dd9b71a97736a8552ee02551 100644 --- a/bsp/x86/SConscript +++ b/bsp/x86/SConscript @@ -1,8 +1,8 @@ # for module compiling import os -Import('RTT_ROOT') +from building import * -cwd = str(Dir('#')) +cwd = GetCurrentDir() objs = [] list = os.listdir(cwd) diff --git a/bsp/x86/applications/SConscript b/bsp/x86/applications/SConscript index 01eb940dfb35f92c503a78b0b49a4354590f9f3a..9ffdfd6d3ac13244a32fb825524e12e0ca88c585 100644 --- a/bsp/x86/applications/SConscript +++ b/bsp/x86/applications/SConscript @@ -1,10 +1,8 @@ -Import('RTT_ROOT') -Import('rtconfig') from building import * -cwd = os.path.join(str(Dir('#')), 'applications') +cwd = GetCurrentDir() src = Glob('*.c') -CPPPATH = [cwd, str(Dir('#'))] +CPPPATH = [cwd] group = DefineGroup('Applications', src, depend = [''], CPPPATH = CPPPATH) diff --git a/bsp/x86/applications/application.c b/bsp/x86/applications/application.c deleted file mode 100644 index 8928e6357ecead779bf3a87a1c0298062614793a..0000000000000000000000000000000000000000 --- a/bsp/x86/applications/application.c +++ /dev/null @@ -1,86 +0,0 @@ -/* - * File : application.c - * This file is part of RT-Thread RTOS - * COPYRIGHT (C) 2006 - 2015, RT-Thread Development Team - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Change Logs: - * Date Author Notes - * 2009-01-05 Bernard the first version - */ - -#include - -#ifdef RT_USING_DFS -#include -#include -#include "floppy.h" -#ifdef RT_USING_MODULE -#include -#endif -extern int elm_init(void); -#endif - -/* components initialization for simulator */ -void components_init(void) -{ -#ifdef RT_USING_DFS - rt_floppy_init(); - /* initialize the device file system */ - dfs_init(); - -#ifdef RT_USING_DFS_ELMFAT - /* initialize the elm chan FatFS file system*/ - elm_init(); -#endif - -#ifdef RT_USING_MODULE - rt_system_dlmodule_init(); -#endif -#endif -} -void rt_init_thread_entry(void *parameter) -{ - components_init(); - - /* File system Initialization */ -#ifdef RT_USING_DFS - { - -#ifdef RT_USING_DFS_ELMFAT - /* mount sd card fatfs as root directory */ - if (dfs_mount("floppy", "/", "elm", 0, 0) == 0) - rt_kprintf("fatfs initialized!\n"); - else - rt_kprintf("fatfs initialization failed!\n"); -#endif - } -#endif -} - -int rt_application_init() -{ - rt_thread_t tid; - - tid = rt_thread_create("init", - rt_init_thread_entry, RT_NULL, - 2048, RT_THREAD_PRIORITY_MAX / 3, 20); - - if (tid != RT_NULL) - rt_thread_startup(tid); - - return 0; -} diff --git a/bsp/x86/applications/main.c b/bsp/x86/applications/main.c new file mode 100644 index 0000000000000000000000000000000000000000..3ab106ed6079c0a428d2afae6c43ff0edc135d7e --- /dev/null +++ b/bsp/x86/applications/main.c @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + */ + +#include +#include +#include +#include + +int main(void) +{ + printf("Hello rtthread-smart x86!\n"); + return 0; +} diff --git a/bsp/x86/applications/mnt.c b/bsp/x86/applications/mnt.c new file mode 100644 index 0000000000000000000000000000000000000000..d55681138f26a6ca086178328776df00b81922d1 --- /dev/null +++ b/bsp/x86/applications/mnt.c @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-07-23 JasonHu first version + */ + +#include + +#ifdef RT_USING_DFS +#include +#include + +int mnt_init(void) +{ + if (dfs_mount(RT_NULL, "/", "rom", 0, &romfs_root) != 0) + { + rt_kprintf("Dir / mount failed!\n"); + return -1; + } + + rt_thread_mdelay(200); + + if (dfs_mount("sd0", "/mnt", "elm", 0, NULL) != 0) + { + rt_kprintf("Dir /mnt mount failed!\n"); + return -1; + } + + rt_kprintf("file system initialization done!\n"); + return 0; +} +INIT_ENV_EXPORT(mnt_init); +#endif diff --git a/bsp/x86/applications/romfs.c b/bsp/x86/applications/romfs.c new file mode 100644 index 0000000000000000000000000000000000000000..f098a76572cad3c0d6bdb688b5d54515f83c98ec --- /dev/null +++ b/bsp/x86/applications/romfs.c @@ -0,0 +1,11 @@ +#include + +static const struct romfs_dirent _romfs_root[] = { + {ROMFS_DIRENT_DIR, "etc", RT_NULL, 0}, + {ROMFS_DIRENT_DIR, "mnt", RT_NULL, 0}, + {ROMFS_DIRENT_DIR, "bin", RT_NULL, 0} +}; + +const struct romfs_dirent romfs_root = { + ROMFS_DIRENT_DIR, "/", (rt_uint8_t *)_romfs_root, sizeof(_romfs_root) / sizeof(_romfs_root[0])}; + diff --git a/bsp/x86/applications/startup.c b/bsp/x86/applications/startup.c deleted file mode 100644 index 72a4eb0a9668c70f0225388572beae7b2e59b3a7..0000000000000000000000000000000000000000 --- a/bsp/x86/applications/startup.c +++ /dev/null @@ -1,109 +0,0 @@ -/* - * File : startup.c - * This file is part of RT-Thread RTOS - * COPYRIGHT (C) 2006 - 2012, RT-Thread Develop Team - * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.fayfayspace.org/license/LICENSE. - * - * Change Logs: - * Date Author Notes - * 2006-09-15 QiuYi the first version - * 2006-10-10 Bernard update to 0.2.2 version - */ - -#include -#include - -#include "board.h" - -extern void rt_hw_console_init(void); -extern void rt_hw_board_init(void); -extern int rt_application_init(void); -//extern void rt_hw_interrupt_init(void); -//extern void rt_system_timer_init(void); -//extern void rt_system_scheduler_init(void); -//extern void rt_thread_idle_init(void); - -#ifdef RT_USING_FINSH -extern int finsh_system_init(void); -extern void finsh_set_device(const char *device); -#endif - -extern unsigned char __bss_start[]; -extern unsigned char __bss_end[]; - -/** - * @addtogroup QEMU - */ - - /*@{*/ - -/* clear .bss */ -void rt_hw_clear_bss(void) -{ - unsigned char *dst; - dst = __bss_start; - while (dst < __bss_end) - *dst++ = 0; -} - -/** - * This function will startup RT-Thread RTOS - */ -void rtthread_startup(void) -{ - /* clear .bss */ - rt_hw_clear_bss(); - - /* init hardware interrupt */ - rt_hw_interrupt_init(); - - /* init the console */ - rt_hw_console_init(); - rt_console_set_device("console"); - - /* init board */ - rt_hw_board_init(); - - rt_show_version(); - - /* init tick */ - rt_system_tick_init(); - - /* init kernel object */ - rt_system_object_init(); - - /* init timer system */ - rt_system_timer_init(); - - /* init memory system */ -#ifdef RT_USING_HEAP - /* RAM 16M */ - rt_system_heap_init((void *)&__bss_end, (void *)(1024UL*1024*8)); -#endif - - /* init scheduler system */ - rt_system_scheduler_init(); - - /* init application */ - rt_application_init(); - -#ifdef RT_USING_FINSH - /* init finsh */ - finsh_system_init(); - finsh_set_device("console"); -#endif - - /* init idle thread */ - rt_thread_idle_init(); - - /* start scheduler */ - rt_system_scheduler_start(); - - /* never reach here */ - return ; -} - -/*@}*/ diff --git a/bsp/x86/drivers/Kconfig b/bsp/x86/drivers/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..f74daba619077f4d28dbc59494a89487dd379fa9 --- /dev/null +++ b/bsp/x86/drivers/Kconfig @@ -0,0 +1,22 @@ +config BSP_USING_DIRECT_UART + bool "Using Direct UART without driver" + default y + +config BSP_DRV_UART + bool "Enabel UART driver" + select RT_USING_SERIAL + default y + +if BSP_DRV_UART + config RT_USING_UART0 + bool "Enabel UART 0" + default y + + config RT_USING_UART1 + bool "Enabel UART 1" + default n +endif + +config BSP_DRV_AHCI + bool "Enabel AHCI disk driver" + default y \ No newline at end of file diff --git a/bsp/x86/drivers/board.c b/bsp/x86/drivers/board.c index 211ae1832afc8e3641ab61f83b5ce4a37992e8b6..07400033c06cb8ceb02fe0d9328efeb2a7cfbac4 100644 --- a/bsp/x86/drivers/board.c +++ b/bsp/x86/drivers/board.c @@ -1,74 +1,121 @@ /* - * File : board.c - * This file is part of RT-Thread RTOS - * COPYRIGHT (C) 2006, RT-Thread Development Team + * Copyright (c) 2006-2021, RT-Thread Development Team * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.fayfayspace.org/license/LICENSE. + * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes - * 2006-09-15 QiuYi the first version - * 2006-10-10 Bernard add hardware related of finsh + * 2021-07-14 JasonHu first version */ -#include #include +#include +#include +#include +#include -#include +#include +#include +#include -/** - * @addtogroup QEMU - */ -/*@{*/ +#include "drv_uart.h" +#include "direct_uart.h" +#include "drv_timer.h" +#include "pci.h" -static void rt_timer_handler(int vector, void* param) -{ - rt_tick_increase(); -} +#ifdef RT_USING_USERSPACE +#include +#include +#include "lwp_arch.h" + +rt_mmu_info mmu_info; + +/* kernel mmu table */ +volatile rt_size_t g_mmu_table[ARCH_PAGE_SIZE / sizeof(rt_size_t)] __attribute__((aligned(ARCH_PAGE_SIZE))); -#ifdef RT_USING_HOOK -static void idle_hook(void) +static size_t page_region_init() { - asm volatile("sti; hlt": : :"memory"); + unsigned int memory_size = *((unsigned int *)0x000001000); + rt_kprintf("physic memory size: %x bytes, %d MB\n", memory_size, memory_size / (1024 * 1024)); + if (memory_size < HW_PHY_MEM_SIZE_MIN) + { + dbg_log(DBG_ERROR, "phyisc memory too small! only %d MB, must >= %d MB\n", + memory_size / (1024 * 1024), HW_PHY_MEM_SIZE_MIN / (1024 * 1024)); + for (;;) + { + } + } + if (memory_size > HW_PAGE_SIZE_MAX) + { + memory_size = HW_PAGE_SIZE_MAX; + } + return memory_size; } + #endif -/** - * This function will init QEMU - * - */ void rt_hw_board_init(void) { - /* initialize 8253 clock to interrupt 1000 times/sec */ - outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT); - outb(IO_TIMER1, TIMER_DIV(RT_TICK_PER_SECOND) % 256); - outb(IO_TIMER1, TIMER_DIV(RT_TICK_PER_SECOND) / 256); +#ifdef BSP_USING_DIRECT_UART + /* init direct serial hardware */ + rt_hw_direct_uart_init(); +#endif /* RT_USING_DIRECT_UART */ - /* install interrupt handler */ - rt_hw_interrupt_install(INTTIMER0, rt_timer_handler, RT_NULL, "tick"); - rt_hw_interrupt_umask(INTTIMER0); +#ifdef RT_USING_USERSPACE + /* init page and mmu */ + rt_region_t init_page_region; + init_page_region.start = (size_t)HW_PAGE_START; + init_page_region.end = page_region_init(); + /* init no mapped area in kernel table, must in kernel space */ + RT_ASSERT(!rt_hw_mmu_map_init(&mmu_info, (void *)HW_KERNEL_DELAY_MAP_START, HW_KERNEL_DELAY_MAP_SIZE, (rt_size_t *)g_mmu_table, 0)) -#ifdef RT_USING_HOOK - rt_thread_idle_sethook(idle_hook); + rt_page_init(init_page_region); + /* map kernel space, then can read/write this area directly. */ + rt_hw_mmu_kernel_map_init(&mmu_info, HW_KERNEL_START, HW_KERNEL_END); + switch_mmu((void *)g_mmu_table); + mmu_enable(); #endif -} -void restart(void) -{ - outb(KBSTATP, 0xFE); /* pulse reset low */ - while(1); -} + /* init cpu special */ + rt_hw_cpu_init(); -#ifdef RT_USING_FINSH -#include -FINSH_FUNCTION_EXPORT(restart, reboot PC) + /* initalize interrupt */ + rt_hw_interrupt_init(); -void reboot(void) +#ifdef BSP_DRV_UART + /* init serial driver */ + rt_hw_uart_init(); +#endif /* BSP_DRV_UART */ + + /* init timer driver */ + rt_hw_timer_init(); + +#ifdef RT_USING_HEAP + rt_kprintf("heap: [0x%08x - 0x%08x]\n", (rt_ubase_t) HW_HEAP_BEGIN, (rt_ubase_t) HW_HEAP_END); + /* initialize memory system */ + rt_system_heap_init((void *)HW_HEAP_BEGIN, (void *)HW_HEAP_END); +#endif + + /* init dma allocator */ + rt_hw_dma_init(HW_DMA_BEGIN, HW_DMA_BEGIN + HW_DMA_SIZE); + + /* init pci bus */ + rt_pci_init(); + +#ifdef RT_USING_COMPONENTS_INIT + rt_components_board_init(); +#endif + +#ifdef RT_USING_CONSOLE + /* set console device */ + rt_console_set_device(RT_CONSOLE_DEVICE_NAME); +#endif /* RT_USING_CONSOLE */ + +} + +void primary_cpu_entry(void) { - restart(); + extern void entry(void); + rt_hw_interrupt_disable(); + entry(); } -FINSH_FUNCTION_EXPORT(reboot, reboot PC) -#endif -/*@}*/ diff --git a/bsp/x86/drivers/board.h b/bsp/x86/drivers/board.h index bc79f9ccfb42c20f53034ddad5fd68f2132fc5d1..ccd3a9b0143b28255ccf55fcc609b78cd7443d06 100644 --- a/bsp/x86/drivers/board.h +++ b/bsp/x86/drivers/board.h @@ -1,20 +1,87 @@ /* - * File : board.h - * This file is part of RT-Thread RTOS - * COPYRIGHT (C) 2006, RT-Thread Develop Team + * Copyright (c) 2006-2021, RT-Thread Development Team * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://openlab.rt-thread.com/license/LICENSE + * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes - * 2006-10-09 Bernard first version + * 2021-07-14 JasonHu first version */ #ifndef __BOARD_H__ #define __BOARD_H__ +#include +#include +#include + +/* boot size */ +#define HW_KERNEL_BEGIN 0x00000000UL +#define HW_KERNEL_SIZE (8 * 1024 * 1024) + +/* DMA start at 8M (DMA must lower than 16 MB address) */ +#define HW_DMA_BEGIN (HW_KERNEL_BEGIN + HW_KERNEL_SIZE) +/* DMA 8 MB size */ +#define HW_DMA_SIZE (8 * 1024 * 1024) + +/* heap start at 16M */ +#define HW_HEAP_BEGIN (HW_DMA_BEGIN + HW_DMA_SIZE) +/* heap 16 MB size */ +#define HW_HEAP_SIZE (16 * 1024 * 1024) + +#define HW_KERNEL_DELAY_MAP_MB 128 + +#ifdef RT_USING_USERSPACE +#define HW_HEAP_END (void*)(KERNEL_VADDR_START + HW_HEAP_BEGIN + HW_HEAP_SIZE) + +#define HW_PAGE_START HW_HEAP_END +/* TODO: use dynamic memroy select size */ +#define HW_PAGE_SIZE_MIN ((64 - 32) * 1024 * 1024) +#define HW_PAGE_SIZE_MAX (((1024 - HW_KERNEL_DELAY_MAP_MB) - 32) * 1024 * 1024) + +#define HW_PAGE_SIZE_DEF ((256 - 32) * 1024 * 1024) + +/* this should at end of phy memory */ +#define HW_PAGE_END (void*)(HW_PAGE_START + HW_PAGE_SIZE_DEF) + +#define HW_PHY_MEM_SIZE_MIN (HW_KERNEL_SIZE + HW_DMA_SIZE + HW_HEAP_SIZE + HW_PAGE_SIZE_MIN) + +#else +#define HW_HEAP_END (void*)(HEAP_BEGIN + HW_HEAP_SIZE) +#endif + +/* start at 1G, end at 4G */ +#define HW_USER_START 0x40000000UL +#define HW_USER_END 0xFFFFF000UL +#define HW_USER_SIZE (HW_USER_END - HW_USER_START) + +/* + * Delay map, don't map when kernel do self map, only map when needed. + * This area was used ioremap. + */ +#define HW_KERNEL_DELAY_MAP_SIZE (HW_KERNEL_DELAY_MAP_MB * (1024 * 1024)) +#define HW_KERNEL_START (0) +#define HW_KERNEL_END (HW_USER_START - HW_KERNEL_DELAY_MAP_SIZE) +#define HW_KERNEL_DELAY_MAP_START HW_KERNEL_END + +/** + * Virtual memory layout: + * + * +------------+ <- 0xFFFFFFFF (4GB) + * | USER | + * +------------+ <- 0x40000000 (1GB) + * | DELAY MAP | + * +------------+ <- 0x38000000 (896MB) + * | PAGE | + * +------------+ <- 0x02000000 (32MB) + * | HEAP | + * +------------+ <- 0x01000000 (16MB) + * | DMA | + * +------------+ <- 0x00800000 (8MB) + * | KERNEL | + * +------------+ <- 0x00000000 + */ + void rt_hw_board_init(void); #endif diff --git a/bsp/x86/drivers/console.c b/bsp/x86/drivers/console.c deleted file mode 100644 index f5c4fe530bc014815ec6960b846c7cd40acd2628..0000000000000000000000000000000000000000 --- a/bsp/x86/drivers/console.c +++ /dev/null @@ -1,337 +0,0 @@ -/* - * File : console.c - * This file is part of RT-Thread RTOS - * COPYRIGHT (C) 2006, RT-Thread Development Team - * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://openlab.rt-thread.com/license/LICENSE - * - * Change Logs: - * Date Author Notes - * 2006-09-15 QiuYi the first version - */ - -#include -#include - -#include - -static unsigned addr_6845; -static rt_uint16_t *crt_buf; -static rt_int16_t crt_pos; - -extern void init_keyboard(); -extern void rt_keyboard_isr(void); -extern rt_bool_t rt_keyboard_getc(char* c); - -extern void rt_serial_init(void); -extern char rt_serial_getc(void); -extern void rt_serial_putc(const char c); - -void rt_console_putc(int c); - -/** - * @addtogroup QEMU - */ -/*@{*/ - -/** - * This function initializes cga - * - */ -void rt_cga_init(void) -{ - rt_uint16_t volatile *cp; - rt_uint16_t was; - rt_uint32_t pos; - - cp = (rt_uint16_t *) (CGA_BUF); - was = *cp; - *cp = (rt_uint16_t) 0xA55A; - if (*cp != 0xA55A) - { - cp = (rt_uint16_t *) (MONO_BUF); - addr_6845 = MONO_BASE; - } - else - { - *cp = was; - addr_6845 = CGA_BASE; - } - - /* Extract cursor location */ - outb(addr_6845, 14); - pos = inb(addr_6845+1) << 8; - outb(addr_6845, 15); - pos |= inb(addr_6845+1); - - crt_buf = (rt_uint16_t *)cp; - crt_pos = pos; -} - -/** - * This function will write a character to cga - * - * @param c the char to write - */ -static void rt_cga_putc(int c) -{ - /* if no attribute given, then use black on white */ - if (!(c & ~0xff)) c |= 0x0700; - - switch (c & 0xff) - { - case '\b': - if (crt_pos > 0) - { - crt_pos--; - crt_buf[crt_pos] = (c&~0xff) | ' '; - } - break; - case '\n': - crt_pos += CRT_COLS; - /* cascade */ - case '\r': - crt_pos -= (crt_pos % CRT_COLS); - break; - case '\t': - rt_console_putc(' '); - rt_console_putc(' '); - rt_console_putc(' '); - rt_console_putc(' '); - rt_console_putc(' '); - break; - default: - crt_buf[crt_pos++] = c; /* write the character */ - break; - } - - if (crt_pos >= CRT_SIZE) - { - rt_int32_t i; - rt_memcpy(crt_buf, crt_buf + CRT_COLS, (CRT_SIZE - CRT_COLS) << 1); - for (i = CRT_SIZE - CRT_COLS; i < CRT_SIZE; i++) - crt_buf[i] = 0x0700 | ' '; - crt_pos -= CRT_COLS; - } - - outb(addr_6845, 14); - outb(addr_6845+1, crt_pos >> 8); - outb(addr_6845, 15); - outb(addr_6845+1, crt_pos); -} - -/** - * This function will write a character to serial an cga - * - * @param c the char to write - */ -void rt_console_putc(int c) -{ - rt_cga_putc(c); - rt_serial_putc(c); -} - -/* RT-Thread Device Interface */ -#define CONSOLE_RX_BUFFER_SIZE 64 -static struct rt_device console_device; -static rt_uint8_t rx_buffer[CONSOLE_RX_BUFFER_SIZE]; -static rt_uint32_t read_index, save_index; - -static rt_err_t rt_console_init (rt_device_t dev) -{ - return RT_EOK; -} - -static rt_err_t rt_console_open(rt_device_t dev, rt_uint16_t oflag) -{ - return RT_EOK; -} - -static rt_err_t rt_console_close(rt_device_t dev) -{ - return RT_EOK; -} - -static rt_err_t rt_console_control(rt_device_t dev, int cmd, void *args) -{ - return RT_EOK; -} - -static rt_size_t rt_console_write(rt_device_t dev, rt_off_t pos, const void * buffer, rt_size_t size) -{ - rt_size_t i = size; - const char* str = buffer; - - while(i--) - { - rt_console_putc(*str++); - } - - return size; -} - -static rt_size_t rt_console_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size) -{ - rt_uint8_t* ptr = buffer; - rt_err_t err_code = RT_EOK; - - /* interrupt mode Rx */ - while (size) - { - rt_base_t level; - - /* disable interrupt */ - level = rt_hw_interrupt_disable(); - - if (read_index != save_index) - { - /* read a character */ - *ptr++ = rx_buffer[read_index]; - size--; - - /* move to next position */ - read_index ++; - if (read_index >= CONSOLE_RX_BUFFER_SIZE) - read_index = 0; - } - else - { - /* set error code */ - err_code = -RT_EEMPTY; - - /* enable interrupt */ - rt_hw_interrupt_enable(level); - break; - } - - /* enable interrupt */ - rt_hw_interrupt_enable(level); - } - - /* set error code */ - rt_set_errno(err_code); - return (rt_uint32_t)ptr - (rt_uint32_t)buffer; -} - -static void rt_console_isr(int vector, void* param) -{ - char c; - rt_bool_t ret; - rt_base_t level; - - if(INTUART0_RX == vector) - { - c = rt_serial_getc(); - ret = RT_TRUE; - } - else - { - rt_keyboard_isr(); - - ret = rt_keyboard_getc(&c); - } - - if(ret == RT_FALSE) - { - /* do nothing */ - } - else - { - /* disable interrupt */ - level = rt_hw_interrupt_disable(); - - /* save character */ - rx_buffer[save_index] = c; - save_index ++; - if (save_index >= CONSOLE_RX_BUFFER_SIZE) - save_index = 0; - - /* if the next position is read index, discard this 'read char' */ - if (save_index == read_index) - { - read_index ++; - if (read_index >= CONSOLE_RX_BUFFER_SIZE) - read_index = 0; - } - - /* enable interrupt */ - rt_hw_interrupt_enable(level); - } - - /* invoke callback */ - if (console_device.rx_indicate != RT_NULL) - { - rt_size_t rx_length; - - /* get rx length */ - rx_length = read_index > save_index ? - CONSOLE_RX_BUFFER_SIZE - read_index + save_index : - save_index - read_index; - - if(rx_length > 0) - { - console_device.rx_indicate(&console_device, rx_length); - } - } - else - { - - } -} - -/** - * This function initializes console - * - */ -void rt_hw_console_init(void) -{ - rt_cga_init(); - rt_serial_init(); - init_keyboard(); - - /* install keyboard isr */ - rt_hw_interrupt_install(INTKEYBOARD, rt_console_isr, RT_NULL, "kbd"); - rt_hw_interrupt_umask(INTKEYBOARD); - - rt_hw_interrupt_install(INTUART0_RX, rt_console_isr, RT_NULL, "COM1"); - rt_hw_interrupt_umask(INTUART0_RX); - - console_device.type = RT_Device_Class_Char; - console_device.rx_indicate = RT_NULL; - console_device.tx_complete = RT_NULL; - console_device.init = rt_console_init; - console_device.open = rt_console_open; - console_device.close = rt_console_close; - console_device.read = rt_console_read; - console_device.write = rt_console_write; - console_device.control = rt_console_control; - console_device.user_data = RT_NULL; - - /* register a character device */ - rt_device_register(&console_device, - "console", - RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_STREAM); -} - -/** - * This function is used to display a string on console, normally, it's - * invoked by rt_kprintf - * - * @param str the displayed string - * - * Modified: - * caoxl 2009-10-14 - * the name is change to rt_hw_console_output in the v0.3.0 - * - */ -void rt_hw_console_output(const char* str) -{ - while (*str) - { - rt_console_putc (*str++); - } -} - -/*@}*/ diff --git a/bsp/x86/drivers/direct_uart.c b/bsp/x86/drivers/direct_uart.c new file mode 100644 index 0000000000000000000000000000000000000000..fa444d4f0df9c8d735b7d49c39b2334df1eb3540 --- /dev/null +++ b/bsp/x86/drivers/direct_uart.c @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-07-15 JasonHu first version + */ + +#include + +#ifdef BSP_USING_DIRECT_UART +#include +#include + +#include "board.h" + +/* I/O port base addr */ +#define COM1_BASE 0X3F8 + +#define MAX_BAUD_VALUE 115200 +#define DEFAULT_BAUD_VALUE 19200 +#define DEFAULT_DIVISOR_VALUE (MAX_BAUD_VALUE / DEFAULT_BAUD_VALUE) + +#define UART_SEND_TIMEOUT + +enum uart_fifo_control_register_bits +{ + FIFO_ENABLE = 1, /* Enable FIFOs */ + FIFO_CLEAR_RECEIVE = (1 << 1), /* Clear Receive FIFO */ + FIFO_CLEAR_TRANSMIT = (1 << 2), /* Clear Transmit FIFO */ + FIFO_DMA_MODE_SELECT = (1 << 3), /* DMA Mode Select */ + FIFO_RESERVED = (1 << 4), /* Reserved */ + FIFO_ENABLE_64 = (1 << 5), /* Enable 64 Byte FIFO(16750) */ + /* Interrupt Trigger Level/Trigger Level */ + FIFO_TRIGGER_1 = (0 << 6), /* 1 Byte */ + FIFO_TRIGGER_4 = (1 << 6), /* 4 Byte */ + FIFO_TRIGGER_8 = (1 << 7), /* 8 Byte */ + FIFO_TRIGGER_14 = (1 << 6) | (1 << 7), /* 14 Byte */ +}; + +enum uart_line_control_register_bits +{ + /* Word Length */ + LINE_WORD_LENGTH_5 = 0, /* 5 Bits */ + LINE_WORD_LENGTH_6 = 1, /* 6 Bits */ + LINE_WORD_LENGTH_7 = (1 << 1), /* 7 Bits */ + LINE_WORD_LENGTH_8 = ((1 << 1) | 1), /* 8 Bits */ + LINE_STOP_BIT_1 = (0 << 2), /* One Stop Bit */ + LINE_STOP_BIT_2 = (1 << 2), /* 1.5 Stop Bits or 2 Stop Bits */ + /* Parity Select */ + LINE_PARITY_NO = (0 << 3), /* No Parity */ + LINE_PARITY_ODD = (1 << 3), /* Odd Parity */ + LINE_PARITY_EVEN = (1 << 3) | (1 << 4), /* Even Parity */ + LINE_PARITY_MARK = (1 << 3) | (1 << 5), /* Mark */ + LINE_PARITY_SPACE = (1 << 3) | (1 << 4) | (1 << 5), /* Space */ + LINE_BREAK_ENABLE = (1 << 6), /* Set Break Enable */ + LINE_DLAB = (1 << 7), /* Divisor Latch Access Bit */ +}; + +enum uart_interrupt_enable_register_bits +{ + INTR_RECV_DATA_AVALIABLE = 1, /* Enable Received Data Available Interrupt */ + INTR_TRANSMIT_HOLDING = (1 << 1), /* Enable Transmitter Holding Register Empty Interrupt */ + INTR_STATUS_CHANGED = (1 << 2), /* Enable Receiver Line Status Interrupt */ + INTR_MODEM_STATUS = (1 << 3), /* Enable Modem Status Interrupt */ + INTR_SLEEP_MODE = (1 << 4), /* Enable Sleep Mode(16750) */ + INTR_LOW_POWER_MODE = (1 << 5), /* Enable Low Power Mode(16750) */ + INTR_RESERVED1 = (1 << 6), /* Reserved */ + INTR_RESERVED2 = (1 << 7), /* Reserved */ +}; + +enum uart_line_status_register_bits { + LINE_STATUS_DATA_READY = 1, /* Data Ready */ + LINE_STATUS_OVERRUN_ERROR = (1 << 1), /* Overrun Error */ + LINE_STATUS_PARITY_ERROR = (1 << 2), /* Parity Error */ + LINE_STATUS_FRAMING_ERROR = (1 << 3), /* Framing Error */ + LINE_STATUS_BREAK_INTERRUPT = (1 << 4), /* Break Interrupt */ + LINE_STATUS_EMPTY_TRANSMITTER_HOLDING = (1 << 5), /* Empty Transmitter Holding Register */ + LINE_STATUS_EMPTY_DATA_HOLDING = (1 << 6), /* Empty Data Holding Registers */ + LINE_STATUS_ERROR_RECEIVE_FIFO = (1 << 7), /* Error in Received FIFO */ +}; + +enum uart_intr_indenty_reg_bits { + INTR_STATUS_PENDING_FLAG = 1, /* Interrupt Pending Flag */ + /* 产生的什么中断 */ + INTR_STATUS_MODEM = (0 << 1), /* Transmitter Holding Register Empty Interrupt */ + INTR_STATUS_TRANSMITTER_HOLDING = (1 << 1), /* Received Data Available Interrupt */ + INTR_STATUS_RECEIVE_DATA = (1 << 2), /* Received Data Available Interrupt */ + INTR_STATUS_RECEIVE_LINE = (1 << 1) | (1 << 2), /* Receiver Line Status Interrupt */ + INTR_STATUS_TIME_OUT_PENDING = (1 << 2) | (1 << 3), /* Time-out Interrupt Pending (16550 & later) */ + INTR_STATUS_64BYTE_FIFO = (1 << 5), /* 64 Byte FIFO Enabled (16750 only) */ + INTR_STATUS_NO_FIFO = (0 << 6), /* No FIFO on chip */ + INTR_STATUS_RESERVED_CONDITION = (1 << 6), /* Reserved condition */ + INTR_STATUS_FIFO_NOT_FUNC = (1 << 7), /* FIFO enabled, but not functioning */ + INTR_STATUS_FIFO = (1 << 6) | (1 << 7), /* FIFO enabled */ +}; + +struct hw_uart +{ + rt_uint16_t iobase; + rt_uint16_t data_reg; + rt_uint16_t divisor_low_reg; + rt_uint16_t intr_enable_reg; + rt_uint16_t divisor_high_reg; + rt_uint16_t intr_indenty_reg; + rt_uint16_t fifo_reg; + rt_uint16_t line_ctrl_reg; + rt_uint16_t modem_ctrl_reg; + rt_uint16_t line_status_reg; + rt_uint16_t modem_status_reg; + rt_uint16_t scratch_reg; +}; +typedef struct hw_uart hw_uart_t; + +static hw_uart_t hw_uart; + +static int uart_send(hw_uart_t *uart, char data) +{ +#ifdef UART_SEND_TIMEOUT + int timeout = 0x100000; + while (!(inb(uart->line_status_reg) & LINE_STATUS_EMPTY_TRANSMITTER_HOLDING) && timeout--) + { + } +#else + while (!(inb(uart->line_status_reg) & LINE_STATUS_EMPTY_TRANSMITTER_HOLDING)) + { + } +#endif + outb(uart->data_reg, data); + return 0; +} + +void rt_hw_direct_uart_putchar(char ch) +{ + if(ch == '\n') { + uart_send(&hw_uart, '\r'); + } + uart_send(&hw_uart, ch); +} + +/** +* This function is used by rt_kprintf to display a string on console. +* +* @param str the displayed string +*/ +void rt_hw_console_output(const char *str) +{ + while (*str) { + rt_hw_direct_uart_putchar(*str++); + } +} + +void rt_hw_direct_uart_init(void) +{ + hw_uart_t *uart = &hw_uart; + rt_uint16_t iobase; + + iobase = COM1_BASE; + uart->iobase = iobase; + uart->data_reg = iobase + 0; + uart->divisor_low_reg = iobase + 0; + uart->intr_enable_reg = iobase + 1; + uart->divisor_high_reg = iobase + 1; + uart->intr_indenty_reg = iobase + 2; + uart->line_ctrl_reg = iobase + 3; + uart->modem_ctrl_reg = iobase + 4; + uart->line_status_reg = iobase + 5; + uart->modem_status_reg = iobase + 6; + uart->scratch_reg = iobase + 7; + + outb(uart->line_ctrl_reg, LINE_DLAB); + + outb(uart->divisor_low_reg, (DEFAULT_DIVISOR_VALUE) & 0xff); + outb(uart->divisor_high_reg, ((DEFAULT_DIVISOR_VALUE) >> 8) & 0xff); + + outb(uart->line_ctrl_reg, LINE_WORD_LENGTH_8 | + LINE_STOP_BIT_1 | LINE_PARITY_NO); + + /* close all intr */ + outb(uart->intr_enable_reg, 0); + + outb(uart->fifo_reg, FIFO_ENABLE | FIFO_CLEAR_TRANSMIT | + FIFO_CLEAR_RECEIVE | FIFO_ENABLE_64 | + FIFO_TRIGGER_14); + + outb(uart->modem_ctrl_reg, 0x00); + outb(uart->scratch_reg, 0x00); +} +#endif /* BSP_USING_DIRECT_UART */ diff --git a/bsp/x86/drivers/direct_uart.h b/bsp/x86/drivers/direct_uart.h new file mode 100644 index 0000000000000000000000000000000000000000..71c30e73e7bdcae33015e248b489501292decd5d --- /dev/null +++ b/bsp/x86/drivers/direct_uart.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-07-15 JasonHu first version + */ + +#ifndef __DIRECT_UART_H__ +#define __DIRECT_UART_H__ + +/* direct means not use driver framework */ + +void rt_hw_direct_uart_init(void); + +#endif /* __DIRECT_UART_H__ */ diff --git a/bsp/x86/drivers/dma.h b/bsp/x86/drivers/dma.h deleted file mode 100644 index f1a8563cb1c435119229a7b02f5f3e6d731e1a7d..0000000000000000000000000000000000000000 --- a/bsp/x86/drivers/dma.h +++ /dev/null @@ -1,187 +0,0 @@ -#ifndef _DMA_H -#define _DMA_H - - -#define MAX_DMA_CHANNELS 8 - -/* 8237 DMA controllers */ -#define IO_DMA1_BASE 0x00 /* 8 bit slave DMA, channels 0..3 */ -#define IO_DMA2_BASE 0xC0 /* 16 bit master DMA, ch 4(=slave input)..7 */ - -/* DMA controller registers */ -#define DMA1_CMD_REG 0x08 /* command register (w) */ -#define DMA1_STAT_REG 0x08 /* status register (r) */ -#define DMA1_REQ_REG 0x09 /* request register (w) */ -#define DMA1_MASK_REG 0x0A /* single-channel mask (w) */ -#define DMA1_MODE_REG 0x0B /* mode register (w) */ -#define DMA1_CLEAR_FF_REG 0x0C /* clear pointer flip-flop (w) */ -#define DMA1_TEMP_REG 0x0D /* Temporary Register (r) */ -#define DMA1_RESET_REG 0x0D /* Master Clear (w) */ -#define DMA1_CLR_MASK_REG 0x0E /* Clear Mask */ -#define DMA1_MASK_ALL_REG 0x0F /* all-channels mask (w) */ - -#define DMA2_CMD_REG 0xD0 /* command register (w) */ -#define DMA2_STAT_REG 0xD0 /* status register (r) */ -#define DMA2_REQ_REG 0xD2 /* request register (w) */ -#define DMA2_MASK_REG 0xD4 /* single-channel mask (w) */ -#define DMA2_MODE_REG 0xD6 /* mode register (w) */ -#define DMA2_CLEAR_FF_REG 0xD8 /* clear pointer flip-flop (w) */ -#define DMA2_TEMP_REG 0xDA /* Temporary Register (r) */ -#define DMA2_RESET_REG 0xDA /* Master Clear (w) */ -#define DMA2_CLR_MASK_REG 0xDC /* Clear Mask */ -#define DMA2_MASK_ALL_REG 0xDE /* all-channels mask (w) */ - -#define DMA_ADDR_0 0x00 /* DMA address registers */ -#define DMA_ADDR_1 0x02 -#define DMA_ADDR_2 0x04 -#define DMA_ADDR_3 0x06 -#define DMA_ADDR_4 0xC0 -#define DMA_ADDR_5 0xC4 -#define DMA_ADDR_6 0xC8 -#define DMA_ADDR_7 0xCC - -#define DMA_CNT_0 0x01 /* DMA count registers */ -#define DMA_CNT_1 0x03 -#define DMA_CNT_2 0x05 -#define DMA_CNT_3 0x07 -#define DMA_CNT_4 0xC2 -#define DMA_CNT_5 0xC6 -#define DMA_CNT_6 0xCA -#define DMA_CNT_7 0xCE - -#define DMA_PAGE_0 0x87 /* DMA page registers */ -#define DMA_PAGE_1 0x83 -#define DMA_PAGE_2 0x81 -#define DMA_PAGE_3 0x82 -#define DMA_PAGE_5 0x8B -#define DMA_PAGE_6 0x89 -#define DMA_PAGE_7 0x8A - -#define DMA_MODE_READ 0x44 /* I/O to memory, no autoinit, increment, single mode */ -#define DMA_MODE_WRITE 0x48 /* memory to I/O, no autoinit, increment, single mode */ -#define DMA_MODE_CASCADE 0xC0 /* pass thru DREQ->HRQ, DACK<-HLDA only */ - -/* - * 启用指定的DMA通道 - */ -static __inline__ void EnableDma(unsigned int dmanr) -{ - if (dmanr<=3) - OUTB(dmanr, DMA1_MASK_REG); - else - OUTB(dmanr & 3, DMA2_MASK_REG); -} - -/* - * 禁用指定的DMA通道 - */ -static __inline__ void DisableDma(unsigned int dmanr) -{ - if (dmanr<=3) - OUTB(dmanr | 4, DMA1_MASK_REG); - else - OUTB((dmanr & 3) | 4, DMA2_MASK_REG); -} - -/* - * 清空DMA 晶体计数器 - */ -static __inline__ void ClearDmaFF(unsigned int dmanr) -{ - if (dmanr<=3) - OUTB(0, DMA1_CLEAR_FF_REG); - else - OUTB(0, DMA2_CLEAR_FF_REG); -} - -/* - * 清空DMA 晶体计数器 - */ -static __inline__ void SetDmaMode(unsigned int dmanr, char mode) -{ - if (dmanr<=3) - OUTB(mode | dmanr, DMA1_MODE_REG); - else - OUTB(mode | (dmanr&3), DMA2_MODE_REG); -} - -/* - * 设定DMA 页面寄存器 - */ -static __inline__ void SetDmaPage(unsigned int dmanr, char pagenr) -{ - switch(dmanr) { - case 0: - OUTB(pagenr, DMA_PAGE_0); - break; - case 1: - OUTB(pagenr, DMA_PAGE_1); - break; - case 2: - OUTB(pagenr, DMA_PAGE_2); - break; - case 3: - OUTB(pagenr, DMA_PAGE_3); - break; - case 5: - OUTB(pagenr & 0xfe, DMA_PAGE_5); - break; - case 6: - OUTB(pagenr & 0xfe, DMA_PAGE_6); - break; - case 7: - OUTB(pagenr & 0xfe, DMA_PAGE_7); - break; - } -} - - -/* - * 设定DMA 传输高速缓冲区地址 - */ -static __inline__ void SetDmaAddr(unsigned int dmanr, unsigned int a) -{ - SetDmaPage(dmanr, a>>16); - if (dmanr <= 3) { - OUTB( a & 0xff, ((dmanr&3)<<1) + IO_DMA1_BASE ); - OUTB( (a>>8) & 0xff, ((dmanr&3)<<1) + IO_DMA1_BASE ); - } else { - OUTB( (a>>1) & 0xff, ((dmanr&3)<<2) + IO_DMA2_BASE ); - OUTB( (a>>9) & 0xff, ((dmanr&3)<<2) + IO_DMA2_BASE ); - } -} - - -/* - * 设定DMA 传输块数 - */ -static __inline__ void SetDmaCount(unsigned int dmanr, unsigned int count) -{ - count--; - if (dmanr <= 3) { - OUTB( count & 0xff, ((dmanr&3)<<1) + 1 + IO_DMA1_BASE ); - OUTB( (count>>8) & 0xff, ((dmanr&3)<<1) + 1 + IO_DMA1_BASE ); - } else { - OUTB( (count>>1) & 0xff, ((dmanr&3)<<2) + 2 + IO_DMA2_BASE ); - OUTB( (count>>9) & 0xff, ((dmanr&3)<<2) + 2 + IO_DMA2_BASE ); - } -} - - -/* - * 获得DMA 传输剩余块数 - */ -static __inline__ int GetDmaResidue(unsigned int dmanr) -{ - unsigned int io_port = (dmanr<=3)? ((dmanr&3)<<1) + 1 + IO_DMA1_BASE - : ((dmanr&3)<<2) + 2 + IO_DMA2_BASE; - - /* using short to get 16-bit wrap around */ - unsigned short count; - count = 1 + inb(io_port); - count += inb(io_port) << 8; - return (dmanr<=3)? count : (count<<1); -} - -#endif - diff --git a/bsp/x86/drivers/drv_ahci.c b/bsp/x86/drivers/drv_ahci.c new file mode 100644 index 0000000000000000000000000000000000000000..16a005bd2d30c73eb7e5c547979d78c17ddd3a15 --- /dev/null +++ b/bsp/x86/drivers/drv_ahci.c @@ -0,0 +1,852 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-08-04 JasonHu first version + */ + +#include + +#ifdef BSP_DRV_AHCI + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "drv_ahci.h" +#include "pci.h" + +#define DEV_NAME "sd" + +// #define RT_DRV_AHCI_DEBUG + +#ifdef RT_DRV_AHCI_DEBUG + #define dbgprint rt_kprintf +#else + #define dbgprint(...) +#endif + +/* memio info on the pci bar 5 */ +#define PCI_AHCI_MEMIO_BAR 5 + +#define LOWER32(a) (rt_uint32_t)((a) & 0xffffffff) +#define LOWER8(a) (rt_uint8_t)((a) & 0xff) +#define HIGHER8(a) (rt_uint8_t)(((a) >> 8) & 0xff) + +/* maxim ports we support */ +#define DRV_AHCI_PORT_NR 32 + +struct device_extension +{ + rt_uint64_t sector_count; /* sectors in this disk. */ + rt_uint8_t type; /* AHCI device type */ + rt_uint8_t port; /* port for each device. */ + rt_uint32_t slots; /* solts for device read/write transfer bits */ + struct rt_mutex lock; /* lock for disk read/write */ + void *fis_vaddr; + void *clb_vaddr; + rt_hw_dma_t clb_dma; + rt_hw_dma_t fis_dma; + void *cmd_hdrs[HBA_COMMAND_HEADER_NUM]; /* command header */ + rt_hw_dma_t cmd_hdrs_dmas[HBA_COMMAND_HEADER_NUM]; /* command header dma */ +}; +typedef struct device_extension rt_device_extension_t; + +static struct hba_memory *g_hba_base; /* hba memory io base addr */ + +static rt_err_t ahci_create_device(rt_device_extension_t *extension); + +static rt_uint32_t ahci_flush_commands(struct hba_port *port) +{ + /* the commands may not take effect until the command + * register is read again by software, because reasons. + */ + rt_hw_dsb(); + volatile rt_uint32_t c = port->command; + rt_hw_dmb(); + return c; +} + +static void ahci_stop_port_command_engine(struct hba_port *port) +{ + rt_hw_dsb(); + port->command &= ~HBA_PxCMD_ST; + rt_hw_dsb(); + port->command &= ~HBA_PxCMD_FRE; + rt_hw_dmb(); + while((port->command & HBA_PxCMD_CR) || (port->command & HBA_PxCMD_FR)) + { + rt_hw_cpu_pause(); + } +} + +static void ahci_start_port_command_engine(struct hba_port *port) +{ + rt_hw_dmb(); + while(port->command & HBA_PxCMD_CR) + { + rt_hw_cpu_pause(); + } + rt_hw_dsb(); + port->command |= HBA_PxCMD_FRE; + rt_hw_dsb(); + port->command |= HBA_PxCMD_ST; + ahci_flush_commands((struct hba_port *)port); +} + +static struct hba_command_header *ahci_initialize_command_header(rt_device_extension_t *dev, struct hba_memory *abar, + struct hba_port *port, int slot, int write, + int atapi, int prd_entries, int fis_len) +{ + struct hba_command_header *hdr = (struct hba_command_header *)dev->clb_vaddr; + hdr += slot; + hdr->write = write ? 1 : 0; + hdr->prdb_count = 0; + hdr->atapi=atapi ? 1 : 0; + hdr->fis_length = fis_len; + hdr->prdt_len = prd_entries; + hdr->prefetchable = 0; + hdr->bist = 0; + hdr->pmport = 0; + hdr->reset = 0; + return hdr; +} + +static struct fis_reg_host_to_device *ahci_initialize_fis_host_to_device(rt_device_extension_t *dev, struct hba_memory *abar, + struct hba_port *port, int slot, int cmdctl, int ata_command) +{ + struct hba_command_table *tbl = (struct hba_command_table *)(dev->cmd_hdrs[slot]); + struct fis_reg_host_to_device *fis = (struct fis_reg_host_to_device *)(tbl->command_fis); + + rt_memset(fis, 0, sizeof(*fis)); + fis->fis_type = FIS_TYPE_REG_H2D; + fis->command = ata_command; + fis->c = cmdctl ? 1 : 0; + return fis; +} + +static void ahci_send_command(struct hba_port *port, int slot) +{ + port->interrupt_status = ~0; + port->command_issue = (1 << slot); + ahci_flush_commands(port); +} + +static int ahci_write_prdt(rt_device_extension_t *dev, struct hba_memory *abar, struct hba_port *port, + int slot, int offset, int length, rt_ubase_t virt_buffer) +{ + int num_entries = ((length - 1) / PRDT_MAX_COUNT) + 1; + struct hba_command_table *tbl = (struct hba_command_table *)(dev->cmd_hdrs[slot]); + int i; + struct hba_prdt_entry *prd; + + for(i = 0; i < num_entries - 1; i++) + { + rt_ubase_t phys_buffer; + phys_buffer = rt_hw_vir2phy(virt_buffer); + prd = &tbl->prdt_entries[i + offset]; + prd->byte_count = PRDT_MAX_COUNT - 1; + prd->data_base_l = LOWER32(phys_buffer); + prd->data_base_h = 0; + prd->interrupt_on_complete = 0; + + length -= PRDT_MAX_COUNT; + virt_buffer += PRDT_MAX_COUNT; + } + + rt_ubase_t phys_buffer; + phys_buffer = rt_hw_vir2phy(virt_buffer); + prd = &tbl->prdt_entries[i + offset]; + prd->byte_count = length - 1; + prd->data_base_l = LOWER32(phys_buffer); + prd->data_base_h = 0; + prd->interrupt_on_complete = 0; + return num_entries; +} + +static void ahci_reset_device(struct hba_memory *abar, struct hba_port *port, rt_device_extension_t *dev) +{ + dbgprint("[ahci] device port %d: sending COMRESET and reinitializing\n", dev->port); + ahci_stop_port_command_engine(port); + port->sata_error = ~0; + /* power on, spin up */ + port->command |= 2; + port->command |= 4; + ahci_flush_commands(port); + rt_thread_mdelay(1); + + /* initialize state */ + port->interrupt_status = ~0; /* clear pending interrupts */ + port->interrupt_enable = AHCI_DEFAULT_INT; /* we want some interrupts */ + port->command &= ~((1 << 27) | (1 << 26)); /* clear some bits */ + port->sata_control |= 1; + rt_thread_mdelay(10); + port->sata_control |= (~1); + rt_thread_mdelay(10); + port->interrupt_status = ~0; /* clear pending interrupts */ + port->interrupt_enable = AHCI_DEFAULT_INT; /* we want some interrupts */ + ahci_start_port_command_engine(port); + dev->slots = 0; + port->sata_error = ~0; +} + +static rt_err_t ahci_port_dma_data_transfer(rt_device_extension_t *dev, struct hba_memory *abar, struct hba_port *port, + int slot, int write, rt_ubase_t virt_buffer, int sectors, rt_uint64_t lba) +{ + struct fis_reg_host_to_device *fis; + int timeout; + int fis_len = sizeof(struct fis_reg_host_to_device) / 4; + + int ne = ahci_write_prdt(dev, abar, port, slot, 0, ATA_SECTOR_SIZE * sectors, virt_buffer); + ahci_initialize_command_header(dev, abar, port, slot, write, 0, ne, fis_len); + fis = ahci_initialize_fis_host_to_device(dev, abar, port, slot, 1, write ? ATA_CMD_WRITE_DMA_EX : ATA_CMD_READ_DMA_EX); + + fis->device = 1 << 6; + fis->count_l = LOWER8(sectors); + fis->count_h = HIGHER8(sectors); + + fis->lba0 = (unsigned char)( lba & 0xFF); + fis->lba1 = (unsigned char)((lba >> 8) & 0xFF); + fis->lba2 = (unsigned char)((lba >> 16) & 0xFF); + fis->lba3 = (unsigned char)((lba >> 24) & 0xFF); + fis->lba4 = (unsigned char)((lba >> 32) & 0xFF); + fis->lba5 = (unsigned char)((lba >> 40) & 0xFF); + port->sata_error = ~0; + + timeout = ATA_TFD_TIMEOUT; + while ((port->task_file_data & (ATA_DEV_BUSY | ATA_DEV_DRQ)) && --timeout) + { + rt_thread_yield(); + } + if(!timeout) + { + goto port_hung; + } + + port->sata_error = ~0; + ahci_send_command(port, slot); + timeout = ATA_TFD_TIMEOUT; + while ((port->task_file_data & (ATA_DEV_BUSY | ATA_DEV_DRQ)) && --timeout) + { + rt_thread_yield(); + } + if(!timeout) + { + goto port_hung; + } + + timeout = AHCI_CMD_TIMEOUT; + while(--timeout) + { + if(!((port->sata_active | port->command_issue) & (1 << slot))) + break; + rt_thread_yield(); + } + if(!timeout) + { + goto port_hung; + } + if(port->sata_error) + { + dbg_log(DBG_ERROR, "[ahci] device %d: ahci error\n", dev->port); + goto error; + } + if(port->task_file_data & ATA_DEV_ERR) + { + dbg_log(DBG_ERROR, "[ahci] device %d: task file data error\n", dev->port); + goto error; + } + return RT_EOK; +port_hung: + dbg_log(DBG_ERROR, "[ahci] device %d: port hung\n", dev->port); +error: + dbg_log(DBG_ERROR, "[ahci] device %d: tfd=%x, serr=%x\n", + dev->port, port->task_file_data, port->sata_error); + ahci_reset_device(abar, port, dev); + return RT_ERROR; +} + +static rt_err_t ahci_device_identify(rt_device_extension_t *dev, struct hba_memory *abar, struct hba_port *port) +{ + int fis_len = sizeof(struct fis_reg_host_to_device) / 4; + rt_hw_dma_t dma; + dma.size = 0x1000; + dma.alignment = 0x1000; + RT_ASSERT(rt_hw_dma_alloc(&dma) == RT_EOK); + + ahci_write_prdt(dev, abar, port, 0, 0, 512, (rt_ubase_t)dma.vaddr); + ahci_initialize_command_header(dev, abar, port, 0, 0, 0, 1, fis_len); + ahci_initialize_fis_host_to_device(dev, abar, port, 0, 1, ATA_CMD_IDENTIFY); + + int timeout = ATA_TFD_TIMEOUT; + port->sata_error = ~0; + while ((port->task_file_data & (ATA_DEV_BUSY | ATA_DEV_DRQ)) && --timeout) + { + rt_hw_cpu_pause(); + } + if(!timeout ) + { + dbg_log(DBG_ERROR, "[ahci] device %d: identify 1: port hung\n", dev->port); + dbg_log(DBG_ERROR, "[ahci] device %d: identify 1: tfd=%x, serr=%x\n", + dev->port, port->task_file_data, port->sata_error); + rt_hw_dma_free(&dma); + return RT_ETIMEOUT; + } + + ahci_send_command(port, 0); + + timeout = AHCI_CMD_TIMEOUT; + while(--timeout) + { + if(!((port->sata_active | port->command_issue) & 1)) + break; + } + if(!timeout) + { + dbg_log(DBG_ERROR, "[ahci] device %d: identify 2: port hung\n", dev->port); + dbg_log(DBG_ERROR, "[ahci] device %d: identify 2: tfd=%x, serr=%x\n", + dev->port, port->task_file_data, port->sata_error); + rt_hw_dma_free(&dma); + return RT_ETIMEOUT; + } + + struct ata_identify *identify = (struct ata_identify *) dma.vaddr; + if (identify->lba48_addressable_sectors) + { + dev->sector_count = identify->lba48_addressable_sectors; + } + else + { + dev->sector_count = 0; + } + dbgprint("[ahci] device %d: num sectors=%d\n", dev->port, dev->sector_count); + + rt_hw_dma_free(&dma); + + if (!dev->sector_count) + { + dbg_log(DBG_ERROR, "[ahci] device %d invalid sectors ZERO.\n", dev->port); + return RT_EINVAL; + } + return RT_EOK; +} + +static rt_uint32_t ahci_check_type(volatile struct hba_port *port) +{ + port->command &= ~1; + while(port->command & (1 << 15)) + { + rt_hw_cpu_pause(); + } + + port->command &= ~(1 << 4); + while(port->command & (1 << 14)) + { + rt_hw_cpu_pause(); + } + + rt_hw_dsb(); + port->command |= 2; + rt_hw_dsb(); + rt_thread_mdelay(10); + + rt_uint32_t s = port->sata_status; + + uint8_t ipm, det; + ipm = (s >> 8) & 0x0F; + det = s & 0x0F; + if(ipm != HBA_PORT_IPM_ACTIVE || det != HBA_PORT_DET_PRESENT) + { + return AHCI_DEV_NULL; + } + + switch (port->signature) + { + case SATA_SIG_ATAPI: + return AHCI_DEV_SATAPI; + case SATA_SIG_SEMB: + return AHCI_DEV_SEMB; + case SATA_SIG_PM: + return AHCI_DEV_PM; + default: + return AHCI_DEV_SATA; + } + return AHCI_DEV_SATA; +} + +int ahci_initialize_device(rt_device_extension_t *dev, struct hba_memory *abar) +{ + struct hba_port *port = (struct hba_port *)&abar->ports[dev->port]; + ahci_stop_port_command_engine(port); + port->sata_error = ~0; + /* power on, spin up */ + port->command |= (2 | 4); + ahci_flush_commands(port); + rt_thread_mdelay(2); + + /* initialize state */ + port->interrupt_status = ~0; /* clear pending interrupts */ + port->interrupt_enable = AHCI_DEFAULT_INT; /* we want some interrupts */ + + port->command &= ~1; + while(port->command & (1 << 15)) + { + rt_hw_cpu_pause(); + } + + port->command &= ~((1 << 27) | (1 << 26) | 1); /* clear some bits */ + ahci_flush_commands(port); + + /* start reset sata */ + port->sata_control |= 1; + rt_thread_mdelay(20); + + /* close DET, after init sata device done. */ + port->sata_control &= (~1); + rt_thread_mdelay(10); + while(!(port->sata_status & 1)) + { + rt_hw_cpu_pause(); + } + + port->sata_error = ~0; + port->command |= (1 << 28); /* set interface to active */ + while((port->sata_status >> 8) != 1) + { + rt_hw_cpu_pause(); + } + + port->interrupt_status = ~0; /* clear pending interrupts */ + port->interrupt_enable = AHCI_DEFAULT_INT; /* we want some interrupts */ + + rt_ubase_t clb_phys, fis_phys; + dev->clb_dma.size = 0x2000; + dev->clb_dma.alignment = 0x1000; + dev->fis_dma.size = 0x1000; + dev->fis_dma.alignment = 0x1000; + + RT_ASSERT(rt_hw_dma_alloc(&dev->clb_dma) == RT_EOK); + RT_ASSERT(rt_hw_dma_alloc(&dev->fis_dma) == RT_EOK); + dev->clb_vaddr = (void *)dev->clb_dma.vaddr; + dev->fis_vaddr = (void *)dev->fis_dma.vaddr; + clb_phys = dev->clb_dma.paddr; + fis_phys = dev->fis_dma.paddr; + + dev->slots=0; + struct hba_command_header *hdr = (struct hba_command_header *)dev->clb_vaddr; + int i; + for(i = 0; i < HBA_COMMAND_HEADER_NUM; i++) + { + dev->cmd_hdrs_dmas[i].size = 0x1000; + dev->cmd_hdrs_dmas[i].alignment = 0x1000; + + RT_ASSERT(rt_hw_dma_alloc(&dev->cmd_hdrs_dmas[i]) == RT_EOK); + dev->cmd_hdrs[i] = (void *)dev->cmd_hdrs_dmas[i].vaddr; + rt_memset(hdr, 0, sizeof(*hdr)); + + hdr->command_table_base_l = LOWER32(dev->cmd_hdrs_dmas[i].paddr); + hdr->command_table_base_h = 0; + + hdr++; + } + + port->command_list_base_l = LOWER32(clb_phys); + port->command_list_base_h = 0; + + port->fis_base_l = LOWER32(fis_phys); + port->fis_base_h = 0; + ahci_start_port_command_engine(port); + + port->sata_error = ~0; + return ahci_device_identify(dev, abar, port); +} + +static rt_uint32_t ahci_probe_ports(struct hba_memory *abar) +{ + rt_uint32_t pi = abar->port_implemented; + dbgprint("[ahci] ports implemented: %x\n", pi); + int counts = 0; /* exist device count */ + int i = 0; + rt_device_extension_t *extension; + while (i < DRV_AHCI_PORT_NR) + { + if (pi & 1) + { + rt_uint32_t type = ahci_check_type(&abar->ports[i]); + if (type == AHCI_DEV_SATA) { /* SATA device */ + dbgprint("[ahci] detected SATA device on port %d\n", i); + + extension = rt_malloc(sizeof(rt_device_extension_t)); + if (extension == RT_NULL) + { + dbg_log(DBG_ERROR, "[ahci] port %d alloc memory for extension failed!\n", i); + return counts; + } + extension->type = type; + extension->port = i; + rt_mutex_init(&extension->lock, "ahci", RT_IPC_FLAG_PRIO); + if (ahci_initialize_device(extension, abar) == RT_EOK)\ + { + if (ahci_create_device(extension) == RT_EOK) { + counts++; + } + else + { + dbg_log(DBG_ERROR, "[ahci] failed to create device %d, disabling port!\n", i); + rt_free(extension); + } + } else { + dbg_log(DBG_ERROR, "[ahci] failed to initialize device %d, disabling port.\n", i); + } + } else if(type == AHCI_DEV_SATAPI) { /* SATAPI device */ + dbg_log(DBG_WARNING, "[ahci] not support SATAPI device on port %d now!\n", i); + } else if(type == AHCI_DEV_PM) { /* PM device */ + dbg_log(DBG_WARNING, "[ahci] not support Port multiplier on port %d now!\n", i); + } else if(type == AHCI_DEV_SEMB) { /* SEMB device */ + dbg_log(DBG_WARNING, "[ahci] not support Enclosure management bridge on port %d now!\n", i); + } + /* do not deal other type now. */ + } + i++; + pi >>= 1; + } + return counts; +} + +static int ahci_port_get_slot(rt_device_extension_t *dev) +{ + for(;;) + { + int i; + rt_mutex_take(&dev->lock, RT_WAITING_FOREVER); + for(i = 0; i < DRV_AHCI_PORT_NR; i++) + { + if(!(dev->slots & (1 << i))) + { + dev->slots |= (1 << i); + rt_mutex_release(&dev->lock); + return i; + } + } + rt_mutex_release(&dev->lock); + rt_thread_yield(); + } +} + +void ahci_port_put_slot(rt_device_extension_t *dev, int slot) +{ + rt_mutex_take(&dev->lock, RT_WAITING_FOREVER); + dev->slots &= ~(1 << slot); + rt_mutex_release(&dev->lock); +} + +/* since a DMA transfer must write to contiguous physical RAM, we need to allocate + * buffers that allow us to create PRDT entries that do not cross a page boundary. + * That means that each PRDT entry can transfer a maximum of PAGE_SIZE bytes (for + * 0x1000 page size, that's 8 sectors). Thus, we allocate a buffer that is page aligned, + * in a multiple of PAGE_SIZE, so that the PRDT will write to contiguous physical ram + * (the key here is that the buffer need not be contiguous across multiple PRDT entries). + */ +static rt_size_t ahci_rw_multiple_do(rt_device_extension_t *dev, int rw, rt_uint64_t blk, unsigned char *out_buffer, int count) +{ + rt_uint32_t length = count * ATA_SECTOR_SIZE; + rt_uint64_t end_blk = dev->sector_count; + if (blk >= end_blk) + { + dbg_log(DBG_ERROR, "ahci: lba %d out of range %d\n", blk, end_blk); + return 0; + } + + if((blk + count) > end_blk) + { + count = end_blk - blk; + } + if(!count) + { + return 0; + } + + int num_pages = ((ATA_SECTOR_SIZE * (count - 1)) / PAGE_SIZE) + 1; + RT_ASSERT((length <= (unsigned)num_pages * 0x1000)); + rt_hw_dma_t dma; + dma.size = 0x1000 * num_pages; + dma.alignment = 0x1000; + RT_ASSERT(rt_hw_dma_alloc(&dma) == RT_EOK); + + rt_size_t num_read_blocks = count; + struct hba_port *port = (struct hba_port *)&g_hba_base->ports[dev->port]; + if(rw == 1) + { + rt_memcpy((void *)dma.vaddr, out_buffer, length); + } + + int slot = ahci_port_get_slot(dev); + if(ahci_port_dma_data_transfer(dev, g_hba_base, port, slot, rw == 1 ? 1 : 0, (rt_ubase_t)dma.vaddr, count, blk) != RT_EOK) + { + num_read_blocks = 0; + } + + ahci_port_put_slot(dev, slot); + + if(rw == 0 && num_read_blocks) + { + rt_memcpy(out_buffer, (void *)dma.vaddr, length); + } + + rt_hw_dma_free(&dma); + return num_read_blocks; +} + +/* and then since there is a maximum transfer amount because of the page size + * limit, wrap the transfer function to allow for bigger transfers than that even. + */ +static rt_size_t ahci_rw_multiple(rt_device_extension_t *dev, int rw, rt_uint64_t blk, unsigned char *out_buffer, int count) +{ + int i = 0; + rt_size_t ret = 0; + int c = count; + for(i = 0; i < count; i += (PRDT_MAX_ENTRIES * PRDT_MAX_COUNT) / ATA_SECTOR_SIZE) + { + int n = (PRDT_MAX_ENTRIES * PRDT_MAX_COUNT) / ATA_SECTOR_SIZE; + if(n > c) + { + n = c; + } + ret += ahci_rw_multiple_do(dev, rw, blk+i, out_buffer + ret, n); + c -= n; + } + return ret; +} + +static rt_pci_device_t *ahci_get_pci_info(void) +{ + rt_pci_device_t *ahci = rt_pci_device_get(0x1, 0x6); + if(ahci == RT_NULL) + { + ahci = rt_pci_device_get(0x8086, 0x8c03); + } + if(ahci == RT_NULL) + { + ahci = rt_pci_device_get(0x8086, 0x2922); + } + if(ahci == RT_NULL) + { + return RT_NULL; + } + + dbgprint("[ahci] device vendorID %x deviceID %x class code %x\n", ahci->vendor_id, ahci->device_id, ahci->class_code); + + rt_pci_enable_bus_mastering(ahci); + + g_hba_base = rt_ioremap((void *) ahci->bars[PCI_AHCI_MEMIO_BAR].base_addr, ahci->bars[PCI_AHCI_MEMIO_BAR].length); + if (g_hba_base == RT_NULL) { + dbgprint("[ahci] device memio_remap on %x length %x failed!\n", ahci->bars[PCI_AHCI_MEMIO_BAR].base_addr, ahci->bars[PCI_AHCI_MEMIO_BAR].length); + return RT_NULL; + } + mmu_flush_tlb(); + + dbgprint("[ahci] mapping memory iobase from paddr %x to vaddr %x\n", ahci->bars[PCI_AHCI_MEMIO_BAR].base_addr, g_hba_base); + dbgprint("[ahci] using interrupt %d\n", ahci->irq_line); + return ahci; +} + +static rt_err_t rt_ahci_init(rt_device_t dev) +{ + return RT_EOK; +} + +static rt_err_t rt_ahci_open(rt_device_t dev, rt_uint16_t oflag) +{ + return RT_EOK; +} + +static rt_err_t rt_ahci_close(rt_device_t dev) +{ + return RT_EOK; +} + +/* + * position: block page address, not bytes address + * buffer: read buffer addr + * size : how many blocks + */ +static rt_size_t rt_ahci_read(rt_device_t device, rt_off_t position, void *buffer, rt_size_t size) +{ + return ahci_rw_multiple((rt_device_extension_t *)device->user_data, 0, position, (unsigned char *)buffer, size); +} + +/* + * position: block page address, not bytes address + * buffer: write buffer addr + * size : how many blocks + */ +static rt_size_t rt_ahci_write(rt_device_t device, rt_off_t position, const void *buffer, rt_size_t size) +{ + return ahci_rw_multiple((rt_device_extension_t *)device->user_data, 1, position, (unsigned char *)buffer, size); +} + +static rt_err_t rt_ahci_control(rt_device_t dev, int cmd, void *args) +{ + RT_ASSERT(dev != RT_NULL); + RT_ASSERT(dev->user_data != NULL); + RT_ASSERT(args != RT_NULL); + + rt_device_extension_t *extension = (rt_device_extension_t *)dev->user_data; + rt_err_t err = RT_EOK; + switch(cmd) + { + case RT_DEVICE_CTRL_BLK_GETGEOME: + { + struct rt_device_blk_geometry *geometry; + + geometry = (struct rt_device_blk_geometry *)args; + if (geometry == RT_NULL) + { + return -RT_ERROR; + } + geometry->bytes_per_sector = ATA_SECTOR_SIZE; + geometry->block_size = ATA_SECTOR_SIZE; + geometry->sector_count = extension->sector_count; + dbgprint("[ahci] getgeome: bytes_per_sector:%d, block_size:%d, sector_count:%d\n", + geometry->bytes_per_sector, geometry->block_size, geometry->sector_count); + break; + } + default: + err = RT_ERROR; + break; + } + return err; +} + +static void rt_hw_ahci_isr(int vector, void *param) +{ + int i; + for (i = 0; i < 32; i++) + { + if (g_hba_base->interrupt_status & (1 << i)) + { + dbgprint("[ahci] interrupt on port %d occured!\n", i); + g_hba_base->ports[i].interrupt_status = ~0; + g_hba_base->interrupt_status = (1 << i); + ahci_flush_commands((struct hba_port *)&g_hba_base->ports[i]); + } + } +} + +static void ahci_init_hba(struct hba_memory *abar) +{ + if(abar->ext_capabilities & 1) + { + /* request BIOS/OS ownership handoff */ + abar->bohc |= (1 << 1); + while((abar->bohc & 1) || !(abar->bohc & (1<<1))) + { + rt_hw_cpu_pause(); + } + } + /* enable the AHCI and reset it */ + abar->global_host_control |= HBA_GHC_AHCI_ENABLE; + abar->global_host_control |= HBA_GHC_RESET; + /* wait for reset to complete */ + while(abar->global_host_control & HBA_GHC_RESET) + { + rt_hw_cpu_pause(); + } + + /* enable the AHCI and interrupts */ + abar->global_host_control |= HBA_GHC_AHCI_ENABLE; + abar->global_host_control |= HBA_GHC_INTERRUPT_ENABLE; + rt_thread_mdelay(20); + dbgprint("[ahci] caps: %x %x ver:%x ctl: %x\n", abar->capability, abar->ext_capabilities, abar->version, abar->global_host_control); +} + +#ifdef RT_USING_DEVICE_OPS +const static struct rt_device_ops ahci_ops = +{ + rt_ahci_init, + rt_ahci_open, + rt_ahci_close, + rt_ahci_read, + rt_ahci_write, + rt_ahci_control +}; +#endif + +static rt_err_t ahci_create_device(rt_device_extension_t *extension) +{ + static int ahci_next_device = 0; /* first is sd0 */ + rt_device_t device = rt_device_create(RT_Device_Class_Block, 0); + if (device == RT_NULL) + { + dbg_log(DBG_ERROR, "[ahci] create device failed!\n"); + return RT_ENOMEM; + } + device->user_data = (void *)extension; + +#ifdef RT_USING_DEVICE_OPS + device->ops = &ahci_ops; +#else + device->init = rt_ahci_init; + device->open = rt_ahci_open; + device->close = rt_ahci_close; + device->read = rt_ahci_read; + device->write = rt_ahci_write; + device->control = rt_ahci_control; +#endif + char devname[8] = {0}; + rt_sprintf(devname, "%s%c", DEV_NAME, '0' + ahci_next_device); + ahci_next_device++; + if (rt_device_register(device, devname, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE) != RT_EOK) + { + dbg_log(DBG_ERROR, "[ahci] register device failed!\n"); + rt_device_destroy(device); + return RT_ENOMEM; + } + return RT_EOK; +} + +static int rt_hw_ahci_init(void) +{ + /* 1. get pci info */ + rt_pci_device_t *ahci_pci = ahci_get_pci_info(); + if(ahci_pci == RT_NULL) + { + dbg_log(DBG_ERROR, "[ahci] no AHCI controllers present!\n"); + return RT_ERROR; + } + + /* 2. install intr */ + if (rt_hw_interrupt_install(ahci_pci->irq_line, rt_hw_ahci_isr, RT_NULL, "ahci") < 0) + { + dbg_log(DBG_ERROR, "[ahci] install IRQ failed!\n"); + rt_iounmap(g_hba_base); + return RT_ERROR; + } + rt_hw_interrupt_umask(ahci_pci->irq_line); + + /* 3. init ahci device */ + ahci_init_hba(g_hba_base); + if (!ahci_probe_ports(g_hba_base)) + { + dbg_log(DBG_ERROR, "[ahci] initializing ahci driver failed!.\n"); + rt_hw_interrupt_mask(ahci_pci->irq_line); + rt_iounmap(g_hba_base); + return RT_ERROR; + } + rt_kprintf("[ahci] disk driver init done!\n"); + return RT_EOK; +} + +#ifdef RT_USING_COMPONENTS_INIT +INIT_DEVICE_EXPORT(rt_hw_ahci_init); +#endif +#endif /* BSP_DRV_AHCI */ diff --git a/bsp/x86/drivers/drv_ahci.h b/bsp/x86/drivers/drv_ahci.h new file mode 100644 index 0000000000000000000000000000000000000000..f9e2bb35bf149337f92ed456ec5a3738c3b86ab4 --- /dev/null +++ b/bsp/x86/drivers/drv_ahci.h @@ -0,0 +1,356 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-08-04 JasonHu first version + */ + +#ifndef __DRV_AHCI_H__ +#define __DRV_AHCI_H__ + +#include + +enum AHCI_FIS_TYPE +{ + FIS_TYPE_REG_H2D = 0x27, // Register FIS - host to device + FIS_TYPE_REG_D2H = 0x34, // Register FIS - device to host + FIS_TYPE_DMA_ACT = 0x39, // DMA activate FIS - device to host + FIS_TYPE_DMA_SETUP = 0x41, // DMA setup FIS - bidirectional + FIS_TYPE_DATA = 0x46, // Data FIS - bidirectional + FIS_TYPE_BIST = 0x58, // BIST activate FIS - bidirectional + FIS_TYPE_PIO_SETUP = 0x5F, // PIO setup FIS - device to host + FIS_TYPE_DEV_BITS = 0xA1, // Set device bits FIS - device to host +}; + +struct fis_reg_host_to_device +{ + rt_uint8_t fis_type; + + rt_uint8_t pmport:4; + rt_uint8_t reserved0:3; + rt_uint8_t c:1; + + rt_uint8_t command; + rt_uint8_t feature_l; + + rt_uint8_t lba0; + rt_uint8_t lba1; + rt_uint8_t lba2; + rt_uint8_t device; + + rt_uint8_t lba3; + rt_uint8_t lba4; + rt_uint8_t lba5; + rt_uint8_t feature_h; + + rt_uint8_t count_l; + rt_uint8_t count_h; + rt_uint8_t icc; + rt_uint8_t control; + + rt_uint8_t reserved1[4]; +}__attribute__ ((packed)); + +struct fis_reg_device_to_host +{ + rt_uint8_t fis_type; + + rt_uint8_t pmport:4; + rt_uint8_t reserved0:2; + rt_uint8_t interrupt:1; + rt_uint8_t reserved1:1; + + rt_uint8_t status; + rt_uint8_t error; + + rt_uint8_t lba0; + rt_uint8_t lba1; + rt_uint8_t lba2; + rt_uint8_t device; + + rt_uint8_t lba3; + rt_uint8_t lba4; + rt_uint8_t lba5; + rt_uint8_t reserved2; + + rt_uint8_t count_l; + rt_uint8_t count_h; + rt_uint8_t reserved3[2]; + + rt_uint8_t reserved4[4]; +}__attribute__ ((packed)); + +struct fis_data +{ + rt_uint8_t fis_type; + rt_uint8_t pmport:4; + rt_uint8_t reserved0:4; + rt_uint8_t reserved1[2]; + + rt_uint32_t data[1]; +}__attribute__ ((packed)); + +struct fis_pio_setup +{ + rt_uint8_t fis_type; + + rt_uint8_t pmport:4; + rt_uint8_t reserved0:1; + rt_uint8_t direction:1; + rt_uint8_t interrupt:1; + rt_uint8_t reserved1:1; + + rt_uint8_t status; + rt_uint8_t error; + + rt_uint8_t lba0; + rt_uint8_t lba1; + rt_uint8_t lba2; + rt_uint8_t device; + + rt_uint8_t lba3; + rt_uint8_t lba4; + rt_uint8_t lba5; + rt_uint8_t reserved2; + + rt_uint8_t count_l; + rt_uint8_t count_h; + rt_uint8_t reserved3; + rt_uint8_t e_status; + + rt_uint16_t transfer_count; + rt_uint8_t reserved4[2]; +}__attribute__ ((packed)); + +struct fis_dma_setup +{ + rt_uint8_t fis_type; + + rt_uint8_t pmport:4; + rt_uint8_t reserved0:1; + rt_uint8_t direction:1; + rt_uint8_t interrupt:1; + rt_uint8_t auto_activate:1; + + rt_uint8_t reserved1[2]; + + rt_uint64_t dma_buffer_id; + + rt_uint32_t reserved2; + + rt_uint32_t dma_buffer_offset; + + rt_uint32_t transfer_count; + + rt_uint32_t reserved3; +}__attribute__ ((packed)); + +struct fis_dev_bits +{ + volatile rt_uint8_t fis_type; + + volatile rt_uint8_t pmport:4; + volatile rt_uint8_t reserved0:2; + volatile rt_uint8_t interrupt:1; + volatile rt_uint8_t notification:1; + + volatile rt_uint8_t status; + volatile rt_uint8_t error; + + volatile rt_uint32_t protocol; +}__attribute__ ((packed)); + +struct hba_port +{ + volatile rt_uint32_t command_list_base_l; + volatile rt_uint32_t command_list_base_h; + volatile rt_uint32_t fis_base_l; + volatile rt_uint32_t fis_base_h; + volatile rt_uint32_t interrupt_status; + volatile rt_uint32_t interrupt_enable; + volatile rt_uint32_t command; + volatile rt_uint32_t reserved0; + volatile rt_uint32_t task_file_data; + volatile rt_uint32_t signature; + volatile rt_uint32_t sata_status; + volatile rt_uint32_t sata_control; + volatile rt_uint32_t sata_error; + volatile rt_uint32_t sata_active; + volatile rt_uint32_t command_issue; + volatile rt_uint32_t sata_notification; + volatile rt_uint32_t fis_based_switch_control; + volatile rt_uint32_t reserved1[11]; + volatile rt_uint32_t vendor[4]; +}__attribute__ ((packed)); + +struct hba_memory +{ + volatile rt_uint32_t capability; + volatile rt_uint32_t global_host_control; + volatile rt_uint32_t interrupt_status; + volatile rt_uint32_t port_implemented; + volatile rt_uint32_t version; + volatile rt_uint32_t ccc_control; + volatile rt_uint32_t ccc_ports; + volatile rt_uint32_t em_location; + volatile rt_uint32_t em_control; + volatile rt_uint32_t ext_capabilities; + volatile rt_uint32_t bohc; + + volatile rt_uint8_t reserved[0xA0 - 0x2C]; + + volatile rt_uint8_t vendor[0x100 - 0xA0]; + + volatile struct hba_port ports[1]; +}__attribute__ ((packed)); + +struct hba_received_fis +{ + volatile struct fis_dma_setup fis_ds; + volatile rt_uint8_t pad0[4]; + + volatile struct fis_pio_setup fis_ps; + volatile rt_uint8_t pad1[12]; + + volatile struct fis_reg_device_to_host fis_r; + volatile rt_uint8_t pad2[4]; + + volatile struct fis_dev_bits fis_sdb; + volatile rt_uint8_t ufis[64]; + volatile rt_uint8_t reserved[0x100 - 0xA0]; +}__attribute__ ((packed)); + +struct hba_command_header +{ + rt_uint8_t fis_length:5; + rt_uint8_t atapi:1; + rt_uint8_t write:1; + rt_uint8_t prefetchable:1; + + rt_uint8_t reset:1; + rt_uint8_t bist:1; + rt_uint8_t clear_busy_upon_r_ok:1; + rt_uint8_t reserved0:1; + rt_uint8_t pmport:4; + + rt_uint16_t prdt_len; + + volatile rt_uint32_t prdb_count; + + rt_uint32_t command_table_base_l; + rt_uint32_t command_table_base_h; + + rt_uint32_t reserved1[4]; +}__attribute__ ((packed)); + +struct hba_prdt_entry +{ + rt_uint32_t data_base_l; + rt_uint32_t data_base_h; + rt_uint32_t reserved0; + + rt_uint32_t byte_count:22; + rt_uint32_t reserved1:9; + rt_uint32_t interrupt_on_complete:1; +}__attribute__ ((packed)); + +struct hba_command_table +{ + rt_uint8_t command_fis[64]; + rt_uint8_t acmd[16]; + rt_uint8_t reserved[48]; + struct hba_prdt_entry prdt_entries[1]; +}__attribute__ ((packed)); + +#define HBA_COMMAND_HEADER_NUM 32 + +struct ata_identify +{ + rt_uint16_t ata_device; + rt_uint16_t dont_care[48]; + rt_uint16_t cap0; + rt_uint16_t cap1; + rt_uint16_t obs[2]; + rt_uint16_t free_fall; + rt_uint16_t dont_care_2[8]; + rt_uint16_t dma_mode0; + rt_uint16_t pio_modes; + rt_uint16_t dont_care_3[4]; + rt_uint16_t additional_supported; + rt_uint16_t rsv1[6]; + rt_uint16_t serial_ata_cap0; + rt_uint16_t rsv2; + + rt_uint16_t serial_ata_features; + rt_uint16_t serial_ata_features_enabled; + + rt_uint16_t maj_ver; + rt_uint16_t min_ver; + + rt_uint16_t features0; + rt_uint16_t features1; + rt_uint16_t features2; + rt_uint16_t features3; + rt_uint16_t features4; + rt_uint16_t features5; + + rt_uint16_t udma_modes; + rt_uint16_t dont_care_4[11]; + rt_uint64_t lba48_addressable_sectors; + rt_uint16_t wqewqe[2]; + rt_uint16_t ss_1; + rt_uint16_t rrrrr[4]; + rt_uint32_t ss_2; + /* ...and more */ +}; + +#define HBA_PxCMD_ST (1 << 0) +#define HBA_PxCMD_FRE (1 << 4) +#define HBA_PxCMD_FR (1 << 14) +#define HBA_PxCMD_CR (1 << 15) + +#define HBA_GHC_AHCI_ENABLE (1 << 31) +#define HBA_GHC_INTERRUPT_ENABLE (1 << 1) +#define HBA_GHC_RESET (1 << 0) + +#define ATA_CMD_IDENTIFY 0xEC + +#define ATA_DEV_BUSY 0x80 +#define ATA_DEV_DRQ 0x08 +#define ATA_DEV_ERR 0x01 + +#define ATA_CMD_READ_DMA_EX 0x25 +#define ATA_CMD_WRITE_DMA_EX 0x35 + +#define PRDT_MAX_COUNT 0x1000 + +#define PRDT_MAX_ENTRIES 65535 + +#define ATA_TFD_TIMEOUT 1000000 +#define AHCI_CMD_TIMEOUT 1000000 + +#define ATA_SECTOR_SIZE 512 + +#define AHCI_DEFAULT_INT 0 + +#define SATA_SIG_ATA 0x00000101 // SATA drive +#define SATA_SIG_ATAPI 0xEB140101 // SATAPI drive +#define SATA_SIG_SEMB 0xC33C0101 // Enclosure management bridge +#define SATA_SIG_PM 0x96690101 // Port multiplier + +enum AHCI_DEVICE_TYPE +{ + AHCI_DEV_NULL = 0, + AHCI_DEV_SATA, + AHCI_DEV_SEMB, + AHCI_DEV_PM, + AHCI_DEV_SATAPI +}; + +#define HBA_PORT_IPM_ACTIVE 1 +#define HBA_PORT_DET_PRESENT 3 + +#endif /* __DRV_AHCI_H__ */ diff --git a/bsp/x86/drivers/drv_timer.c b/bsp/x86/drivers/drv_timer.c new file mode 100644 index 0000000000000000000000000000000000000000..f83a8513c9a91dcd1cf40e6ab1ff949d441e3bb5 --- /dev/null +++ b/bsp/x86/drivers/drv_timer.c @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-07-16 JasonHu first version + */ + +#include +#include +#include + +#include "board.h" + +/* PIT (Programmable Interval Timer)8253/8254 可编程中断计时器 */ + +/* +Port 40h, 8253 Counter 0 Time of Day Clock (normally mode 3) +*/ +#define PIT_COUNTER0 0x40 + +/* +Port 41h, 8253 Counter 1 RAM Refresh Counter (normally mode 2) +*/ +#define PIT_COUNTER1 0x41 + +/* +Port 42h, 8253 Counter 2 Cassette and Speaker Functions +*/ +#define PIT_COUNTER2 0x42 + +/* +Programmable interrupt timer, control word register: +Port 43h, 8253 Mode Control Register, data format: + + |7|6|5|4|3|2|1|0| Mode Control Register + | | | | | | | `---- 0=16 binary counter, 1=4 decade BCD counter + | | | | `--------- counter mode bits + | | `------------ read/write/latch format bits + `--------------- counter select bits (also 8254 read back command) + +Read Back Command Format (8254 only) + + |7|6|5|4|3|2|1|0| Read Back Command (written to Mode Control Reg) + | | | | | | | `--- must be zero + | | | | | | `---- select counter 0 + | | | | | `----- select counter 1 + | | | | `------ select counter 2 + | | | `------- 0 = latch status of selected counters + | | `-------- 0 = latch count of selected counters + `----------- 11 = read back command + +Read Back Command Status (8254 only, read from counter register) + + |7|6|5|4|3|2|1|0| Read Back Command Status + | | | | | | | `--- 0=16 binary counter, 1=4 decade BCD counter + | | | | `-------- counter mode bits (see Mode Control Reg above) + | | `----------- read/write/latch format (see Mode Control Reg) + | `------------ 1=null count (no count set), 0=count available + `------------- state of OUT pin (1=high, 0=low) +*/ +#define PIT_CTRL 0x43 + +/* Mode Control Register */ +enum ctrl_mode_bits +{ + /* Bits 76 Counter Select Bits */ + PIT_MODE_COUNTER_0 = (0), /* 00 select counter 0 */ + PIT_MODE_COUNTER_1 = (1 << 6), /* 01 select counter 1 */ + PIT_MODE_COUNTER_2 = (1 << 7), /* 10 select counter 2 */ + PIT_MODE_READ_BACK = ((1 << 6) | (1 << 7)), /* 11 read back command (8254 only, illegal on 8253, see below) */ + /* Bits 54 Read/Write/Latch Format Bits */ + PIT_MODE_LPCV = (0), /* 00 latch present counter value */ + PIT_MODE_MSB = (1 << 4), /* 01 read/write of MSB only */ + PIT_MODE_LSB = (1 << 5), /* 10 read/write of LSB only */ + PIT_MODE_MSB_LSB = ((1 << 4) | (1 << 5)), /* 11 read/write LSB, followed by write of MSB */ + /* Bits 321 Counter Mode Bits */ + + /* + 000 mode 0, interrupt on terminal count; countdown, interrupt, + then wait for a new mode or count; loading a new count in the + middle of a count stops the countdown + */ + PIT_MODE_0 = (0), + /* + 001 mode 1, programmable one-shot; countdown with optional + restart; reloading the counter will not affect the countdown + until after the following trigger + */ + PIT_MODE_1 = (1 << 1), + /* + 010 mode 2, rate generator; generate one pulse after 'count' CLK + cycles; output remains high until after the new countdown has + begun; reloading the count mid-period does not take affect + until after the period + */ + PIT_MODE_2 = (1 << 2), + /* + 011 mode 3, square wave rate generator; generate one pulse after + 'count' CLK cycles; output remains high until 1/2 of the next + countdown; it does this by decrementing by 2 until zero, at + which time it lowers the output signal, reloads the counter + and counts down again until interrupting at 0; reloading the + count mid-period does not take affect until after the period + + */ + PIT_MODE_3 = ((1 << 1) | (1 << 2)), + /* + 100 mode 4, software triggered strobe; countdown with output high + until counter zero; at zero output goes low for one CLK + period; countdown is triggered by loading counter; reloading + counter takes effect on next CLK pulse + + */ + PIT_MODE_4 = (1 << 3), + /* + 101 mode 5, hardware triggered strobe; countdown after triggering + with output high until counter zero; at zero output goes low + for one CLK period + */ + PIT_MODE_5 = ((1 << 1) | (1 << 3)), + + /* Bits 0 Counter Mode Bits */ + PIT_MODE_BINARY = (0), /* 0 0= 16 binary counter */ + PIT_MODE_BCD = (1), /* 1 1= 4 decade BCD counter */ +}; + +#define TIMER_FREQ 1193180 /* clock frequency */ +#define COUNTER0_VALUE (TIMER_FREQ / RT_TICK_PER_SECOND) + +static void rt_hw_timer_isr(int vector, void *param) +{ + rt_tick_increase(); +} + +int rt_hw_timer_init(void) +{ + outb(PIT_CTRL, PIT_MODE_2 | PIT_MODE_MSB_LSB | + PIT_MODE_COUNTER_0 | PIT_MODE_BINARY); + outb(PIT_COUNTER0, (rt_uint8_t) (COUNTER0_VALUE & 0xff)); + outb(PIT_COUNTER0, (rt_uint8_t) (COUNTER0_VALUE >> 8) & 0xff); + + rt_hw_interrupt_install(IRQ0_CLOCK, rt_hw_timer_isr, RT_NULL, "tick"); + rt_hw_interrupt_umask(IRQ0_CLOCK); + return 0; +} diff --git a/bsp/x86/drivers/drv_timer.h b/bsp/x86/drivers/drv_timer.h new file mode 100644 index 0000000000000000000000000000000000000000..ec052afcb21aa71a3c3b02d709d1fe78873f047e --- /dev/null +++ b/bsp/x86/drivers/drv_timer.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-07-16 JasonHu first version + */ + +#ifndef __DRV_TIMER_H__ +#define __DRV_TIMER_H__ + +int rt_hw_timer_init(void); + +#endif /* __DRV_TIMER_H__ */ diff --git a/bsp/x86/drivers/drv_uart.c b/bsp/x86/drivers/drv_uart.c new file mode 100644 index 0000000000000000000000000000000000000000..6c1c0063b8ae4a8c834daeb643b8793422e05c87 --- /dev/null +++ b/bsp/x86/drivers/drv_uart.c @@ -0,0 +1,302 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-07-15 JasonHu first version + */ + +#include + +#ifdef BSP_DRV_UART +#include +#include +#include "drv_uart.h" +#include "board.h" + +struct hw_uart_device +{ + rt_uint32_t hw_base; + rt_uint32_t irqno; + + rt_uint16_t data_reg; + rt_uint16_t divisor_low_reg; + rt_uint16_t intr_enable_reg; + rt_uint16_t divisor_high_reg; + rt_uint16_t intr_indenty_reg; + rt_uint16_t fifo_reg; + rt_uint16_t line_ctrl_reg; + rt_uint16_t modem_ctrl_reg; + rt_uint16_t line_status_reg; + rt_uint16_t modem_status_reg; + rt_uint16_t scratch_reg; +}; + +/* I/O port base addr */ +#define SERIAL0_BASE 0X3F8 +#define SERIAL1_BASE 0X2F8 + +#define SERIAL0_IRQ 4 +#define SERIAL1_IRQ 3 + +#define MAX_BAUD_VALUE 11520 +#define DEFAULT_BAUD_VALUE 11520 +#define DEFAULT_DIVISOR_VALUE (MAX_BAUD_VALUE / DEFAULT_BAUD_VALUE) + +enum uart_fifo_control_register_bits +{ + FIFO_ENABLE = 1, /* Enable FIFOs */ + FIFO_CLEAR_RECEIVE = (1 << 1), /* Clear Receive FIFO */ + FIFO_CLEAR_TRANSMIT = (1 << 2), /* Clear Transmit FIFO */ + FIFO_DMA_MODE_SELECT = (1 << 3), /* DMA Mode Select */ + FIFO_RESERVED = (1 << 4), /* Reserved */ + FIFO_ENABLE_64 = (1 << 5), /* Enable 64 Byte FIFO(16750) */ + /* Interrupt Trigger Level/Trigger Level */ + FIFO_TRIGGER_1 = (0 << 6), /* 1 Byte */ + FIFO_TRIGGER_4 = (1 << 6), /* 4 Byte */ + FIFO_TRIGGER_8 = (1 << 7), /* 8 Byte */ + FIFO_TRIGGER_14 = (1 << 6) | (1 << 7), /* 14 Byte */ +}; + +enum uart_line_control_register_bits +{ + /* Word Length */ + LINE_WORD_LENGTH_5 = 0, /* 5 Bits */ + LINE_WORD_LENGTH_6 = 1, /* 6 Bits */ + LINE_WORD_LENGTH_7 = (1 << 1), /* 7 Bits */ + LINE_WORD_LENGTH_8 = ((1 << 1) | 1), /* 8 Bits */ + LINE_STOP_BIT_1 = (0 << 2), /* One Stop Bit */ + LINE_STOP_BIT_2 = (1 << 2), /* 1.5 Stop Bits or 2 Stop Bits */ + /* Parity Select */ + LINE_PARITY_NO = (0 << 3), /* No Parity */ + LINE_PARITY_ODD = (1 << 3), /* Odd Parity */ + LINE_PARITY_EVEN = (1 << 3) | (1 << 4), /* Even Parity */ + LINE_PARITY_MARK = (1 << 3) | (1 << 5), /* Mark */ + LINE_PARITY_SPACE = (1 << 3) | (1 << 4) | (1 << 5), /* Space */ + LINE_BREAK_ENABLE = (1 << 6), /* Set Break Enable */ + LINE_DLAB = (1 << 7), /* Divisor Latch Access Bit */ +}; +enum uart_interrupt_enable_register_bits +{ + INTR_RECV_DATA_AVALIABLE = 1, /* Enable Received Data Available Interrupt */ + INTR_TRANSMIT_HOLDING = (1 << 1), /* Enable Transmitter Holding Register Empty Interrupt */ + INTR_STATUS_CHANGED = (1 << 2), /* Enable Receiver Line Status Interrupt */ + INTR_MODEM_STATUS = (1 << 3), /* Enable Modem Status Interrupt */ + INTR_SLEEP_MODE = (1 << 4), /* Enable Sleep Mode(16750) */ + INTR_LOW_POWER_MODE = (1 << 5), /* Enable Low Power Mode(16750) */ + INTR_RESERVED1 = (1 << 6), /* Reserved */ + INTR_RESERVED2 = (1 << 7), /* Reserved */ +}; + +enum uart_line_status_register_bits +{ + LINE_STATUS_DATA_READY = 1, /* Data Ready */ + LINE_STATUS_OVERRUN_ERROR = (1 << 1), /* Overrun Error */ + LINE_STATUS_PARITY_ERROR = (1 << 2), /* Parity Error */ + LINE_STATUS_FRAMING_ERROR = (1 << 3), /* Framing Error */ + LINE_STATUS_BREAK_INTERRUPT = (1 << 4), /* Break Interrupt */ + LINE_STATUS_EMPTY_TRANSMITTER_HOLDING = (1 << 5), /* Empty Transmitter Holding Register */ + LINE_STATUS_EMPTY_DATA_HOLDING = (1 << 6), /* Empty Data Holding Registers */ + LINE_STATUS_ERROR_RECEIVE_FIFO = (1 << 7), /* Error in Received FIFO */ +}; + +enum uart_intr_indenty_reg_bits +{ + INTR_STATUS_PENDING_FLAG = 1, /* Interrupt Pending Flag */ + /* 产生的什么中断 */ + INTR_STATUS_MODEM = (0 << 1), /* Transmitter Holding Register Empty Interrupt */ + INTR_STATUS_TRANSMITTER_HOLDING = (1 << 1), /* Received Data Available Interrupt */ + INTR_STATUS_RECEIVE_DATA = (1 << 2), /* Received Data Available Interrupt */ + INTR_STATUS_RECEIVE_LINE = (1 << 1) | (1 << 2), /* Receiver Line Status Interrupt */ + INTR_STATUS_TIME_OUT_PENDING = (1 << 2) | (1 << 3), /* Time-out Interrupt Pending (16550 & later) */ + INTR_STATUS_64BYTE_FIFO = (1 << 5), /* 64 Byte FIFO Enabled (16750 only) */ + INTR_STATUS_NO_FIFO = (0 << 6), /* No FIFO on chip */ + INTR_STATUS_RESERVED_CONDITION = (1 << 6), /* Reserved condition */ + INTR_STATUS_FIFO_NOT_FUNC = (1 << 7), /* FIFO enabled, but not functioning */ + INTR_STATUS_FIFO = (1 << 6) | (1 << 7), /* FIFO enabled */ +}; + +enum uart_modem_control_register_bits +{ + MCR_DTR = 1, /* Programs -DTR. If set, -DTR is low and the DTR pin of the port goes 'high'. */ + MCR_RTS = (1 << 1), /* Programs -RTS. dito. */ + MCR_OUT1 = (1 << 2), /* Programs -OUT1. Normally not used in a PC, but used with some + multi-port serial adapters to enable or disable a port. Best + thing is to write a '1' to this bit. */ + MCR_OUT2 = (1 << 3), /* Programs -OUT2. If set to 1, interrupts generated by the UART + are transferred to the ICU (Interrupt Control Unit) while 0 + sets the interrupt output of the card to high impedance. + (This is PC-only). */ + MCR_LOOPBACK = (1 << 4), /* '1': local loopback. All outputs disabled. This is a means of + testing the chip: you 'receive' all the data you send. */ +}; + +static void rt_hw_uart_isr(int irqno, void *param) +{ + struct rt_serial_device *serial = (struct rt_serial_device *)param; + rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND); +} + +static rt_err_t uart_configure(struct rt_serial_device *serial, struct serial_configure *cfg) +{ + RT_ASSERT(serial != RT_NULL); + serial->config = *cfg; + return RT_EOK; +} + +static rt_err_t uart_control(struct rt_serial_device *serial, int cmd, void *arg) +{ + struct hw_uart_device *uart; + + RT_ASSERT(serial != RT_NULL); + uart = (struct hw_uart_device *)serial->parent.user_data; + rt_uint8_t val; + switch (cmd) + { + case RT_DEVICE_CTRL_CLR_INT: + /* disable rx irq */ + val = inb(uart->intr_enable_reg); + outb(uart->intr_enable_reg, val & ~INTR_RECV_DATA_AVALIABLE); + break; + + case RT_DEVICE_CTRL_SET_INT: + /* enable rx irq */ + val = inb(uart->intr_enable_reg); + outb(uart->intr_enable_reg, val | INTR_RECV_DATA_AVALIABLE); + break; + } + return RT_EOK; +} + +static int uart_putc(struct rt_serial_device *serial, char c) +{ + struct hw_uart_device *uart; + + RT_ASSERT(serial != RT_NULL); + uart = (struct hw_uart_device *)serial->parent.user_data; + + int timeout = 100000; + while (!(inb(uart->line_status_reg) & LINE_STATUS_EMPTY_TRANSMITTER_HOLDING) && timeout--) + { + } + outb(uart->data_reg, c); + return 1; +} + +static int uart_getc(struct rt_serial_device *serial) +{ + struct hw_uart_device *uart; + + RT_ASSERT(serial != RT_NULL); + uart = (struct hw_uart_device *)serial->parent.user_data; + + int timeout = 100000; + while (!(inb(uart->line_status_reg) & LINE_STATUS_DATA_READY) && timeout--) + { + } + int data = -1; + if (timeout > 0) + { + data = inb(uart->data_reg); + } + return data; +} + +static const struct rt_uart_ops _uart_ops = +{ + uart_configure, + uart_control, + uart_putc, + uart_getc, +}; + +#ifdef RT_USING_UART0 +/* UART device driver structure */ +static struct hw_uart_device _uart0_device = +{ + SERIAL0_BASE, + SERIAL0_IRQ, +}; +static struct rt_serial_device _serial0; +#endif /* RT_USING_UART0 */ + +#ifdef RT_USING_UART1 +/* UART1 device driver structure */ +static struct hw_uart_device _uart1_device = +{ + SERIAL1_BASE, + SERIAL1_IRQ, +}; +static struct rt_serial_device _serial1; +#endif /* RT_USING_UART1 */ + +#if defined(RT_USING_UART0) || defined(RT_USING_UART1) +static void do_uart_init(char *name, struct hw_uart_device *uart, struct rt_serial_device *serial) +{ + struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT; + rt_uint32_t iobase = uart->hw_base; + + uart->data_reg = iobase + 0; + uart->divisor_low_reg = iobase + 0; + uart->intr_enable_reg = iobase + 1; + uart->divisor_high_reg = iobase + 1; + uart->intr_indenty_reg = iobase + 2; + uart->line_ctrl_reg = iobase + 3; + uart->modem_ctrl_reg = iobase + 4; + uart->line_status_reg = iobase + 5; + uart->modem_status_reg = iobase + 6; + uart->scratch_reg = iobase + 7; + + /* Setting can change the baud rate Baud */ + outb(uart->line_ctrl_reg, LINE_DLAB); + + /* Set Baud rate */ + outb(uart->divisor_low_reg, (MAX_BAUD_VALUE / config.baud_rate) & 0xff); + outb(uart->divisor_high_reg, ((MAX_BAUD_VALUE / config.baud_rate) >> 8) & 0xff); + + /* Set DLAB to 0, set the character width to 8, stop bit to 1, no parity, break signal Disabled */ + outb(uart->line_ctrl_reg, LINE_WORD_LENGTH_8 | + LINE_STOP_BIT_1 | LINE_PARITY_NO); + + /* enable recv intr */ + outb(uart->intr_enable_reg, INTR_RECV_DATA_AVALIABLE | + INTR_STATUS_CHANGED | INTR_LOW_POWER_MODE); + + /* + * Set FIFO, open FIFO, clear receive FIFO, clear transmit FIFO Open 64Byte FIFO, + * interrupt trigger level is 14Byte + */ + outb(uart->fifo_reg, FIFO_ENABLE | FIFO_CLEAR_TRANSMIT | + FIFO_CLEAR_RECEIVE | FIFO_ENABLE_64 | + FIFO_TRIGGER_14); + + /* IRQs enabled, RTS/DSR set */ + outb(uart->modem_ctrl_reg, MCR_DTR | MCR_RTS | MCR_OUT2); + outb(uart->scratch_reg, 0x00); + + serial->ops = &_uart_ops; + serial->config = config; + + /* register device */ + rt_hw_serial_register(serial, name, + RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, + uart); + rt_hw_interrupt_install(uart->irqno, rt_hw_uart_isr, serial, name); + rt_hw_interrupt_umask(uart->irqno); +} +#endif + +int rt_hw_uart_init(void) +{ +#ifdef RT_USING_UART0 + do_uart_init("uart0", &_uart0_device, &_serial0); +#endif /* RT_USING_UART0 */ + +#ifdef RT_USING_UART1 + do_uart_init("uart1", &_uart1_device, &_serial1); +#endif /* RT_USING_UART1 */ + return 0; +} +#endif /* BSP_DRV_UART */ diff --git a/bsp/x86/drivers/drv_uart.h b/bsp/x86/drivers/drv_uart.h new file mode 100644 index 0000000000000000000000000000000000000000..b22beca5d2869d540e338f71cd95be7ca789f5c6 --- /dev/null +++ b/bsp/x86/drivers/drv_uart.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-07-15 JasonHu first version + */ + +#ifndef __DRV_UART_H__ +#define __DRV_UART_H__ + +int rt_hw_uart_init(void); + +#endif /* __DRV_UART_H__ */ diff --git a/bsp/x86/drivers/floppy.c b/bsp/x86/drivers/floppy.c deleted file mode 100644 index c7876a68f8a2a658fea989545b0013747a36689f..0000000000000000000000000000000000000000 --- a/bsp/x86/drivers/floppy.c +++ /dev/null @@ -1,360 +0,0 @@ - -#include -#include - -#include - -typedef rt_uint8_t u8; -typedef rt_uint16_t u16; -typedef rt_uint32_t u32; - -typedef rt_int8_t s8; -typedef rt_int16_t s16; -typedef rt_int32_t s32; - -#define OUTB(v,p) outb(p,v) - -#include "floppy.h" -#include "dma.h" - -#define NULL RT_NULL -#define SECTOR_SIZE 512 -#define panic(str,...) do { rt_kprintf("panic::" str,##__VA_ARGS__); while(1); } while(0) - -#define _local_irq_save(level) level = rt_hw_interrupt_disable() -#define _local_irq_restore(level) rt_hw_interrupt_enable(level) - -static u8 floppy_buffer[512]; /* 软盘高速缓冲区地址指针 */ - -#define MAX_REPLIES 7 -static u8 floppy_reply_buffer[MAX_REPLIES]; /* 软驱回应缓冲区 */ -#define ST0 (floppy_reply_buffer[0]) /* 软驱回应0号字节 */ -#define ST1 (floppy_reply_buffer[1]) /* 软驱回应1号字节 */ -#define ST2 (floppy_reply_buffer[2]) /* 软驱回应2号字节 */ -#define ST3 (floppy_reply_buffer[3]) /* 软驱回应3号字节 */ - - -static char *floppy_inc_name; /* 软驱型号名 */ -static char *floppy_type; -static u32 floppy_motor=0; /* 软驱马达状态字节 */ -static u32 floppy_size =0; -/**********************功能函数***************************/ -static void floppy_result(void); /* 获得软驱响应状态 */ -static u32 floppy_sendbyte(u32); /* 向软驱控制寄存器发送一个控制字节 */ -static u32 floppy_getbyte(void); /* 从软驱数据寄存器得到一个数据字节 */ -static u32 floppy_get_info(void); /* 得到软驱信息 */ -static void floppy_motorOn(void); /* 打开软驱马达 */ -static void floppy_motorOff(void); /* 关闭软驱马达 */ -static void floppy_setmode(void); /* 软驱模式设置 */ -static void block_to_hts(u32, u32*, u32*, u32*); /* 逻辑块转为磁盘头、磁道号和扇区号 */ -static void floppy_setupDMA(void); /* 设置软驱DMA通道 */ -static void floppy_read_cmd(u32 blk); /* 从软盘上读取指定的逻辑块到缓冲区 */ - - -void floppy_result(void) -{ - u8 stat, i,count; - i=0; - for(count=0; count<0xFF; count++) - { - stat = inb( FD_STATUS ) & (STATUS_READY|STATUS_DIR|STATUS_BUSY); //读取状态寄存器 - if (stat == STATUS_READY) - return; - if (stat == (STATUS_READY|STATUS_DIR|STATUS_BUSY)) - { - if(i>7) break; - floppy_reply_buffer[i++]=inb_p(FD_DATA); - } - } - - panic("Get floppy status times out !\n"); -} - -u32 floppy_sendbyte( u32 value ) -{ - u8 stat, i; - - for ( i = 0; i < 128; i++ ) { - stat = inb( FD_STATUS ) & (STATUS_READY|STATUS_DIR); //读取状态寄存器 - if ( stat == STATUS_READY ) - { - OUTB( value ,FD_DATA); //将参数写入数据寄存器 - return 1; - } - io_delay(); // 作一些延迟 - } - return 0; -} - - -u32 floppy_getbyte(void) -{ - u8 stat, i; - - for ( i = 0; i < 128; i++ ) { - stat = inb( FD_STATUS ) & (STATUS_READY|STATUS_DIR|STATUS_BUSY); //读取状态寄存器 - if (stat == STATUS_READY) - return -1; - if ( stat == 0xD0 ) - return inb(FD_DATA); - io_delay(); - } - return 0; -} - - -u32 floppy_get_info(void) -{ - u32 i; - u8 CmType, FdType; - - floppy_sendbyte(0x10); - i = floppy_getbyte(); - - switch (i) - { - case 0x80: floppy_inc_name = "NEC765A controller"; break; - case 0x90: floppy_inc_name = "NEC765B controller"; break; - default: floppy_inc_name = "Enhanced controller"; break; - } - - CmType = readcmos(0x10); //read floppy type from cmos - FdType = (CmType>>4) & 0x07; - - if ( FdType == 0 ) - panic("Floppy driver not found!"); - - switch( FdType ) - { - case 0x02: // 1.2MB - floppy_type = "1.2MB"; - floppy_size = 2458*512; - break; - - case 0x04: // 1.44MB 标准软盘 - floppy_type = "1.44MB"; - floppy_size = 2880*512; - break; - - case 0x05: // 2.88MB - floppy_type = "2.88MB"; - floppy_size = 2*2880*512; - break; - } - return 1; -} - - -void floppy_motorOn( void ) -{ - u32 eflags; - if (!floppy_motor) - { - _local_irq_save(eflags); - OUTB(28,FD_DOR); - floppy_motor = 1; - _local_irq_restore(eflags); - } - return; -} - - -void floppy_motorOff( void ) -{ - u32 eflags; - if (floppy_motor) - { - _local_irq_save(eflags); - OUTB(12,FD_DOR); - floppy_motor = 0; - _local_irq_restore(eflags); - - } - return; -} - - -void floppy_setmode(void) -{ - floppy_sendbyte (FD_SPECIFY); - floppy_sendbyte (0xcf); - floppy_sendbyte (0x06); - OUTB (0,FD_DCR); -} - - -void block_to_hts(u32 block, u32 *head, u32 *track, u32 *sector ) -{ - *head = ( block % ( 18 * 2 ) ) /18; - *track = block / ( 18 * 2 ); - *sector = block % 18 + 1; -} - - -void floppy_setupDMA(void) -{ - u32 eflags; - _local_irq_save(eflags); - DisableDma(2); - ClearDmaFF(2); - SetDmaMode(2,DMA_MODE_READ); - SetDmaAddr(2,(unsigned long)floppy_buffer); - SetDmaCount(2,512); - EnableDma(2); - _local_irq_restore(eflags); -} - - -void floppy_read_cmd(u32 blk) -{ - u32 head; - u32 track; - u32 sector; - - block_to_hts(blk,&head,&track,§or); - - floppy_motorOn(); - io_delay(); - - floppy_setupDMA(); - io_delay(); - - floppy_setmode(); - io_delay(); - floppy_sendbyte (FD_READ); //send read command - floppy_sendbyte (head*4 + 0); - floppy_sendbyte (track); /* Cylinder */ - floppy_sendbyte (head); /* Head */ - floppy_sendbyte (sector); /* Sector */ - floppy_sendbyte (2); /* 0=128, 1=256, 2=512, 3=1024, ... */ - floppy_sendbyte (18); - //floppy_sendbyte (sector+secs-1); /* Last sector in track:here are sectors count */ - floppy_sendbyte (0x1B); - floppy_sendbyte (0xff); - return; -} - -static struct rt_device devF; -static struct rt_mutex lock; -static struct rt_semaphore sem; - -/* RT-Thread device interface */ - -static rt_err_t rt_floppy_init_internal(rt_device_t dev) -{ - return RT_EOK; -} - -static rt_err_t rt_floppy_open(rt_device_t dev, rt_uint16_t oflag) -{ - return RT_EOK; -} - -static rt_err_t rt_floppy_close(rt_device_t dev) -{ - return RT_EOK; -} - -/* position: block page address, not bytes address - * buffer: - * size : how many blocks - */ -static rt_size_t rt_floppy_read(rt_device_t device, rt_off_t position, void *buffer, rt_size_t size) -{ - rt_size_t doSize = size; - - rt_mutex_take(&lock, RT_WAITING_FOREVER); - while(size>0) - { - floppy_read_cmd(position); - - rt_sem_take(&sem, RT_WAITING_FOREVER); /* waiting isr sem forever */ - - floppy_result(); - io_delay(); - - if(ST1 != 0 || ST2 != 0) - { - panic("ST0 %d ST1 %d ST2 %d\n",ST0,ST1,ST2); - } - - rt_memcpy(buffer, floppy_buffer, 512); - - floppy_motorOff(); - io_delay(); - - position += 1; - size -= 1; - } - rt_mutex_release(&lock); - - return doSize; -} - -/* position: block page address, not bytes address - * buffer: - * size : how many blocks - */ -static rt_size_t rt_floppy_write(rt_device_t device, rt_off_t position, const void *buffer, rt_size_t size) -{ - rt_mutex_take(&lock, RT_WAITING_FOREVER); - panic("FIXME:I don't know how!\n"); - rt_mutex_release(&lock); - return size; -} - -static rt_err_t rt_floppy_control(rt_device_t dev, int cmd, void *args) -{ - RT_ASSERT(dev != RT_NULL); - - if (cmd == RT_DEVICE_CTRL_BLK_GETGEOME) - { - struct rt_device_blk_geometry *geometry; - - geometry = (struct rt_device_blk_geometry *)args; - if (geometry == RT_NULL) return -RT_ERROR; - - geometry->bytes_per_sector = SECTOR_SIZE; - geometry->block_size = SECTOR_SIZE; - - geometry->sector_count = floppy_size / SECTOR_SIZE; - } - - return RT_EOK; -} - -static void rt_floppy_isr(int vector, void* param) -{ - (void)vector; - (void)param; - rt_sem_release(&sem); -} - -void rt_floppy_init(void) -{ - struct rt_device *device; - - rt_mutex_init(&lock,"fdlock", RT_IPC_FLAG_FIFO); - rt_sem_init(&sem, "fdsem", 0, RT_IPC_FLAG_FIFO); - - rt_hw_interrupt_install(FLOPPY_IRQ, rt_floppy_isr, RT_NULL, "floppy"); - rt_hw_interrupt_umask(FLOPPY_IRQ); - - floppy_get_info(); - rt_kprintf("Floppy Inc : %s Floppy Type : %s\n",floppy_inc_name,floppy_type); - - device = &(devF); - - device->type = RT_Device_Class_Block; - device->init = rt_floppy_init_internal; - device->open = rt_floppy_open; - device->close = rt_floppy_close; - device->read = rt_floppy_read; - device->write = rt_floppy_write; - device->control = rt_floppy_control; - device->user_data = NULL; - - rt_device_register(device, "floppy", - RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_REMOVABLE | RT_DEVICE_FLAG_STANDALONE); - -} diff --git a/bsp/x86/drivers/floppy.h b/bsp/x86/drivers/floppy.h deleted file mode 100644 index f619508c43b7b7a0f06a7cec10ea94bd5999bdba..0000000000000000000000000000000000000000 --- a/bsp/x86/drivers/floppy.h +++ /dev/null @@ -1,71 +0,0 @@ -#ifndef _FLOPPY_H -#define _FLOPPY_H - -#define FD_STATUS 0x3f4 // 主状态寄存器端口。 -#define FD_DATA 0x3f5 // 数据端口。 -#define FD_DOR 0x3f2 // 数字输出寄存器(也称为数字控制寄存器)。 -#define FD_DIR 0x3f7 // 数字输入寄存器。 -#define FD_DCR 0x3f7 // 数据传输率控制寄存器。 - -/* 主状态寄存器各比特位的含义 */ - -#define STATUS_BUSYMASK 0x0F // 驱动器忙位(每位对应一个驱动器)。 -#define STATUS_BUSY 0x10 // 软盘控制器忙。 -#define STATUS_DMA 0x20 // 0 - 为DMA 数据传输模式,1 - 为非DMA 模式。 -#define STATUS_DIR 0x40 // 传输方向:0 - CPU .. fdc,1 - 相反。 -#define STATUS_READY 0x80 // 数据寄存器就绪位。 - - -/*状态字节0(ST0)各比特位的含义 */ - -#define ST0_DS 0x03 // 驱动器选择号(发生中断时驱动器号)。 -#define ST0_HA 0x04 // 磁头号。 -#define ST0_NR 0x08 // 磁盘驱动器未准备好。 -#define ST0_ECE 0x10 // 设备检测出错(零磁道校准出错)。 -#define ST0_SE 0x20 // 寻道或重新校正操作执行结束。 -#define ST0_INTR 0xC0 // 中断代码位(中断原因),00 - 命令正常结束; - // 01 - 命令异常结束;10 - 命令无效;11 - FDD 就绪状态改变。 - -/*状态字节1(ST1)各比特位的含义 */ - -#define ST1_MAM 0x01 // 未找到地址标志(ID AM)。 -#define ST1_WP 0x02 // 写保护。 -#define ST1_ND 0x04 // 未找到指定的扇区。 -#define ST1_OR 0x10 // 数据传输超时(DMA 控制器故障)。 -#define ST1_CRC 0x20 // CRC 检验出错。 -#define ST1_EOC 0x80 // 访问超过一个磁道上的最大扇区号。 - -/*状态字节2(ST2)各比特位的含义 */ - -#define ST2_MAM 0x01 // 未找到数据地址标志。 -#define ST2_BC 0x02 // 磁道坏。 -#define ST2_SNS 0x04 // 检索(扫描)条件不满足。 -#define ST2_SEH 0x08 // 检索条件满足。 -#define ST2_WC 0x10 // 磁道(柱面)号不符。 -#define ST2_CRC 0x20 // 数据场CRC 校验错。 -#define ST2_CM 0x40 // 读数据遇到删除标志。 - -/*状态字节3(ST3)各比特位的含义 */ - -#define ST3_HA 0x04 // 磁头号。 -#define ST3_TZ 0x10 // 零磁道信号。 -#define ST3_WP 0x40 // 写保护。 - - -/* 软盘命令码 */ - -#define FD_RECALIBRATE 0x07 // 重新校正(磁头退到零磁道)。 -#define FD_SEEK 0x0F // 磁头寻道。 -#define FD_READ 0xE6 // 读数据(MT 多磁道操作,MFM 格式,跳过删除数据)。 -#define FD_WRITE 0xC5 // 写数据(MT,MFM)。 -#define FD_SENSEI 0x08 // 检测中断状态。 -#define FD_SPECIFY 0x03 // 设定驱动器参数(步进速率、磁头卸载时间等)。 - - -/* DMA 命令 */ -#define DMA_READ 0x46 // DMA 读盘,DMA 方式字(送DMA 端口12,11)。 -#define DMA_WRITE 0x4A - -extern void rt_floppy_init(void); - -#endif diff --git a/bsp/x86/drivers/include/bsp.h b/bsp/x86/drivers/include/bsp.h deleted file mode 100644 index 724f518c6e67eaa43f3a451fcc2f94fa45c782f3..0000000000000000000000000000000000000000 --- a/bsp/x86/drivers/include/bsp.h +++ /dev/null @@ -1,148 +0,0 @@ -/* - * File : bsp.h - * This file is part of RT-Thread RTOS - * COPYRIGHT (C) 2006, RT-Thread Develop Team - * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://openlab.rt-thread.com/license/LICENSE - * - * Change Logs: - * Date Author Notes - * 2006-09-15 QiuYi the first version */ - -#ifndef __BSP_H_ -#define __BSP_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/*******************************************************************/ -/* Timer Register */ -/*******************************************************************/ -#define TIMER_CNTR0 (IO_TIMER1 + 0) /* timer 0 counter port */ -#define TIMER_CNTR1 (IO_TIMER1 + 1) /* timer 1 counter port */ -#define TIMER_CNTR2 (IO_TIMER1 + 2) /* timer 2 counter port */ -#define TIMER_MODE (IO_TIMER1 + 3) /* timer mode port */ -#define TIMER_SEL0 0x00 /* select counter 0 */ -#define TIMER_SEL1 0x40 /* select counter 1 */ -#define TIMER_INTTC 0x00 /* mode 0, intr on terminal cnt */ -#define TIMER_ONESHOT 0x02 /* mode 1, one shot */ -#define TIMER_RATEGEN 0x04 /* mode 2, rate generator */ -#define TIMER_SQWAVE 0x06 /* mode 3, square wave */ -#define TIMER_SWSTROBE 0x08 /* mode 4, s/w triggered strobe */ -#define TIMER_HWSTROBE 0x0a /* mode 5, h/w triggered strobe */ -#define TIMER_LATCH 0x00 /* latch counter for reading */ -#define TIMER_LSB 0x10 /* r/w counter LSB */ -#define TIMER_MSB 0x20 /* r/w counter MSB */ -#define TIMER_16BIT 0x30 /* r/w counter 16 bits, LSB first */ -#define TIMER_BCD 0x01 /* count in BCD */ - -#define TIMER_FREQ 1193182 -#define TIMER_DIV(x) ((TIMER_FREQ+(x)/2)/(x)) - -#define IO_TIMER1 0x040 /* 8253 Timer #1 */ - -/*******************************************************************/ -/* Interrupt Controller */ -/*******************************************************************/ -/* these are processor defined */ -#define T_DIVIDE 0 /* divide error */ -#define T_DEBUG 1 /* debug exception */ -#define T_NMI 2 /* non-maskable interrupt */ -#define T_BRKPT 3 /* breakpoint */ -#define T_OFLOW 4 /* overflow */ -#define T_BOUND 5 /* bounds check */ -#define T_ILLOP 6 /* illegal opcode */ -#define T_DEVICE 7 /* device not available */ -#define T_DBLFLT 8 /* double fault */ -/* 9 is reserved */ -#define T_TSS 10 /* invalid task switch segment */ -#define T_SEGNP 11 /* segment not present */ -#define T_STACK 12 /* stack exception */ -#define T_GPFLT 13 /* genernal protection fault */ -#define T_PGFLT 14 /* page fault */ -/* 15 is reserved */ -#define T_FPERR 16 /* floating point error */ -#define T_ALIGN 17 /* aligment check */ -#define T_MCHK 18 /* machine check */ -#define T_DEFAULT 500 /* catchall */ - -#define INTTIMER0 0 -#define INTKEYBOARD 1 -#define INTUART0_RX 4 -#define CLOCK_IRQ 0 -#define KEYBOARD_IRQ 1 -#define CASCADE_IRQ 2 /* cascade enable for 2nd AT controller */ -#define ETHER_IRQ 3 /* default ethernet interrupt vector */ -#define SECONDARY_IRQ 3 /* RS232 interrupt vector for port 2 */ -#define RS232_IRQ 4 /* RS232 interrupt vector for port 1 */ -#define XT_WINI_IRQ 5 /* xt winchester */ -#define FLOPPY_IRQ 6 /* floppy disk */ -#define PRINTER_IRQ 7 -#define AT_WINI_IRQ 14 /* at winchester */ -/* I/O Addresses of the two 8259A programmable interrupt controllers */ -#define IO_PIC1 0x20 /* Master(IRQs 0-7) */ -#define IO_PIC2 0xa0 /* Slave(IRQs 8-15) */ -#define IRQ_SLAVE 0x2 /* IRQ at which slave connects to master */ -#define IRQ_OFFSET 0x20 /* IRQ 0 corresponds to int IRQ_OFFSET */ - -#define MAX_HANDLERS 16 /*max number of isr handler*/ - -/*******************************************************************/ -/* CRT Register */ -/*******************************************************************/ -#define MONO_BASE 0x3b4 -#define MONO_BUF 0xb0000 -#define CGA_BASE 0x3d4 -#define CGA_BUF 0xb8000 - -#define CRT_ROWS 25 -#define CRT_COLS 80 -#define CRT_SIZE (CRT_ROWS * CRT_COLS) - -/*******************************************************************/ -/* Keyboard Register */ -/*******************************************************************/ -#define KBSTATP 0x64 /* kbd controller status port(I) */ -#define KBS_DIB 0x01 /* kbd data in buffer */ -#define KBDATAP 0x60 /* kbd data port(I) */ -/* AT keyboard */ -/* 8042 ports */ -#define KB_DATA 0x60 /* I/O port for keyboard data - Read : Read Output Buffer - Write: Write Input Buffer(8042 Data&8048 Command) */ -#define KB_CMD 0x64 /* I/O port for keyboard command - Read : Read Status Register - Write: Write Input Buffer(8042 Command) */ -#define LED_CODE 0xED -#define KB_ACK 0xFA - -/*******************************************************************/ -/* Serial Register */ -/*******************************************************************/ -/*Serial I/O code */ -#define COM1 0x3F8 -#define COMSTATUS 5 -#define COMDATA 0x01 -#define COMREAD 0 -#define COMWRITE 0 - -/* Bits definition of the Line Status Register (LSR)*/ -#define DR 0x01 /* Data Ready */ -#define OE 0x02 /* Overrun Error */ -#define PE 0x04 /* Parity Error */ -#define FE 0x08 /* Framing Error */ -#define BI 0x10 /* Break Interrupt */ -#define THRE 0x20 /* Transmitter Holding Register Empty */ -#define TEMT 0x40 /* Transmitter Empty */ -#define ERFIFO 0x80 /* Error receive Fifo */ - -#ifdef __cplusplus -} -#endif - -#endif /* __BSP_H_ */ diff --git a/bsp/x86/drivers/include/grub.h b/bsp/x86/drivers/include/grub.h deleted file mode 100644 index dcfa36b81987177cb097b6612d092c60760a4ddb..0000000000000000000000000000000000000000 --- a/bsp/x86/drivers/include/grub.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * File : grub.h - * This file is part of RT-Thread RTOS - * COPYRIGHT (C) 2006, RT-Thread Develop Team - * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://openlab.rt-thread.com/license/LICENSE - * - * Change Logs: - * Date Author Notes - * 2006-10-09 Bernard the grub related definitions - * (multiboot) - */ - -#ifndef __GRUB_H__ -#define __GRUB_H__ - -/* the magic number for the multiboot header. */ -#define MULTIBOOT_HEADER_MAGIC 0x1BADB002 - -/* the flags for the multiboot header. */ -#define MULTIBOOT_HEADER_FLAGS 0x00000003 - -/* the magic number passed by a multiboot-compliant boot loader. */ -#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002 - -#ifndef __ASM__ -/* the multiboot header. */ -typedef struct multiboot_header -{ - unsigned long magic; - unsigned long flags; - unsigned long checksum; - unsigned long header_addr; - unsigned long load_addr; - unsigned long load_end_addr; - unsigned long bss_end_addr; - unsigned long entry_addr; -} multiboot_header_t; - -/* the section header table for elf. */ -typedef struct elf_section_header_table -{ - unsigned long num; - unsigned long size; - unsigned long addr; - unsigned long shndx; -} elf_section_header_table_t; - -/* the multiboot information. */ -typedef struct multiboot_info -{ - unsigned long flags; - unsigned long mem_lower; - unsigned long mem_upper; - unsigned long boot_device; - unsigned long cmdline; - unsigned long mods_count; - unsigned long mods_addr; - union - { - aout_symbol_table_t aout_sym; - elf_section_header_table_t elf_sec; - } u; - unsigned long mmap_length; - unsigned long mmap_addr; -} multiboot_info_t; - -/* the module structure. */ -typedef struct module -{ - unsigned long mod_start; - unsigned long mod_end; - unsigned long string; - unsigned long reserved; -} module_t; - -/* the memory map. be careful that the offset 0 is base_addr_low - but no size. */ -typedef struct memory_map -{ - unsigned long size; - unsigned long base_addr_low; - unsigned long base_addr_high; - unsigned long length_low; - unsigned long length_high; - unsigned long type; -} memory_map_t; - -#endif - -#endif diff --git a/bsp/x86/drivers/include/i386.h b/bsp/x86/drivers/include/i386.h deleted file mode 100644 index 68c854932be5f725ecbd5c478458a8cc6b7b9d42..0000000000000000000000000000000000000000 --- a/bsp/x86/drivers/include/i386.h +++ /dev/null @@ -1,147 +0,0 @@ -#ifndef __I386_H_ -#define __I386_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -static __inline unsigned char inb(int port) -{ - unsigned char data; - __asm __volatile("inb %w1,%0" : "=a" (data) : "d" (port)); - return data; -} -static __inline unsigned char inb_p(unsigned short port) -{ - unsigned char _v; - __asm__ __volatile__ ("inb %1, %0\n\t" - // "outb %0,$0x80\n\t" - // "outb %0,$0x80\n\t" - // "outb %0,$0x80\n\t" - "outb %0,$0x80" - :"=a" (_v) - :"d" ((unsigned short) port)); - return _v; -} - -static __inline unsigned short inw(int port) -{ - unsigned short data; - __asm __volatile("inw %w1,%0" : "=a" (data) : "d" (port)); - return data; -} - -static __inline unsigned int inl(int port) -{ - unsigned int data; - __asm __volatile("inl %w1,%0" : "=a" (data) : "d" (port)); - return data; -} - -static __inline void insl(int port, void *addr, int cnt) -{ - __asm __volatile("cld\n\trepne\n\tinsl" : - "=D" (addr), "=c" (cnt) : - "d" (port), "0" (addr), "1" (cnt) : - "memory", "cc"); -} - -static __inline void outb(int port, unsigned char data) -{ - __asm __volatile("outb %0,%w1" : : "a" (data), "d" (port)); -} - - -static __inline void outb_p(char value, unsigned short port) -{ - __asm__ __volatile__ ("outb %0,%1\n\t" - "outb %0,$0x80" - ::"a" ((char) value),"d" ((unsigned short) port)); -} - -static __inline void outw(int port, unsigned short data) -{ - __asm __volatile("outw %0,%w1" : : "a" (data), "d" (port)); -} - -static __inline unsigned char readcmos(int reg) -{ - outb(0x70,reg); - return (unsigned char) inb(0x71); -} - -#define io_delay() \ - __asm__ __volatile__ ("pushal \n\t"\ - "mov $0x3F6, %dx \n\t" \ - "inb %dx, %al \n\t" \ - "inb %dx, %al \n\t" \ - "inb %dx, %al \n\t" \ - "inb %dx, %al \n\t" \ - "popal") - -/* Gate descriptors are slightly different*/ -struct Gatedesc { - unsigned gd_off_15_0 : 16; // low 16 bits of offset in segment - unsigned gd_ss : 16; // segment selector - unsigned gd_args : 5; // # args, 0 for interrupt/trap gates - unsigned gd_rsv1 : 3; // reserved(should be zero I guess) - unsigned gd_type :4; // type(STS_{TG,IG32,TG32}) - unsigned gd_s : 1; // must be 0 (system) - unsigned gd_dpl : 2; // descriptor(meaning new) privilege level - unsigned gd_p : 1; // Present - unsigned gd_off_31_16 : 16; // high bits of offset in segment -}; - -/* Pseudo-descriptors used for LGDT, LLDT and LIDT instructions*/ -struct Pseudodesc { - rt_uint16_t pd__garbage; // LGDT supposed to be from address 4N+2 - rt_uint16_t pd_lim; // Limit - rt_uint32_t pd_base __attribute__ ((packed)); // Base address -}; - -#define SETGATE(gate, istrap, sel, off, dpl) \ -{ \ - (gate).gd_off_15_0 = (rt_uint32_t) (off) & 0xffff; \ - (gate).gd_ss = (sel); \ - (gate).gd_args = 0; \ - (gate).gd_rsv1 = 0; \ - (gate).gd_type = (istrap) ? STS_TG32 : STS_IG32; \ - (gate).gd_s = 0; \ - (gate).gd_dpl = dpl; \ - (gate).gd_p = 1; \ - (gate).gd_off_31_16 = (rt_uint32_t) (off) >> 16; \ -} - -/* Global descriptor numbers*/ -#define GD_KT 0x08 // kernel text -#define GD_KD 0x10 // kernel data -#define GD_UT 0x18 // user text -#define GD_UD 0x20 // user data - -/* Application segment type bits*/ -#define STA_X 0x8 // Executable segment -#define STA_E 0x4 // Expand down(non-executable segments) -#define STA_C 0x4 // Conforming code segment(executable only) -#define STA_W 0x2 // Writeable(non-executable segments) -#define STA_R 0x2 // Readable(executable segments) -#define STA_A 0x1 // Accessed - -/* System segment type bits*/ -#define STS_T16A 0x1 // Available 16-bit TSS -#define STS_LDT 0x2 // Local Descriptor Table -#define STS_T16B 0x3 // Busy 16-bit TSS -#define STS_CG16 0x4 // 16-bit Call Gate -#define STS_TG 0x5 // Task Gate / Coum Transmitions -#define STS_IG16 0x6 // 16-bit Interrupt Gate -#define STS_TG16 0x7 // 16-bit Trap Gate -#define STS_T32A 0x9 // Available 32-bit TSS -#define STS_T32B 0xb // Busy 32-bit TSS -#define STS_CG32 0xc // 32-bit Call Gate -#define STS_IG32 0xe // 32-bit Interrupt Gate -#define STS_TG32 0xf // 32-bit Trap Gate - -#ifdef __cplusplus - } -#endif - -#endif diff --git a/bsp/x86/drivers/keyboard.c b/bsp/x86/drivers/keyboard.c deleted file mode 100644 index 3716c367cced425b436f2453b5a4f76e9f9e081c..0000000000000000000000000000000000000000 --- a/bsp/x86/drivers/keyboard.c +++ /dev/null @@ -1,366 +0,0 @@ -/* - * File : keyboard.c - * This file is part of RT-Thread RTOS - * COPYRIGHT (C) 2006, RT-Thread Development Team - * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://openlab.rt-thread.com/license/LICENSE - * - * Change Logs: - * Date Author Notes - * 2006-09-15 QiuYi the first version - * 2017-08-16 Parai the 2nd version - */ - -#include -#include - -#include -#include "keyboard.h" -#include "keymap.h" - -#define FALSE RT_FALSE -#define TRUE RT_TRUE -#define PRIVATE static -#define PUBLIC -#define t_bool rt_bool_t -#define t_8 rt_uint8_t -#define t_32 rt_uint32_t - -PRIVATE KB_INPUT kb_in; -PRIVATE t_bool code_with_E0 = FALSE; -PRIVATE t_bool shift_l; /* l shift state */ -PRIVATE t_bool shift_r; /* r shift state */ -PRIVATE t_bool alt_l; /* l alt state */ -PRIVATE t_bool alt_r; /* r left state */ -PRIVATE t_bool ctrl_l; /* l ctrl state */ -PRIVATE t_bool ctrl_r; /* l ctrl state */ -PRIVATE t_bool caps_lock; /* Caps Lock */ -PRIVATE t_bool num_lock; /* Num Lock */ -PRIVATE t_bool scroll_lock; /* Scroll Lock */ -PRIVATE int column = 0; /* keyrow[column] is one value of keymap */ - -PRIVATE t_8 get_byte_from_kb_buf(); -PRIVATE void set_leds(); -PRIVATE void kb_wait(); -PRIVATE void kb_ack(); - -PUBLIC void init_keyboard() -{ - kb_in.count = 0; - kb_in.p_head = kb_in.p_tail = kb_in.buf; - - caps_lock = 0; - num_lock = 1; - scroll_lock = 0; - - set_leds(); -} -PUBLIC rt_bool_t keyboard_read(rt_uint32_t *pkey) -{ - t_8 scan_code; - t_bool make; /* TRUE : make */ - /* FALSE: break */ - t_32 key = 0; - t_32* keyrow; - - if(kb_in.count > 0){ - code_with_E0 = FALSE; - scan_code = get_byte_from_kb_buf(); - - /* start scan */ - if (scan_code == 0xE1) { - int i; - static const t_8 pausebreak_scan_code[] = {0xE1, 0x1D, 0x45, 0xE1, 0x9D, 0xC5}; - t_bool is_pausebreak = TRUE; - for(i=1;i<6;i++){ - if (get_byte_from_kb_buf() != pausebreak_scan_code[i]) { - is_pausebreak = FALSE; - break; - } - } - if (is_pausebreak) { - key = PAUSEBREAK; - } - } - else if (scan_code == 0xE0) { - code_with_E0 = TRUE; - scan_code = get_byte_from_kb_buf(); - - /* PrintScreen pressed */ - if (scan_code == 0x2A) { - code_with_E0 = FALSE; - if ((scan_code = get_byte_from_kb_buf()) == 0xE0) { - code_with_E0 = TRUE; - if ((scan_code = get_byte_from_kb_buf()) == 0x37) { - key = PRINTSCREEN; - make = TRUE; - } - } - } - /* PrintScreen released */ - else if (scan_code == 0xB7) { - code_with_E0 = FALSE; - if ((scan_code = get_byte_from_kb_buf()) == 0xE0) { - code_with_E0 = TRUE; - if ((scan_code = get_byte_from_kb_buf()) == 0xAA) { - key = PRINTSCREEN; - make = FALSE; - } - } - } - } /* if is not PrintScreen, scan_code is the one after 0xE0 */ - if ((key != PAUSEBREAK) && (key != PRINTSCREEN)) { - /* is Make Code or Break Code */ - make = (scan_code & FLAG_BREAK ? FALSE : TRUE); - - keyrow = &keymap[(scan_code & 0x7F) * MAP_COLS]; - - column = 0; - - t_bool caps = shift_l || shift_r; - if (caps_lock) { - if ((keyrow[0] >= 'a') && (keyrow[0] <= 'z')){ - caps = !caps; - } - } - if (caps) { - column = 1; - } - - if (code_with_E0) { - column = 2; - } - - key = keyrow[column]; - - switch(key) { - case SHIFT_L: - shift_l = make; - break; - case SHIFT_R: - shift_r = make; - break; - case CTRL_L: - ctrl_l = make; - break; - case CTRL_R: - ctrl_r = make; - break; - case ALT_L: - alt_l = make; - break; - case ALT_R: - alt_l = make; - break; - case CAPS_LOCK: - if (make) { - caps_lock = !caps_lock; - set_leds(); - } - break; - case NUM_LOCK: - if (make) { - num_lock = !num_lock; - set_leds(); - } - break; - case SCROLL_LOCK: - if (make) { - scroll_lock = !scroll_lock; - set_leds(); - } - break; - default: - break; - } - } - - if(make){ /* ignore Break Code */ - t_bool pad = FALSE; - - /* handle the small pad first */ - if ((key >= PAD_SLASH) && (key <= PAD_9)) { - pad = TRUE; - switch(key) { /* '/', '*', '-', '+', and 'Enter' in num pad */ - case PAD_SLASH: - key = '/'; - break; - case PAD_STAR: - key = '*'; - break; - case PAD_MINUS: - key = '-'; - break; - case PAD_PLUS: - key = '+'; - break; - case PAD_ENTER: - key = ENTER; - break; - default: /* keys whose value depends on the NumLock */ - if (num_lock) { /* '0' ~ '9' and '.' in num pad */ - if ((key >= PAD_0) && (key <= PAD_9)) { - key = key - PAD_0 + '0'; - } - else if (key == PAD_DOT) { - key = '.'; - } - } - else{ - switch(key) { - case PAD_HOME: - key = HOME; - break; - case PAD_END: - key = END; - break; - case PAD_PAGEUP: - key = PAGEUP; - break; - case PAD_PAGEDOWN: - key = PAGEDOWN; - break; - case PAD_INS: - key = INSERT; - break; - case PAD_UP: - key = UP; - break; - case PAD_DOWN: - key = DOWN; - break; - case PAD_LEFT: - key = LEFT; - break; - case PAD_RIGHT: - key = RIGHT; - break; - case PAD_DOT: - key = DELETE; - break; - default: - break; - } - } - break; - } - } - key |= shift_l ? FLAG_SHIFT_L : 0; - key |= shift_r ? FLAG_SHIFT_R : 0; - key |= ctrl_l ? FLAG_CTRL_L : 0; - key |= ctrl_r ? FLAG_CTRL_R : 0; - key |= alt_l ? FLAG_ALT_L : 0; - key |= alt_r ? FLAG_ALT_R : 0; - key |= pad ? FLAG_PAD : 0; - - *pkey = key; - return TRUE; - } - } - - return FALSE; -} - -PRIVATE t_8 get_byte_from_kb_buf() -{ - t_8 scan_code; - - RT_ASSERT(kb_in.count>0); - scan_code = *(kb_in.p_tail); - kb_in.p_tail++; - if (kb_in.p_tail == kb_in.buf + KB_IN_BYTES) { - kb_in.p_tail = kb_in.buf; - } - kb_in.count--; - - return scan_code; -} - -PRIVATE void kb_wait() /* wait inpit cache of 8042 */ -{ - t_8 kb_stat; - - do { - kb_stat = inb(KB_CMD); - } while (kb_stat & 0x02); -} - -PRIVATE void kb_ack() -{ - t_8 kb_read; - - do { - kb_read = inb(KB_DATA); - } while (kb_read != KB_ACK); -} - -PRIVATE void set_leds() -{ - t_8 leds = (caps_lock << 2) | (num_lock << 1) | scroll_lock; - - kb_wait(); - outb(KB_DATA, LED_CODE); - kb_ack(); - - kb_wait(); - outb(KB_DATA, leds); - kb_ack(); -} - -/** - * @addtogroup QEMU - */ -/*@{*/ - -void rt_keyboard_isr(void) -{ - rt_uint8_t data; - - if ((inb(KBSTATP) & KBS_DIB) == 0) - return ; - - data = inb(KBDATAP); - - if (kb_in.count < KB_IN_BYTES) { - *(kb_in.p_head) = data; - kb_in.p_head++; - if (kb_in.p_head == kb_in.buf + KB_IN_BYTES) { - kb_in.p_head = kb_in.buf; - } - kb_in.count++; - } -} -/* generally, this should be called in task level for all key inpit support, -but here only support a key that is composed of 2 bytes */ -rt_bool_t rt_keyboard_getc(char* c) -{ - if(kb_in.count>=2) - { - rt_uint32_t key = 0; - rt_bool_t rv=keyboard_read(&key); - - switch(key) - { - case TAB: - *c = '\t'; - break; - case ENTER: - *c = '\n'; - break; - case BACKSPACE: - *c = '\b'; - break; - default: - *c = key; - break; - } - - return rv; - } - - return RT_FALSE; -} - -/*@}*/ diff --git a/bsp/x86/drivers/keyboard.h b/bsp/x86/drivers/keyboard.h deleted file mode 100644 index f3e849df96702fb389e0715faf6128017a2cb31e..0000000000000000000000000000000000000000 --- a/bsp/x86/drivers/keyboard.h +++ /dev/null @@ -1,132 +0,0 @@ - -/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - keyboard.h -++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - Forrest Yu, 2005 -++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ - -#ifndef _TINIX_KEYBOARD_H_ -#define _TINIX_KEYBOARD_H_ - - -/************************************************************************/ -/* Macros Declaration */ -/************************************************************************/ -#define KB_IN_BYTES 32 /* size of keyboard input buffer */ -#define MAP_COLS 3 /* Number of columns in keymap */ -#define NR_SCAN_CODES 0x80 /* Number of scan codes (rows in keymap) */ - -#define FLAG_BREAK 0x0080 /* Break Code */ -#define FLAG_EXT 0x0100 /* Normal function keys */ -#define FLAG_SHIFT_L 0x0200 /* Shift key */ -#define FLAG_SHIFT_R 0x0400 /* Shift key */ -#define FLAG_CTRL_L 0x0800 /* Control key */ -#define FLAG_CTRL_R 0x1000 /* Control key */ -#define FLAG_ALT_L 0x2000 /* Alternate key */ -#define FLAG_ALT_R 0x4000 /* Alternate key */ -#define FLAG_PAD 0x8000 /* keys in num pad */ - -#define MASK_RAW 0x01FF /* raw key value = code passed to tty & MASK_RAW - the value can be found either in the keymap column 0 - or in the list below */ - -/* Special keys */ -#define ESC (0x01 + FLAG_EXT) /* Esc */ -#define TAB (0x02 + FLAG_EXT) /* Tab */ -#define ENTER (0x03 + FLAG_EXT) /* Enter */ -#define BACKSPACE (0x04 + FLAG_EXT) /* BackSpace */ - -#define GUI_L (0x05 + FLAG_EXT) /* L GUI */ -#define GUI_R (0x06 + FLAG_EXT) /* R GUI */ -#define APPS (0x07 + FLAG_EXT) /* APPS */ - -/* Shift, Ctrl, Alt */ -#define SHIFT_L (0x08 + FLAG_EXT) /* L Shift */ -#define SHIFT_R (0x09 + FLAG_EXT) /* R Shift */ -#define CTRL_L (0x0A + FLAG_EXT) /* L Ctrl */ -#define CTRL_R (0x0B + FLAG_EXT) /* R Ctrl */ -#define ALT_L (0x0C + FLAG_EXT) /* L Alt */ -#define ALT_R (0x0D + FLAG_EXT) /* R Alt */ - -/* Lock keys */ -#define CAPS_LOCK (0x0E + FLAG_EXT) /* Caps Lock */ -#define NUM_LOCK (0x0F + FLAG_EXT) /* Number Lock */ -#define SCROLL_LOCK (0x10 + FLAG_EXT) /* Scroll Lock */ - -/* Function keys */ -#define F1 (0x11 + FLAG_EXT) /* F1 */ -#define F2 (0x12 + FLAG_EXT) /* F2 */ -#define F3 (0x13 + FLAG_EXT) /* F3 */ -#define F4 (0x14 + FLAG_EXT) /* F4 */ -#define F5 (0x15 + FLAG_EXT) /* F5 */ -#define F6 (0x16 + FLAG_EXT) /* F6 */ -#define F7 (0x17 + FLAG_EXT) /* F7 */ -#define F8 (0x18 + FLAG_EXT) /* F8 */ -#define F9 (0x19 + FLAG_EXT) /* F9 */ -#define F10 (0x1A + FLAG_EXT) /* F10 */ -#define F11 (0x1B + FLAG_EXT) /* F11 */ -#define F12 (0x1C + FLAG_EXT) /* F12 */ - -/* Control Pad */ -#define PRINTSCREEN (0x1D + FLAG_EXT) /* Print Screen */ -#define PAUSEBREAK (0x1E + FLAG_EXT) /* Pause/Break */ -#define INSERT (0x1F + FLAG_EXT) /* Insert */ -#define DELETE (0x20 + FLAG_EXT) /* Delete */ -#define HOME (0x21 + FLAG_EXT) /* Home */ -#define END (0x22 + FLAG_EXT) /* End */ -#define PAGEUP (0x23 + FLAG_EXT) /* Page Up */ -#define PAGEDOWN (0x24 + FLAG_EXT) /* Page Down */ -#define UP (0x25 + FLAG_EXT) /* Up */ -#define DOWN (0x26 + FLAG_EXT) /* Down */ -#define LEFT (0x27 + FLAG_EXT) /* Left */ -#define RIGHT (0x28 + FLAG_EXT) /* Right */ - -/* ACPI keys */ -#define POWER (0x29 + FLAG_EXT) /* Power */ -#define SLEEP (0x2A + FLAG_EXT) /* Sleep */ -#define WAKE (0x2B + FLAG_EXT) /* Wake Up */ - -/* Num Pad */ -#define PAD_SLASH (0x2C + FLAG_EXT) /* / */ -#define PAD_STAR (0x2D + FLAG_EXT) /* * */ -#define PAD_MINUS (0x2E + FLAG_EXT) /* - */ -#define PAD_PLUS (0x2F + FLAG_EXT) /* + */ -#define PAD_ENTER (0x30 + FLAG_EXT) /* Enter */ -#define PAD_DOT (0x31 + FLAG_EXT) /* . */ -#define PAD_0 (0x32 + FLAG_EXT) /* 0 */ -#define PAD_1 (0x33 + FLAG_EXT) /* 1 */ -#define PAD_2 (0x34 + FLAG_EXT) /* 2 */ -#define PAD_3 (0x35 + FLAG_EXT) /* 3 */ -#define PAD_4 (0x36 + FLAG_EXT) /* 4 */ -#define PAD_5 (0x37 + FLAG_EXT) /* 5 */ -#define PAD_6 (0x38 + FLAG_EXT) /* 6 */ -#define PAD_7 (0x39 + FLAG_EXT) /* 7 */ -#define PAD_8 (0x3A + FLAG_EXT) /* 8 */ -#define PAD_9 (0x3B + FLAG_EXT) /* 9 */ -#define PAD_UP PAD_8 /* Up */ -#define PAD_DOWN PAD_2 /* Down */ -#define PAD_LEFT PAD_4 /* Left */ -#define PAD_RIGHT PAD_6 /* Right */ -#define PAD_HOME PAD_7 /* Home */ -#define PAD_END PAD_1 /* End */ -#define PAD_PAGEUP PAD_9 /* Page Up */ -#define PAD_PAGEDOWN PAD_3 /* Page Down */ -#define PAD_INS PAD_0 /* Ins */ -#define PAD_MID PAD_5 /* Middle key */ -#define PAD_DEL PAD_DOT /* Del */ - - -/************************************************************************/ -/* Stucture Definition */ -/************************************************************************/ -/* Keyboard structure, 1 per console. */ -typedef struct s_kb { - char* p_head; /* input cache pointer */ - char* p_tail; /* read cache pointer */ - int count; - char buf[KB_IN_BYTES]; -}KB_INPUT; - - - -#endif /* _TINIX_KEYBOARD_H_ */ diff --git a/bsp/x86/drivers/keymap.h b/bsp/x86/drivers/keymap.h deleted file mode 100644 index 3031438a1bea56c13c63e4d7a5457587be321295..0000000000000000000000000000000000000000 --- a/bsp/x86/drivers/keymap.h +++ /dev/null @@ -1,239 +0,0 @@ - -/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - keymap.h -++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - Forrest Yu, 2005 -++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ - -/********************************************************************/ -/* "scan code" <--> "key" map. */ -/* It should be and can only be included by keyboard.c! */ -/********************************************************************/ - -#ifndef _TINIX_KEYMAP_H_ -#define _TINIX_KEYMAP_H_ - - -/* Keymap for US MF-2 keyboard. */ - -rt_uint32_t keymap[NR_SCAN_CODES * MAP_COLS] = { - -/* scan-code !Shift Shift E0 XX */ -/* ==================================================================== */ -/* 0x00 - none */ 0, 0, 0, -/* 0x01 - ESC */ ESC, ESC, 0, -/* 0x02 - '1' */ '1', '!', 0, -/* 0x03 - '2' */ '2', '@', 0, -/* 0x04 - '3' */ '3', '#', 0, -/* 0x05 - '4' */ '4', '$', 0, -/* 0x06 - '5' */ '5', '%', 0, -/* 0x07 - '6' */ '6', '^', 0, -/* 0x08 - '7' */ '7', '&', 0, -/* 0x09 - '8' */ '8', '*', 0, -/* 0x0A - '9' */ '9', '(', 0, -/* 0x0B - '0' */ '0', ')', 0, -/* 0x0C - '-' */ '-', '_', 0, -/* 0x0D - '=' */ '=', '+', 0, -/* 0x0E - BS */ BACKSPACE, BACKSPACE, 0, -/* 0x0F - TAB */ TAB, TAB, 0, -/* 0x10 - 'q' */ 'q', 'Q', 0, -/* 0x11 - 'w' */ 'w', 'W', 0, -/* 0x12 - 'e' */ 'e', 'E', 0, -/* 0x13 - 'r' */ 'r', 'R', 0, -/* 0x14 - 't' */ 't', 'T', 0, -/* 0x15 - 'y' */ 'y', 'Y', 0, -/* 0x16 - 'u' */ 'u', 'U', 0, -/* 0x17 - 'i' */ 'i', 'I', 0, -/* 0x18 - 'o' */ 'o', 'O', 0, -/* 0x19 - 'p' */ 'p', 'P', 0, -/* 0x1A - '[' */ '[', '{', 0, -/* 0x1B - ']' */ ']', '}', 0, -/* 0x1C - CR/LF */ ENTER, ENTER, PAD_ENTER, -/* 0x1D - l. Ctrl */ CTRL_L, CTRL_L, CTRL_R, -/* 0x1E - 'a' */ 'a', 'A', 0, -/* 0x1F - 's' */ 's', 'S', 0, -/* 0x20 - 'd' */ 'd', 'D', 0, -/* 0x21 - 'f' */ 'f', 'F', 0, -/* 0x22 - 'g' */ 'g', 'G', 0, -/* 0x23 - 'h' */ 'h', 'H', 0, -/* 0x24 - 'j' */ 'j', 'J', 0, -/* 0x25 - 'k' */ 'k', 'K', 0, -/* 0x26 - 'l' */ 'l', 'L', 0, -/* 0x27 - ';' */ ';', ':', 0, -/* 0x28 - '\'' */ '\'', '"', 0, -/* 0x29 - '`' */ '`', '~', 0, -/* 0x2A - l. SHIFT */ SHIFT_L, SHIFT_L, 0, -/* 0x2B - '\' */ '\\', '|', 0, -/* 0x2C - 'z' */ 'z', 'Z', 0, -/* 0x2D - 'x' */ 'x', 'X', 0, -/* 0x2E - 'c' */ 'c', 'C', 0, -/* 0x2F - 'v' */ 'v', 'V', 0, -/* 0x30 - 'b' */ 'b', 'B', 0, -/* 0x31 - 'n' */ 'n', 'N', 0, -/* 0x32 - 'm' */ 'm', 'M', 0, -/* 0x33 - ',' */ ',', '<', 0, -/* 0x34 - '.' */ '.', '>', 0, -/* 0x35 - '/' */ '/', '?', PAD_SLASH, -/* 0x36 - r. SHIFT */ SHIFT_R, SHIFT_R, 0, -/* 0x37 - '*' */ '*', '*', 0, -/* 0x38 - ALT */ ALT_L, ALT_L, ALT_R, -/* 0x39 - ' ' */ ' ', ' ', 0, -/* 0x3A - CapsLock */ CAPS_LOCK, CAPS_LOCK, 0, -/* 0x3B - F1 */ F1, F1, 0, -/* 0x3C - F2 */ F2, F2, 0, -/* 0x3D - F3 */ F3, F3, 0, -/* 0x3E - F4 */ F4, F4, 0, -/* 0x3F - F5 */ F5, F5, 0, -/* 0x40 - F6 */ F6, F6, 0, -/* 0x41 - F7 */ F7, F7, 0, -/* 0x42 - F8 */ F8, F8, 0, -/* 0x43 - F9 */ F9, F9, 0, -/* 0x44 - F10 */ F10, F10, 0, -/* 0x45 - NumLock */ NUM_LOCK, NUM_LOCK, 0, -/* 0x46 - ScrLock */ SCROLL_LOCK, SCROLL_LOCK, 0, -/* 0x47 - Home */ PAD_HOME, '7', HOME, -/* 0x48 - CurUp */ PAD_UP, '8', UP, -/* 0x49 - PgUp */ PAD_PAGEUP, '9', PAGEUP, -/* 0x4A - '-' */ PAD_MINUS, '-', 0, -/* 0x4B - Left */ PAD_LEFT, '4', LEFT, -/* 0x4C - MID */ PAD_MID, '5', 0, -/* 0x4D - Right */ PAD_RIGHT, '6', RIGHT, -/* 0x4E - '+' */ PAD_PLUS, '+', 0, -/* 0x4F - End */ PAD_END, '1', END, -/* 0x50 - Down */ PAD_DOWN, '2', DOWN, -/* 0x51 - PgDown */ PAD_PAGEDOWN, '3', PAGEDOWN, -/* 0x52 - Insert */ PAD_INS, '0', INSERT, -/* 0x53 - Delete */ PAD_DOT, '.', DELETE, -/* 0x54 - Enter */ 0, 0, 0, -/* 0x55 - ??? */ 0, 0, 0, -/* 0x56 - ??? */ 0, 0, 0, -/* 0x57 - F11 */ F11, F11, 0, -/* 0x58 - F12 */ F12, F12, 0, -/* 0x59 - ??? */ 0, 0, 0, -/* 0x5A - ??? */ 0, 0, 0, -/* 0x5B - ??? */ 0, 0, GUI_L, -/* 0x5C - ??? */ 0, 0, GUI_R, -/* 0x5D - ??? */ 0, 0, APPS, -/* 0x5E - ??? */ 0, 0, 0, -/* 0x5F - ??? */ 0, 0, 0, -/* 0x60 - ??? */ 0, 0, 0, -/* 0x61 - ??? */ 0, 0, 0, -/* 0x62 - ??? */ 0, 0, 0, -/* 0x63 - ??? */ 0, 0, 0, -/* 0x64 - ??? */ 0, 0, 0, -/* 0x65 - ??? */ 0, 0, 0, -/* 0x66 - ??? */ 0, 0, 0, -/* 0x67 - ??? */ 0, 0, 0, -/* 0x68 - ??? */ 0, 0, 0, -/* 0x69 - ??? */ 0, 0, 0, -/* 0x6A - ??? */ 0, 0, 0, -/* 0x6B - ??? */ 0, 0, 0, -/* 0x6C - ??? */ 0, 0, 0, -/* 0x6D - ??? */ 0, 0, 0, -/* 0x6E - ??? */ 0, 0, 0, -/* 0x6F - ??? */ 0, 0, 0, -/* 0x70 - ??? */ 0, 0, 0, -/* 0x71 - ??? */ 0, 0, 0, -/* 0x72 - ??? */ 0, 0, 0, -/* 0x73 - ??? */ 0, 0, 0, -/* 0x74 - ??? */ 0, 0, 0, -/* 0x75 - ??? */ 0, 0, 0, -/* 0x76 - ??? */ 0, 0, 0, -/* 0x77 - ??? */ 0, 0, 0, -/* 0x78 - ??? */ 0, 0, 0, -/* 0x78 - ??? */ 0, 0, 0, -/* 0x7A - ??? */ 0, 0, 0, -/* 0x7B - ??? */ 0, 0, 0, -/* 0x7C - ??? */ 0, 0, 0, -/* 0x7D - ??? */ 0, 0, 0, -/* 0x7E - ??? */ 0, 0, 0, -/* 0x7F - ??? */ 0, 0, 0 -}; - -/*====================================================================================* - Appendix: Scan code set 1 - *====================================================================================* - -KEY MAKE BREAK ----- KEY MAKE BREAK ----- KEY MAKE BREAK --------------------------------------------------------------------------------------- -A 1E 9E 9 0A 8A [ 1A 9A -B 30 B0 ` 29 89 INSERT E0,52 E0,D2 -C 2E AE - 0C 8C HOME E0,47 E0,C7 -D 20 A0 = 0D 8D PG UP E0,49 E0,C9 -E 12 92 \ 2B AB DELETE E0,53 E0,D3 -F 21 A1 BKSP 0E 8E END E0,4F E0,CF -G 22 A2 SPACE 39 B9 PG DN E0,51 E0,D1 -H 23 A3 TAB 0F 8F U ARROW E0,48 E0,C8 -I 17 97 CAPS 3A BA L ARROW E0,4B E0,CB -J 24 A4 L SHFT 2A AA D ARROW E0,50 E0,D0 -K 25 A5 L CTRL 1D 9D R ARROW E0,4D E0,CD -L 26 A6 L GUI E0,5B E0,DB NUM 45 C5 -M 32 B2 L ALT 38 B8 KP / E0,35 E0,B5 -N 31 B1 R SHFT 36 B6 KP * 37 B7 -O 18 98 R CTRL E0,1D E0,9D KP - 4A CA -P 19 99 R GUI E0,5C E0,DC KP + 4E CE -Q 10 19 R ALT E0,38 E0,B8 KP EN E0,1C E0,9C -R 13 93 APPS E0,5D E0,DD KP . 53 D3 -S 1F 9F ENTER 1C 9C KP 0 52 D2 -T 14 94 ESC 01 81 KP 1 4F CF -U 16 96 F1 3B BB KP 2 50 D0 -V 2F AF F2 3C BC KP 3 51 D1 -W 11 91 F3 3D BD KP 4 4B CB -X 2D AD F4 3E BE KP 5 4C CC -Y 15 95 F5 3F BF KP 6 4D CD -Z 2C AC F6 40 C0 KP 7 47 C7 -0 0B 8B F7 41 C1 KP 8 48 C8 -1 02 82 F8 42 C2 KP 9 49 C9 -2 03 83 F9 43 C3 ] 1B 9B -3 04 84 F10 44 C4 ; 27 A7 -4 05 85 F11 57 D7 ' 28 A8 -5 06 86 F12 58 D8 , 33 B3 - -6 07 87 PRTSCRN E0,2A E0,B7 . 34 B4 - E0,37 E0,AA - -7 08 88 SCROLL 46 C6 / 35 B5 - -8 09 89 PAUSE E1,1D,45 -NONE- - E1,9D,C5 - - ------------------ -ACPI Scan Codes: -------------------------------------------- -Key Make Code Break Code -------------------------------------------- -Power E0, 5E E0, DE -Sleep E0, 5F E0, DF -Wake E0, 63 E0, E3 - - -------------------------------- -Windows Multimedia Scan Codes: -------------------------------------------- -Key Make Code Break Code -------------------------------------------- -Next Track E0, 19 E0, 99 -Previous Track E0, 10 E0, 90 -Stop E0, 24 E0, A4 -Play/Pause E0, 22 E0, A2 -Mute E0, 20 E0, A0 -Volume Up E0, 30 E0, B0 -Volume Down E0, 2E E0, AE -Media Select E0, 6D E0, ED -E-Mail E0, 6C E0, EC -Calculator E0, 21 E0, A1 -My Computer E0, 6B E0, EB -WWW Search E0, 65 E0, E5 -WWW Home E0, 32 E0, B2 -WWW Back E0, 6A E0, EA -WWW Forward E0, 69 E0, E9 -WWW Stop E0, 68 E0, E8 -WWW Refresh E0, 67 E0, E7 -WWW Favorites E0, 66 E0, E6 - -*=====================================================================================*/ - - - -#endif /* _TINIX_KEYMAP_H_ */ diff --git a/bsp/x86/drivers/pci.c b/bsp/x86/drivers/pci.c new file mode 100644 index 0000000000000000000000000000000000000000..16b561bf33bd20ed7b568d47a0dc853626797ab6 --- /dev/null +++ b/bsp/x86/drivers/pci.c @@ -0,0 +1,366 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-08-04 JasonHu first version + */ + +#include "pci.h" +#include "board.h" + +#include + +// #define RT_PCI_DEBUG + +#ifdef RT_PCI_DEBUG + #define dbgprint rt_kprintf +#else + #define dbgprint(...) +#endif + +static rt_list_t g_pci_device_list_head; + +static void pci_device_bar_init(rt_pci_device_bar_t *bar, rt_uint32_t addr_reg_val, rt_uint32_t len_reg_val) +{ + if (addr_reg_val == 0xffffffff) { + addr_reg_val = 0; + } + /*we judge type by addr register bit 0, if 1, type is io, if 0, type is memory*/ + if (addr_reg_val & 1) { + bar->type = PCI_BAR_TYPE_IO; + bar->base_addr = addr_reg_val & PCI_BASE_ADDR_IO_MASK; + bar->length = ~(len_reg_val & PCI_BASE_ADDR_IO_MASK) + 1; + } else { + bar->type = PCI_BAR_TYPE_MEM; + bar->base_addr = addr_reg_val & PCI_BASE_ADDR_MEM_MASK; + bar->length = ~(len_reg_val & PCI_BASE_ADDR_MEM_MASK) + 1; + } +} + +void rt_pci_device_bar_dump(rt_pci_device_bar_t *bar) +{ + rt_kprintf(" type: %s, ", bar->type == PCI_BAR_TYPE_IO ? "io base address" : "mem base address"); + rt_kprintf(" base address: %x, ", bar->base_addr); + rt_kprintf(" len: %x\n", bar->length); +} + +static void pci_device_init(rt_pci_device_t *device, rt_uint8_t bus, rt_uint8_t dev, rt_uint8_t function, + rt_uint16_t vendor_id, rt_uint16_t device_id, rt_uint32_t class_code, + rt_uint8_t revision_id, rt_uint8_t multi_function) +{ + device->bus = bus; + device->dev = dev; + device->function = function; + + device->vendor_id = vendor_id; + device->device_id = device_id; + device->multi_function = multi_function; + device->class_code = class_code; + device->revision_id = revision_id; + int i; + for (i = 0; i < PCI_MAX_BAR_NR; i++) + { + device->bars[i].type = PCI_BAR_TYPE_INVALID; + } + device->irq_line = -1; +} + +static rt_uint32_t pci_read_config(rt_uint32_t bus, rt_uint32_t device, rt_uint32_t function, rt_uint32_t addr) +{ + rt_uint32_t reg = 0x80000000; + reg |= (bus & 0xFF) << 16; + reg |= (device & 0x1F) << 11; + reg |= (function & 0x7) << 8; + reg |= (addr & 0xFF) & 0xFC; /*bit 0 and 1 always 0*/ + outl(PCI_CONFIG_ADDR, reg); + return inl(PCI_CONFIG_DATA); +} + +static void pci_write_config(rt_uint32_t bus, rt_uint32_t device, rt_uint32_t function, rt_uint32_t addr, rt_uint32_t val) +{ + rt_uint32_t reg = 0x80000000; + reg |= (bus & 0xFF) << 16; + reg |= (device & 0x1F) << 11; + reg |= (function & 0x7) << 8; + reg |= (addr & 0xFF) & 0xFC; /*bit 0 and 1 always 0*/ + outl(PCI_CONFIG_ADDR, reg); + outl(PCI_CONFIG_DATA, val); +} + +static rt_pci_device_t *pci_create_device() +{ + rt_pci_device_t *device = rt_malloc(sizeof(rt_pci_device_t)); + if (device == RT_NULL) + { + return RT_NULL; + } + rt_list_insert_after(&g_pci_device_list_head, &device->list); + return device; +} + +void rt_pci_device_dump(rt_pci_device_t *device) +{ + rt_kprintf("vendor id: 0x%x\n", device->vendor_id); + rt_kprintf("device id: 0x%x\n", device->device_id); + rt_kprintf("class code: 0x%x\n", device->class_code); + rt_kprintf("revision id: 0x%x\n", device->revision_id); + rt_kprintf("multi function: %d\n", device->multi_function); + rt_kprintf("card bus CIS pointer: %x\n", device->card_bus_pointer); + rt_kprintf("subsystem vendor id: %x\n", device->subsystem_vendor_id); + rt_kprintf("subsystem device id: %x\n", device->subsystem_device_id); + rt_kprintf("expansion ROM base address: %x\n", device->expansion_rom_base_addr); + rt_kprintf("capability list pointer: %x\n", device->capability_list); + rt_kprintf("irq line: %d\n", device->irq_line); + rt_kprintf("irq pin: %d\n", device->irq_pin); + rt_kprintf("min Gnt: %d\n", device->min_gnt); + rt_kprintf("max Lat: %d\n", device->max_lat); + int i; + for (i = 0; i < PCI_MAX_BAR_NR; i++) + { + if (device->bars[i].type != PCI_BAR_TYPE_INVALID) + { + rt_kprintf("bar %d:\n", i); + rt_pci_device_bar_dump(&device->bars[i]); + } + } + rt_kprintf("\n"); +} + +static void pci_scan_device(rt_uint8_t bus, rt_uint8_t device, rt_uint8_t function) +{ + rt_uint32_t val = pci_read_config(bus, device, function, PCI_DEVICE_VENDER); + rt_uint32_t vendor_id = val & 0xffff; + rt_uint32_t device_id = val >> 16; + /*if vendor id is 0xffff, it means that this bus , device not exist!*/ + if (vendor_id == 0xffff) + { + return; + } + + rt_pci_device_t *pci_dev = pci_create_device(); + if (pci_dev == RT_NULL) + { + return; + } + + val = pci_read_config(bus, device, function, PCI_BIST_HEADER_TYPE); + rt_uint8_t header_type = ((val >> 16)); + val = pci_read_config(bus, device, function, PCI_STATUS_COMMAND); + + pci_dev->command = val & 0xffff; + pci_dev->status = (val >> 16) & 0xffff; + + val = pci_read_config(bus, device, function, PCI_CLASS_CODE_REVISION_ID); + rt_uint32_t classcode = val >> 8; + rt_uint8_t revision_id = val & 0xff; + + pci_device_init(pci_dev, bus, device, function, vendor_id, device_id, classcode, revision_id, (header_type & 0x80)); + + int bar, reg; + for (bar = 0; bar < PCI_MAX_BAR_NR; bar++) + { + reg = PCI_BASS_ADDRESS0 + (bar*4); + val = pci_read_config(bus, device, function, reg); + /*set 0xffffffff to bass address[0~5], so that if we pci_read_config again, it's addr len*/ + pci_write_config(bus, device, function, reg, 0xffffffff); + + /*pci_read_config bass address[0~5] to get addr len*/ + rt_uint32_t len = pci_read_config(bus, device, function, reg); + /*pci_write_config the io/mem address back to confige space*/ + pci_write_config(bus, device, function, reg, val); + + if (len != 0 && len != 0xffffffff) + { + pci_device_bar_init(&pci_dev->bars[bar], val, len); + } + } + + val = pci_read_config(bus, device, function, PCI_CARD_BUS_POINTER); + pci_dev->card_bus_pointer = val; + + val = pci_read_config(bus, device, function, PCI_SUBSYSTEM_ID); + pci_dev->subsystem_vendor_id = val & 0xffff; + pci_dev->subsystem_device_id = (val >> 16) & 0xffff; + + val = pci_read_config(bus, device, function, PCI_EXPANSION_ROM_BASE_ADDR); + pci_dev->expansion_rom_base_addr = val; + + val = pci_read_config(bus, device, function, PCI_CAPABILITY_LIST); + pci_dev->capability_list = val; + + val = pci_read_config(bus, device, function, PCI_IRQ_PIN_IRQ_LINE); + if ((val & 0xff) > 0 && (val & 0xff) < 32) + { + int irq = val & 0xff; + pci_dev->irq_line = irq; + pci_dev->irq_pin = (val >> 8)& 0xff; + } + pci_dev->min_gnt = (val >> 16) & 0xff; + pci_dev->max_lat = (val >> 24) & 0xff; +} + +static void rt_pci_scan_all_buses() +{ + rt_uint32_t bus; + rt_uint8_t device, function; + for (bus = 0; bus < PCI_MAX_BUS_NR; bus++) + { + for (device = 0; device < PCI_MAX_DEV_NR; device++) + { + for (function = 0; function < PCI_MAX_FUN_NR; function++) + { + pci_scan_device(bus, device, function); + } + } + } +} + +rt_pci_device_t *rt_pci_device_get(rt_uint32_t vendor_id, rt_uint32_t device_id) +{ + rt_pci_device_t* device; + + rt_list_for_each_entry(device, &g_pci_device_list_head, list) + { + if (device->vendor_id == vendor_id && device->device_id == device_id) + { + return device; + } + } + return RT_NULL; +} + +rt_pci_device_t *rt_pci_device_get_by_class_code(rt_uint32_t class, rt_uint32_t sub_class) +{ + rt_pci_device_t* device; + rt_uint32_t class_code = ((class & 0xff) << 16) | ((sub_class & 0xff) << 8); + + rt_list_for_each_entry(device, &g_pci_device_list_head, list) + { + if ((device->class_code & 0xffff00) == class_code) + { + return device; + } + } + return RT_NULL; +} + +void rt_pci_enable_bus_mastering(rt_pci_device_t *device) +{ + rt_uint32_t val = pci_read_config(device->bus, device->dev, device->function, PCI_STATUS_COMMAND); + dbgprint("PCI enable bus mastering: before command: %x\n", val); + val |= 0x04; + pci_write_config(device->bus, device->dev, device->function, PCI_STATUS_COMMAND, val); + val = pci_read_config(device->bus, device->dev, device->function, PCI_STATUS_COMMAND); + dbgprint("PCI enable bus mastering: after command: %x\n", val); +} + +rt_uint32_t rt_pci_device_read(rt_pci_device_t *device, rt_uint32_t reg) +{ + return pci_read_config(device->bus, device->dev, device->function, reg); +} + +void rt_pci_device_write(rt_pci_device_t *device, rt_uint32_t reg, rt_uint32_t value) +{ + pci_write_config(device->bus, device->dev, device->function, reg, value); +} + +rt_uint32_t rt_pci_device_get_io_addr(rt_pci_device_t *device) +{ + int i; + for (i = 0; i < PCI_MAX_BAR_NR; i++) + { + if (device->bars[i].type == PCI_BAR_TYPE_IO) + { + return device->bars[i].base_addr; + } + } + return 0; +} + +rt_uint32_t rt_pci_device_get_mem_addr(rt_pci_device_t *device) +{ + int i; + for (i = 0; i < PCI_MAX_BAR_NR; i++) + { + if (device->bars[i].type == PCI_BAR_TYPE_MEM) + { + return device->bars[i].base_addr; + } + } + return 0; +} + +rt_uint32_t rt_pci_device_get_mem_len(rt_pci_device_t *device) +{ + int i; + for(i = 0; i < PCI_MAX_BAR_NR; i++) + { + if(device->bars[i].type == PCI_BAR_TYPE_MEM) + { + return device->bars[i].length; + } + } + return 0; +} + +rt_uint32_t rt_pci_device_get_irq_line(rt_pci_device_t *device) +{ + return device->irq_line; +} + +static rt_uint32_t pic_get_connected_counts() +{ + rt_uint32_t n = 0; + rt_pci_device_t *device; + rt_list_for_each_entry(device, &g_pci_device_list_head, list) + { + n++; + } + return n; +} + +#ifdef RT_USING_FINSH +static void rt_pci_device_list(rt_pci_device_t *device) +{ + rt_kprintf("device bus: %d, device: %d function: %d\n", device->bus, device->dev, device->function); + rt_kprintf(" vendor id: 0x%x\n", device->vendor_id); + rt_kprintf(" device id: 0x%x\n", device->device_id); + rt_kprintf(" class code: 0x%x\n", device->class_code); + rt_kprintf(" irq line: %d\n", device->irq_line); + int i; + for (i = 0; i < PCI_MAX_BAR_NR; i++) + { + if (device->bars[i].type != PCI_BAR_TYPE_INVALID) + { + rt_kprintf(" bar %d:\n", i); + rt_pci_device_bar_dump(&device->bars[i]); + } + } + rt_kprintf("\n"); +} + +static void list_pci_device() +{ + rt_kprintf("list pci device:\n"); + rt_pci_device_t *device; + rt_list_for_each_entry(device, &g_pci_device_list_head, list) + { + rt_pci_device_list(device); + } +} +#endif /* RT_USING_FINSH */ + +void rt_pci_init(void) +{ + rt_list_init(&g_pci_device_list_head); + rt_pci_scan_all_buses(); + rt_kprintf("PCI device: device found %d.\n", pic_get_connected_counts()); +} + +#ifdef RT_USING_FINSH +#include +MSH_CMD_EXPORT(list_pci_device, list PCI device on computer) +#endif /* RT_USING_FINSH */ diff --git a/bsp/x86/drivers/pci.h b/bsp/x86/drivers/pci.h new file mode 100644 index 0000000000000000000000000000000000000000..6c492a61f2fef42f5edca46efd62d495eebd5093 --- /dev/null +++ b/bsp/x86/drivers/pci.h @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-08-04 JasonHu first version + */ + +#ifndef __PCI_H__ +#define __PCI_H__ + +#include + +#define PCI_CONFIG_ADDR 0xCF8 /* PCI configuration space address port */ +#define PCI_CONFIG_DATA 0xCFC /* PCI configuration space data port */ + +#define PCI_DEVICE_VENDER 0x00 +#define PCI_STATUS_COMMAND 0x04 +#define PCI_CLASS_CODE_REVISION_ID 0x08 +#define PCI_BIST_HEADER_TYPE 0x0C +#define PCI_BASS_ADDRESS0 0x10 +#define PCI_BASS_ADDRESS1 0x14 +#define PCI_BASS_ADDRESS2 0x18 +#define PCI_BASS_ADDRESS3 0x1C +#define PCI_BASS_ADDRESS4 0x20 +#define PCI_BASS_ADDRESS5 0x24 +#define PCI_CARD_BUS_POINTER 0x28 +#define PCI_SUBSYSTEM_ID 0x2C +#define PCI_EXPANSION_ROM_BASE_ADDR 0x30 +#define PCI_CAPABILITY_LIST 0x34 +#define PCI_RESERVED 0x38 +#define PCI_IRQ_PIN_IRQ_LINE 0x3C + +#define PCI_COMMAND_IO 0x1 /* Enable response in I/O space */ +#define PCI_COMMAND_MEMORY 0x2 /* Enable response in Memory space */ +#define PCI_COMMAND_MASTER 0x4 /* Enable bus mastering */ +#define PCI_COMMAND_SPECIAL 0x8 /* Enable response to special cycles */ +#define PCI_COMMAND_INVALIDATE 0x10 /* Use memory write and invalidate */ +#define PCI_COMMAND_VGA_PALETTE 0x20 /* Enable palette snooping */ +#define PCI_COMMAND_PARITY 0x40 /* Enable parity checking */ +#define PCI_COMMAND_WAIT 0x80 /* Enable address/data stepping */ +#define PCI_COMMAND_SERR 0x100 /* Enable SERR */ +#define PCI_COMMAND_FAST_BACK 0x200 /* Enable back-to-back writes */ +#define PCI_COMMAND_INTX_DISABLE 0x400 /* INTx Emulation Disable */ + +#define PCI_BASE_ADDR_MEM_MASK (~0x0FUL) +#define PCI_BASE_ADDR_IO_MASK (~0x03UL) + +#define PCI_BAR_TYPE_INVALID 0 +#define PCI_BAR_TYPE_MEM 1 +#define PCI_BAR_TYPE_IO 2 + +#define PCI_MAX_BAR_NR 6 /* Each device has up to 6 address information */ +#define PCI_MAX_BUS_NR 256 /* PCI has a total of 256 buses */ +#define PCI_MAX_DEV_NR 32 /* There are a total of 32 devices on each PCI bus */ +#define PCI_MAX_FUN_NR 8 /* PCI devices have a total of 8 function numbers */ + +#ifndef PCI_ANY_ID +#define PCI_ANY_ID (~0) +#endif + +struct rt_pci_device_id +{ + rt_uint32_t vendor, device; /* vendor and device id or PCI_ANY_ID */ + rt_uint32_t subvendor, subdevice; /* subsystem's id or PCI_ANY_ID */ + rt_uint32_t class_value, class_mask; +}; +typedef struct rt_pci_device_id rt_pci_device_id_t; + +struct rt_pci_device_bar +{ + rt_uint32_t type; /* Type of address bar (IO address/MEM address) */ + rt_uint32_t base_addr; + rt_uint32_t length; /* Length of address */ +}; +typedef struct rt_pci_device_bar rt_pci_device_bar_t; + +struct rt_pci_device +{ + rt_list_t list; /* list for all pci device */ + rt_uint8_t bus; /* bus number */ + rt_uint8_t dev; /* device number */ + rt_uint8_t function; /* Function number */ + + rt_uint16_t vendor_id; /* Configuration space:Vendor ID */ + rt_uint16_t device_id; /* Configuration space:Device ID */ + rt_uint16_t command; /* Configuration space:Command */ + rt_uint16_t status; /* Configuration space:Status */ + + rt_uint32_t class_code; /* Configuration space:Class Code */ + rt_uint8_t revision_id; /* Configuration space:Revision ID */ + rt_uint8_t multi_function; + rt_uint32_t card_bus_pointer; + rt_uint16_t subsystem_vendor_id; + rt_uint16_t subsystem_device_id; + rt_uint32_t expansion_rom_base_addr; + rt_uint32_t capability_list; + + rt_uint8_t irq_line; /*Configuration space:IRQ line*/ + rt_uint8_t irq_pin; /*Configuration space:IRQ pin*/ + rt_uint8_t min_gnt; + rt_uint8_t max_lat; + rt_pci_device_bar_t bars[PCI_MAX_BAR_NR]; +}; +typedef struct rt_pci_device rt_pci_device_t; + +rt_uint32_t rt_pci_device_get_io_addr(rt_pci_device_t *device); +rt_uint32_t rt_pci_device_get_mem_addr(rt_pci_device_t *device); +rt_uint32_t rt_pci_device_get_mem_len(rt_pci_device_t *device); +rt_uint32_t rt_pci_device_get_irq_line(rt_pci_device_t *device); + +void rt_pci_enable_bus_mastering(rt_pci_device_t *device); + +rt_pci_device_t* rt_pci_device_get(rt_uint32_t vendor_id, rt_uint32_t device_id); +rt_pci_device_t* rt_pci_device_get_by_class_code(rt_uint32_t class_value, rt_uint32_t sub_class); + +void rt_pci_device_bar_dump(rt_pci_device_bar_t *bar); +void rt_pci_device_dump(rt_pci_device_t *device); + +rt_uint32_t rt_pci_device_read(rt_pci_device_t *device, rt_uint32_t reg); +void rt_pci_device_write(rt_pci_device_t *device, rt_uint32_t reg, rt_uint32_t value); + +void rt_pci_init(void); + +#endif /* __PCI_H__ */ diff --git a/bsp/x86/drivers/serial.c b/bsp/x86/drivers/serial.c deleted file mode 100644 index 51b7a0d96df1cf13301406dd393c85c8e532dcf6..0000000000000000000000000000000000000000 --- a/bsp/x86/drivers/serial.c +++ /dev/null @@ -1,72 +0,0 @@ -/* - * File : serial.c - * This file is part of RT-Thread RTOS - * COPYRIGHT (C) 2006, RT-Thread Development Team - * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://openlab.rt-thread.com/license/LICENSE - * - * Change Logs: - * Date Author Notes - * 2006-09-15 QiuYi the first version - * 2006-10-10 Bernard use keyboard instead of serial - */ - -#include -#include - -#include - -/** - * @addtogroup QEMU - */ -/*@{*/ - -/** - * This function initializes serial - */ -void rt_serial_init(void) -{ - outb(COM1+3,0x80); /* set DLAB of line control reg */ - outb(COM1,0x0c); /* LS of divisor (48 -> 2400 bps */ - outb(COM1+1,0x00); /* MS of divisor */ - outb(COM1+3,0x03); /* reset DLAB */ - outb(COM1+4,0x0b); /* set DTR,RTS, OUT_2 */ - outb(COM1+1,0x0d); /* enable all intrs but writes */ - inb(COM1); /* read data port to reset things (?) */ -} - -/** - * This function read a character from serial without interrupt enable mode - * - * @return the read char - */ -char rt_serial_getc(void) -{ - - while(!(inb(COM1+COMSTATUS) & COMDATA)); - - return inb(COM1+COMREAD); - -} - -/** - * This function will write a character to serial without interrupt enable mode - * - * @param c the char to write - */ -void rt_serial_putc(const char c) -{ - int val; - - while(1) - { - if ((val = inb(COM1+COMSTATUS)) & THRE) - break; - } - - outb(COM1+COMWRITE, c&0xff); -} - -/*@}*/ diff --git a/bsp/x86/get_grub.sh b/bsp/x86/get_grub.sh new file mode 100644 index 0000000000000000000000000000000000000000..6024ffd282c8169490c9640760b23bec2138730b --- /dev/null +++ b/bsp/x86/get_grub.sh @@ -0,0 +1,6 @@ +# 1. download +git clone https://gitee.com/hzc1998/grub2for-rt-smartx86 +# 2. unzip +unzip grub2for-rt-smartx86/grub-2.04-for-rt-smartx86.zip +# 3. remove hub +rm -rf grub2for-rt-smartx86 \ No newline at end of file diff --git a/bsp/x86/link.lds b/bsp/x86/link.lds new file mode 100644 index 0000000000000000000000000000000000000000..b58d26401586f91fd2259f07334c383f3720c571 --- /dev/null +++ b/bsp/x86/link.lds @@ -0,0 +1,106 @@ +OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") +OUTPUT_ARCH(i386) +ENTRY(_start) +SECTIONS +{ + . = 0x00100000; + + . = ALIGN(4); + __text_start = .; + .text : + { + _stext = .; + *(.init) + *(.text) + + /* section information for utest */ + . = ALIGN(4); + __rt_utest_tc_tab_start = .; + KEEP(*(UtestTcTab)) + __rt_utest_tc_tab_end = .; + + /* section information for finsh shell */ + . = ALIGN(4); + __fsymtab_start = .; + KEEP(*(FSymTab)) + __fsymtab_end = .; + . = ALIGN(4); + __vsymtab_start = .; + KEEP(*(VSymTab)) + __vsymtab_end = .; + . = ALIGN(4); + + /* section information for modules */ + . = ALIGN(4); + __rtmsymtab_start = .; + KEEP(*(RTMSymTab)) + __rtmsymtab_end = .; + + /* section information for initialization */ + . = ALIGN(4); + __rt_init_start = .; + KEEP(*(SORT(.rti_fn*))) + __rt_init_end = .; + _etext = .; /* define a global symbols at end of code */ + } =0 + __text_end = .; + + . = ALIGN(4); + __rodata_start = .; + .rodata : { *(.rodata) *(.rodata.*) } + __rodata_end = .; + + . = ALIGN(4); + .ctors : + { + PROVIDE(__ctors_start__ = .); + KEEP(*(SORT(.ctors.*))) + KEEP(*(.ctors)) + PROVIDE(__ctors_end__ = .); + } + + .dtors : + { + PROVIDE(__dtors_start__ = .); + KEEP(*(SORT(.dtors.*))) + KEEP(*(.dtors)) + PROVIDE(__dtors_end__ = .); + } + + . = ALIGN(4); + __data_start = .; + .data : + { + *(.data) + *(.data.*) + } + __data_end = .; + + . = ALIGN(4); + __bss_start = .; + .bss : + { + *(.bss) + *(.bss.*) + *(COMMON) + . = ALIGN(4); + } + . = ALIGN(4); + __bss_end = .; + + /* stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_info 0 : { *(.debug_info) } + .debug_line 0 : { *(.debug_line) } + .debug_pubnames 0 : { *(.debug_pubnames) } + .debug_aranges 0 : { *(.debug_aranges) } + + _end = .; +} diff --git a/bsp/x86/memlayout.md b/bsp/x86/memlayout.md new file mode 100644 index 0000000000000000000000000000000000000000..930e6a6e8f21568fa9f5fc3987d06e1898c999cf --- /dev/null +++ b/bsp/x86/memlayout.md @@ -0,0 +1,52 @@ +# 物理内存分布图 +``` + +---------------------+-------------------------------------------+ + | Address | details | + +---------------------+-------------------------------------------+ + | 0x00~0x400 | int vectors | + +---------------------+-------------------------------------------+ + | 0x400~0x500 | ROM BIOS parameter area | + +---------------------+-------------------------------------------+ + | 0x1000~0x1100 | ards | + +---------------------+-------------------------------------------+ + | 0x9d000~0x9f000 | kernel statck | + +---------------------+-------------------------------------------+ + | 0x9fc00~0xa0000 | extended BIOS data area (EBDA) | + +---------------------+-------------------------------------------+ + | 0xa0000~0xc0000 | display adapter reserved | + +---------------------+-------------------------------------------+ + | 0xc0000~0xe0000 | Reserved for ROM expansion | + +---------------------+-------------------------------------------+ + | 0xe0000~0xf0000 | Expansion of system ROM | + +---------------------+-------------------------------------------+ + | 0xf0000~0x100000 | System ROM | + +---------------------+-------------------------------------------+ + | 0x100000~0x3F0000 | kernel | + +---------------------+-------------------------------------------+ + | 0x3F0000~0x3F0800 | GDT | + +---------------------+-------------------------------------------+ + | 0x3F0800~0x3F1000 | IDT | + +-----------------------------------------------------------------+ + | 0x3F1000~0x3F2000 | GRUB MODULE INFO | + +---------------------+-------------------------------------------+ + | 0x3F2000~0x3F3000 | KERNEL PAGE DIR TABLE | + +---------------------+-------------------------------------------+ + | 0x3F3000~0x3F4000 | KERNEL PAGE TABLE | + +---------------------+-------------------------------------------+ + | 0x3F3000~0x800000 | KERNEL PAGE TABLE STATIC(1G) | + +---------------------+-------------------------------------------+ + | 0x800000~0x1000000 | DMA device special addr | + +---------------------+-------------------------------------------+ + | 0x1000000~0xffffffff| avaliable memory | + +---------------------+-------------------------------------------+ +``` +# 虚拟内存分布图 +``` + +-------------------------+---------------------------------------+ + | Address | details | + +-------------------------+---------------------------------------+ + | 0x0~0x3FFFFFFF | kernel space | + +-------------------------+---------------------------------------+ + | 0x40000000~0xFFFFFFFF | user space | + +---------------------+-------------------------------------------+ +``` \ No newline at end of file diff --git a/bsp/x86/rtconfig.h b/bsp/x86/rtconfig.h index c4cdac1fdca971e331a25795c97a11164d0c2c6a..4a08143cd5391ea5e1d7886b5ddcb20e75f61f6e 100644 --- a/bsp/x86/rtconfig.h +++ b/bsp/x86/rtconfig.h @@ -1,180 +1,198 @@ -/* RT-Thread config file */ -#ifndef __RTTHREAD_CFG_H__ -#define __RTTHREAD_CFG_H__ +#ifndef RT_CONFIG_H__ +#define RT_CONFIG_H__ -/* RT_NAME_MAX*/ -#define RT_NAME_MAX 8 +/* Automatically generated file; DO NOT EDIT. */ +/* RT-Thread Project Configuration */ -/* RT_ALIGN_SIZE*/ -#define RT_ALIGN_SIZE 8 +/* RT-Thread Kernel */ -/* PRIORITY_MAX */ -#define RT_THREAD_PRIORITY_MAX 32 - -/* Tick per Second */ -#define RT_TICK_PER_SECOND 1000 - -/* SECTION: RT_DEBUG */ -/* Thread Debug */ -#define RT_DEBUG -#define RT_DEBUG_COLOR -#define RT_DEBUG_MODULE 0 - -#define RT_USING_OVERFLOW_CHECK - -/* Using Hook */ +#define RT_NAME_MAX 20 +#define RT_USING_SMART +#define RT_ALIGN_SIZE 4 +#define RT_THREAD_PRIORITY_32 +#define RT_THREAD_PRIORITY_MAX 32 +#define RT_TICK_PER_SECOND 100 #define RT_USING_HOOK +#define RT_USING_IDLE_HOOK +#define RT_IDLE_HOOK_LIST_SIZE 4 +#define IDLE_THREAD_STACK_SIZE 16384 +#define RT_USING_TIMER_SOFT +#define RT_TIMER_THREAD_PRIO 4 +#define RT_TIMER_THREAD_STACK_SIZE 16384 +#define RT_DEBUG -/* Using Software Timer */ -/* #define RT_USING_TIMER_SOFT */ -#define RT_TIMER_THREAD_PRIO 4 -#define RT_TIMER_THREAD_STACK_SIZE 512 -#define RT_TIMER_TICK_PER_SECOND 10 +/* Inter-Thread communication */ -/* SECTION: IPC */ -/* Using Semaphore*/ #define RT_USING_SEMAPHORE - -/* Using Mutex */ #define RT_USING_MUTEX - -/* Using Event */ #define RT_USING_EVENT - -/* Using MailBox */ #define RT_USING_MAILBOX - -/* Using Message Queue */ #define RT_USING_MESSAGEQUEUE +#define RT_USING_SIGNALS -/* SECTION: Memory Management */ -/* Using Memory Pool Management*/ -#define RT_USING_MEMPOOL +/* Memory Management */ -/* Using Dynamic Heap Management */ +#define RT_USING_MEMPOOL +#define RT_USING_SMALL_MEM #define RT_USING_HEAP -/* Using Small MM */ -#define RT_USING_SMALL_MEM +/* Kernel Device Object */ -/* SECTION: Device System */ -/* Using Device System */ #define RT_USING_DEVICE - -/* SECTION: Console options */ #define RT_USING_CONSOLE -/* the buffer size of console*/ -#define RT_CONSOLEBUF_SIZE 128 +#define RT_CONSOLEBUF_SIZE 256 +#define RT_CONSOLE_DEVICE_NAME "uart0" +#define RT_VER_NUM 0x50000 +#define RT_USING_CACHE +#define RT_USING_USERSPACE +#define KERNEL_VADDR_START 0x00000000 +#define PV_OFFSET 0 +#define ARCH_X86 + +/* RT-Thread Components */ + +#define RT_USING_COMPONENTS_INIT +#define RT_USING_USER_MAIN +#define RT_MAIN_THREAD_STACK_SIZE 2048 +#define RT_MAIN_THREAD_PRIORITY 10 + +/* C++ features */ + -#define IDLE_THREAD_STACK_SIZE 1024 /* idle stack 1K */ +/* Command shell */ -/* SECTION: finsh, a C-Express shell */ #define RT_USING_FINSH -#define FINSH_USING_MSH -#define FINSH_USING_MSH_ONLY -/* Using symbol table */ +#define RT_USING_MSH +#define FINSH_THREAD_NAME "tshell" +#define FINSH_USING_HISTORY +#define FINSH_HISTORY_LINES 5 #define FINSH_USING_SYMTAB #define FINSH_USING_DESCRIPTION +#define FINSH_THREAD_PRIORITY 20 +#define FINSH_THREAD_STACK_SIZE 4096 +#define FINSH_CMD_SIZE 80 +#define FINSH_ARG_MAX 10 + +/* Device virtual file system */ + +#define RT_USING_DFS +#define DFS_USING_WORKDIR +#define DFS_FILESYSTEMS_MAX 3 +#define DFS_FILESYSTEM_TYPES_MAX 3 +#define DFS_FD_MAX 16 +#define RT_USING_DFS_ELMFAT -// #define RT_USING_LIBC -// #define RT_USING_PTHREADS - -/* SECTION: device filesystem */ - #define RT_USING_DFS +/* elm-chan's FatFs, Generic FAT Filesystem Module */ -#define RT_USING_DFS_ELMFAT +#define RT_DFS_ELM_CODE_PAGE 437 #define RT_DFS_ELM_WORD_ACCESS -/* Reentrancy (thread safe) of the FatFs module. */ +#define RT_DFS_ELM_USE_LFN_3 +#define RT_DFS_ELM_USE_LFN 3 +#define RT_DFS_ELM_MAX_LFN 255 +#define RT_DFS_ELM_DRIVES 2 +#define RT_DFS_ELM_MAX_SECTOR_SIZE 512 #define RT_DFS_ELM_REENTRANT -/* Number of volumes (logical drives) to be used. */ -#define RT_DFS_ELM_DRIVES 2 -/* #define RT_DFS_ELM_USE_LFN 1 */ -#define RT_DFS_ELM_MAX_LFN 255 -/* Maximum sector size to be handled. */ -#define RT_DFS_ELM_MAX_SECTOR_SIZE 512 - -/* the max number of mounted filesystem */ -#define DFS_FILESYSTEMS_MAX 2 -/* the max number of opened files */ -#define DFS_FD_MAX 4 - #define RT_USING_DFS_DEVFS +#define RT_USING_DFS_ROMFS + +/* Device Drivers */ + +#define RT_USING_DEVICE_IPC +#define RT_PIPE_BUFSZ 512 +#define RT_USING_SERIAL +#define RT_SERIAL_RB_BUFSZ 64 + +/* Using USB */ + + +/* POSIX layer and C standard library */ + +#define RT_USING_LIBC +#define RT_USING_MUSL +#define RT_USING_POSIX +#define RT_USING_POSIX_CLOCKTIME + +/* Network */ + +/* Socket abstraction layer */ + + +/* Network interface device */ + + +/* light weight TCP/IP stack */ + + +/* AT commands */ + + +/* VBUS(Virtual Software BUS) */ + + +/* Utilities */ + +#define RT_USING_LWP +#define RT_LWP_MAX_NR 30 +#define LWP_TASK_STACK_SIZE 16384 +#define RT_CH_MSG_MAX_NR 1024 +#define RT_LWP_SHM_MAX_NR 64 +#define LWP_CONSOLE_INPUT_BUFFER_SIZE 1024 +#define LWP_TID_MAX_NR 64 + +/* RT-Thread online packages */ + +/* IoT - internet of things */ + + +/* Wi-Fi */ + +/* Marvell WiFi */ + + +/* Wiced WiFi */ + + +/* IoT Cloud */ + + +/* security packages */ + + +/* language packages */ + + +/* multimedia packages */ + + +/* tools packages */ + + +/* system packages */ + +/* acceleration: Assembly language or algorithmic acceleration packages */ + + +/* Micrium: Micrium software products porting for RT-Thread */ + + +/* peripheral libraries and drivers */ + + +/* AI packages */ + + +/* miscellaneous packages */ + + +/* samples: kernel and components samples */ + + +/* entertainment: terminal games and other interesting software packages */ + +#define BOARD_x86 +#define BSP_USING_DIRECT_UART +#define BSP_DRV_UART +#define RT_USING_UART0 +#define BSP_DRV_AHCI -/* SECTION: lwip, a lighwight TCP/IP protocol stack */ -//#define RT_USING_LWIP -/* Enable ICMP protocol*/ -#define RT_LWIP_ICMP -/* Enable UDP protocol*/ -#define RT_LWIP_UDP -/* Enable TCP protocol*/ -#define RT_LWIP_TCP -/* Enable DNS */ -#define RT_LWIP_DNS - -/* the number of simulatenously active TCP connections*/ -#define RT_LWIP_TCP_PCB_NUM 5 - -/* Using DHCP */ -/* #define RT_LWIP_DHCP */ - -/* ip address of target*/ -#define RT_LWIP_IPADDR0 192 -#define RT_LWIP_IPADDR1 168 -#define RT_LWIP_IPADDR2 1 -#define RT_LWIP_IPADDR3 30 - -/* gateway address of target*/ -#define RT_LWIP_GWADDR0 192 -#define RT_LWIP_GWADDR1 168 -#define RT_LWIP_GWADDR2 1 -#define RT_LWIP_GWADDR3 1 - -/* mask address of target*/ -#define RT_LWIP_MSKADDR0 255 -#define RT_LWIP_MSKADDR1 255 -#define RT_LWIP_MSKADDR2 255 -#define RT_LWIP_MSKADDR3 0 - -/* tcp thread options */ -#define RT_LWIP_TCPTHREAD_PRIORITY 12 -#define RT_LWIP_TCPTHREAD_MBOX_SIZE 10 -#define RT_LWIP_TCPTHREAD_STACKSIZE 1024 - -/* ethernet if thread options */ -#define RT_LWIP_ETHTHREAD_PRIORITY 15 -#define RT_LWIP_ETHTHREAD_MBOX_SIZE 10 -#define RT_LWIP_ETHTHREAD_STACKSIZE 512 - -/* TCP sender buffer space */ -#define RT_LWIP_TCP_SND_BUF 8192 -/* TCP receive window. */ -#define RT_LWIP_TCP_WND 8192 - -/* SECTION: RT-Thread/GUI */ -/* #define RT_USING_RTGUI */ - -/* name length of RTGUI object */ -#define RTGUI_NAME_MAX 12 -/* support 16 weight font */ -#define RTGUI_USING_FONT16 -/* support Chinese font */ -#define RTGUI_USING_FONTHZ -/* use DFS as file interface */ -#define RTGUI_USING_DFS_FILERW -/* use font file as Chinese font */ -#define RTGUI_USING_HZ_FILE -/* use Chinese bitmap font */ -#define RTGUI_USING_HZ_BMP -/* use small size in RTGUI */ -#define RTGUI_USING_SMALL_SIZE -/* use mouse cursor */ -/* #define RTGUI_USING_MOUSE_CURSOR */ -/* default font size in RTGUI */ -#define RTGUI_DEFAULT_FONT_SIZE 16 - -/* image support */ -/* #define RTGUI_IMAGE_XPM */ -/* #define RTGUI_IMAGE_BMP */ - -// #define RT_USING_MODULE #endif diff --git a/bsp/x86/rtconfig.py b/bsp/x86/rtconfig.py index b833f4de49f8625cb4e1d5918d05704e52ac49f8..49fbcffc90a9a5ea113a2f2f5e73d7b3cfb09339 100644 --- a/bsp/x86/rtconfig.py +++ b/bsp/x86/rtconfig.py @@ -1,10 +1,12 @@ import os # toolchains options -ARCH='ia32' -CPU='' +ARCH='x86' +CPU='i386' CROSS_TOOL='gcc' +RTT_ROOT = os.getenv('RTT_ROOT') or os.path.join(os.getcwd(), '..', '..') + if os.getenv('RTT_CC'): CROSS_TOOL = os.getenv('RTT_CC') @@ -13,7 +15,7 @@ if os.getenv('RTT_CC'): if CROSS_TOOL == 'gcc': PLATFORM = 'gcc' - EXEC_PATH = 'E:/Program Files/CodeSourcery/Sourcery_CodeBench_Lite_for_IA32_ELF/bin' + EXEC_PATH = '/home/jasonhu/Desktop/rtthread-smart/tools/gnu_gcc/i386-linux-musleabi_for_x86_64-pc-linux-gnu/bin' elif CROSS_TOOL == 'keil': print('================ERROR============================') print('Not support keil yet!') @@ -32,11 +34,11 @@ BUILD = 'debug' if PLATFORM == 'gcc': # toolchains - PREFIX = '' - CC = PREFIX + 'gcc -m32 -fno-builtin -fno-stack-protector -nostdinc' - AS = PREFIX + 'gcc -m32' + PREFIX = 'i386-unknown-linux-musl-' + CC = PREFIX + 'gcc -fno-builtin -fno-stack-protector -nostdinc -nostdlib' + AS = PREFIX + 'gcc -nostdinc -nostdlib' AR = PREFIX + 'ar' - LINK = PREFIX + 'ld -melf_i386' + LINK = PREFIX + 'ld' TARGET_EXT = 'elf' SIZE = PREFIX + 'size' OBJDUMP = PREFIX + 'objdump' @@ -45,7 +47,7 @@ if PLATFORM == 'gcc': DEVICE = '' CFLAGS = DEVICE + ' -Wall' AFLAGS = ' -c' + DEVICE + ' -x assembler-with-cpp' - LFLAGS = DEVICE + ' -Map rtthread-ia32.map -T x86_ram.lds -nostdlib' + LFLAGS = DEVICE + ' -Map rtthread-i386.map -nostdlib -n -T link.lds' CPATH = '' LPATH = '' @@ -55,5 +57,5 @@ if PLATFORM == 'gcc': AFLAGS += ' -gdwarf-2' else: CFLAGS += ' -O2' - - POST_ACTION = OBJCPY + ' -O binary $TARGET rtthread.bin\n' + SIZE + ' $TARGET \n' +DUMP_ACTION = OBJDUMP + ' -D -S $TARGET > rtthread.asm\n' +POST_ACTION = OBJCPY + ' -O binary $TARGET rtthread.bin\n' + SIZE + ' $TARGET \n' \ No newline at end of file diff --git a/bsp/x86/src/extract.sh b/bsp/x86/src/extract.sh deleted file mode 100755 index 89f8baef7a10543839633101b7229115e707e2ea..0000000000000000000000000000000000000000 --- a/bsp/x86/src/extract.sh +++ /dev/null @@ -1,28 +0,0 @@ -#! /bin/sh - - -imap=$1 -iout=$2 - -echo "!!! extract symbol from $imap to $iout !!!" - -symlist="rt_kprintf \ -rt_kputs \ -rt_vsprintf \ -rt_sprintf \ -rt_snprintf \ -rt_thread_create \ -" - -echo "#ifndef RT_THREAD_SYM_H_H" > $iout -echo "#define RT_THREAD_SYM_H_H" >> $iout - -for sym in $symlist -do -dlim=`echo $sym | cut -b 1` -addr=`cat $imap | grep $sym | head -n 1 | cut -d $dlim -f 1` - -echo "#define __abs_$sym $addr" >> $iout -done - -echo "#endif /* RT_THREAD_SYM_H_H */" >> $iout diff --git a/bsp/x86/src/hello.c b/bsp/x86/src/hello.c deleted file mode 100644 index a075f18ef1c829e1ae6ae671843040579eca6d5f..0000000000000000000000000000000000000000 --- a/bsp/x86/src/hello.c +++ /dev/null @@ -1,36 +0,0 @@ - -#include -const char* g_str = "Hello World!"; - -static int a = 1234; -int b = 5678; - -extern void rt_kprintf(const char* fmt,...); - -int add(int a, int b) -{ - return a+b; -} - -int main(int argc, char* argv[]) -{ - int i; - char str[32] = "Hello World\n"; - - for(i=0; i - -typedef unsigned int size_t; - -typedef int (*sprintf_fcn_t)(char *buf ,const char *format, ...); -typedef int (*snprintf_fcn_t)(char *buf, size_t size, const char *format, ...); -typedef void (*puts_fcn_t)(const char *str); -typedef void (*printf_fcn_t)(const char *fmt, ...); - -#define printf ((printf_fcn_t)__abs_rt_kprintf) -#define puts ((printf_fcn_t)__abs_rt_kputs) -#define sprintf ((printf_fcn_t)__abs_rt_sprintf) -#define snprintf ((printf_fcn_t)__abs_rt_snprintf) - -#endif diff --git a/bsp/x86/x86_ram.lds b/bsp/x86/x86_ram.lds deleted file mode 100644 index afac69f04b8b5964202af8c783c56af65be65d19..0000000000000000000000000000000000000000 --- a/bsp/x86/x86_ram.lds +++ /dev/null @@ -1,55 +0,0 @@ -OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") -OUTPUT_ARCH(i386) -ENTRY(_start) -SECTIONS -{ - . = 0x00100000; - - . = ALIGN(4); - .text : - { - *(.init) - *(.text) - - /* section information for finsh shell */ - . = ALIGN(4); - __fsymtab_start = .; - KEEP(*(FSymTab)) - __fsymtab_end = .; - . = ALIGN(4); - __vsymtab_start = .; - KEEP(*(VSymTab)) - __vsymtab_end = .; - . = ALIGN(4); - __rtmsymtab_start = .; - KEEP(*(RTMSymTab)); - __rtmsymtab_end = .; - } - - . = ALIGN(4); - .rodata : { *(.rodata*) } - - . = ALIGN(4); - .data : { *(.data) } - - . = ALIGN(4); - __bss_start = .; - .bss : { *(.bss) } - __bss_end = .; - - /* stabs debugging sections. */ - .stab 0 : { *(.stab) } - .stabstr 0 : { *(.stabstr) } - .stab.excl 0 : { *(.stab.excl) } - .stab.exclstr 0 : { *(.stab.exclstr) } - .stab.index 0 : { *(.stab.index) } - .stab.indexstr 0 : { *(.stab.indexstr) } - .comment 0 : { *(.comment) } - .debug_abbrev 0 : { *(.debug_abbrev) } - .debug_info 0 : { *(.debug_info) } - .debug_line 0 : { *(.debug_line) } - .debug_pubnames 0 : { *(.debug_pubnames) } - .debug_aranges 0 : { *(.debug_aranges) } - - _end = .; -} diff --git a/components/finsh/shell.c b/components/finsh/shell.c index dbf285ae86f17d7f18b01499beaf1378d1963a8c..edb115bb0147fa1d43ab1b08d74b6acb04bb07de 100644 --- a/components/finsh/shell.c +++ b/components/finsh/shell.c @@ -413,6 +413,12 @@ static void shell_push_history(struct finsh_shell *shell) } #endif +#ifdef RT_USING_GDBSERVER +pid_t exec(char*, int, int, char**); +#else +pid_t exec(char*, int, char**); +#endif + void finsh_thread_entry(void *parameter) { int ch; @@ -450,7 +456,7 @@ void finsh_thread_entry(void *parameter) #endif rt_kprintf(FINSH_PROMPT); - + while (1) { ch = finsh_getchar(); diff --git a/components/libc/compilers/musl/SConscript b/components/libc/compilers/musl/SConscript index 6d5e8fc021b7d52d1ac52029d1cdf1951c6e394b..f3de78a7184eacfb362cb39fdfa5dd1a28811d64 100644 --- a/components/libc/compilers/musl/SConscript +++ b/components/libc/compilers/musl/SConscript @@ -9,7 +9,7 @@ group = [] if rtconfig.PLATFORM == 'gcc' and GetDepend('RT_USING_MUSL'): CPPDEFINES = ['__STDC_ISO_10646__=201206L', '_STDC_PREDEF_H'] LIBS = ['c', 'gcc'] - + if os.path.exists(os.path.join(cwd, 'libc', 'lib', 'libc.a')): CFLAGS = ' -nostdinc' CPPPATH = [cwd, cwd + '/libc/include'] diff --git a/components/lwp/Kconfig b/components/lwp/Kconfig index da5ca2a1906ad0a6b73c559cdc7d33ca6d758d13..469948ad5e421af0af8479fea9ee36407a97fa91 100644 --- a/components/lwp/Kconfig +++ b/components/lwp/Kconfig @@ -3,7 +3,7 @@ config RT_USING_LWP select RT_USING_DFS select RT_USING_LIBC select RT_USING_POSIX_CLOCKTIME - depends on ARCH_ARM_CORTEX_M || ARCH_ARM_ARM9 || ARCH_ARM_CORTEX_A || ARCH_RISCV64 + depends on ARCH_ARM_CORTEX_M || ARCH_ARM_ARM9 || ARCH_ARM_CORTEX_A || ARCH_RISCV64 || ARCH_X86 default n help The lwP is a light weight process running in user mode. diff --git a/components/lwp/SConscript b/components/lwp/SConscript index b77df25870b5a8a412037892a2dad92774417233..7dedd1389c2d82677075a6a7cb2b249b10e63609 100644 --- a/components/lwp/SConscript +++ b/components/lwp/SConscript @@ -5,7 +5,10 @@ cwd = GetCurrentDir() src = [] CPPPATH = [cwd] -support_arch = {"arm": ["cortex-m3", "cortex-m4", "cortex-m7", "arm926", "cortex-a"],"aarch64":["cortex-a"],"risc-v": ["rv64"]} +support_arch = {"arm": ["cortex-m3", "cortex-m4", "cortex-m7", "arm926", "cortex-a"], + "aarch64":["cortex-a"], + "risc-v": ["rv64"], + "x86": ["i386"]} platform_file = {'armcc': 'rvds.S', 'gcc': 'gcc.S', 'iar': 'iar.S'} platform = rtconfig.PLATFORM diff --git a/components/lwp/arch/x86/i386/SConscript b/components/lwp/arch/x86/i386/SConscript new file mode 100644 index 0000000000000000000000000000000000000000..c0d3aead777d389ef93caf0803640b8a4d5d89cf --- /dev/null +++ b/components/lwp/arch/x86/i386/SConscript @@ -0,0 +1,11 @@ +# RT-Thread building script for component + +from building import * + +cwd = GetCurrentDir() +src = Glob('*.c') + Glob('*.S') +CPPPATH = [cwd] + +group = DefineGroup('lwp-x86-i386', src, depend = ['RT_USING_LWP'], CPPPATH = CPPPATH) + +Return('group') diff --git a/components/lwp/arch/x86/i386/lwp_arch.c b/components/lwp/arch/x86/i386/lwp_arch.c new file mode 100644 index 0000000000000000000000000000000000000000..c4a78b8ed2d89bd8b255b859bdac5ec687381d89 --- /dev/null +++ b/components/lwp/arch/x86/i386/lwp_arch.c @@ -0,0 +1,351 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-7-14 JasonHu first version + */ + +#include +#include +#include + +#ifdef RT_USING_USERSPACE + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +extern size_t g_mmu_table[]; + +int arch_expand_user_stack(void *addr) +{ + int ret = 0; + size_t stack_addr = (size_t)addr; + + stack_addr &= ~PAGE_OFFSET_MASK; + if ((stack_addr >= (size_t)USER_STACK_VSTART) && (stack_addr < (size_t)USER_STACK_VEND)) + { + void *map = lwp_map_user(lwp_self(), (void *)stack_addr, PAGE_SIZE, RT_FALSE); + + if (map || lwp_user_accessable(addr, 1)) + { + ret = 1; + } + } + return ret; +} + +void *get_thread_kernel_stack_top(rt_thread_t thread) +{ + return RT_NULL; +} + +/** + * don't support this in i386, it's ok! + */ +void *lwp_get_user_sp() +{ + return RT_NULL; +} + +int arch_user_space_init(struct rt_lwp *lwp) +{ + rt_size_t *mmu_table; + + mmu_table = (rt_size_t *)rt_pages_alloc(0); + if (!mmu_table) + { + return -1; + } + rt_memset(mmu_table, 0, ARCH_PAGE_SIZE); + + lwp->end_heap = USER_HEAP_VADDR; + memcpy(mmu_table, g_mmu_table, ARCH_PAGE_SIZE / 4); + memset((rt_uint8_t *)mmu_table + ARCH_PAGE_SIZE / 4, 0, ARCH_PAGE_SIZE / 4 * 3); + rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, mmu_table, ARCH_PAGE_SIZE); + if (rt_hw_mmu_map_init(&lwp->mmu_info, (void*)USER_VADDR_START, USER_VADDR_TOP - USER_VADDR_START, mmu_table, PV_OFFSET) < 0) + { + rt_pages_free(mmu_table, 0); + return -1; + } + return 0; +} + +void *arch_kernel_mmu_table_get(void) +{ + return (void *)((char *)g_mmu_table); +} + +void arch_user_space_vtable_free(struct rt_lwp *lwp) +{ + if (lwp && lwp->mmu_info.vtable) + { + rt_pages_free(lwp->mmu_info.vtable, 0); + lwp->mmu_info.vtable = NULL; + } +} + +void lwp_set_thread_area(void *p) +{ + rt_hw_seg_tls_set((rt_ubase_t) p); + rt_thread_t cur = rt_thread_self(); + cur->thread_idr = p; /* update thread idr after first set */ +} + +void *rt_cpu_get_thread_idr(void) +{ + rt_thread_t cur = rt_thread_self(); + if (!cur->lwp) /* no lwp, don't get thread idr from tls seg */ + return NULL; + return (void *)rt_hw_seg_tls_get(); /* get thread idr from tls seg */ +} + +void rt_cpu_set_thread_idr(void *p) +{ + rt_thread_t cur = rt_thread_self(); + if (!cur->lwp) /* no lwp, don't set thread idr to tls seg */ + return; + rt_hw_seg_tls_set((rt_ubase_t) p); /* set tls seg addr as thread idr */ +} + +static void lwp_user_stack_init(rt_hw_stack_frame_t *frame) +{ + frame->ds = frame->es = USER_DATA_SEL; + frame->cs = USER_CODE_SEL; + frame->ss = USER_STACK_SEL; + frame->gs = USER_TLS_SEL; + frame->fs = 0; /* unused */ + + frame->edi = frame->esi = \ + frame->ebp = frame->esp_dummy = 0; + frame->eax = frame->ebx = \ + frame->ecx = frame->edx = 0; + + frame->error_code = 0; + frame->vec_no = 0; + + frame->eflags = (EFLAGS_MBS | EFLAGS_IF_1 | EFLAGS_IOPL_3); +} + +extern void lwp_switch_to_user(void *frame); +/** + * user entry, set frame. + * at the end of execute, we need enter user mode, + * in x86, we can set stack, arg, text entry in a stack frame, + * then pop then into register, final use iret to switch kernel mode to user mode. + */ +void lwp_user_entry(void *args, const void *text, void *ustack, void *k_stack) +{ + rt_uint8_t *stk = k_stack; + stk -= sizeof(struct rt_hw_stack_frame); + struct rt_hw_stack_frame *frame = (struct rt_hw_stack_frame *)stk; + + lwp_user_stack_init(frame); + frame->esp = (rt_uint32_t)ustack - 32; + frame->ebx = (rt_uint32_t)args; + frame->eip = (rt_uint32_t)text; + lwp_switch_to_user(frame); + /* should never return */ +} + +void lwp_exec_user(void *args, void *kernel_stack, void *user_entry) +{ + lwp_user_entry(args, (const void *)user_entry, (void *)USER_STACK_VEND, kernel_stack); +} + +extern void lwp_thread_return(); +extern void lwp_thread_return_end(); + +static void *lwp_copy_return_code_to_user_stack(void *ustack) +{ + size_t size = (size_t)lwp_thread_return_end - (size_t)lwp_thread_return; + void *retcode = (void *)((size_t)ustack - size); + memcpy(retcode, (void *)lwp_thread_return, size); + return retcode; +} + +/** + * when called sys_thread_create, need create a thread, after thread stared, will come here, + * like lwp_user_entry, will enter user mode, but we must set thread exit function. it looks like: + * void func(void *arg) + * { + * ... + * } + * when thread func return, we must call exit code to exit thread, or not the program runs away. + * so we need copy exit code to user and call exit code when func return. + */ +void lwp_user_thread_entry(void *args, const void *text, void *ustack, void *k_stack) +{ + RT_ASSERT(ustack != NULL); + + rt_uint8_t *stk; + stk = (rt_uint8_t *)((rt_uint8_t *)k_stack + sizeof(rt_ubase_t)); + stk = (rt_uint8_t *)RT_ALIGN_DOWN(((rt_ubase_t)stk), sizeof(rt_ubase_t)); + stk -= sizeof(struct rt_hw_stack_frame); + struct rt_hw_stack_frame *frame = (struct rt_hw_stack_frame *)stk; + + lwp_user_stack_init(frame); + + /* make user thread stack */ + unsigned long *retcode = lwp_copy_return_code_to_user_stack(ustack); /* copy ret code */ + unsigned long *retstack = (unsigned long *)RT_ALIGN_DOWN(((rt_ubase_t)retcode), sizeof(rt_ubase_t)); + + /** + * x86 call stack + * + * retcode here + * + * arg n + * arg n - 1 + * ... + * arg 2 + * arg 1 + * arg 0 + * eip (caller return addr, point to retcode) + * esp + */ + *(--retstack) = (unsigned long) args; /* arg */ + *(--retstack) = (unsigned long) retcode; /* ret eip */ + + frame->esp = (rt_uint32_t)retstack; + frame->eip = (rt_uint32_t)text; + lwp_switch_to_user(frame); + /* should never return */ +} + +rt_thread_t rt_thread_sp_to_thread(void *spmember_addr) +{ + return (rt_thread_t)(((rt_ubase_t)spmember_addr) - (offsetof(struct rt_thread, sp))); +} + +/** + * set exec context for fork/clone. + * user_stack(unused) + */ +void lwp_set_thread_context(void *exit_addr, void *new_thread_stack, void *user_stack, void **thread_sp) +{ + /** + * thread kernel stack was set to tss.esp0, when intrrupt/syscall occur, + * the stack frame will store in kernel stack top, so we can get the stack + * frame by kernel stack top. + */ + rt_hw_stack_frame_t *frame = (rt_hw_stack_frame_t *)((rt_ubase_t)new_thread_stack - sizeof(rt_hw_stack_frame_t)); + + frame->eax = 0; /* child return 0 */ + + rt_hw_context_t *context = (rt_hw_context_t *) (((rt_uint32_t *)frame) - HW_CONTEXT_MEMBER_NR); + context->eip = (void *)exit_addr; /* when thread started, jump to intr exit for enter user mode */ + context->ebp = context->ebx = context->esi = context->edi = 0; + + /** + * set sp as the address of first member of rt_hw_context, + * when scheduler call switch, pop stack from context stack. + */ + *thread_sp = (void *)&context->ebp; + + /** + * after set context, the stack like this: + * + * ----------- + * stack frame| eax = 0 + * ----------- + * context(only HW_CONTEXT_MEMBER_NR)| eip = rt_hw_intr_exit + * ----------- + * thread sp | to <- rt_hw_context_switch(from, to) + * ----------- + */ +} + +#ifdef RT_USING_SIGNALS + +#define SIGNAL_RET_CODE_SIZE 16 + +struct rt_signal_frame +{ + char *ret_addr; /* return addr when handler return */ + int signo; /* signal for user handler arg */ + rt_hw_stack_frame_t frame; /* save kernel signal stack */ + char ret_code[SIGNAL_RET_CODE_SIZE]; /* save return code */ +}; +typedef struct rt_signal_frame rt_signal_frame_t; + +extern void lwp_signal_return(); +extern void lwp_signal_return_end(); + +void lwp_try_do_signal(rt_hw_stack_frame_t *frame) +{ + if (!lwp_signal_check()) + return; + + /* 1. backup signal mask */ + int signal = lwp_signal_backup((void *) frame->esp, (void *) frame->eip, (void *) frame->eflags); + + /* 2. get signal handler */ + lwp_sighandler_t handler = lwp_sighandler_get(signal); + if (handler == RT_NULL) /* no handler, ignore */ + { + lwp_signal_restore(); + return; + } + + rt_base_t level = rt_hw_interrupt_disable(); + /* 3. backup frame */ + rt_signal_frame_t *sig_frame = (rt_signal_frame_t *)((frame->esp - sizeof(rt_signal_frame_t)) & -8UL); + memcpy(&sig_frame->frame, frame, sizeof(rt_hw_stack_frame_t)); + sig_frame->signo = signal; + + /** + * 4. copy user return code into user stack + * + * save current frame on user stack. the user stack like: + * + * ---------- + * user code stack + * ----------+ -> esp before enter kernel + * signal frame + * ----------+ -> esp when handle signal handler + * signal handler stack + * ---------- + */ + size_t ret_code_size = (size_t)lwp_signal_return_end - (size_t)lwp_signal_return; + memcpy(sig_frame->ret_code, (void *)lwp_signal_return, ret_code_size); + sig_frame->ret_addr = sig_frame->ret_code; + + /* 5. jmp to user execute handler, update frame register info */ + lwp_user_stack_init(frame); + frame->eip = (rt_uint32_t) handler; + frame->esp = (rt_uint32_t) sig_frame; + + rt_hw_interrupt_enable(level); +} + +void lwp_signal_do_return(rt_hw_stack_frame_t *frame) +{ + /** + * ASSUME: in x86, each stack push and pop element is 4 byte. so STACK_ELEM_SIZE = sizeof(int) => 4. + * when signal handler return, the stack move to the buttom of signal frame. + * but return will pop eip from esp, then {esp += STACK_ELEM_SIZE}, thus {esp = (signal frame) + STACK_ELEM_SIZE}. + * so {(signal frame) = esp - STACK_ELEM_SIZE} + */ + rt_signal_frame_t *sig_frame = (rt_signal_frame_t *)(frame->esp - sizeof(rt_uint32_t)); + memcpy(frame, &sig_frame->frame, sizeof(rt_hw_stack_frame_t)); + + /** + * restore signal info, but don't use rt_user_context, + * we use sig_frame to restore stack frame + */ + lwp_signal_restore(); +} +#endif /* RT_USING_SIGNALS */ + +#endif /* RT_USING_USERSPACE */ diff --git a/components/lwp/arch/x86/i386/lwp_arch.h b/components/lwp/arch/x86/i386/lwp_arch.h new file mode 100644 index 0000000000000000000000000000000000000000..74049be6d0091587ac07274343f728c43574638a --- /dev/null +++ b/components/lwp/arch/x86/i386/lwp_arch.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-07-18 JasonHu first version + */ + +#ifndef LWP_ARCH_H__ +#define LWP_ARCH_H__ + +#include +#include + +#ifdef RT_USING_USERSPACE +#define USER_VADDR_TOP 0xFFFFF000UL +#define USER_HEAP_VEND 0xE0000000UL +#define USER_HEAP_VADDR 0x90000000UL +#define USER_STACK_VSTART 0x80000000UL +#define USER_STACK_VEND USER_HEAP_VADDR +#define LDSO_LOAD_VADDR 0x70000000UL +#define USER_VADDR_START 0x40000000UL +#define USER_LOAD_VADDR USER_VADDR_START + +#define SIGNAL_RETURN_SYSCAL_ID 0xe000 + +#ifdef __cplusplus +extern "C" { +#endif + +int arch_user_space_init(struct rt_lwp *lwp); +void arch_user_space_vtable_free(struct rt_lwp *lwp); +void *arch_kernel_mmu_table_get(void); +void arch_kuser_init(rt_mmu_info *mmu_info, void *vectors); +int arch_expand_user_stack(void *addr); + +rt_thread_t rt_thread_sp_to_thread(void *spmember_addr); + +void lwp_signal_do_return(rt_hw_stack_frame_t *frame); + +rt_inline unsigned long ffz(unsigned long x) +{ + return __builtin_ffs(~x) - 1; +} + +#ifdef __cplusplus +} +#endif + +#endif /* RT_USING_USERSPACE */ + +#endif /*LWP_ARCH_H__*/ diff --git a/components/lwp/arch/x86/i386/lwp_gcc.S b/components/lwp/arch/x86/i386/lwp_gcc.S new file mode 100644 index 0000000000000000000000000000000000000000..bda54e2924365f7e1661124dfe19fb3694748e45 --- /dev/null +++ b/components/lwp/arch/x86/i386/lwp_gcc.S @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-7-14 JasonHu first version + */ + +#include "rtconfig.h" + +.section .text.lwp + +/* + * void lwp_switch_to_user(frame); + */ +.global lwp_switch_to_user +lwp_switch_to_user: + movl 0x4(%esp), %esp + addl $4,%esp // skip intr no + popal + popl %gs + popl %fs + popl %es + popl %ds + addl $4, %esp // skip error_code + iret // enter to user mode + +.extern syscall_exit +.global sys_fork +.global sys_vfork +.global sys_fork_exit +sys_fork: +sys_vfork: + jmp _sys_fork +sys_fork_exit: + jmp syscall_exit + +.global sys_clone +.global sys_clone_exit +sys_clone: + jmp _sys_clone +sys_clone_exit: + jmp syscall_exit + +/** + * rt thread return code + */ +.align 4 +.global lwp_thread_return +lwp_thread_return: + movl $1, %eax // eax = 1, sys_exit + movl $0, %ebx + int $0x80 +.align 4 +.global lwp_thread_return_end +lwp_thread_return_end: + +#ifdef RT_USING_SIGNALS +/** + * signal return code + */ +.align 4 +.global lwp_signal_return +lwp_signal_return: + movl $0xe000, %eax // special syscall id for return code + int $0x80 +.align 4 +.global lwp_signal_return_end +lwp_signal_return_end: + +#endif /* RT_USING_SIGNALS */ diff --git a/components/lwp/arch/x86/i386/reloc.c b/components/lwp/arch/x86/i386/reloc.c new file mode 100644 index 0000000000000000000000000000000000000000..04bbe8b4ed2923c24319992516a1a9e48a0086a8 --- /dev/null +++ b/components/lwp/arch/x86/i386/reloc.c @@ -0,0 +1,31 @@ +#include +#include +#include +#include +#ifdef RT_USING_USERSPACE +#include +#include +#endif + +typedef struct +{ + Elf32_Word st_name; + Elf32_Addr st_value; + Elf32_Word st_size; + unsigned char st_info; + unsigned char st_other; + Elf32_Half st_shndx; +} Elf32_sym; + +#ifdef RT_USING_USERSPACE +void lwp_elf_reloc(rt_mmu_info *m_info, void *text_start, void *rel_dyn_start, size_t rel_dyn_size, void *got_start, size_t got_size, Elf32_sym *dynsym) +{ + +} +#else + +void lwp_elf_reloc(void *text_start, void *rel_dyn_start, size_t rel_dyn_size, void *got_start, size_t got_size, Elf32_sym *dynsym) +{ + +} +#endif diff --git a/components/lwp/lwp_syscall.c b/components/lwp/lwp_syscall.c index 2886c8ecc96fb76159db499b3303412344f1392f..81dae58dfd3e3d826d2e5f365094dd48f0d04489 100644 --- a/components/lwp/lwp_syscall.c +++ b/components/lwp/lwp_syscall.c @@ -169,6 +169,7 @@ int sys_futex(int *uaddr, int op, int val, void *timeout, void *uaddr2, int val3 #define INTF_IPV6_V6ONLY 26 #define IMPL_IPV6_V6ONLY 27 +#ifdef RT_USING_SAL static void convert_sockopt(int *level, int *optname) { if (*level == INTF_SOL_SOCKET) @@ -316,6 +317,7 @@ static void convert_sockopt(int *level, int *optname) } } +#endif /* RT_USING_SAL */ #ifdef RT_USING_LWIP static void sockaddr_tolwip(const struct musl_sockaddr *std, struct sockaddr *lwip) diff --git a/libcpu/Kconfig b/libcpu/Kconfig index 93a534a57d65bb223e4bb96ebb5ddaf5650c95c3..cf8ed60d19d74b24f30a54a8c1bbedbbe859d493 100644 --- a/libcpu/Kconfig +++ b/libcpu/Kconfig @@ -159,3 +159,6 @@ config ARCH_TIDSP_C28X config ARCH_HOST_SIMULATOR bool + +config ARCH_X86 + bool \ No newline at end of file diff --git a/libcpu/x86/SConscript b/libcpu/x86/SConscript new file mode 100644 index 0000000000000000000000000000000000000000..01afd9a24eef4c92c317509029391d59602a2033 --- /dev/null +++ b/libcpu/x86/SConscript @@ -0,0 +1,20 @@ +# RT-Thread building script for bridge +import os +from building import * + +Import('rtconfig') + +cwd = GetCurrentDir() +group = [] +list = os.listdir(cwd) + +# add common code files +if rtconfig.CPU == "i386" : + group = group +else : + group = group + SConscript(os.path.join(cwd, 'common', 'SConscript')) + +# cpu porting code files +group = group + SConscript(os.path.join(cwd, rtconfig.CPU, 'SConscript')) + +Return('group') \ No newline at end of file diff --git a/libcpu/x86/i386/SConscript b/libcpu/x86/i386/SConscript new file mode 100644 index 0000000000000000000000000000000000000000..b0ae20ba0298e00e05eba2ddc73df9424d22ec79 --- /dev/null +++ b/libcpu/x86/i386/SConscript @@ -0,0 +1,14 @@ +# RT-Thread building script for component + +from building import * + +Import('rtconfig') + +cwd = GetCurrentDir() +src = Glob('*.c') + Glob('*.cpp') + Glob('*_gcc.S') +CPPPATH = [cwd] +ASFLAGS = '' + +group = DefineGroup('cpu', src, depend = [''], CPPPATH = CPPPATH, ASFLAGS = ASFLAGS) + +Return('group') diff --git a/libcpu/x86/i386/backtrace.c b/libcpu/x86/i386/backtrace.c new file mode 100644 index 0000000000000000000000000000000000000000..a72562a1abcd1e221bf19edbb1207573a85b37fb --- /dev/null +++ b/libcpu/x86/i386/backtrace.c @@ -0,0 +1,33 @@ +#include +#include + +static int rt_hw_backtrace(void **buffer, int size) +{ + int i = 0; + int n = 0; + unsigned int _ebp = 0; + unsigned int _eip = 0; + __asm__ __volatile__(" movl %%ebp, %0" :"=g" (_ebp)::"memory"); + for(i = 0; i < size && _ebp != 0 && *(unsigned int*)_ebp != 0 && + *(unsigned int *)_ebp != _ebp; i++) { + _eip = (unsigned int)((unsigned int*)_ebp + 1); + _eip = *(unsigned int*)_eip; + _ebp = *(unsigned int*)_ebp; + buffer[i] = (void*)_eip; + n++; + } + return n; +} + +void rt_hw_print_backtrace(void) +{ + void *buf[BACKTRACE_CNT] = {RT_NULL}; + int cnt = rt_hw_backtrace(buf, BACKTRACE_CNT); + rt_kprintf("[!] Call backtrace:\n"); + int i; + for (i = 0; i < cnt; i++) + { + rt_kprintf("%d: call %p\n", i, buf[i]); + } + rt_kprintf("[!] Call backtrace done.\n"); +} diff --git a/libcpu/x86/i386/backtrace.h b/libcpu/x86/i386/backtrace.h new file mode 100644 index 0000000000000000000000000000000000000000..bc4d686bf9bac1a933359a9db6d4092963b2d3e8 --- /dev/null +++ b/libcpu/x86/i386/backtrace.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-07-28 JasonHu first version + */ + +#ifndef __HW_BACKTRACE_H__ +#define __HW_BACKTRACE_H__ + +#define BACKTRACE_CNT 10 +void rt_hw_print_backtrace(void); + +#endif /* __HW_BACKTRACE_H__ */ diff --git a/libcpu/x86/i386/bitmap.c b/libcpu/x86/i386/bitmap.c new file mode 100644 index 0000000000000000000000000000000000000000..f0399dd4c00266cceda8f907bde4bb2a5b22ab7e --- /dev/null +++ b/libcpu/x86/i386/bitmap.c @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-08-04 JasonHu First Version + */ + +#include +#include +#include + +void rt_bitmap_init(rt_bitmap_t *bitmap, uint8_t *bits, rt_size_t byte_len) +{ + bitmap->bits = bits; + bitmap->byte_length = byte_len; + memset(bitmap->bits, 0, bitmap->byte_length); +} + +static rt_bool_t rt_bitmap_test(rt_bitmap_t *bitmap, rt_ubase_t index) +{ + rt_ubase_t byte_idx = index / 8; + rt_ubase_t bit_odd = index % 8; + return (bitmap->bits[byte_idx] & (RT_BITMAP_MASK << bit_odd)); +} + +rt_base_t rt_bitmap_scan(rt_bitmap_t *bitmap, rt_size_t count) +{ + if (!bitmap || !count) + { + return -1; + } + + rt_ubase_t idx_byte = 0; + + while ((0xff == bitmap->bits[idx_byte]) && (idx_byte < bitmap->byte_length)) + { + idx_byte++; + } + + if (idx_byte == bitmap->byte_length) /* out of array range */ + { + return -1; + } + + rt_base_t idx_bit = 0; + + while ((rt_uint8_t)(RT_BITMAP_MASK << idx_bit) & bitmap->bits[idx_byte]) + { + idx_bit++; + } + + rt_base_t idx_start = idx_byte * 8 + idx_bit; + if (count == 1) + { + return idx_start; + } + + rt_ubase_t bit_left = (bitmap->byte_length * 8 - idx_start); + rt_ubase_t next_bit = idx_start + 1; + rt_ubase_t ret_count = 1; + + idx_start = -1; + while (bit_left-- > 0) + { + if (!(rt_bitmap_test(bitmap, next_bit))) + { + ret_count++; + } + else + { + ret_count = 0; /* no consecutive bits, reset count */ + } + + if (ret_count == count) + { + idx_start = next_bit - ret_count + 1; + break; + } + next_bit++; + } + return idx_start; +} + +void rt_bitmap_set(rt_bitmap_t *bitmap, rt_ubase_t index, rt_bool_t value) +{ + rt_ubase_t byte_idx = index / 8; + rt_ubase_t bit_odd = index % 8; + + if (value) { + bitmap->bits[byte_idx] |= (RT_BITMAP_MASK << bit_odd); + } else { + bitmap->bits[byte_idx] &= ~(RT_BITMAP_MASK << bit_odd); + } +} + +rt_bool_t rt_bitmap_change(rt_bitmap_t *bitmap, rt_ubase_t index) +{ + rt_ubase_t byte_idx = index / 8; + rt_ubase_t bit_odd = index % 8; + + bitmap->bits[byte_idx] ^= (RT_BITMAP_MASK << bit_odd); /* xor */ + return (bitmap->bits[byte_idx] & (RT_BITMAP_MASK << bit_odd)); +} + +rt_bool_t rt_bitmap_test_and_change(rt_bitmap_t *bitmap, rt_ubase_t index) +{ + rt_ubase_t byte_idx = index / 8; + rt_ubase_t bit_odd = index % 8; + + rt_bool_t ret = (rt_bool_t) bitmap->bits[byte_idx] & (RT_BITMAP_MASK << bit_odd); + + bitmap->bits[byte_idx] ^= (RT_BITMAP_MASK << bit_odd); /* xor */ + return ret; +} diff --git a/libcpu/x86/i386/bitmap.h b/libcpu/x86/i386/bitmap.h new file mode 100644 index 0000000000000000000000000000000000000000..7c480d7dc89e4f106458f05a14ba0fc940af9f65 --- /dev/null +++ b/libcpu/x86/i386/bitmap.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-08-04 JasonHu first version + */ + +#ifndef __RT_BITMAP_H__ +#define __RT_BITMAP_H__ + +#include + +#define RT_BITMAP_MASK 1UL + +/** + * rt_bitmap structure + */ +struct rt_bitmap +{ + rt_size_t byte_length; /**< rt_bitmap size in byte. */ + rt_uint8_t *bits; /**< rt_bitmap bits base addr. */ +}; +typedef struct rt_bitmap rt_bitmap_t; + +void rt_bitmap_init(rt_bitmap_t *bitmap, uint8_t *bits, rt_size_t byte_len); +rt_base_t rt_bitmap_scan(rt_bitmap_t *bitmap, rt_size_t count); +void rt_bitmap_set(rt_bitmap_t *bitmap, rt_ubase_t index, rt_bool_t value); +rt_bool_t rt_bitmap_change(rt_bitmap_t *bitmap, rt_ubase_t index); +rt_bool_t rt_bitmap_test_and_change(rt_bitmap_t *bitmap, rt_ubase_t index); + +#endif /* __RT_BITMAP_H__ */ diff --git a/libcpu/x86/i386/boot_module.c b/libcpu/x86/i386/boot_module.c new file mode 100644 index 0000000000000000000000000000000000000000..f637a83a5df11bdfbec0c5cf4704b329b00efcd2 --- /dev/null +++ b/libcpu/x86/i386/boot_module.c @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-07-15 JasonHu,GUI first version + */ + +#include "boot_module.h" +#include "multiboot2.h" +#include + +static void boot_module_init(struct multiboot_tag *tag) +{ + struct boot_modules_info_block *modules_info = (struct boot_modules_info_block *)BOOT_MODULE_INFO_ADDR; + int index = modules_info->modules_num; + + if (index >= MAX_BOOT_MODULES_NUM + || modules_info->modules_size + ((struct multiboot_tag_module *)tag)->size > MAX_BOOT_MODULES_SIZE) + { + return; + } + + modules_info->modules[index].size = ((struct multiboot_tag_module *)tag)->size; + modules_info->modules[index].start = ((struct multiboot_tag_module *)tag)->mod_start; + modules_info->modules[index].end = ((struct multiboot_tag_module *)tag)->mod_end; + modules_info->modules[index].type = BOOT_MODULE_UNKNOWN; + + modules_info->modules_size += modules_info->modules[index].size; + ++modules_info->modules_num; +} + +static void boot_memory_init(struct multiboot_tag *tag) +{ + unsigned long mem_upper = ((struct multiboot_tag_basic_meminfo *)tag)->mem_upper; + unsigned long mem_lower = ((struct multiboot_tag_basic_meminfo *)tag)->mem_lower; + // memory size store in 0x000001000 + *((unsigned int *)0x000001000) = ((mem_upper - mem_lower) << 10) + 0x100000; +} + +int rt_boot_setup_entry(unsigned long magic, unsigned long addr) +{ + // whether a multiboot + if (magic != MULTIBOOT2_BOOTLOADER_MAGIC || addr & 7) + return -1; + struct multiboot_tag *tag; + + boot_module_info_init(); + + for (tag = (struct multiboot_tag*)(addr + 8); tag->type != MULTIBOOT_TAG_TYPE_END; \ + tag = (struct multiboot_tag*)((rt_uint8_t *)tag + ((tag->size + 7) & ~7))) + { + switch (tag->type) + { + case MULTIBOOT_TAG_TYPE_MODULE: + boot_module_init(tag); + break; + case MULTIBOOT_TAG_TYPE_BASIC_MEMINFO: + boot_memory_init(tag); + break; + default: // other type, do nothing + break; + } + } + return 0; +} diff --git a/libcpu/x86/i386/boot_module.h b/libcpu/x86/i386/boot_module.h new file mode 100644 index 0000000000000000000000000000000000000000..8bc880ab491f6d0d63cae58041fa68b03c5f7d4c --- /dev/null +++ b/libcpu/x86/i386/boot_module.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-07-15 JasonHu,GuEe-GUI first version + */ + +#ifndef __BOOT_MODULE_H__ +#define __BOOT_MODULE_H__ + +#include + +#define BOOT_MODULE_INFO_ADDR 0x3F1000 + +#define SIZE_MB (1024*1024) +#define MAX_BOOT_MODULES_NUM 1 +#define MAX_BOOT_MODULES_SIZE (1 * SIZE_MB) + +enum boot_module_type +{ + // Unknown type + BOOT_MODULE_UNKNOWN = 0, +}; + +struct boot_modules_info_block +{ + rt_uint32_t modules_num; + rt_uint32_t modules_size; + struct { + rt_uint32_t type; + rt_uint32_t size; + rt_uint32_t start; + rt_uint32_t end; + } modules[MAX_BOOT_MODULES_NUM]; +} __attribute__((packed)); + +rt_inline void boot_module_info_init() +{ + struct boot_modules_info_block *modules_info = (struct boot_modules_info_block *)BOOT_MODULE_INFO_ADDR; + modules_info->modules_num = 0; + modules_info->modules_size = 0; +} + +rt_inline void *boot_module_info_find(unsigned long base_addr, enum boot_module_type type) +{ + int i; + struct boot_modules_info_block *modules_info; + modules_info = (struct boot_modules_info_block *)(base_addr + BOOT_MODULE_INFO_ADDR); + + for (i = 0; i < modules_info->modules_num; ++i) + { + if (modules_info->modules[i].type == type) + { + return (void*)(base_addr + modules_info->modules[i].start); + } + } + return (void*)0; +} + +#endif /* __BOOT_MODULE_H__ */ diff --git a/libcpu/x86/i386/cache.c b/libcpu/x86/i386/cache.c new file mode 100644 index 0000000000000000000000000000000000000000..cb36fdd4d135fb18618689e16f8f12a1244dc566 --- /dev/null +++ b/libcpu/x86/i386/cache.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-07-14 JasonHu first version + */ + +#include +#include + +#include "cache.h" + +void rt_hw_cpu_icache_invalidate(void *addr,int size) +{ + +} + +void rt_hw_cpu_dcache_invalidate(void *addr,int size) +{ + +} + +void rt_hw_cpu_dcache_clean(void *addr,int size) +{ + +} + +void rt_hw_cpu_icache_ops(int ops,void *addr,int size) +{ + +} + +void rt_hw_cpu_dcache_ops(int ops,void *addr,int size) +{ + +} + +void rt_hw_cpu_dcache_flush_all() +{ + +} + +void rt_hw_cpu_icache_invalidate_all() +{ + +} + +rt_base_t rt_hw_cpu_icache_status() +{ + return 0; +} + +rt_base_t rt_hw_cpu_dcache_status() +{ + return 0; +} + +int sys_cacheflush(void *addr, int size, int cache) +{ + return 0; +} diff --git a/libcpu/x86/i386/cache.h b/libcpu/x86/i386/cache.h new file mode 100644 index 0000000000000000000000000000000000000000..273adea2842a311024c5d045f8ef584c4499486a --- /dev/null +++ b/libcpu/x86/i386/cache.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-7-19 JasonHu The first version + */ + +#ifndef __CACHE_H__ +#define __CACHE_H__ + +#include + +rt_inline rt_uint32_t rt_cpu_icache_line_size() +{ + return 0; +} + +rt_inline rt_uint32_t rt_cpu_dcache_line_size() +{ + return 0; +} + +void rt_hw_cpu_icache_invalidate(void *addr,int size); +void rt_hw_cpu_dcache_invalidate(void *addr,int size); +void rt_hw_cpu_dcache_clean(void *addr,int size); +void rt_hw_cpu_icache_ops(int ops,void *addr,int size); +void rt_hw_cpu_dcache_ops(int ops,void *addr,int size); +void rt_hw_cpu_dcache_flush_all(); +void rt_hw_cpu_icache_invalidate_all(); +rt_base_t rt_hw_cpu_icache_status(); +rt_base_t rt_hw_cpu_dcache_status(); + +#endif /* __CACHE_H__ */ diff --git a/libcpu/x86/i386/context_gcc.S b/libcpu/x86/i386/context_gcc.S new file mode 100644 index 0000000000000000000000000000000000000000..455e9cd91a80fb684203cfda3b1fb4d8e052680f --- /dev/null +++ b/libcpu/x86/i386/context_gcc.S @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021/07/14 JasonHu First version + */ + +#define __ASSEMBLY__ +#include + +.code32 +.text + +/* + * void rt_hw_context_switch_to_real(rt_ubase_t to); + */ +.globl rt_hw_context_switch_to_real +rt_hw_context_switch_to_real: + movl 0x4(%esp), %eax // get thread "to" + movl (%eax), %esp // restore sp + + popl %ebp + popl %ebx + popl %edi + popl %esi + ret + +/* + * void rt_hw_context_switch_real(rt_ubase_t from, rt_ubase_t to); + */ +.globl rt_hw_context_switch_real +rt_hw_context_switch_real: + pushl %esi + pushl %edi + pushl %ebx + pushl %ebp + + movl 0x14(%esp), %eax // get "from" + movl %esp, (%eax) // save sp + + movl 0x18(%esp), %eax // get "to" + movl (%eax), %esp // restore sp + + popl %ebp + popl %ebx + popl %edi + popl %esi + ret diff --git a/libcpu/x86/i386/cpuport.c b/libcpu/x86/i386/cpuport.c new file mode 100644 index 0000000000000000000000000000000000000000..3f6e296cf8666f74da5c9182099c9624fce7d058 --- /dev/null +++ b/libcpu/x86/i386/cpuport.c @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-07-14 JasonHu First Version + */ + +#include +#include +#include +#include + +#include "cpuport.h" +#include "tss.h" +#include "segment.h" +#include "gate.h" +#include "stackframe.h" +#include "page.h" +#include "mmu.h" +#include +#include +#include + +/** + * @brief from thread used interrupt context switch + * + */ +volatile rt_ubase_t rt_interrupt_from_thread = 0; +/** + * @brief to thread used interrupt context switch + * + */ +volatile rt_ubase_t rt_interrupt_to_thread = 0; +/** + * @brief flag to indicate context switch in interrupt or not + * + */ +volatile rt_ubase_t rt_thread_switch_interrupt_flag = 0; + +extern void rt_hw_context_switch_to_real(rt_ubase_t to); +extern void rt_hw_context_switch_real(rt_ubase_t from, rt_ubase_t to); + +/** + * any thread will come here when first start + */ +static void rt_hw_thread_entry(hw_thread_func_t function, void *arg, void (*texit)()) +{ + rt_hw_interrupt_enable(EFLAGS_IF); /* enable interrupt, avoid not sched */ + function(arg); + if (texit) + texit(); + dbg_log(DBG_ERROR, "rt thread execute done, should never be here!"); + for (;;) + ; +} + +rt_uint8_t *rt_hw_stack_init(void *tentry, + void *parameter, + rt_uint8_t *stack_addr, + void *texit) +{ + rt_uint8_t *stk; + stk = stack_addr + sizeof(rt_ubase_t); + stk = (rt_uint8_t *)RT_ALIGN_DOWN((rt_ubase_t)stk, sizeof(rt_ubase_t)); + stk -= sizeof(struct rt_hw_stack_frame); + stk -= sizeof(rt_hw_context_t); + + rt_hw_context_t *context = (rt_hw_context_t *)stk; + context->eip = rt_hw_thread_entry; + context->function = tentry; + context->arg = parameter; + context->texit = texit; + context->ebp = context->ebx = context->esi = context->edi = 0; + return stk; +} + +void rt_hw_context_switch_to(rt_ubase_t to) +{ + rt_thread_t to_thread = rt_thread_sp_to_thread((void *)to); + +#ifdef RT_USING_USERSPACE + /** + * update kernel esp0 as to thread's kernel stack, to make sure process can't + * get the correct kernel stack from tss esp0 when interrupt occur in user mode. + */ + rt_ubase_t stacktop = (rt_ubase_t)(to_thread->stack_addr + to_thread->stack_size); + rt_hw_tss_set_kstacktop(stacktop); + lwp_mmu_switch(to_thread); /* switch mmu before switch context */ +#endif /* RT_USING_USERSPACE */ + rt_hw_context_switch_to_real(to); +} + +void rt_hw_context_switch(rt_ubase_t from, rt_ubase_t to) +{ + rt_thread_t from_thread = rt_thread_sp_to_thread((void *)from); + rt_thread_t to_thread = rt_thread_sp_to_thread((void *)to); + +#ifdef RT_USING_LWP + lwp_user_setting_save(from_thread); +#endif /* RT_USING_LWP */ + +#ifdef RT_USING_USERSPACE + /** + * update kernel esp0 as to thread's kernel stack, to make sure process can't + * get the correct kernel stack from tss esp0 when interrupt occur in user mode. + */ + rt_ubase_t stacktop = (rt_ubase_t)(to_thread->stack_addr + to_thread->stack_size); + rt_hw_tss_set_kstacktop(stacktop); + lwp_mmu_switch(to_thread); /* switch mmu before switch context */ +#endif /* RT_USING_USERSPACE */ + + rt_hw_context_switch_real(from, to); + +#ifdef RT_USING_LWP + lwp_user_setting_restore(to_thread); +#endif /* RT_USING_LWP */ +} + +/** + * when called rt_hw_context_switch_interrupt, just set from and to thread stack. + * when interrupt leave, we check rt_thread_switch_interrupt_flag. if it's 1, we + * will set rt_thread_switch_interrupt_flag as 0 then do context switch. + * see interrupt_gcc.S on lable rt_hw_intr_thread_switch. + */ +void rt_hw_context_switch_interrupt(rt_ubase_t from, rt_ubase_t to, rt_thread_t from_thread, rt_thread_t to_thread) +{ + if (rt_thread_switch_interrupt_flag == 0) + rt_interrupt_from_thread = from; + + rt_interrupt_to_thread = to; + rt_thread_switch_interrupt_flag = 1; + return ; +} + +void rt_hw_cpu_shutdown() +{ +} + +void rt_hw_cpu_init() +{ + rt_hw_segment_init(); + rt_hw_gate_init(); + rt_hw_tss_init(); +} diff --git a/libcpu/x86/i386/cpuport.h b/libcpu/x86/i386/cpuport.h new file mode 100644 index 0000000000000000000000000000000000000000..a718da3d28ca03ebdeab30988739696c0934b9f1 --- /dev/null +++ b/libcpu/x86/i386/cpuport.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-7-14 JasonHu The first version + */ + +#ifndef __CPUPORT_H__ +#define __CPUPORT_H__ + +#include +#include + +#ifndef __ASSEMBLY__ + +/* write memory */ +rt_inline void rt_hw_dsb(void) +{ + asm volatile ("sfence": : :"memory"); +} + +/* read memory */ +rt_inline void rt_hw_dmb(void) +{ + asm volatile ("lfence": : :"memory"); +} + +/* instruction */ +rt_inline void rt_hw_isb(void) +{ + asm volatile ("": : :"memory"); +} + +#endif /* __ASSEMBLY__ */ + +void rt_hw_cpu_init(); + +#endif /* __CPUPORT_H__ */ diff --git a/libcpu/x86/i386/dma.c b/libcpu/x86/i386/dma.c new file mode 100644 index 0000000000000000000000000000000000000000..e8f4bb2a2514687495f3b932ae8853c5a20373de --- /dev/null +++ b/libcpu/x86/i386/dma.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-08-04 JasonHu First Version + */ + +#include +#include +#include +#include +#include +#include + +/** + * dma is physical addr + */ +struct rt_hw_dma_manager +{ + rt_ubase_t start; + rt_ubase_t end; + rt_bitmap_t bitmap; +}; +typedef struct rt_hw_dma_manager rt_hw_dma_manager_t; + +static rt_hw_dma_manager_t g_dma_manager; + +rt_err_t rt_hw_dma_init(rt_ubase_t start, rt_ubase_t end) +{ + g_dma_manager.start = start; + g_dma_manager.end = end; + rt_size_t pages = (end - start) / ARCH_PAGE_SIZE; + RT_ASSERT(pages > 0); + rt_size_t byte_len = pages / 8; + rt_uint8_t *bits = rt_malloc(byte_len); + if (!bits) + { + return RT_ENOMEM; + } + rt_kprintf("dma: range:%x~%x, pages:%d, bitmap bits:%x, byte_len:0x%x\n", + start, end, pages, bits, byte_len); + rt_bitmap_init(&g_dma_manager.bitmap, bits, byte_len); + + return RT_EOK; +} + +static rt_ubase_t dma_alloc_pages(rt_size_t npages) +{ + rt_base_t off = rt_bitmap_scan(&g_dma_manager.bitmap, npages); + if (off < 0) + { + return 0; + } + int i; + for (i = 0; i < npages; i++) + { + rt_bitmap_set(&g_dma_manager.bitmap, off + i, 1); + } + return (rt_ubase_t) (g_dma_manager.start + off * ARCH_PAGE_SIZE); +} + +static void dma_free_pages(rt_ubase_t addr, rt_size_t npages) +{ + rt_ubase_t start_idx = (addr - g_dma_manager.start) / ARCH_PAGE_SIZE; + int i; + for (i = 0; i < npages; i++) + { + rt_bitmap_set(&g_dma_manager.bitmap, start_idx + i, 0); + } +} + +rt_err_t rt_hw_dma_alloc(rt_hw_dma_t *dma) +{ + if (!dma->size) + { + return RT_EINVAL; + } + int npages = (dma->size + (ARCH_PAGE_SIZE - 1)) / ARCH_PAGE_SIZE; + dma->paddr = dma_alloc_pages(npages); + if(dma->paddr == 0) + { + return RT_ENOMEM; + } + + dma->vaddr = rt_hw_phy2vir(dma->paddr); + rt_memset((void *)dma->vaddr, 0, npages * ARCH_PAGE_SIZE); + return RT_EOK; +} + +rt_err_t rt_hw_dma_free(rt_hw_dma_t *dma) +{ + if (!dma->size || !dma->paddr || !dma->vaddr) + return RT_EINVAL; + + dma_free_pages(dma->paddr, (dma->size + (ARCH_PAGE_SIZE - 1)) / ARCH_PAGE_SIZE); + dma->paddr = dma->vaddr = 0; + return RT_EOK; +} diff --git a/libcpu/x86/i386/dma.h b/libcpu/x86/i386/dma.h new file mode 100644 index 0000000000000000000000000000000000000000..e6b47b0936430eeb418e09ceee90db9948cca719 --- /dev/null +++ b/libcpu/x86/i386/dma.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-08-04 JasonHu First Version + */ + +#ifndef __HW_DMA_H__ +#define __HW_DMA_H__ + +#include + +struct rt_hw_dma +{ + rt_ubase_t paddr; + rt_ubase_t vaddr; + rt_size_t size; + rt_ubase_t alignment; /* addr align */ +}; +typedef struct rt_hw_dma rt_hw_dma_t; + +rt_err_t rt_hw_dma_alloc(rt_hw_dma_t *dma); +rt_err_t rt_hw_dma_free(rt_hw_dma_t *dma); +rt_err_t rt_hw_dma_init(rt_ubase_t start, rt_ubase_t end); + +#endif /* __HW_DMA_H__ */ diff --git a/libcpu/x86/i386/gate.c b/libcpu/x86/i386/gate.c new file mode 100644 index 0000000000000000000000000000000000000000..59536ddfe91d80e32dfa3f13d97f0314b096e267 --- /dev/null +++ b/libcpu/x86/i386/gate.c @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-07-16 JasonHu first version + */ + +#include "gate.h" +#include "segment.h" +#include "interrupt.h" +#include + +struct rt_hw_gate +{ + rt_uint16_t offset_low, selector; + rt_uint8_t datacount; + rt_uint8_t attributes; /* P(1) DPL(2) DT(1) TYPE(4) */ + rt_uint16_t offset_high; +}; +typedef struct rt_hw_gate rt_hw_gate_t; + +typedef void (*rt_hw_intr_entry_t)(void); + +extern void rt_hw_intr_entry0x00(void); +extern void rt_hw_intr_entry0x01(void); +extern void rt_hw_intr_entry0x02(void); +extern void rt_hw_intr_entry0x03(void); +extern void rt_hw_intr_entry0x04(void); +extern void rt_hw_intr_entry0x05(void); +extern void rt_hw_intr_entry0x06(void); +extern void rt_hw_intr_entry0x07(void); +extern void rt_hw_intr_entry0x08(void); +extern void rt_hw_intr_entry0x09(void); +extern void rt_hw_intr_entry0x0a(void); +extern void rt_hw_intr_entry0x0b(void); +extern void rt_hw_intr_entry0x0c(void); +extern void rt_hw_intr_entry0x0d(void); +extern void rt_hw_intr_entry0x0e(void); +extern void rt_hw_intr_entry0x0f(void); +extern void rt_hw_intr_entry0x10(void); +extern void rt_hw_intr_entry0x11(void); +extern void rt_hw_intr_entry0x12(void); +extern void rt_hw_intr_entry0x13(void); +extern void rt_hw_intr_entry0x14(void); +extern void rt_hw_intr_entry0x15(void); +extern void rt_hw_intr_entry0x16(void); +extern void rt_hw_intr_entry0x17(void); +extern void rt_hw_intr_entry0x18(void); +extern void rt_hw_intr_entry0x19(void); +extern void rt_hw_intr_entry0x1a(void); +extern void rt_hw_intr_entry0x1b(void); +extern void rt_hw_intr_entry0x1c(void); +extern void rt_hw_intr_entry0x1d(void); +extern void rt_hw_intr_entry0x1e(void); +extern void rt_hw_intr_entry0x1f(void); + +extern void rt_hw_intr_entry0x20(void); +extern void rt_hw_intr_entry0x21(void); +extern void rt_hw_intr_entry0x22(void); +extern void rt_hw_intr_entry0x23(void); +extern void rt_hw_intr_entry0x24(void); +extern void rt_hw_intr_entry0x25(void); +extern void rt_hw_intr_entry0x26(void); +extern void rt_hw_intr_entry0x27(void); +extern void rt_hw_intr_entry0x28(void); +extern void rt_hw_intr_entry0x29(void); +extern void rt_hw_intr_entry0x2a(void); +extern void rt_hw_intr_entry0x2b(void); +extern void rt_hw_intr_entry0x2c(void); +extern void rt_hw_intr_entry0x2d(void); +extern void rt_hw_intr_entry0x2e(void); +extern void rt_hw_intr_entry0x2f(void); + +static void gate_set(rt_hw_gate_t *gate, rt_hw_intr_entry_t handler, + rt_uint32_t selector, rt_uint32_t attributes, rt_uint8_t privilege) +{ + rt_ubase_t offset = (rt_ubase_t) handler; + gate->offset_low = offset & 0xffff; + gate->selector = selector; + gate->attributes = attributes | (privilege << 5); + gate->datacount = 0; + gate->offset_high = (offset >> 16) & 0xffff; +} + +void rt_hw_gate_init(void) +{ + rt_hw_gate_t *idt = (rt_hw_gate_t *) (IDT_VADDR); + /* + 将中断描述符表的内容设置成内核下的中断门 + 并把汇编部分的中断处理函数传入进去 + */ + int i; + for (i = 0; i < MAX_IDT_NR; i++) { + gate_set(IDT_OFF2PTR(idt, i), 0, 0, 0, 0); + } + gate_set(IDT_OFF2PTR(idt, EXCEPTION_INTR_BASE), rt_hw_intr_entry0x00, KERNEL_CODE_SEL, DA_386_INTR_GATE, DA_GATE_DPL0); + gate_set(IDT_OFF2PTR(idt, EXCEPTION_INTR_BASE+1), rt_hw_intr_entry0x01, KERNEL_CODE_SEL, DA_386_INTR_GATE, DA_GATE_DPL0); + gate_set(IDT_OFF2PTR(idt, EXCEPTION_INTR_BASE+2), rt_hw_intr_entry0x02, KERNEL_CODE_SEL, DA_386_INTR_GATE, DA_GATE_DPL0); + gate_set(IDT_OFF2PTR(idt, EXCEPTION_INTR_BASE+3), rt_hw_intr_entry0x03, KERNEL_CODE_SEL, DA_386_INTR_GATE, DA_GATE_DPL0); + gate_set(IDT_OFF2PTR(idt, EXCEPTION_INTR_BASE+4), rt_hw_intr_entry0x04, KERNEL_CODE_SEL, DA_386_INTR_GATE, DA_GATE_DPL0); + gate_set(IDT_OFF2PTR(idt, EXCEPTION_INTR_BASE+5), rt_hw_intr_entry0x05, KERNEL_CODE_SEL, DA_386_INTR_GATE, DA_GATE_DPL0); + gate_set(IDT_OFF2PTR(idt, EXCEPTION_INTR_BASE+6), rt_hw_intr_entry0x06, KERNEL_CODE_SEL, DA_386_INTR_GATE, DA_GATE_DPL0); + gate_set(IDT_OFF2PTR(idt, EXCEPTION_INTR_BASE+7), rt_hw_intr_entry0x07, KERNEL_CODE_SEL, DA_386_INTR_GATE, DA_GATE_DPL0); + gate_set(IDT_OFF2PTR(idt, EXCEPTION_INTR_BASE+8), rt_hw_intr_entry0x08, KERNEL_CODE_SEL, DA_386_INTR_GATE, DA_GATE_DPL0); + gate_set(IDT_OFF2PTR(idt, EXCEPTION_INTR_BASE+9), rt_hw_intr_entry0x09, KERNEL_CODE_SEL, DA_386_INTR_GATE, DA_GATE_DPL0); + gate_set(IDT_OFF2PTR(idt, EXCEPTION_INTR_BASE+10), rt_hw_intr_entry0x0a, KERNEL_CODE_SEL, DA_386_INTR_GATE, DA_GATE_DPL0); + gate_set(IDT_OFF2PTR(idt, EXCEPTION_INTR_BASE+11), rt_hw_intr_entry0x0b, KERNEL_CODE_SEL, DA_386_INTR_GATE, DA_GATE_DPL0); + gate_set(IDT_OFF2PTR(idt, EXCEPTION_INTR_BASE+12), rt_hw_intr_entry0x0c, KERNEL_CODE_SEL, DA_386_INTR_GATE, DA_GATE_DPL0); + gate_set(IDT_OFF2PTR(idt, EXCEPTION_INTR_BASE+13), rt_hw_intr_entry0x0d, KERNEL_CODE_SEL, DA_386_INTR_GATE, DA_GATE_DPL0); + gate_set(IDT_OFF2PTR(idt, EXCEPTION_INTR_BASE+14), rt_hw_intr_entry0x0e, KERNEL_CODE_SEL, DA_386_INTR_GATE, DA_GATE_DPL0); + gate_set(IDT_OFF2PTR(idt, EXCEPTION_INTR_BASE+15), rt_hw_intr_entry0x0f, KERNEL_CODE_SEL, DA_386_INTR_GATE, DA_GATE_DPL0); + gate_set(IDT_OFF2PTR(idt, EXCEPTION_INTR_BASE+16), rt_hw_intr_entry0x10, KERNEL_CODE_SEL, DA_386_INTR_GATE, DA_GATE_DPL0); + gate_set(IDT_OFF2PTR(idt, EXCEPTION_INTR_BASE+17), rt_hw_intr_entry0x11, KERNEL_CODE_SEL, DA_386_INTR_GATE, DA_GATE_DPL0); + gate_set(IDT_OFF2PTR(idt, EXCEPTION_INTR_BASE+18), rt_hw_intr_entry0x12, KERNEL_CODE_SEL, DA_386_INTR_GATE, DA_GATE_DPL0); + gate_set(IDT_OFF2PTR(idt, EXCEPTION_INTR_BASE+19), rt_hw_intr_entry0x13, KERNEL_CODE_SEL, DA_386_INTR_GATE, DA_GATE_DPL0); + gate_set(IDT_OFF2PTR(idt, EXCEPTION_INTR_BASE+20), rt_hw_intr_entry0x14, KERNEL_CODE_SEL, DA_386_INTR_GATE, DA_GATE_DPL0); + gate_set(IDT_OFF2PTR(idt, EXCEPTION_INTR_BASE+21), rt_hw_intr_entry0x15, KERNEL_CODE_SEL, DA_386_INTR_GATE, DA_GATE_DPL0); + gate_set(IDT_OFF2PTR(idt, EXCEPTION_INTR_BASE+22), rt_hw_intr_entry0x16, KERNEL_CODE_SEL, DA_386_INTR_GATE, DA_GATE_DPL0); + gate_set(IDT_OFF2PTR(idt, EXCEPTION_INTR_BASE+23), rt_hw_intr_entry0x17, KERNEL_CODE_SEL, DA_386_INTR_GATE, DA_GATE_DPL0); + gate_set(IDT_OFF2PTR(idt, EXCEPTION_INTR_BASE+24), rt_hw_intr_entry0x18, KERNEL_CODE_SEL, DA_386_INTR_GATE, DA_GATE_DPL0); + gate_set(IDT_OFF2PTR(idt, EXCEPTION_INTR_BASE+25), rt_hw_intr_entry0x19, KERNEL_CODE_SEL, DA_386_INTR_GATE, DA_GATE_DPL0); + gate_set(IDT_OFF2PTR(idt, EXCEPTION_INTR_BASE+26), rt_hw_intr_entry0x1a, KERNEL_CODE_SEL, DA_386_INTR_GATE, DA_GATE_DPL0); + gate_set(IDT_OFF2PTR(idt, EXCEPTION_INTR_BASE+27), rt_hw_intr_entry0x1b, KERNEL_CODE_SEL, DA_386_INTR_GATE, DA_GATE_DPL0); + gate_set(IDT_OFF2PTR(idt, EXCEPTION_INTR_BASE+28), rt_hw_intr_entry0x1c, KERNEL_CODE_SEL, DA_386_INTR_GATE, DA_GATE_DPL0); + gate_set(IDT_OFF2PTR(idt, EXCEPTION_INTR_BASE+29), rt_hw_intr_entry0x1d, KERNEL_CODE_SEL, DA_386_INTR_GATE, DA_GATE_DPL0); + gate_set(IDT_OFF2PTR(idt, EXCEPTION_INTR_BASE+30), rt_hw_intr_entry0x1e, KERNEL_CODE_SEL, DA_386_INTR_GATE, DA_GATE_DPL0); + gate_set(IDT_OFF2PTR(idt, EXCEPTION_INTR_BASE+31), rt_hw_intr_entry0x1f, KERNEL_CODE_SEL, DA_386_INTR_GATE, DA_GATE_DPL0); + + gate_set(IDT_OFF2PTR(idt, IRQ_INTR_BASE), rt_hw_intr_entry0x20, KERNEL_CODE_SEL, DA_386_INTR_GATE, DA_GATE_DPL0); + gate_set(IDT_OFF2PTR(idt, IRQ_INTR_BASE+1), rt_hw_intr_entry0x21, KERNEL_CODE_SEL, DA_386_INTR_GATE, DA_GATE_DPL0); + gate_set(IDT_OFF2PTR(idt, IRQ_INTR_BASE+2), rt_hw_intr_entry0x22, KERNEL_CODE_SEL, DA_386_INTR_GATE, DA_GATE_DPL0); + gate_set(IDT_OFF2PTR(idt, IRQ_INTR_BASE+3), rt_hw_intr_entry0x23, KERNEL_CODE_SEL, DA_386_INTR_GATE, DA_GATE_DPL0); + gate_set(IDT_OFF2PTR(idt, IRQ_INTR_BASE+4), rt_hw_intr_entry0x24, KERNEL_CODE_SEL, DA_386_INTR_GATE, DA_GATE_DPL0); + gate_set(IDT_OFF2PTR(idt, IRQ_INTR_BASE+5), rt_hw_intr_entry0x25, KERNEL_CODE_SEL, DA_386_INTR_GATE, DA_GATE_DPL0); + gate_set(IDT_OFF2PTR(idt, IRQ_INTR_BASE+6), rt_hw_intr_entry0x26, KERNEL_CODE_SEL, DA_386_INTR_GATE, DA_GATE_DPL0); + gate_set(IDT_OFF2PTR(idt, IRQ_INTR_BASE+7), rt_hw_intr_entry0x27, KERNEL_CODE_SEL, DA_386_INTR_GATE, DA_GATE_DPL0); + gate_set(IDT_OFF2PTR(idt, IRQ_INTR_BASE+8), rt_hw_intr_entry0x28, KERNEL_CODE_SEL, DA_386_INTR_GATE, DA_GATE_DPL0); + gate_set(IDT_OFF2PTR(idt, IRQ_INTR_BASE+9), rt_hw_intr_entry0x29, KERNEL_CODE_SEL, DA_386_INTR_GATE, DA_GATE_DPL0); + gate_set(IDT_OFF2PTR(idt, IRQ_INTR_BASE+10), rt_hw_intr_entry0x2a, KERNEL_CODE_SEL, DA_386_INTR_GATE, DA_GATE_DPL0); + gate_set(IDT_OFF2PTR(idt, IRQ_INTR_BASE+11), rt_hw_intr_entry0x2b, KERNEL_CODE_SEL, DA_386_INTR_GATE, DA_GATE_DPL0); + gate_set(IDT_OFF2PTR(idt, IRQ_INTR_BASE+12), rt_hw_intr_entry0x2c, KERNEL_CODE_SEL, DA_386_INTR_GATE, DA_GATE_DPL0); + gate_set(IDT_OFF2PTR(idt, IRQ_INTR_BASE+13), rt_hw_intr_entry0x2d, KERNEL_CODE_SEL, DA_386_INTR_GATE, DA_GATE_DPL0); + gate_set(IDT_OFF2PTR(idt, IRQ_INTR_BASE+14), rt_hw_intr_entry0x2e, KERNEL_CODE_SEL, DA_386_INTR_GATE, DA_GATE_DPL0); + gate_set(IDT_OFF2PTR(idt, IRQ_INTR_BASE+15), rt_hw_intr_entry0x2f, KERNEL_CODE_SEL, DA_386_INTR_GATE, DA_GATE_DPL0); + /* 系统调用处理中断 */ +#ifdef RT_USING_USERSPACE + extern void hw_syscall_entry(void); + gate_set(IDT_OFF2PTR(idt, SYSCALL_INTR_BASE), hw_syscall_entry, KERNEL_CODE_SEL, DA_386_INTR_GATE, DA_GATE_DPL3); +#endif /* RT_USING_USERSPACE */ + + extern void load_new_idt(rt_ubase_t size, rt_ubase_t idtr); + load_new_idt(IDT_LIMIT, IDT_VADDR); +} diff --git a/libcpu/x86/i386/gate.h b/libcpu/x86/i386/gate.h new file mode 100644 index 0000000000000000000000000000000000000000..b3fd706a1b72ab7bc81962ecd667cc7b98e91cab --- /dev/null +++ b/libcpu/x86/i386/gate.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-07-16 JasonHu first version + */ + +#ifndef __X86_GATE_H__ +#define __X86_GATE_H__ + +#include + +#define IDT_LIMIT 0x000007ff +#define IDT_PADDR 0x003F0800 + +#define IDT_VADDR (KERNEL_VADDR_START + IDT_PADDR) + +#define MAX_IDT_NR (IDT_LIMIT/8) + +#define IDT_OFF2PTR(idt, off) (idt + off) + +/* DA: Descriptor Attribute */ +#define DA_TASK_GATE 0x85 +#define DA_386_CALL_GATE 0x8C +#define DA_386_INTR_GATE 0x8E +#define DA_386_TRAP_GATE 0x8F + +#define DA_GATE_DPL0 0 +#define DA_GATE_DPL1 1 +#define DA_GATE_DPL2 2 +#define DA_GATE_DPL3 3 + +#ifndef __ASSEMBLY__ +void rt_hw_gate_init(void); +#endif + +#endif /* __X86_GATE_H__ */ diff --git a/libcpu/x86/i386/i386.h b/libcpu/x86/i386/i386.h new file mode 100644 index 0000000000000000000000000000000000000000..7a0a07f1b6037461285ddc60a281fed6d36f756c --- /dev/null +++ b/libcpu/x86/i386/i386.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-07-14 JasonHu first version + */ + +#ifndef __I386_H__ +#define __I386_H__ + +#include + +#define EFLAGS_MBS (1 << 1) +#define EFLAGS_IF_1 (1 << 9) +#define EFLAGS_IF_0 0 +#define EFLAGS_IOPL_3 (3 << 12) +#define EFLAGS_IOPL_1 (1 << 12) +#define EFLAGS_IOPL_0 (0 << 12) + +#define EFLAGS_IF (EFLAGS_IF_1) + +/* cr0 bit 31 is page enable bit, 1: enable MMU, 0: disable MMU */ +#define CR0_PG (1 << 31) + +rt_inline rt_uint8_t inb(int port) +{ + rt_uint8_t data; + __asm__ __volatile__("inb %w1,%0" : "=a" (data) : "d" (port)); + return data; +} + +rt_inline rt_uint16_t inw(int port) +{ + rt_uint16_t data; + __asm__ __volatile__("inw %w1,%0" : "=a" (data) : "d" (port)); + return data; +} + +rt_inline rt_uint32_t inl(int port) +{ + rt_uint32_t data; + __asm__ __volatile__("inl %w1,%0" : "=a" (data) : "d" (port)); + return data; +} + +rt_inline void outb(int port, rt_uint8_t data) +{ + __asm__ __volatile__("outb %0,%w1" : : "a" (data), "d" (port)); +} + +rt_inline void outw(int port, rt_uint16_t data) +{ + __asm__ __volatile__("outw %0,%w1" : : "a" (data), "d" (port)); +} + +rt_inline void outl(int port, rt_uint32_t data) +{ + __asm__ __volatile__("outl %0,%w1" : : "a" (data), "d" (port)); +} + +rt_inline rt_uint8_t read_cmos(int reg) +{ + outb(0x70, reg); + return (rt_uint8_t) inb(0x71); +} + +#define io_delay() \ + __asm__ __volatile__ ("pushal \n\t"\ + "mov $0x3F6, %dx \n\t" \ + "inb %dx, %al \n\t" \ + "inb %dx, %al \n\t" \ + "inb %dx, %al \n\t" \ + "inb %dx, %al \n\t" \ + "popal") + +rt_inline void ltr(rt_uint32_t selector) +{ + __asm__ __volatile__("ltr %w0" : : "q" (selector)); +} + +rt_uint32_t read_cr0(void); +rt_uint32_t read_cr2(void); +void write_cr0(rt_uint32_t value); +void write_cr3(rt_uint32_t pgdir); + +rt_inline void rt_hw_cpu_pause(void) +{ + __asm__ __volatile__ ("pause"); +} + +#endif /* __I386_H__ */ diff --git a/libcpu/x86/i386/interrupt.c b/libcpu/x86/i386/interrupt.c new file mode 100644 index 0000000000000000000000000000000000000000..0348e30b0b3da3dcb7f8ca6404b86e4d492e8d53 --- /dev/null +++ b/libcpu/x86/i386/interrupt.c @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-07-14 JasonHu first version + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +typedef void (*rt_hw_intr_handler_t)(rt_hw_stack_frame_t *); + +static rt_hw_intr_handler_t interrupt_handlers[MAX_INTR_NR] = {0}; +static struct rt_irq_desc irq_desc[MAX_IRQ_NR] = {0}; + +static char *hw_exception_names[] = { + "#DE Divide Error", + "#DB Debug Exception", + "NMI Interrupt", + "#BP Breakpoint Exception", + "#OF Overflow Exception", + "#BR BOUND Range Exceeded Exception", + "#UD Invalid Opcode Exception", + "#NM Device Not Available Exception", + "#DF Double Fault Exception", + "Coprocessor Segment Overrun", + "#TS Invalid TSS Exception", + "#NP Segment Not Present", + "#SS Stack Fault Exception", + "#GP General Protection Exception", + "#PF Page-Fault Exception", + "Reserved", + "#MF x87 FPU Floating-Point Error", + "#AC Alignment Check Exception", + "#MC Machine-Check Exception", + "#XF SIMD Floating-Point Exception", + "Unknown Exception" +}; + +static void exception_frame_dump(rt_hw_stack_frame_t *frame); + +static void rt_hw_interrupt_handle(int vector, void *param) +{ + rt_kprintf("UN-handled interrupt %d occurred!!!\n", vector); +} + +static void hw_general_handler(rt_hw_stack_frame_t *frame) +{ + rt_kprintf("general intr %d handled\n", frame->vec_no); +} + +static void hw_external_handler(rt_hw_stack_frame_t *frame) +{ + int irqno = frame->vec_no - IRQ_INTR_BASE; + if (irqno < 0 || irqno >= MAX_IRQ_NR) + { + dbg_log(DBG_ERROR, "unknown IRQ %d occurred!!\n", irqno); + return; + } + irq_desc[irqno].handler(irqno, irq_desc[irqno].param); + rt_hw_pic_ack(irqno); +} + + +#ifdef RT_USING_LWP +static int check_user_stack(rt_hw_stack_frame_t *frame) +{ + if (frame->vec_no == EXCEPTION_PAGE_FAULT) + { + void *fault_addr = (void *)read_cr2(); // get page fault addr + rt_interrupt_leave(); + if (arch_expand_user_stack(fault_addr)) + { + rt_interrupt_enter(); + return 1; + } + rt_interrupt_enter(); + } + return 0; +} +#endif /* RT_USING_LWP */ + +static void hw_exception_handler(rt_hw_stack_frame_t *frame) +{ +#ifdef RT_USING_LWP + if (check_user_stack(frame)) + return; +#endif /* RT_USING_LWP */ + rt_thread_t cur = rt_thread_self(); + rt_kprintf("thread name: %s\n", cur->name); + +#ifdef RT_USING_LWP + if (cur->lwp) + { + struct rt_lwp *lwp = cur->lwp; + rt_kprintf("thread id:%d\n", lwp->pid); + } +#endif /* RT_USING_LWP */ + + exception_frame_dump(frame); + rt_hw_print_backtrace(); + /* unhandled exception */ + rt_hw_interrupt_disable(); + for (;;) + ; +} + +rt_base_t rt_hw_interrupt_disable(void) +{ + rt_base_t level; + __asm__ __volatile__("pushfl ; popl %0 ; cli":"=g" (level): :"memory"); + return level; +} + +void rt_hw_interrupt_enable(rt_base_t level) +{ + __asm__ __volatile__("pushl %0 ; popfl": :"g" (level):"memory", "cc"); +} + +void rt_hw_interrupt_dispatch(rt_hw_stack_frame_t *frame) +{ + rt_ubase_t vec_no = frame->vec_no; + if (vec_no < 0 || vec_no >= MAX_INTR_NR) + { + dbg_log(DBG_ERROR, "unknown intr vector %x!\n", frame->vec_no); + return; + } + interrupt_handlers[vec_no](frame); +} + +void rt_hw_stack_frame_dump(rt_hw_stack_frame_t *frame) +{ + rt_kprintf("====stack frame dump====\n"); + rt_kprintf("edi:%x esi:%x ebp:%x esp dummy:%x ebx:%x edx:%x ecx:%x eax:%x\n", + frame->edi, frame->esi, frame->ebp, frame->esp_dummy, + frame->ebx, frame->edx, frame->ecx, frame->eax); + rt_kprintf("gs:%x fs:%x es:%x ds:%x error code:%x eip:%x cs:%x eflags:%x esp:%x ss:%x\n", + frame->gs, frame->fs, frame->es, frame->ds, frame->error_code, + frame->eip, frame->cs, frame->eflags, frame->esp, frame->ss); +} + +static void exception_frame_dump(rt_hw_stack_frame_t *frame) +{ + rt_kprintf("====exception frame dump====\n"); + rt_kprintf("Stack frame: exception name %s\n", hw_exception_names[frame->vec_no]); + if (frame->vec_no == 14) + { + rt_kprintf("page fault addr: %p\n", read_cr2()); + } + rt_hw_stack_frame_dump(frame); + if (frame->error_code != 0xFFFFFFFF) + { + if (frame->error_code & 1) + { + rt_kprintf(" External Event: NMI,hard interruption,ect.\n"); + } + else + { + rt_kprintf(" Not External Event: inside.\n"); + } + if (frame->error_code & (1 << 1)) + { + rt_kprintf(" IDT: selector in idt.\n"); + } + else + { + rt_kprintf(" IDT: selector in gdt or ldt.\n"); + } + if(frame->error_code & (1 <<2 )) + { + rt_kprintf(" TI: selector in ldt.\n"); + } + else + { + rt_kprintf(" TI: selector in gdt.\n"); + } + rt_kprintf(" Selector: idx %d\n", (frame->error_code&0xfff8)>>3); + } +} + +/** + * This function will mask a interrupt. + * @param vector the interrupt number + */ +void rt_hw_interrupt_mask(int vector) +{ + rt_hw_pic_disable(vector); +} + +/** + * This function will un-mask a interrupt. + * @param vector the interrupt number + */ +void rt_hw_interrupt_umask(int vector) +{ + rt_hw_pic_enable(vector); +} + +/** + * This function will install a interrupt service routine to a interrupt. + * @param vector the interrupt number + * @param new_handler the interrupt service routine to be installed + * @param old_handler the old interrupt service routine + */ +rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler, + void *param, const char *name) +{ + rt_isr_handler_t old_handler = RT_NULL; + + if(vector < MAX_IRQ_NR) + { + old_handler = irq_desc[vector].handler; + if (handler != RT_NULL) + { + irq_desc[vector].handler = (rt_isr_handler_t)handler; + irq_desc[vector].param = param; +#ifdef RT_USING_INTERRUPT_INFO + rt_snprintf(irq_desc[vector].name, RT_NAME_MAX - 1, "%s", name); + irq_desc[vector].counter = 0; +#endif + } + } + + return old_handler; +} + +extern volatile rt_ubase_t rt_interrupt_from_thread; +extern volatile rt_ubase_t rt_interrupt_to_thread; +extern volatile rt_ubase_t rt_thread_switch_interrupt_flag; +/** + * This function will initialize hardware interrupt + */ +void rt_hw_interrupt_init(void) +{ + rt_interrupt_from_thread = 0; + rt_interrupt_to_thread = 0; + rt_thread_switch_interrupt_flag = 0; + int i; + for (i = 0; i < MAX_INTR_NR; i++) + { + if (i < IRQ_INTR_BASE) + { + interrupt_handlers[i] = hw_exception_handler; + } + else if (i >= IRQ_INTR_BASE && i < IRQ_INTR_BASE + MAX_IRQ_NR) + { + interrupt_handlers[i] = hw_external_handler; + } + else + { + interrupt_handlers[i] = hw_general_handler; + } + } + for (i = 0; i < MAX_IRQ_NR; i++) + { + irq_desc[i].handler = rt_hw_interrupt_handle; + irq_desc[i].param = RT_NULL; +#ifdef RT_USING_INTERRUPT_INFO + rt_snprintf(irq_desc[i].name, RT_NAME_MAX - 1, "default"); + irq_desc[i].counter = 0; +#endif + } + /* init intr controller */ + rt_hw_pic_init(); +} diff --git a/libcpu/x86/i386/interrupt.h b/libcpu/x86/i386/interrupt.h new file mode 100644 index 0000000000000000000000000000000000000000..22893de11dc755d43124649bfa6be1007560c617 --- /dev/null +++ b/libcpu/x86/i386/interrupt.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-07-16 JasonHu first version + */ + +#ifndef __INTERRUPT_H__ +#define __INTERRUPT_H__ + +#define MAX_INTR_NR 0x81 +#define EXCEPTION_INTR_BASE 0x00 +#define IRQ_INTR_BASE 0x20 +#define SYSCALL_INTR_BASE 0x80 + +#define MAX_IRQ_NR 16 + +#define EXCEPTION_PAGE_FAULT 14 + +#include "irq.h" +#include "i386.h" + +#endif /* __INTERRUPT_H__ */ diff --git a/libcpu/x86/i386/interrupt_gcc.S b/libcpu/x86/i386/interrupt_gcc.S new file mode 100644 index 0000000000000000000000000000000000000000..f01a2e67b60a3666ebb46699d8166f0d2849f360 --- /dev/null +++ b/libcpu/x86/i386/interrupt_gcc.S @@ -0,0 +1,249 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021/07/15 JasonHu The first version + */ +#define __ASSEMBLY__ +#include + +.code32 +.text + +.extern rt_interrupt_enter +.extern rt_interrupt_leave +.extern rt_thread_switch_interrupt_flag +.extern rt_interrupt_from_thread +.extern rt_interrupt_to_thread +.extern rt_hw_interrupt_dispatch +.extern rt_hw_context_switch + +// cpu no error code, need push by us +.macro rt_hw_intr_entry_push_errcode p1 +.global rt_hw_intr_entry\p1 +rt_hw_intr_entry\p1: + pushl $0x00 + + pushl %ds + pushl %es + pushl %fs + pushl %gs + + pushal + + movl %ss, %edx + movl %edx, %ds + movl %edx, %es + + pushl $\p1 + + call rt_interrupt_enter + pushl %esp + call rt_hw_interrupt_dispatch + addl $4, %esp + call rt_interrupt_leave + +#ifdef RT_USING_SIGNALS + // check signal and do signal + pushl %esp + call lwp_try_do_signal + addl $4, %esp +#endif /* RT_USING_SIGNALS */ + + /** + * if rt_thread_switch_interrupt_flag == 1 then + * jmp rt_hw_intr_thread_switch + * end + */ + movl $rt_thread_switch_interrupt_flag, %eax + movl (%eax), %ebx + cmp $0x1, %ebx + jz rt_hw_intr_thread_switch + + // jmp to exit + movl $rt_hw_intr_exit, %eax + jmp *%eax +.endm + +// cpu with error code +.macro rt_hw_intr_entry p1 +.global rt_hw_intr_entry\p1 +rt_hw_intr_entry\p1: + nop; + pushl %ds + pushl %es + pushl %fs + pushl %gs + + pushal + + movl %ss, %edx + movl %edx, %ds + movl %edx, %es + + pushl $\p1 + + call rt_interrupt_enter + pushl %esp; + call rt_hw_interrupt_dispatch + addl $4, %esp; + call rt_interrupt_leave + +#ifdef RT_USING_SIGNALS + // check signal and do signal + pushl %esp + call lwp_try_do_signal + addl $4, %esp +#endif /* RT_USING_SIGNALS */ + + /** + * if rt_thread_switch_interrupt_flag == 1 then + * jmp rt_hw_intr_thread_switch + * end + */ + movl $rt_thread_switch_interrupt_flag, %eax + movl (%eax), %ebx + cmp $0x1, %ebx + jz rt_hw_intr_thread_switch + + // jmp to exit + movl $rt_hw_intr_exit, %eax + jmp *%eax +.endm + +rt_hw_intr_entry_push_errcode 0x00 +rt_hw_intr_entry_push_errcode 0x01 +rt_hw_intr_entry_push_errcode 0x02 +rt_hw_intr_entry_push_errcode 0x03 +rt_hw_intr_entry_push_errcode 0x04 +rt_hw_intr_entry_push_errcode 0x05 +rt_hw_intr_entry_push_errcode 0x06 +rt_hw_intr_entry_push_errcode 0x07 +rt_hw_intr_entry 0x08 +rt_hw_intr_entry_push_errcode 0x09 +rt_hw_intr_entry 0x0a +rt_hw_intr_entry 0x0b +rt_hw_intr_entry_push_errcode 0x0c +rt_hw_intr_entry 0x0d +rt_hw_intr_entry 0x0e +rt_hw_intr_entry_push_errcode 0x0f +rt_hw_intr_entry_push_errcode 0x10 +rt_hw_intr_entry 0x11 +rt_hw_intr_entry_push_errcode 0x12 +rt_hw_intr_entry_push_errcode 0x13 +rt_hw_intr_entry_push_errcode 0x14 +rt_hw_intr_entry_push_errcode 0x15 +rt_hw_intr_entry_push_errcode 0x16 +rt_hw_intr_entry_push_errcode 0x17 +rt_hw_intr_entry 0x18 +rt_hw_intr_entry_push_errcode 0x19 +rt_hw_intr_entry 0x1a +rt_hw_intr_entry 0x1b +rt_hw_intr_entry_push_errcode 0x1c +rt_hw_intr_entry 0x1d +rt_hw_intr_entry 0x1e +rt_hw_intr_entry_push_errcode 0x1f +rt_hw_intr_entry_push_errcode 0x20 +rt_hw_intr_entry_push_errcode 0x21 +rt_hw_intr_entry_push_errcode 0x22 +rt_hw_intr_entry_push_errcode 0x23 +rt_hw_intr_entry_push_errcode 0x24 +rt_hw_intr_entry_push_errcode 0x25 +rt_hw_intr_entry_push_errcode 0x26 +rt_hw_intr_entry_push_errcode 0x27 +rt_hw_intr_entry_push_errcode 0x28 +rt_hw_intr_entry_push_errcode 0x29 +rt_hw_intr_entry_push_errcode 0x2a +rt_hw_intr_entry_push_errcode 0x2b +rt_hw_intr_entry_push_errcode 0x2c +rt_hw_intr_entry_push_errcode 0x2d +rt_hw_intr_entry_push_errcode 0x2e +rt_hw_intr_entry_push_errcode 0x2f +rt_hw_intr_entry_push_errcode 0x80 // syscall + +rt_hw_intr_thread_switch: + // set rt_thread_switch_interrupt_flag as 0 + movl $0x0, %ebx + movl %ebx, (%eax) + + // push to into stack + movl $rt_interrupt_to_thread, %eax // get "to" + movl (%eax), %ebx + + // push from into stack + movl $rt_interrupt_from_thread, %ecx // get "from" + movl (%ecx), %edx + + pushl %ebx + pushl %edx + call rt_hw_context_switch + addl $8, %esp // restore stack + + // jmp to exit + movl $rt_hw_intr_exit, %eax + jmp *%eax + +#ifdef RT_USING_USERSPACE + +.extern rt_hw_syscall_dispath + +#ifdef RT_USING_SIGNALS +.extern lwp_try_do_signal +#endif /* RT_USING_SIGNALS */ + +.global hw_syscall_entry +hw_syscall_entry: + pushl $0x00 + + pushl %ds + pushl %es + pushl %fs + pushl %gs + + pushal + + movl %ss, %edx + movl %edx, %ds + movl %edx, %es + + pushl $0x80 + + sti // enable interrupt + + pushl %esp + call rt_hw_syscall_dispath + addl $4, %esp + +#ifdef RT_USING_SIGNALS + // check signal and do signal + pushl %esp + call lwp_try_do_signal + addl $4, %esp +#endif /* RT_USING_SIGNALS */ + + cli // disable interrupt + + // jmp to exit + movl $rt_hw_intr_exit, %eax + jmp *%eax + +.global syscall_exit +syscall_exit: +#endif /* RT_USING_USERSPACE */ +.global rt_hw_intr_exit +rt_hw_intr_exit: + addl $4, %esp // skip intr no + + popal + + popl %gs + popl %fs + popl %es + popl %ds + + addl $4, %esp // skip error_code + + iret \ No newline at end of file diff --git a/libcpu/x86/i386/irq.h b/libcpu/x86/i386/irq.h new file mode 100644 index 0000000000000000000000000000000000000000..5ea06e3843d5233b1df9a75180aa770e0cc4ec4b --- /dev/null +++ b/libcpu/x86/i386/irq.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-07-16 JasonHu first version + */ + +#ifndef __IRQ_H__ +#define __IRQ_H__ + +#define IRQ0_CLOCK 0 +#define IRQ1_KEYBOARD 1 +#define IRQ2_CONNECT 2 /* connect to slave */ +#define IRQ3_SERIAL2 3 +#define IRQ4_SERIAL1 4 +#define IRQ5_PARALLEL2 5 +#define IRQ6_FLOPPY 6 +#define IRQ7_PARALLEL1 7 + +#define IRQ8_RTCLOCK 8 /* real-time clock */ +#define IRQ9_REDIRECT 9 /* redirect to IRQ2 */ +#define IRQ10_RESERVED 10 +#define IRQ11_RESERVED 11 +#define IRQ12_MOUSE 12 +#define IRQ13_FPU 13 +#define IRQ14_HARDDISK 14 +#define IRQ15_RESERVE 15 + +#endif /* __IRQ_H__ */ diff --git a/libcpu/x86/i386/mmu.c b/libcpu/x86/i386/mmu.c new file mode 100644 index 0000000000000000000000000000000000000000..7f155baa1617948bc3c27feb7f0ab9f288f525a9 --- /dev/null +++ b/libcpu/x86/i386/mmu.c @@ -0,0 +1,664 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-07-14 JasonHu first version + */ + +#include +#include +#include +#include +#include + +#include "mmu.h" +#include "cache.h" + +#ifdef RT_USING_USERSPACE +#include "page.h" +#endif /* RT_USING_USERSPACE */ + +// #define RT_DEBUG_MMU_X86 + +static void __rt_hw_mmu_unmap(rt_mmu_info *mmu_info,void *v_addr,rt_size_t npages); + +#ifdef RT_USING_USERSPACE +void *_rt_hw_mmu_map(rt_mmu_info *mmu_info,void *v_addr,void *p_addr,rt_size_t size,rt_size_t attr); +void *_rt_hw_mmu_map_auto(rt_mmu_info *mmu_info,void *v_addr,rt_size_t size,rt_size_t attr); +#else +void *rt_hw_mmu_map(rt_mmu_info *mmu_info, void* p_addr, size_t size, size_t attr); +#endif + +void _rt_hw_mmu_unmap(rt_mmu_info *mmu_info,void *v_addr,rt_size_t size); +void *_rt_hw_mmu_v2p(rt_mmu_info *mmu_info,void *v_addr); + +void *current_mmu_table = RT_NULL; + +static void rt_hw_cpu_tlb_invalidate() +{ + mmu_flush_tlb(); +} + +void *mmu_table_get() +{ + return current_mmu_table; +} + +void switch_mmu(void *mmu_table) +{ + current_mmu_table = mmu_table; + if (mmu_table == RT_NULL) + { + dbg_log(DBG_ERROR, "switch_mmu: NULL mmu table!\n"); + } + else + { + RT_ASSERT(__CHECKALIGN(mmu_table,PAGE_OFFSET_BIT)); + mmu_set_pagetable((rt_ubase_t)mmu_table); + } +} + +/** + * init page table, check vaddr whether used. + */ +int rt_hw_mmu_map_init(rt_mmu_info *mmu_info,void *v_address,rt_size_t size,rt_size_t *vtable,rt_size_t pv_off) +{ + size_t l1_off,va_s,va_e; + rt_base_t level; + + if((!mmu_info) || (!vtable)) + { + return -1; + } + + va_s = (rt_size_t)v_address; + va_e = ((rt_size_t)v_address) + size - 1; + + if(va_e < va_s) + { + dbg_log(DBG_ERROR, "end=%p lower than start=%p\n", va_e, va_s); + return -1; + } + + //convert address to level 1 page frame id + va_s = GET_L1(va_s); + va_e = GET_L1(va_e); + + if(va_s == 0) + { + return -1; + } + + level = rt_hw_interrupt_disable(); + + //vtable initialization check + for(l1_off = va_s;l1_off <= va_e;l1_off++) + { + size_t v = vtable[l1_off]; + + if(PTE_USED(v)) + { + rt_hw_interrupt_enable(level); + return -1; + } + } + + va_s = (rt_size_t)v_address; + va_e = ((rt_size_t)v_address) + size; + + mmu_info -> vtable = vtable; + mmu_info -> vstart = va_s; + mmu_info -> vend = va_e; + mmu_info -> pv_off = pv_off; + + rt_hw_interrupt_enable(level); + return 0; +} + +void rt_hw_mmu_kernel_map_init(rt_mmu_info *mmu_info,rt_size_t vaddr_start,rt_size_t size) +{ + vaddr_start = vaddr_start & PAGE_ADDR_MASK; + rt_size_t paddr_start = vaddr_start; + rt_size_t vaddr_end = vaddr_start + __ALIGNUP(size, PAGE_OFFSET_BIT); + + rt_kprintf("kernel: map on [%p~%p]\n", vaddr_start, vaddr_end); + pde_t *pdt = (pde_t *)mmu_info->vtable; + + rt_size_t pde_nr = (vaddr_end - vaddr_start) / (PTE_PER_PAGE * PAGE_SIZE); + rt_size_t pte_nr = ((vaddr_end - vaddr_start) / PAGE_SIZE) % PTE_PER_PAGE; + rt_size_t *pte_addr = (rt_size_t *) PAGE_TABLE_VADDR; + rt_size_t pde_off = GET_L1(vaddr_start); + int i, j; + for (i = 0; i < pde_nr; i++) + { + pdt[pde_off + i] = MAKE_PTE(pte_addr, KERNEL_PAGE_ATTR); + for (j = 0; j < PTE_PER_PAGE; j++) + { + pte_addr[j] = MAKE_PTE(paddr_start, KERNEL_PAGE_ATTR); + paddr_start += PAGE_SIZE; + } + pte_addr += PAGE_SIZE; + } + if (pte_nr > 0) + { + pdt[pde_off + i] = MAKE_PTE(pte_addr, KERNEL_PAGE_ATTR); + for (j = 0; j < pte_nr; j++) + { + pte_addr[j] = MAKE_PTE(paddr_start, KERNEL_PAGE_ATTR); + paddr_start += PAGE_SIZE; + } + } +} + +static int __rt_hw_mmu_map(rt_mmu_info *mmu_info,void *v_addr,void *p_addr,rt_size_t npages,rt_size_t attr) +{ + size_t loop_va = (size_t)v_addr & ~ARCH_PAGE_MASK; + size_t loop_pa = (size_t)p_addr & ~ARCH_PAGE_MASK; + size_t l1_off, l2_off; + size_t *mmu_l1, *mmu_l2; + + if (!mmu_info) + { + return -1; + } + while (npages--) + { + l1_off = GET_L1(loop_va); + l2_off = GET_L2(loop_va); + mmu_l1 = (size_t*)mmu_info->vtable + l1_off; + if(PTE_USED(*mmu_l1)) + { + mmu_l2 = ((size_t *)GET_PADDR(*mmu_l1)); + rt_page_ref_inc(mmu_l2, 0); /* mmu l2 ref inc when map */ + mmu_l2 += l2_off; + } + else + { + mmu_l2 = (size_t*)rt_pages_alloc(0); + if (mmu_l2) + { + rt_memset(mmu_l2, 0, ARCH_PAGE_SIZE); + /* cache maintain */ + rt_hw_cpu_dcache_clean(mmu_l2, ARCH_PAGE_SIZE); + + *mmu_l1 = MAKE_PTE((size_t)mmu_l2, attr | PTE_P); + /* cache maintain */ + rt_hw_cpu_dcache_clean(mmu_l1, sizeof(*mmu_l1)); + + mmu_l2 += l2_off; + } + else + { + /* error, unmap and quit */ + __rt_hw_mmu_unmap(mmu_info, v_addr, npages); + return -1; + } + } + *mmu_l2 = MAKE_PTE(loop_pa, attr | PTE_P); + /* cache maintain */ + rt_hw_cpu_dcache_clean(mmu_l2, sizeof(*mmu_l2)); + + loop_va += ARCH_PAGE_SIZE; + loop_pa += ARCH_PAGE_SIZE; + } + return 0; +} + +#ifdef RT_USING_USERSPACE +//check whether the range of virtual address are free +static int check_vaddr(rt_mmu_info *mmu_info,void *va,rt_size_t pages) +{ + rt_size_t loop_va = __UMASKVALUE((rt_size_t)va,PAGE_OFFSET_MASK); + rt_size_t l1_off, l2_off; + rt_size_t *mmu_l1,*mmu_l2; + + if(!pages) + { + dbg_log(DBG_ERROR, "%s: check vaddr=%p pages=zero!\n", __func__, va); + return -1; + } + + if(!mmu_info) + { + dbg_log(DBG_ERROR, "%s: check vaddr=%p pages=%d mmu NULL!\n", __func__, va, pages); + return -1; + } + + while(pages--) + { + l1_off = GET_L1(loop_va); + l2_off = GET_L2(loop_va); + mmu_l1 = ((rt_size_t *)mmu_info -> vtable) + l1_off; + + if(PTE_USED(*mmu_l1)) + { + mmu_l2 = ((rt_size_t *)GET_PADDR(*mmu_l1)) + l2_off; + + if(PTE_USED(*mmu_l2)) + { + dbg_log(DBG_ERROR, "%s: check vaddr=%p pages=%d mmu l2 used %p->%x!\n", __func__, va, pages, mmu_l2, *mmu_l2); + return -1; + } + } + + loop_va += PAGE_SIZE; + } + + return 0; +} +#endif /* RT_USING_USERSPACE */ + +//find a range of free virtual address specified by pages +static size_t find_vaddr(rt_mmu_info *mmu_info, int pages) +{ + size_t va; + size_t find_va = 0; + int n = 0; + size_t start, end; + + if (!pages) + { + return 0; + } + + if (!mmu_info) + { + return 0; + } + + start = mmu_info->vstart; + end = mmu_info->vend; + va = mmu_info->vstart; + for (; start < end; start += ARCH_PAGE_SIZE, va += ARCH_PAGE_SIZE) + { + if (_rt_hw_mmu_v2p(mmu_info, (void *)va)) + { + n = 0; + find_va = 0; + continue; + } + if (!find_va) + { + find_va = va; + } + n++; + if (n >= pages) + { + return find_va; + } + } + return 0; +} + +#ifdef RT_USING_USERSPACE +void *_rt_hw_mmu_map(rt_mmu_info *mmu_info,void *v_addr,void *p_addr,rt_size_t size,rt_size_t attr) +{ + rt_size_t pa_s,pa_e; + rt_size_t vaddr; + rt_size_t pages; + int ret; + + if(!size) + { + return 0; + } + + pa_s = (rt_size_t)p_addr; + pa_e = ((rt_size_t)p_addr) + size - 1; + pa_s = GET_PF_ID(pa_s); + pa_e = GET_PF_ID(pa_e); + pages = pa_e - pa_s + 1; + if(v_addr) + { + vaddr = (rt_size_t)v_addr; + pa_s = (rt_size_t)p_addr; + if(GET_PF_OFFSET(vaddr) != GET_PF_OFFSET(pa_s)) + { + return 0; + } + + vaddr = __UMASKVALUE(vaddr,PAGE_OFFSET_MASK); + + if(check_vaddr(mmu_info,(void *)vaddr,pages) != 0) + { + dbg_log(DBG_ERROR, "%s: check vaddr=%p pages=%d failed!\n", __func__, vaddr, pages); + return 0; + } + } + else + { + vaddr = find_vaddr(mmu_info,pages); + } + + if(vaddr) + { + ret = __rt_hw_mmu_map(mmu_info,(void *)vaddr,p_addr,pages,attr); + + if(ret == 0) + { + rt_hw_cpu_tlb_invalidate(); + return (void *)(vaddr | GET_PF_OFFSET((rt_size_t)p_addr)); + } + } + + return 0; +} + +#else +void *_rt_hw_mmu_map(rt_mmu_info *mmu_info, void* p_addr, size_t size, size_t attr) +{ + size_t pa_s, pa_e; + size_t vaddr; + int pages; + int ret; + + pa_s = (size_t)p_addr; + pa_e = (size_t)p_addr + size - 1; + pa_s >>= ARCH_PAGE_SHIFT; + pa_e >>= ARCH_PAGE_SHIFT; + pages = pa_e - pa_s + 1; + vaddr = find_vaddr(mmu_info, pages); + if (vaddr) { + ret = __rt_hw_mmu_map(mmu_info, (void*)vaddr, p_addr, pages, attr); + if (ret == 0) + { + rt_hw_cpu_tlb_invalidate(); + return (void*)(vaddr + ((size_t)p_addr & ARCH_PAGE_MASK)); + } + } + return 0; +} +#endif /* RT_USING_USERSPACE */ + +#ifdef RT_USING_USERSPACE +static int __rt_hw_mmu_map_auto(rt_mmu_info *mmu_info,void *v_addr,rt_size_t npages,rt_size_t attr) +{ + rt_size_t loop_va = __UMASKVALUE((rt_size_t)v_addr, PAGE_OFFSET_MASK); + rt_size_t loop_pa; + rt_size_t i; + rt_size_t left_npages = npages; + rt_size_t used_npages; + void *va,*pa; + + if (!mmu_info) + { + return -1; + } + + while (left_npages) + { + loop_pa = (rt_size_t)rt_pages_alloc(0); + if (!loop_pa) + { + goto err; + } + rt_memset((void *)loop_pa, 0, ARCH_PAGE_SIZE); + if (__rt_hw_mmu_map(mmu_info, (void *)loop_va, (void *)loop_pa, 1, attr) < 0) + { + rt_pages_free((void *)loop_pa, 0); /* free unmaped phy page first */ + goto err; + } + --left_npages; + loop_va += PAGE_SIZE; + } + return 0; +err: + va = (void *)__UMASKVALUE((rt_size_t)v_addr, PAGE_OFFSET_MASK); + used_npages = npages - left_npages; + + for (i = 0; i < used_npages; i++) + { + pa = rt_hw_mmu_v2p(mmu_info, va); + if (pa) + { + rt_pages_free(pa, 0); + } + va = (void *)((rt_uint8_t *)va + PAGE_SIZE); + } + __rt_hw_mmu_unmap(mmu_info,v_addr, used_npages); + return -1; +} + +void *_rt_hw_mmu_map_auto(rt_mmu_info *mmu_info,void *v_addr,rt_size_t size,rt_size_t attr) +{ + rt_size_t vaddr; + rt_size_t offset; + rt_size_t pages; + int ret; + + if(!size) + { + return 0; + } + + offset = GET_PF_OFFSET((rt_size_t)v_addr); + size += (offset + ARCH_PAGE_SIZE - 1); + pages = size >> PAGE_OFFSET_BIT; + + if(v_addr) + { + vaddr = __UMASKVALUE((rt_size_t)v_addr, PAGE_OFFSET_MASK); + + if(check_vaddr(mmu_info,(void *)vaddr, pages) != 0) + { + dbg_log(DBG_ERROR, "_rt_hw_mmu_map_auto: check vaddr %p on pages %d failed!\n", vaddr, pages); + return 0; + } + } + else + { + vaddr = find_vaddr(mmu_info,pages); + } + + if(vaddr) + { + ret = __rt_hw_mmu_map_auto(mmu_info, (void *)vaddr, pages, attr); + + if(ret == 0) + { + rt_hw_cpu_tlb_invalidate(); + return (void *)(vaddr | offset); + } + dbg_log(DBG_ERROR, "_rt_hw_mmu_map_auto: do __rt_hw_mmu_map_auto failed!\n"); + } + else + { + dbg_log(DBG_ERROR, "_rt_hw_mmu_map_auto: get vaddr failed!\n"); + } + return 0; +} +#endif /* RT_USING_USERSPACE */ + +/** + * unmap page on v_addr, free page if unmapped, further more, if page table empty, need free it. + */ +static void __rt_hw_mmu_unmap(rt_mmu_info *mmu_info,void *v_addr,rt_size_t npages) +{ + rt_size_t loop_va = __UMASKVALUE((rt_size_t)v_addr, PAGE_OFFSET_MASK); + rt_size_t l1_off, l2_off; + rt_size_t *mmu_l1, *mmu_l2; + + RT_ASSERT(mmu_info); + + if ((rt_size_t)v_addr < mmu_info->vstart || (rt_size_t)v_addr >= mmu_info -> vend) + { + dbg_log(DBG_ERROR, "unmap vaddr %p out of range [%p~%p)\n", v_addr, mmu_info->vstart, mmu_info->vend); + return; + } + + while(npages--) + { + l1_off = (rt_size_t)GET_L1(loop_va); + l2_off = (rt_size_t)GET_L2(loop_va); + mmu_l1 = ((rt_size_t *)mmu_info -> vtable) + l1_off; + if (!PTE_USED(*mmu_l1)) + { + dbg_log(DBG_ERROR, "unmap vaddr %p mmu l1 unused %p->%x\n", v_addr, mmu_l1, *mmu_l1); + } + RT_ASSERT(PTE_USED(*mmu_l1)) + mmu_l2 = (rt_size_t *)(GET_PADDR(*mmu_l1)) + l2_off; + if (!PTE_USED(*mmu_l2)) + { + dbg_log(DBG_ERROR, "unmap vaddr %p mmu l2 unused %p->%x\n", v_addr, mmu_l2, *mmu_l2); + } + RT_ASSERT(PTE_USED(*mmu_l2)); + *mmu_l2 = 0; /* clear page table entry */ + rt_hw_cpu_dcache_clean(mmu_l2, sizeof(*mmu_l2)); + mmu_l2 -= l2_off; /* get base addr on page aligned */ + rt_page_ref_dec(mmu_l2, 0); /* page ref dec when unmap */ + + if(!rt_page_ref_get(mmu_l2, 0)) /* page table no phy page, empty */ + { + rt_page_ref_inc(mmu_l2, 0); /* page ref inc before free, make sure ref > 0 */ + //release level 2 page + rt_pages_free(mmu_l2, 0); //entry page and ref_cnt page + *mmu_l1 = 0; /* clear page dir table entry */ + rt_hw_cpu_dcache_clean(mmu_l1, sizeof(*mmu_l1)); + } + loop_va += PAGE_SIZE; + } +} + +void _rt_hw_mmu_unmap(rt_mmu_info *mmu_info,void *v_addr,rt_size_t size) +{ + rt_size_t va_s,va_e; + rt_size_t pages; + + va_s = ((rt_size_t)v_addr) >> PAGE_OFFSET_BIT; + va_e = (((rt_size_t)v_addr) + size - 1) >> PAGE_OFFSET_BIT; + pages = va_e - va_s + 1; + __rt_hw_mmu_unmap(mmu_info,v_addr,pages); + rt_hw_cpu_tlb_invalidate(); +} + +#ifdef RT_USING_USERSPACE +/** + * map vaddr in vtable with size and attr, this need a phy addr + * + * if v_addr == RT_NULL, get a valid vaddr to map. + * + * success return start vaddr, failed return RT_NULL + */ +void *rt_hw_mmu_map(rt_mmu_info *mmu_info,void *v_addr,void *p_addr,rt_size_t size,rt_size_t attr) +{ + void *ret; + rt_base_t level; + + level = rt_hw_interrupt_disable(); + ret = _rt_hw_mmu_map(mmu_info,v_addr,p_addr,size,attr); + rt_hw_interrupt_enable(level); + return ret; +} + +/** + * map vaddr in vtable with size and attr, this will auto alloc phy addr + * + * if v_addr == RT_NULL, get a valid vaddr to map. + * + * success return start vaddr, failed return RT_NULL + */ +void *rt_hw_mmu_map_auto(rt_mmu_info *mmu_info,void *v_addr,rt_size_t size,rt_size_t attr) +{ + void *ret; + rt_base_t level; + + level = rt_hw_interrupt_disable(); + ret = _rt_hw_mmu_map_auto(mmu_info,v_addr,size,attr); + rt_hw_interrupt_enable(level); + return ret; +} +#else +/** + * map vaddr in vtable with size and attr, this need a phy addr + * + * success return start vaddr, failed return RT_NULL + */ +void *rt_hw_mmu_map(rt_mmu_info *mmu_info, void* p_addr, size_t size, size_t attr) +{ + void *ret; + rt_base_t level; + + level = rt_hw_interrupt_disable(); + ret = _rt_hw_mmu_map(mmu_info, p_addr, size, attr); + rt_hw_interrupt_enable(level); + return ret; +} +#endif + +/** + * unmap vaddr in vtable, free phyaddr and page table + */ +void rt_hw_mmu_unmap(rt_mmu_info *mmu_info,void *v_addr,rt_size_t size) +{ + rt_base_t level; + + level = rt_hw_interrupt_disable(); + _rt_hw_mmu_unmap(mmu_info,v_addr,size); + rt_hw_interrupt_enable(level); +} + +void *_rt_hw_mmu_v2p(rt_mmu_info *mmu_info, void *v_addr) +{ + size_t l1 = GET_L1((size_t)v_addr); + pde_t *pde = &mmu_info->vtable[l1]; + if (*pde & PTE_P) + { + size_t *pte_addr = (size_t *)GET_PADDR(*pde); + size_t l2 = GET_L2((size_t)v_addr); + pte_t *pte = (pte_t *)&pte_addr[l2]; + if (*pte & PTE_P) + { + return (void *)(GET_PADDR(*pte) | GET_PF_OFFSET((rt_size_t)v_addr)); + } + } + return RT_NULL; +} + +#ifdef RT_DEBUG_MMU_X86 +void *_rt_hw_mmu_v2p_with_dbg(rt_mmu_info *mmu_info, void *v_addr) +{ + rt_kprintf("v2p: mmu vtable=%p, vaddr=%p\n", mmu_info->vtable, v_addr); + size_t l1 = GET_L1((size_t)v_addr); + rt_kprintf("=>L1=%d ", l1); + pde_t *pde = &mmu_info->vtable[l1]; + rt_kprintf("pde=>%p:%x (%x|%x)\n", pde, *pde, GET_PADDR(*pde), GET_PATTR(*pde)); + if (*pde & PTE_P) + { + size_t *pte_addr = (size_t *)GET_PADDR(*pde); + size_t l2 = GET_L2((size_t)v_addr); + rt_kprintf(" =>L2=%d ", l2); + pte_t *pte = (pte_t *)&pte_addr[l2]; + rt_kprintf("pte=>%p:%x (%x|%x)\n", pte, *pte, GET_PADDR(*pte), GET_PATTR(*pte)); + if (*pte & PTE_P) + { + rt_kprintf(" =>paddr:%p\n", GET_PADDR(*pte)); + return (void *)GET_PADDR(*pte); + } + } + rt_kprintf("v2p: mmu v2p %p failed!\n", v_addr); + return RT_NULL; +} +#endif + +/** + * virtual addr to physical addr + * + * success return phyaddr, failed return RT_NULL + */ +void *rt_hw_mmu_v2p(rt_mmu_info *mmu_info,void *v_addr) +{ + void *ret; + rt_base_t level; + + level = rt_hw_interrupt_disable(); +#ifdef RT_DEBUG_MMU_X86 + ret = _rt_hw_mmu_v2p_with_dbg(mmu_info,v_addr); +#else + ret = _rt_hw_mmu_v2p(mmu_info,v_addr); +#endif + rt_hw_interrupt_enable(level); + return ret; +} diff --git a/libcpu/x86/i386/mmu.h b/libcpu/x86/i386/mmu.h new file mode 100644 index 0000000000000000000000000000000000000000..859301639a1ce06a2c23668effe70f14bb16f969 --- /dev/null +++ b/libcpu/x86/i386/mmu.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-07-14 JasonHu first version + */ + +#ifndef __MMU_H__ +#define __MMU_H__ + +#include +#include +#include + +#include "x86_mmu.h" + +typedef struct +{ + rt_size_t *vtable; + rt_size_t vstart; + rt_size_t vend; + rt_size_t pv_off; +}rt_mmu_info; + +typedef rt_size_t pde_t; /* page dir entry */ +typedef rt_size_t pte_t; /* page table entry */ + +/* page offset */ +#define GET_PF_ID(addr) ((addr) >> PAGE_OFFSET_BIT) +#define GET_PF_OFFSET(addr) __MASKVALUE(addr,PAGE_OFFSET_MASK) +#define GET_L1(addr) __PARTBIT(addr,PDE_SHIFT,PDE_BIT) +#define GET_L2(addr) __PARTBIT(addr,PTE_SHIFT,PTE_BIT) +#define GET_PADDR(pte) ((pte) & PAGE_ADDR_MASK) +#define GET_PATTR(pte) ((pte) & PAGE_OFFSET_MASK) + +#define PTE_PER_PAGE 1024 + +#define PAGE_TABLE_PADDR 0X3F3000 +#define PAGE_TABLE_VADDR (KERNEL_VADDR_START + PAGE_TABLE_PADDR) + +#define MAKE_PTE(paddr, attr) (rt_size_t) (((rt_size_t)(paddr) & PAGE_ADDR_MASK) | ((attr) & PAGE_OFFSET_MASK)) + +// page table entry (PTE) fields +#define PTE_P 0x001 // Present +#define PTE_R 0x000 // Read +#define PTE_W 0x002 // Write +#define PTE_X 0x000 // Execute +#define PTE_U 0x004 // User +#define PTE_PWT 0x008 // Write-through +#define PTE_S 0x000 // System +#define PTE_A 0x020 // Accessed +#define PTE_D 0x040 // Dirty + +#define PAGE_ATTR_RWX (PTE_X | PTE_W | PTE_R) +#define PAGE_ATTR_READONLY (PTE_R) +#define PAGE_ATTR_READEXECUTE (PTE_X | PTE_R) + +#define PAGE_ATTR_USER (PTE_U) +#define PAGE_ATTR_SYSTEM (PTE_S) + +#define KERNEL_PAGE_ATTR (PTE_P | PAGE_ATTR_RWX | PAGE_ATTR_SYSTEM) + +#define PTE_USED(pte) __MASKVALUE(pte,PTE_P) + +#define MMU_MAP_K_RO (PTE_S | PTE_R) +#define MMU_MAP_K_RWCB (PTE_S | PTE_R | PTE_W) +#define MMU_MAP_K_RW (PTE_S | PTE_R | PTE_W) +#define MMU_MAP_K_DEVICE (PTE_S | PTE_R | PTE_W) +#define MMU_MAP_U_RO (PTE_U | PTE_R) +#define MMU_MAP_U_RWCB (PTE_U | PTE_R | PTE_W) +#define MMU_MAP_U_RW (PTE_U | PTE_R | PTE_W) +#define MMU_MAP_U_DEVICE (PTE_U | PTE_R | PTE_W) + +#define PAGE_ATTR_MASK PAGE_OFFSET_MASK + +void *mmu_table_get(); +void switch_mmu(void *mmu_table); +int rt_hw_mmu_map_init(rt_mmu_info *mmu_info,void *v_address,rt_size_t size,rt_size_t *vtable,rt_size_t pv_off); +void rt_hw_mmu_kernel_map_init(rt_mmu_info *mmu_info,rt_size_t vaddr_start,rt_size_t size); + +#ifdef RT_USING_USERSPACE +void *rt_hw_mmu_map(rt_mmu_info *mmu_info,void *v_addr,void *p_addr,rt_size_t size,rt_size_t attr); +void *rt_hw_mmu_map_auto(rt_mmu_info *mmu_info,void *v_addr,rt_size_t size,rt_size_t attr); +#else +void *rt_hw_mmu_map(rt_mmu_info *mmu_info, void* p_addr, size_t size, size_t attr); +#endif /* RT_USING_USERSPACE */ + +void rt_hw_mmu_unmap(rt_mmu_info *mmu_info,void *v_addr,rt_size_t size); +void *rt_hw_mmu_v2p(rt_mmu_info *mmu_info,void *v_addr); + +/* used in kernel mmaped area */ +#define rt_hw_phy2vir(p) ((p) + KERNEL_VADDR_START) +#define rt_hw_vir2phy(v) ((v) - KERNEL_VADDR_START) + +#endif diff --git a/libcpu/x86/i386/multiboot2.h b/libcpu/x86/i386/multiboot2.h new file mode 100644 index 0000000000000000000000000000000000000000..9534b81b262cb396fa3c09fc8c3649f028e2346b --- /dev/null +++ b/libcpu/x86/i386/multiboot2.h @@ -0,0 +1,401 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-07-17 JasonHu,GuEe-GUI used in i386 + */ + +#ifndef __MULTIBOOT_H__ +#define __MULTIBOOT_H__ + +/* How many bytes from the start of the file we search for the header. */ +#define MULTIBOOT_SEARCH 32768 +#define MULTIBOOT_HEADER_ALIGN 8 + +/* The magic field should contain this. */ +#define MULTIBOOT2_HEADER_MAGIC 0xe85250d6 + +/* This should be in %eax. */ +#define MULTIBOOT2_BOOTLOADER_MAGIC 0x36d76289 + +/* Alignment of multiboot modules. */ +#define MULTIBOOT_MOD_ALIGN 0x00001000 + +/* Alignment of the multiboot info structure. */ +#define MULTIBOOT_INFO_ALIGN 0x00000008 + +/* Flags set in the ’flags’ member of the multiboot header. */ + +#define MULTIBOOT_TAG_ALIGN 8 +#define MULTIBOOT_TAG_TYPE_END 0 +#define MULTIBOOT_TAG_TYPE_CMDLINE 1 +#define MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME 2 +#define MULTIBOOT_TAG_TYPE_MODULE 3 +#define MULTIBOOT_TAG_TYPE_BASIC_MEMINFO 4 +#define MULTIBOOT_TAG_TYPE_BOOTDEV 5 +#define MULTIBOOT_TAG_TYPE_MMAP 6 +#define MULTIBOOT_TAG_TYPE_VBE 7 +#define MULTIBOOT_TAG_TYPE_FRAMEBUFFER 8 +#define MULTIBOOT_TAG_TYPE_ELF_SECTIONS 9 +#define MULTIBOOT_TAG_TYPE_APM 10 +#define MULTIBOOT_TAG_TYPE_EFI32 11 +#define MULTIBOOT_TAG_TYPE_EFI64 12 +#define MULTIBOOT_TAG_TYPE_SMBIOS 13 +#define MULTIBOOT_TAG_TYPE_ACPI_OLD 14 +#define MULTIBOOT_TAG_TYPE_ACPI_NEW 15 +#define MULTIBOOT_TAG_TYPE_NETWORK 16 +#define MULTIBOOT_TAG_TYPE_EFI_MMAP 17 +#define MULTIBOOT_TAG_TYPE_EFI_BS 18 +#define MULTIBOOT_TAG_TYPE_EFI32_IH 19 +#define MULTIBOOT_TAG_TYPE_EFI64_IH 20 +#define MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR 21 + +#define MULTIBOOT_HEADER_TAG_END 0 +#define MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST 1 +#define MULTIBOOT_HEADER_TAG_ADDRESS 2 +#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS 3 +#define MULTIBOOT_HEADER_TAG_CONSOLE_FLAGS 4 +#define MULTIBOOT_HEADER_TAG_FRAMEBUFFER 5 +#define MULTIBOOT_HEADER_TAG_MODULE_ALIGN 6 +#define MULTIBOOT_HEADER_TAG_EFI_BS 7 +#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI32 8 +#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI64 9 +#define MULTIBOOT_HEADER_TAG_RELOCATABLE 10 + +#define MULTIBOOT_ARCHITECTURE_I386 0 +#define MULTIBOOT_ARCHITECTURE_MIPS32 4 +#define MULTIBOOT_HEADER_TAG_OPTIONAL 1 + +#define MULTIBOOT_LOAD_PREFERENCE_NONE 0 +#define MULTIBOOT_LOAD_PREFERENCE_LOW 1 +#define MULTIBOOT_LOAD_PREFERENCE_HIGH 2 + +#define MULTIBOOT_CONSOLE_FLAGS_CONSOLE_REQUIRED 1 +#define MULTIBOOT_CONSOLE_FLAGS_EGA_TEXT_SUPPORTED 2 + +#ifndef __ASSEMBLY__ + +struct multiboot_header +{ + /* Must be MULTIBOOT_MAGIC - see above. */ + rt_uint32_t magic; + + /* ISA */ + rt_uint32_t architecture; + + /* Total header length. */ + rt_uint32_t header_length; + + /* The above fields plus this one must equal 0 mod 2^32. */ + rt_uint32_t checksum; +}; + +struct multiboot_header_tag +{ + rt_uint16_t type; + rt_uint16_t flags; + rt_uint32_t size; +}; + +struct multiboot_header_tag_information_request +{ + rt_uint16_t type; + rt_uint16_t flags; + rt_uint32_t size; + rt_uint32_t requests[0]; +}; + +struct multiboot_header_tag_address +{ + rt_uint16_t type; + rt_uint16_t flags; + rt_uint32_t size; + rt_uint32_t header_addr; + rt_uint32_t load_addr; + rt_uint32_t load_end_addr; + rt_uint32_t bss_end_addr; +}; + +struct multiboot_header_tag_entry_address +{ + rt_uint16_t type; + rt_uint16_t flags; + rt_uint32_t size; + rt_uint32_t entry_addr; +}; + +struct multiboot_header_tag_console_flags +{ + rt_uint16_t type; + rt_uint16_t flags; + rt_uint32_t size; + rt_uint32_t console_flags; +}; + +struct multiboot_header_tag_framebuffer +{ + rt_uint16_t type; + rt_uint16_t flags; + rt_uint32_t size; + rt_uint32_t width; + rt_uint32_t height; + rt_uint32_t depth; +}; + +struct multiboot_header_tag_module_align +{ + rt_uint16_t type; + rt_uint16_t flags; + rt_uint32_t size; +}; + +struct multiboot_header_tag_relocatable +{ + rt_uint16_t type; + rt_uint16_t flags; + rt_uint32_t size; + rt_uint32_t min_addr; + rt_uint32_t max_addr; + rt_uint32_t align; + rt_uint32_t preference; +}; + +struct multiboot_color +{ + rt_uint8_t red; + rt_uint8_t green; + rt_uint8_t blue; +}; + +struct multiboot_mmap_entry +{ + rt_uint64_t addr; + rt_uint64_t len; +#define MULTIBOOT_MEMORY_AVAILABLE 1 +#define MULTIBOOT_MEMORY_RESERVED 2 +#define MULTIBOOT_MEMORY_ACPI_RECLAIMABLE 3 +#define MULTIBOOT_MEMORY_NVS 4 +#define MULTIBOOT_MEMORY_BADRAM 5 + rt_uint32_t type; + rt_uint32_t zero; +}; +typedef struct multiboot_mmap_entry multiboot_memory_map_t; + +struct multiboot_tag +{ + rt_uint32_t type; + rt_uint32_t size; +}; + +struct multiboot_tag_string +{ + rt_uint32_t type; + rt_uint32_t size; + char string[0]; +}; + +struct multiboot_tag_module +{ + rt_uint32_t type; + rt_uint32_t size; + rt_uint32_t mod_start; + rt_uint32_t mod_end; + char cmdline[0]; +}; + +struct multiboot_tag_basic_meminfo +{ + rt_uint32_t type; + rt_uint32_t size; + rt_uint32_t mem_lower; + rt_uint32_t mem_upper; +}; + +struct multiboot_tag_bootdev +{ + rt_uint32_t type; + rt_uint32_t size; + rt_uint32_t biosdev; + rt_uint32_t slice; + rt_uint32_t part; +}; + +struct multiboot_tag_mmap +{ + rt_uint32_t type; + rt_uint32_t size; + rt_uint32_t entry_size; + rt_uint32_t entry_version; + struct multiboot_mmap_entry entries[0]; +}; + +struct multiboot_vbe_info_block +{ + rt_uint8_t external_specification[512]; +}; + +struct multiboot_vbe_mode_info_block +{ + rt_uint8_t external_specification[256]; +}; + +struct multiboot_tag_vbe +{ + rt_uint32_t type; + rt_uint32_t size; + + rt_uint16_t vbe_mode; + rt_uint16_t vbe_interface_seg; + rt_uint16_t vbe_interface_off; + rt_uint16_t vbe_interface_len; + + struct multiboot_vbe_info_block vbe_control_info; + struct multiboot_vbe_mode_info_block vbe_mode_info; +}; + +struct multiboot_tag_framebuffer_common +{ + rt_uint32_t type; + rt_uint32_t size; + + rt_uint64_t framebuffer_addr; + rt_uint32_t framebuffer_pitch; + rt_uint32_t framebuffer_width; + rt_uint32_t framebuffer_height; + rt_uint8_t framebuffer_bpp; +#define MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED 0 +#define MULTIBOOT_FRAMEBUFFER_TYPE_RGB 1 +#define MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT 2 + rt_uint8_t framebuffer_type; + rt_uint16_t reserved; +}; + +struct multiboot_tag_framebuffer +{ + struct multiboot_tag_framebuffer_common common; + + union + { + struct + { + rt_uint16_t framebuffer_palette_num_colors; + struct multiboot_color framebuffer_palette[0]; + }; + struct + { + rt_uint8_t framebuffer_red_field_position; + rt_uint8_t framebuffer_red_mask_size; + rt_uint8_t framebuffer_green_field_position; + rt_uint8_t framebuffer_green_mask_size; + rt_uint8_t framebuffer_blue_field_position; + rt_uint8_t framebuffer_blue_mask_size; + }; + }; +}; + +struct multiboot_tag_elf_sections +{ + rt_uint32_t type; + rt_uint32_t size; + rt_uint32_t num; + rt_uint32_t entsize; + rt_uint32_t shndx; + char sections[0]; +}; + +struct multiboot_tag_apm +{ + rt_uint32_t type; + rt_uint32_t size; + rt_uint16_t version; + rt_uint16_t cseg; + rt_uint32_t offset; + rt_uint16_t cseg_16; + rt_uint16_t dseg; + rt_uint16_t flags; + rt_uint16_t cseg_len; + rt_uint16_t cseg_16_len; + rt_uint16_t dseg_len; +}; + +struct multiboot_tag_efi32 +{ + rt_uint32_t type; + rt_uint32_t size; + rt_uint32_t pointer; +}; + +struct multiboot_tag_efi64 +{ + rt_uint32_t type; + rt_uint32_t size; + rt_uint64_t pointer; +}; + +struct multiboot_tag_smbios +{ + rt_uint32_t type; + rt_uint32_t size; + rt_uint8_t major; + rt_uint8_t minor; + rt_uint8_t reserved[6]; + rt_uint8_t tables[0]; +}; + +struct multiboot_tag_old_acpi +{ + rt_uint32_t type; + rt_uint32_t size; + rt_uint8_t rsdp[0]; +}; + +struct multiboot_tag_new_acpi +{ + rt_uint32_t type; + rt_uint32_t size; + rt_uint8_t rsdp[0]; +}; + +struct multiboot_tag_network +{ + rt_uint32_t type; + rt_uint32_t size; + rt_uint8_t dhcpack[0]; +}; + +struct multiboot_tag_efi_mmap +{ + rt_uint32_t type; + rt_uint32_t size; + rt_uint32_t descr_size; + rt_uint32_t descr_vers; + rt_uint8_t efi_mmap[0]; +}; + +struct multiboot_tag_efi32_ih +{ + rt_uint32_t type; + rt_uint32_t size; + rt_uint32_t pointer; +}; + +struct multiboot_tag_efi64_ih +{ + rt_uint32_t type; + rt_uint32_t size; + rt_uint64_t pointer; +}; + +struct multiboot_tag_load_base_addr +{ + rt_uint32_t type; + rt_uint32_t size; + rt_uint32_t load_base_addr; +}; + +#endif /* __ASSEMBLY__ */ + +#endif /* __MULTIBOOT_H__ */ diff --git a/libcpu/x86/i386/page.c b/libcpu/x86/i386/page.c new file mode 100644 index 0000000000000000000000000000000000000000..487b835bd754c6db1b00801d130ff7e601bb1665 --- /dev/null +++ b/libcpu/x86/i386/page.c @@ -0,0 +1,489 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-01-29 lizhirui first version + * 2021-07-17 JasonHu used in i386 + */ + +#include +#include +#include +#include + +#ifdef RT_USING_USERSPACE + +#include "page.h" +#include "mmu.h" + +#define PAGE_LIST_SIZE (ADDRESS_WIDTH_BITS - PAGE_OFFSET_BIT) + +// #define RT_PAGE_DEBUG + +#ifdef RT_PAGE_DEBUG + #define dprintf rt_kprintf +#else + #define dprintf(...) +#endif + +#define RT_PASSERT RT_ASSERT + +struct page +{ + struct page *next; + struct page *pre; + rt_size_t size_bits; + int ref_cnt; +}; + +static struct page *page_start; +static void *page_addr; +static rt_size_t page_nr; + +#define PAGE_VALID(pageobj) RT_PASSERT(!((((rt_size_t)pageobj) - ((rt_size_t)page_start)) % sizeof(struct page))) + +static struct page *page_list[ADDRESS_WIDTH_BITS] = {0}; + +//get the correct page_list index according the actual size +rt_size_t rt_page_bits(rt_size_t size) +{ + rt_base_t bit; + + //get highest 1 bit index + bit = __builtin_clzl(size); + bit = sizeof(rt_size_t) * 8 - bit - 1; + + //if bits remained has 1,the large page is needed + if((size ^ (1UL << bit)) != 0) + { + bit++; + } + + bit -= PAGE_OFFSET_BIT; + + if(bit < 0) + { + bit = 0; + } + + return (rt_size_t)bit; +} + +//convert physical address to page object +static struct page *addr_to_page(void *addr) +{ + rt_size_t off; + + if(addr < page_addr) + { + return 0; + } + RT_PASSERT(__CHECKALIGN(addr,PAGE_OFFSET_BIT)); + off = ((rt_size_t)addr) - ((rt_size_t)page_addr); + off >>= PAGE_OFFSET_BIT; + + if(off >= page_nr) + { + return 0; + } + + return &page_start[off]; +} + +//convert page object to physical address +static void *page_to_addr(struct page *p) +{ + if(!p) + { + return 0; + } + + PAGE_VALID(p); + return (void *)(((rt_size_t)page_addr) + ((p - page_start) << PAGE_OFFSET_BIT)); +} + +//get the buddy of page specified by p(split a page to two page according to size_bits) +static inline struct page *buddy_get(struct page *p,rt_size_t size_bits) +{ + rt_size_t addr; + + PAGE_VALID(p); + addr = (rt_size_t)page_to_addr(p); + RT_PASSERT(__CHECKALIGN(addr,size_bits + PAGE_OFFSET_BIT)); + addr ^= (1UL << (size_bits + PAGE_OFFSET_BIT)); + return addr_to_page((void *)addr); +} + +//remove the page from the linked list +static void page_remove(struct page *p,rt_size_t size_bits) +{ + PAGE_VALID(p); + + if(p -> pre) + { + p -> pre -> next = p -> next; + } + else + { + page_list[size_bits] = p -> next; + } + + if(p -> next) + { + p -> next -> pre = p -> pre; + } + + p -> size_bits = ADDRESS_WIDTH_BITS; +} + +static void _pages_ref_inc(struct page *p, uint32_t size_bits) +{ + struct page *page_head; + int idx; + + /* find page group head */ + idx = p - page_start; + if (idx < 0 || idx >= page_nr) + { + return; + } + idx = idx & ~((1UL << size_bits) - 1); + + page_head = page_start + idx; + page_head->ref_cnt++; +} + +void rt_page_ref_inc(void *addr, uint32_t size_bits) +{ + struct page *p; + rt_base_t level; + + p = addr_to_page(addr); + level = rt_hw_interrupt_disable(); + _pages_ref_inc(p, size_bits); + rt_hw_interrupt_enable(level); +} + +static void _pages_ref_dec(struct page *p, uint32_t size_bits) +{ + struct page *page_head; + int idx; + + /* find page group head */ + idx = p - page_start; + if (idx < 0 || idx >= page_nr) + { + return; + } + idx = idx & ~((1UL << size_bits) - 1); + + page_head = page_start + idx; + page_head->ref_cnt--; +} + +void rt_page_ref_dec(void *addr, uint32_t size_bits) +{ + struct page *p; + rt_base_t level; + + p = addr_to_page(addr); + level = rt_hw_interrupt_disable(); + _pages_ref_dec(p, size_bits); + rt_hw_interrupt_enable(level); +} + +static int _pages_ref_get(struct page *p, uint32_t size_bits) +{ + struct page *page_head; + int idx; + + /* find page group head */ + idx = p - page_start; + if (idx < 0 || idx >= page_nr) + { + return - 1; + } + idx = idx & ~((1UL << size_bits) - 1); + + page_head = page_start + idx; + return page_head->ref_cnt; +} + +int rt_page_ref_get(void *addr, uint32_t size_bits) +{ + struct page *p; + rt_base_t level; + int ref_cnt; + p = addr_to_page(addr); + level = rt_hw_interrupt_disable(); + ref_cnt = _pages_ref_get(p, size_bits); + rt_hw_interrupt_enable(level); + return ref_cnt; +} + +//add new page to the first item of the linked list +static void page_insert(struct page *p,rt_size_t size_bits) +{ + PAGE_VALID(p); + + p -> next = page_list[size_bits]; + + if(p -> next) + { + p -> next -> pre = p; + } + + p -> pre = 0; + page_list[size_bits] = p; + p -> size_bits = size_bits; +} + +static struct page *_pages_alloc(rt_size_t size_bits) +{ + struct page *p; + + if(page_list[size_bits]) + { + //if appropriate page exists,just get new page from the linked list specified by size_bits + p = page_list[size_bits]; + page_remove(p,size_bits); + } + else + { + //otherwise get new page from large linked list + rt_size_t level; + rt_size_t high = PAGE_LIST_SIZE; + + for(level = size_bits + 1;level <= high;level++) + { + if(page_list[level]) + { + break; + } + } + + RT_ASSERT(level <= (high + 2)); + + if(level == high + 2) + { + return 0;//couldn't find a appropriate page + } + + p = page_list[level]; + page_remove(p,level); + + //push down this page,and split it to the size specified by size_bits + while(level > size_bits) + { + page_insert(p,level - 1); + p = buddy_get(p,level - 1); + level--; + } + } + p->size_bits = ADDRESS_WIDTH_BITS; + p->ref_cnt = 1; + dprintf("page_alloc:paddr = 0x%p,size_bits = 0x%p\n",page_to_addr(p),size_bits); + return p; +} + +static int _pages_free(struct page *p,rt_size_t size_bits) +{ + rt_size_t level = size_bits; + rt_size_t high = ADDRESS_WIDTH_BITS - size_bits - 1; + struct page *buddy; + + if (p->ref_cnt <= 0) + { + rt_kprintf("page ref %d\n", p->ref_cnt); + } + RT_ASSERT(p->ref_cnt > 0); + RT_ASSERT(p->size_bits == ADDRESS_WIDTH_BITS); + + p->ref_cnt--; + if (p->ref_cnt != 0) + { + return 0; + } + + dprintf("page_free:paddr = 0x%p,size_bits = 0x%p\n",page_to_addr(p),size_bits); + PAGE_VALID(p); + + while(level < high) + { + buddy = buddy_get(p,level); + + if(buddy && (buddy -> size_bits == level)) + { + page_remove(buddy,level); + p = (p < buddy) ? p : buddy; + level++; + } + else + { + break; + } + } + + page_insert(p,level); + return 1; +} + +void *rt_pages_alloc(rt_size_t size_bits) +{ + struct page *p; + rt_base_t level; + + level = rt_hw_interrupt_disable(); + p = _pages_alloc(size_bits); + rt_hw_interrupt_enable(level); + return page_to_addr(p); +} + +int rt_pages_free(void *addr,rt_size_t size_bits) +{ + struct page *p; + RT_PASSERT(__CHECKALIGN(addr,size_bits)); + p = addr_to_page(addr); + int real_free = 0; + + if(p) + { + rt_base_t level; + level = rt_hw_interrupt_disable(); + real_free = _pages_free(p,size_bits); + rt_hw_interrupt_enable(level); + } + return real_free; +} + +void rt_pageinfo_dump() +{ + rt_size_t i; + rt_size_t total = 0; + + rt_base_t level; + level = rt_hw_interrupt_disable(); + + for(i = 0;i < PAGE_LIST_SIZE;i++) + { + struct page *p = page_list[i]; + + rt_kprintf("level %d ",i); + + while(p) + { + total += (1UL << i); + rt_kprintf("[0x%08x]",page_to_addr(p)); + p = p -> next; + } + + rt_kprintf("\n"); + } + + rt_hw_interrupt_enable(level); + rt_kprintf("free pages is %08x\n",total); + rt_kprintf("-------------------------------\n"); +} +MSH_CMD_EXPORT(rt_pageinfo_dump, show page info); + +void rt_page_get_info(size_t *total_nr, size_t *free_nr) +{ + rt_size_t i; + rt_size_t total_free = 0; + rt_base_t level; + + level = rt_hw_interrupt_disable(); + + for (i = 0;i < PAGE_LIST_SIZE;i++) + { + struct page *p = page_list[i]; + + while (p) + { + total_free += (1UL << i); + p = p -> next; + } + } + + rt_hw_interrupt_enable(level); + *total_nr = page_nr; + *free_nr = total_free; +} + +void rt_page_init(rt_region_t reg) +{ + rt_size_t align_bits; + rt_size_t size_bits; + rt_size_t i; + + dprintf("split 0x%08x 0x%08x\n",reg.start,reg.end); + + reg.start = __ALIGNUP(reg.start,PAGE_OFFSET_BIT); + reg.end = __ALIGNDOWN(reg.end,PAGE_OFFSET_BIT); + + rt_size_t nr = PAGE_SIZE / sizeof(struct page); + rt_size_t total = (reg.end - reg.start) >> PAGE_OFFSET_BIT; + + /* + equation:cell((total - mnr) / nr) = mnr + let total - mnr = knr + p(k is integer,0 <= p < nr) + then,k + cell(p / nr) = mnr + when p = 0,k = (total - mnr) / nr,mnr = total / (nr + 1) + when p > 0,k = (total - mnr - p) / nr,cell(p / nr) = 1,mnr = (total - p + nr) / (nr + 1) + to be simple,let all free memory remained can be indicated in page struct memory,so let use the upbound of mnr + let p = 0,mnr = max(total / (nr + 1),(total - p + nr) / (nr + 1)) = (total + nr) / (nr + 1) + */ + rt_size_t mnr = (total + nr) / (nr + 1); + + dprintf("nr = 0x%08x\n",nr); + dprintf("total = 0x%08x\n",total); + dprintf("mnr = 0x%08x\n",mnr); + + page_start = (struct page *)reg.start; + reg.start += (mnr << PAGE_OFFSET_BIT);//now reg.start is the start point of free memory remained + page_addr = (void *)reg.start; + page_nr = (reg.end - reg.start) >> PAGE_OFFSET_BIT; + + dprintf("align 0x%08x 0x%08x\n",reg.start,reg.end); + + //init page struct + for(i = 0;i < page_nr;i++) + { + page_start[i].size_bits = ADDRESS_WIDTH_BITS; + } + + //init free list + for(i = 0;i < PAGE_LIST_SIZE;i++) + { + page_list[i] = RT_NULL; + } + + //init buddy list + while(reg.start != reg.end) + { + struct page *p; + size_bits = ADDRESS_WIDTH_BITS - 1 - __builtin_clzl(reg.end - reg.start); + align_bits = __builtin_ctzl(reg.start); + + /* + align_bits < size_bits:a small page exists + align_bits = size_bits:this is a page + align_bits > size_bits:the size of memory is less than the align size of current addr + */ + if(align_bits < size_bits) + { + size_bits = align_bits; + } + p = addr_to_page((void*)reg.start); + p->ref_cnt = 1; + _pages_free(addr_to_page((void *)reg.start),size_bits - PAGE_OFFSET_BIT); + reg.start += (1U << size_bits); + } + + rt_pages_alloc(0); +} + +#endif /* RT_USING_USERSPACE */ diff --git a/libcpu/x86/i386/page.h b/libcpu/x86/i386/page.h new file mode 100644 index 0000000000000000000000000000000000000000..b776f6802b0e556c8fae4b6e6acc4998a7978eb0 --- /dev/null +++ b/libcpu/x86/i386/page.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-01-29 lizhirui first version + * 2021-07-17 JasonHu used in i386 + */ + +#ifndef __PAGE_H__ +#define __PAGE_H__ + +#include + +struct tag_region +{ + size_t start; + size_t end; +}; +typedef struct tag_region rt_region_t; + +rt_size_t rt_page_bits(rt_size_t size); +void *rt_pages_alloc(rt_size_t size_bits); +void rt_page_ref_inc(void *addr, uint32_t size_bits); +int rt_page_ref_get(void *addr, uint32_t size_bits); +void rt_page_ref_dec(void *addr, uint32_t size_bits); +int rt_pages_free(void *addr,rt_size_t size_bits); +void rt_pageinfo_dump(); +void rt_page_get_info(size_t *total_nr, size_t *free_nr); +void rt_page_init(rt_region_t reg); + +#endif diff --git a/libcpu/x86/i386/pic.c b/libcpu/x86/i386/pic.c new file mode 100644 index 0000000000000000000000000000000000000000..4be3a81b8f89f582a1685a6c04bffcd0d02082fb --- /dev/null +++ b/libcpu/x86/i386/pic.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-07-16 JasonHu first version + */ + +#include "pic.h" +#include + +void rt_hw_pic_init(void) +{ + /* mask all interrupts */ + outb(PIC_MASTER_CTLMASK, 0xff); + outb(PIC_SLAVE_CTLMASK, 0xff); + + outb(PIC_MASTER_CTL, 0x11); + outb(PIC_MASTER_CTLMASK, 0x20); + outb(PIC_MASTER_CTLMASK, 1 << 2); + outb(PIC_MASTER_CTLMASK, 0x01); + + outb(PIC_SLAVE_CTL, 0x11); + outb(PIC_SLAVE_CTLMASK, 0x28); + outb(PIC_SLAVE_CTLMASK, 2); + outb(PIC_SLAVE_CTLMASK, 0x01); + + /* mask all interrupts */ + outb(PIC_MASTER_CTLMASK, 0xff); + outb(PIC_SLAVE_CTLMASK, 0xff); +} + +void rt_hw_pic_enable(int irq) +{ + if (irq < 8) /* clear master */ + { + outb(PIC_MASTER_CTLMASK, inb(PIC_MASTER_CTLMASK) & ~(1 << irq)); + } + else /* clear irq 2 first, then clear slave */ + { + outb(PIC_MASTER_CTLMASK, inb(PIC_MASTER_CTLMASK) & ~(1 << PIC_SLAVE_CONNECT_IRQ)); + outb(PIC_SLAVE_CTLMASK, inb(PIC_SLAVE_CTLMASK) & ~ (1 << (irq - 8))); + } +} + +void rt_hw_pic_disable(int irq) +{ + if(irq < 8) /* set master */ + { + outb(PIC_MASTER_CTLMASK, inb(PIC_MASTER_CTLMASK) | (1 << irq)); + } + else /* set slave */ + { + outb(PIC_SLAVE_CTLMASK, inb(PIC_SLAVE_CTLMASK) | (1 << (irq - 8))); + } +} + +void rt_hw_pic_ack(int irq) +{ + if (irq >= 8) /* slaver */ + { + outb(PIC_SLAVE_CTL, PIC_EIO); + } + outb(PIC_MASTER_CTL, PIC_EIO); +} diff --git a/libcpu/x86/i386/pic.h b/libcpu/x86/i386/pic.h new file mode 100644 index 0000000000000000000000000000000000000000..5de220dd47af89b8d2dfb95ae37a2a2b91451c7f --- /dev/null +++ b/libcpu/x86/i386/pic.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-07-16 JasonHu first version + */ + +#ifndef __PIC_H__ +#define __PIC_H__ + +#define PIC_MASTER_CTL 0x20 /* I/O port for interrupt controller */ +#define PIC_MASTER_CTLMASK 0x21 /* setting bits in this port disables ints */ +#define PIC_SLAVE_CTL 0xa0 /* I/O port for second interrupt controller */ +#define PIC_SLAVE_CTLMASK 0xa1 /* setting bits in this port disables ints */ + +#define PIC_EIO 0x20 /* end of IO port */ + +#define PIC_SLAVE_CONNECT_IRQ 2 /* irq2 connected to slaver pic */ + +void rt_hw_pic_init(); +void rt_hw_pic_enable(int irq); +void rt_hw_pic_disable(int irq); +void rt_hw_pic_ack(int irq); + +#endif /* __PIC_H__ */ diff --git a/libcpu/x86/i386/segment.c b/libcpu/x86/i386/segment.c new file mode 100644 index 0000000000000000000000000000000000000000..54c82caee5efe4a71dce773c809cecb520c3efc3 --- /dev/null +++ b/libcpu/x86/i386/segment.c @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-08-06 JasonHu first version + */ + +#include "segment.h" +#include "tss.h" +#include "cpuport.h" + +#include +#include + +struct rt_hw_segment +{ + rt_uint16_t limit_low, base_low; + rt_uint8_t base_mid, access_right; + rt_uint8_t limit_high, base_high; +}; +typedef struct rt_hw_segment rt_hw_segment_t; + +static void segment_set(rt_hw_segment_t *seg, rt_ubase_t limit, + rt_ubase_t base, rt_ubase_t attributes) +{ + seg->limit_low = limit & 0xffff; + seg->base_low = base & 0xffff; + seg->base_mid = (base >> 16) & 0xff; + seg->access_right = attributes & 0xff; + seg->limit_high = ((limit >> 16) & 0x0f) | ((attributes >> 8) & 0xf0); + seg->base_high = (base >> 24) & 0xff; +} + +/** + * in x86, we can use fs/gs segment to save thread info, + * set thread info base addr, os can use gs:0 to get the first + * data on [base] + */ +void rt_hw_seg_tls_set(rt_ubase_t base) +{ + rt_hw_segment_t *seg = GDT_OFF2PTR(((rt_hw_segment_t *) GDT_VADDR), INDEX_USER_TLS); + seg->base_low = base & 0xffff; + seg->base_mid = (base >> 16) & 0xff; + seg->base_high = (base >> 24) & 0xff; +} + +rt_ubase_t rt_hw_seg_tls_get() +{ + rt_hw_segment_t *seg = GDT_OFF2PTR(((rt_hw_segment_t *) GDT_VADDR), INDEX_USER_TLS); + return (seg->base_low & 0xffff) | ((seg->base_mid & 0xff) << 16) | ((seg->base_high & 0xff) << 24); +} + +void rt_hw_segment_init(void) +{ + /* Global segment table */ + rt_hw_segment_t *gdt = (rt_hw_segment_t *) GDT_VADDR; + + int i; + for (i = 0; i <= GDT_LIMIT/8; i++) + { + segment_set(GDT_OFF2PTR(gdt, i), 0, 0, 0); + } + + segment_set(GDT_OFF2PTR(gdt, INDEX_KERNEL_CODE), GDT_BOUND_TOP, GDT_BOUND_BOTTOM, GDT_KERNEL_CODE_ATTR); + segment_set(GDT_OFF2PTR(gdt, INDEX_KERNEL_DATA), GDT_BOUND_TOP, GDT_BOUND_BOTTOM, GDT_KERNEL_DATA_ATTR); + + rt_hw_tss_t *tss = rt_hw_tss_get(); + segment_set(GDT_OFF2PTR(gdt, INDEX_TSS), sizeof(rt_hw_tss_t) - 1, (rt_ubase_t )tss, GDT_TSS_ATTR); + + segment_set(GDT_OFF2PTR(gdt, INDEX_USER_CODE), GDT_BOUND_TOP, GDT_BOUND_BOTTOM, GDT_USER_CODE_ATTR); + segment_set(GDT_OFF2PTR(gdt, INDEX_USER_DATA), GDT_BOUND_TOP, GDT_BOUND_BOTTOM, GDT_USER_DATA_ATTR); + + segment_set(GDT_OFF2PTR(gdt, INDEX_USER_TLS), GDT_BOUND_TOP, GDT_BOUND_BOTTOM, GDT_USER_TLS_ATTR); + + extern void load_new_gdt(rt_ubase_t size, rt_ubase_t gdtr); + load_new_gdt(GDT_LIMIT, GDT_VADDR); +} diff --git a/libcpu/x86/i386/segment.h b/libcpu/x86/i386/segment.h new file mode 100644 index 0000000000000000000000000000000000000000..57997dfb275d40a8bfc4e43d4a4e2664065e9200 --- /dev/null +++ b/libcpu/x86/i386/segment.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-08-06 JasonHu first version + */ + +#ifndef __X86_SEGMENT_H__ +#define __X86_SEGMENT_H__ + +#include + +/* DA: Descriptor Attribute */ +#define DA_32 0x4000 /* 32 bits segment */ +#define DA_G 0x8000 /* segment limit is 4KB */ +#define DA_DPL0 0x00 /* DPL = 0 */ +#define DA_DPL1 0x20 /* DPL = 1 */ +#define DA_DPL2 0x40 /* DPL = 2 */ +#define DA_DPL3 0x60 /* DPL = 3 */ +#define DA_DR 0x90 /* readonly data */ +#define DA_DRW 0x92 /* read/write data */ +#define DA_DRWA 0x93 /* accessed read/write data */ +#define DA_C 0x98 /* code */ +#define DA_CR 0x9A /* readable code */ +#define DA_CCO 0x9C /* only execute consistent code segment */ +#define DA_CCOR 0x9E /* executable readable and consistent code segment */ +#define DA_LDT 0x82 /* local descriptor table */ +#define DA_386TSS 0x89 /* 386 TSS */ + +/* SA : Selector Attribute */ +#define SA_RPL0 0 +#define SA_RPL1 1 +#define SA_RPL2 2 +#define SA_RPL3 3 + +#define SA_TIG 0 /* selector in GDT */ +#define SA_TIL 1 /* selector in IDT */ + +/* index of descriptor */ +#define INDEX_DUMMY 0 +#define INDEX_KERNEL_CODE 1 +#define INDEX_KERNEL_DATA 2 +#define INDEX_TSS 3 +#define INDEX_USER_CODE 4 +#define INDEX_USER_DATA 5 +#define INDEX_USER_TLS 6 + +#define KERNEL_CODE_SEL ((INDEX_KERNEL_CODE << 3) + (SA_TIG << 2) + SA_RPL0) +#define KERNEL_DATA_SEL ((INDEX_KERNEL_DATA << 3) + (SA_TIG << 2) + SA_RPL0) +#define KERNEL_STACK_SEL KERNEL_DATA_SEL + +#define KERNEL_TSS_SEL ((INDEX_TSS << 3) + (SA_TIG << 2) + SA_RPL0) + +#define USER_CODE_SEL ((INDEX_USER_CODE << 3) + (SA_TIG << 2) + SA_RPL3) +#define USER_DATA_SEL ((INDEX_USER_DATA << 3) + (SA_TIG << 2) + SA_RPL3) +#define USER_STACK_SEL USER_DATA_SEL + +#define USER_TLS_SEL ((INDEX_USER_TLS << 3) + (SA_TIG << 2) + SA_RPL3) + +#define GDT_LIMIT 0x000007ff +#define GDT_PADDR 0x003F0000 + +#define GDT_VADDR (KERNEL_VADDR_START + GDT_PADDR) + +#define GDT_OFF2PTR(gdt, off) (gdt + off) + +#define GDT_BOUND_BOTTOM 0 +#define GDT_BOUND_TOP 0xffffffff + +#define GDT_KERNEL_CODE_ATTR (DA_CR | DA_DPL0 | DA_32 | DA_G) +#define GDT_KERNEL_DATA_ATTR (DA_DRW | DA_DPL0 | DA_32 | DA_G) +#define GDT_USER_CODE_ATTR (DA_CR | DA_DPL3 | DA_32 | DA_G) +#define GDT_USER_DATA_ATTR (DA_DRW | DA_DPL3 | DA_32 | DA_G) +#define GDT_TSS_ATTR (DA_386TSS) +#define GDT_USER_TLS_ATTR (DA_DR | DA_DPL3 | DA_32 | DA_G) /* read only data seg */ + +#ifndef __ASSEMBLY__ + +#include + +void rt_hw_segment_init(void); + +void rt_hw_seg_tls_set(rt_ubase_t base); +rt_ubase_t rt_hw_seg_tls_get(); + +#endif + +#endif /*__X86_SEGMENT_H__*/ diff --git a/libcpu/x86/i386/stackframe.h b/libcpu/x86/i386/stackframe.h new file mode 100644 index 0000000000000000000000000000000000000000..37e2d3e4221b083c1d2b6b0427ed941458e43496 --- /dev/null +++ b/libcpu/x86/i386/stackframe.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-07-16 JasonHu first version + */ + +#ifndef __STACK_FRAME_H__ +#define __STACK_FRAME_H__ + +#include + +struct rt_hw_stack_frame +{ + rt_uint32_t vec_no; + + rt_uint32_t edi; + rt_uint32_t esi; + rt_uint32_t ebp; + rt_uint32_t esp_dummy; /* esp_dummy not used, only use a position */ + rt_uint32_t ebx; + rt_uint32_t edx; + rt_uint32_t ecx; + rt_uint32_t eax; + + rt_uint32_t gs; + rt_uint32_t fs; + rt_uint32_t es; + rt_uint32_t ds; + rt_uint32_t error_code; /* error code will push into stack if exception has it, or not push 0 by ourself */ + rt_uint32_t eip; + rt_uint32_t cs; + rt_uint32_t eflags; + /* + * below will push into stack when from user privilege level enter + * kernel privilege level (syscall/excption/interrupt) + */ + rt_uint32_t esp; + rt_uint32_t ss; +} __attribute__((packed)); + +typedef struct rt_hw_stack_frame rt_hw_stack_frame_t; + +typedef void (*hw_thread_func_t)(void *); + +/* we use ebp, ebx, edi, esi, eip as context for fork/clone */ +#define HW_CONTEXT_MEMBER_NR 5 + +struct rt_hw_context +{ + rt_uint32_t ebp; + rt_uint32_t ebx; + rt_uint32_t edi; + rt_uint32_t esi; + + /* first run point to func, other time point to the ret addr of switch_to */ + void (*eip) (hw_thread_func_t func, void *arg, void (*texit)()); + + rt_uint32_t unused; + hw_thread_func_t function; + void *arg; + void *texit; /* thread exit call */ +}; +typedef struct rt_hw_context rt_hw_context_t; + +void rt_hw_stack_frame_dump(rt_hw_stack_frame_t *frame); + +#endif /* __STACK_FRAME_H__ */ diff --git a/libcpu/x86/i386/start_gcc.S b/libcpu/x86/i386/start_gcc.S new file mode 100644 index 0000000000000000000000000000000000000000..f582af9c54c137c8e417c080591a33c824c033ce --- /dev/null +++ b/libcpu/x86/i386/start_gcc.S @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-07-16 JasonHu,GuEe-GUI first version + */ + +#define __ASSEMBLY__ +#include "multiboot2.h" + +# the size of stack is 16KB +#define STACK_SIZE 0x4000 + +#define KSTACK_TOP_PHY 0x9f000 + +.code32 + +.extern rt_boot_setup_entry, primary_cpu_entry + +.section .init +.globl start, _start + +start: +_start: + jmp multiboot_entry + +.align 8 +multiboot_header: + .long MULTIBOOT2_HEADER_MAGIC # magic number (multiboot 2) + .long MULTIBOOT_ARCHITECTURE_I386 # architecture 0 (protected mode i386) + .long multiboot_header_end - multiboot_header # header length + # checksum + .long -(MULTIBOOT2_HEADER_MAGIC + MULTIBOOT_ARCHITECTURE_I386 + (multiboot_header_end - multiboot_header)) + # insert optional multiboot tags here + + # required end tag + .align 8 + .short MULTIBOOT_HEADER_TAG_END # type + .short 0 # flags + .long 8 # size +multiboot_header_end: +multiboot_entry: + # initialize the stack pointer + movl $(stack + STACK_SIZE), %esp + + # reset EFLAGS + pushl $0 + popf + + # push the pointer to the Multiboot information structure + pushl %ebx + # push the magic value + pushl %eax + + # jump to rt_boot_setup_entry + call rt_boot_setup_entry + + # jump to setup_fail if rt_boot_setup_entry return -1 + popl %eax + cmpl $-1, %eax + je setup_fail + + # set kernel stack top + movl $KSTACK_TOP_PHY, %esp + + # jump to kernel_start + movl $primary_cpu_entry, %eax + jmp *%eax + +setup_fail: + # print "Error!" in protected mode + movl $0xcf72cf45, 0xb8000 + movl $0xcf6fcf72, 0xb8004 + movl $0xcf21cf72, 0xb8008 + +multiboot_hlt: + hlt + jmp multiboot_hlt + + .comm stack, STACK_SIZE \ No newline at end of file diff --git a/libcpu/x86/i386/syscall_c.c b/libcpu/x86/i386/syscall_c.c new file mode 100644 index 0000000000000000000000000000000000000000..db8767d1c01d9fb1375b845be9c2523fe5aa67eb --- /dev/null +++ b/libcpu/x86/i386/syscall_c.c @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-02-03 lizhirui first version + * 2021-07-27 JasonHu port to i386 + */ + +#include +#include + +//#define DBG_LEVEL DBG_WARNING +//#define DBG_LEVEL DBG_INFO +#include + +#ifdef RT_USING_USERSPACE + +#include +#include +#include +#include +#include +#include + +#include "stackframe.h" + +typedef rt_size_t (*syscallfunc_t)(rt_size_t,rt_size_t,rt_size_t,rt_size_t,rt_size_t,rt_size_t,rt_size_t); +syscallfunc_t lwp_get_sys_api(uint32_t); + +void rt_hw_syscall_dispath(struct rt_hw_stack_frame *frame) +{ + if(frame->eax == 0) + { + rt_kprintf("syscall id = 0!\n"); + while(1); // TODO: raise signal + } + + if(frame->eax == 0xdeadbeef) + { + rt_kprintf("syscall id = 0xdeadbeef\n"); + while(1); // TODO: raise signal + } + +#ifdef RT_USING_SIGNALS + if(frame->eax == SIGNAL_RETURN_SYSCAL_ID) /* signal return */ + { + lwp_signal_do_return(frame); + return; + } +#endif /* RT_USING_SIGNALS */ + + syscallfunc_t syscallfunc = (syscallfunc_t)lwp_get_sys_api(frame->eax); + + if(syscallfunc == RT_NULL) + { + rt_kprintf("unsupported syscall %d!\n", frame->eax); + while(1); // TODO: raise signal + } + /* TODO: support arg6 */ + LOG_I("\033[36msyscall id = %d,arg0 = 0x%p,arg1 = 0x%p,arg2 = 0x%p,arg3 = 0x%p,arg4 = 0x%p,arg5 = 0x%p,arg6 = 0x%p(unsupport)\n\033[37m", + frame->eax, frame->ebx, frame->ecx, frame->edx, frame->esi, frame->edi, frame->ebp, 0); + frame->eax = syscallfunc(frame->ebx, frame->ecx, frame->edx, frame->esi, frame->edi, frame->ebp, 0); + LOG_I("\033[36msyscall deal ok,ret = 0x%p\n\033[37m",frame->eax); +} + +#endif /* RT_USING_USERSPACE */ diff --git a/libcpu/x86/i386/tss.c b/libcpu/x86/i386/tss.c new file mode 100644 index 0000000000000000000000000000000000000000..ffe3c5c9f2a07e456ba5a08d0aed208077243dc2 --- /dev/null +++ b/libcpu/x86/i386/tss.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-08-06 JasonHu first version + */ + +#include "tss.h" +#include "cpuport.h" +#include "segment.h" +#include +#include +#include + +static rt_hw_tss_t tss; + +rt_hw_tss_t *rt_hw_tss_get() +{ + return &tss; +} + +/** + * @brief : set current process kernel stack top + * + * @param top : stack top + */ +void rt_hw_tss_set_kstacktop(rt_ubase_t top) +{ + // tss.esp0 is kernel statck + tss.esp0 = top; +} + +void rt_hw_tss_init() +{ + memset(&tss, 0, sizeof(rt_hw_tss_t)); + tss.esp0 = KERNEL_STACK_TOP; + tss.ss0 = KERNEL_DATA_SEL; + tss.iobase = sizeof(rt_hw_tss_t); + /* load tr */ + ltr(KERNEL_TSS_SEL); +} diff --git a/libcpu/x86/i386/tss.h b/libcpu/x86/i386/tss.h new file mode 100644 index 0000000000000000000000000000000000000000..fb1022e73b5ed5b1f019a602f2d1541436b4bf8c --- /dev/null +++ b/libcpu/x86/i386/tss.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-08-06 JasonHu first version + */ + +#ifndef __X86_TSS_H__ +#define __X86_TSS_H__ + +#include +#include + +#define KERNEL_STACK_TOP_PHY 0x9f000 +#define KERNEL_STACK_TOP (KERNEL_VADDR_START + KERNEL_STACK_TOP_PHY) + +struct rt_hw_tss +{ + rt_uint32_t backlink; + rt_uint32_t esp0; + rt_uint32_t ss0; + rt_uint32_t esp1; + rt_uint32_t ss1; + rt_uint32_t esp2; + rt_uint32_t ss2; + rt_uint32_t cr3; + rt_uint32_t eip; + rt_uint32_t eflags; + rt_uint32_t eax; + rt_uint32_t ecx; + rt_uint32_t edx; + rt_uint32_t ebx; + rt_uint32_t esp; + rt_uint32_t ebp; + rt_uint32_t esi; + rt_uint32_t edi; + rt_uint32_t es; + rt_uint32_t cs; + rt_uint32_t ss; + rt_uint32_t ds; + rt_uint32_t fs; + rt_uint32_t gs; + rt_uint32_t ldtr; + rt_uint32_t trap; + rt_uint32_t iobase; +}; +typedef struct rt_hw_tss rt_hw_tss_t; + +void rt_hw_tss_init(); +rt_hw_tss_t *rt_hw_tss_get(); +void rt_hw_tss_set_kstacktop(rt_ubase_t top); + +#endif /* __X86_TSS_H__ */ diff --git a/libcpu/x86/i386/x86_gcc.S b/libcpu/x86/i386/x86_gcc.S new file mode 100644 index 0000000000000000000000000000000000000000..68d1442ca8c8d8c4128935d985a85dc835d59393 --- /dev/null +++ b/libcpu/x86/i386/x86_gcc.S @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-07-13 JasonHu first version + */ + +#define __ASSEMBLY__ +#include "segment.h" + +.global load_new_gdt +load_new_gdt: + movl 4(%esp), %eax + movw %ax, 6(%esp) + lgdt 6(%esp) + + # flush segment registers + movw $KERNEL_DATA_SEL, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %ss + xor %eax, %eax + movw %ax, %fs + movw %ax, %gs + ljmp $KERNEL_CODE_SEL, $.newpc +.newpc: + ret + +.global load_new_idt +load_new_idt: + movl 4(%esp), %eax + movw %ax, 6(%esp) + lidt 6(%esp) + ret + +.global write_cr3 +write_cr3: + movl 4(%esp), %eax + movl %eax, %cr3 + ret + +.global read_cr0 +read_cr0: + movl %cr0, %eax + ret + +.global read_cr2 +read_cr2: + movl %cr2, %eax + ret + +.global write_cr0 +write_cr0: + movl 4(%esp), %eax + movl %eax, %cr0 + ret \ No newline at end of file diff --git a/libcpu/x86/i386/x86_mmu.c b/libcpu/x86/i386/x86_mmu.c new file mode 100644 index 0000000000000000000000000000000000000000..fbff1b424d8eff35240976efa05c154652e06fa2 --- /dev/null +++ b/libcpu/x86/i386/x86_mmu.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-07-17 JasonHu first version + */ + +#include +#include + +#include "mmu.h" +#include + +void mmu_set_pagetable(rt_ubase_t addr) +{ + /* set new pgdir will flush tlb */ + write_cr3(addr); +} + +void mmu_enable_user_page_access() +{ +} + +void mmu_disable_user_page_access() +{ +} + +void mmu_enable() +{ + write_cr0(read_cr0() | CR0_PG); +} diff --git a/libcpu/x86/i386/x86_mmu.h b/libcpu/x86/i386/x86_mmu.h new file mode 100644 index 0000000000000000000000000000000000000000..4415731d0c0b7ff9248ecbd958eb2db7f4122a1b --- /dev/null +++ b/libcpu/x86/i386/x86_mmu.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-07-17 JasonHu first version + */ + +#ifndef __X86_MMU_H__ +#define __X86_MMU_H__ + +#include + +#undef PAGE_SIZE + +#define ADDRESS_WIDTH_BITS 32 +#define PHYSICAL_ADDRESS_WIDTH_BITS ADDRESS_WIDTH_BITS +#define ARCH_ADDRESS_WIDTH_BITS ADDRESS_WIDTH_BITS + +#define __SIZE(bit) (1U << (bit)) +#define __MASK(bit) (__SIZE(bit) - 1UL) +#define __UMASK(bit) (~(__MASK(bit))) +#define __MASKVALUE(value,maskvalue) ((value) & (maskvalue)) +#define __UMASKVALUE(value,maskvalue) ((value) & (~(maskvalue))) +#define __CHECKUPBOUND(value,bit_count) (!(((rt_size_t)(value)) & (~__MASK(bit_count)))) +#define __CHECKALIGN(value,start_bit) (!(((rt_size_t)(value)) & (__MASK(start_bit)))) + +#define __PARTBIT(value,start_bit,length) (((value) >> (start_bit)) & __MASK(length)) + +#define __ALIGNUP(value,bit) (((value) + __MASK(bit)) & __UMASK(bit)) +#define __ALIGNDOWN(value,bit) ((value) & __UMASK(bit)) + +#define PAGE_OFFSET_SHIFT 0 +#define PAGE_OFFSET_BIT 12 +#define PAGE_SIZE __SIZE(PAGE_OFFSET_BIT) +#define PAGE_OFFSET_MASK __MASK(PAGE_OFFSET_BIT) +#define PAGE_ADDR_MASK __UMASK(PAGE_OFFSET_BIT) + +#define PTE_SHIFT (PAGE_OFFSET_SHIFT + PAGE_OFFSET_BIT) +#define PTE_BIT 10 +#define PDE_SHIFT (PTE_SHIFT + PTE_BIT) +#define PDE_BIT 10 + +#define mmu_flush_tlb() \ + do \ + { \ + unsigned long tmpreg; \ + __asm__ __volatile__ ( \ + "movl %%cr3, %0 \n\t" \ + "movl %0, %%cr3 \n\t" \ + :"=r"(tmpreg) \ + : \ + :"memory" \ + ); \ + } \ + while(0) + +#define ARCH_PAGE_SIZE PAGE_SIZE +#define ARCH_PAGE_MASK (ARCH_PAGE_SIZE - 1) +#define ARCH_PAGE_SHIFT PAGE_OFFSET_BIT + +void mmu_set_pagetable(rt_ubase_t addr); +void mmu_enable_user_page_access(); +void mmu_disable_user_page_access(); +void mmu_enable(); + +#endif /* __X86_MMU_H__ */ diff --git a/src/kservice.c b/src/kservice.c index 7b35b903c3faa6e289cb9d14a4eddbfec510afed..ed3fa8072c221ff410892d1fa8e7986ea834a955 100644 --- a/src/kservice.c +++ b/src/kservice.c @@ -575,7 +575,7 @@ void rt_show_version(void) #endif rt_kprintf(" / | \\ %d.%d.%d build %s\n", RT_VERSION, RT_SUBVERSION, RT_REVISION, __DATE__); - rt_kprintf(" 2006 - 2020 Copyright by rt-thread team\n"); + rt_kprintf(" 2006 - 2021 Copyright by rt-thread team\n"); } RTM_EXPORT(rt_show_version);