Просмотр исходного кода

!286 RT-Smart在x86处理器上面的基础移植支持
Merge pull request !286 from 胡自成/rt-smart

bernard 4 лет назад
Родитель
Сommit
e7d65dc737
89 измененных файлов с 8394 добавлено и 2750 удалено
  1. 1 0
      .gitignore
  2. 594 0
      bsp/x86/.config
  3. 31 0
      bsp/x86/.gitignore
  4. 34 0
      bsp/x86/Kconfig
  5. 60 44
      bsp/x86/Makefile
  6. 24 0
      bsp/x86/README.md
  7. 2 2
      bsp/x86/SConscript
  8. 2 4
      bsp/x86/applications/SConscript
  9. 0 86
      bsp/x86/applications/application.c
  10. 19 0
      bsp/x86/applications/main.c
  11. 37 0
      bsp/x86/applications/mnt.c
  12. 21 0
      bsp/x86/applications/romfs.c
  13. 0 109
      bsp/x86/applications/startup.c
  14. 22 0
      bsp/x86/drivers/Kconfig
  15. 95 48
      bsp/x86/drivers/board.c
  16. 74 7
      bsp/x86/drivers/board.h
  17. 0 337
      bsp/x86/drivers/console.c
  18. 191 0
      bsp/x86/drivers/direct_uart.c
  19. 18 0
      bsp/x86/drivers/direct_uart.h
  20. 0 187
      bsp/x86/drivers/dma.h
  21. 852 0
      bsp/x86/drivers/drv_ahci.c
  22. 356 0
      bsp/x86/drivers/drv_ahci.h
  23. 148 0
      bsp/x86/drivers/drv_timer.c
  24. 16 0
      bsp/x86/drivers/drv_timer.h
  25. 302 0
      bsp/x86/drivers/drv_uart.c
  26. 16 0
      bsp/x86/drivers/drv_uart.h
  27. 0 360
      bsp/x86/drivers/floppy.c
  28. 0 71
      bsp/x86/drivers/floppy.h
  29. 0 148
      bsp/x86/drivers/include/bsp.h
  30. 0 93
      bsp/x86/drivers/include/grub.h
  31. 0 147
      bsp/x86/drivers/include/i386.h
  32. 0 366
      bsp/x86/drivers/keyboard.c
  33. 0 132
      bsp/x86/drivers/keyboard.h
  34. 0 239
      bsp/x86/drivers/keymap.h
  35. 366 0
      bsp/x86/drivers/pci.c
  36. 127 0
      bsp/x86/drivers/pci.h
  37. 0 72
      bsp/x86/drivers/serial.c
  38. 6 0
      bsp/x86/get_grub.sh
  39. 106 0
      bsp/x86/link.lds
  40. 52 0
      bsp/x86/memlayout.md
  41. 167 150
      bsp/x86/rtconfig.h
  42. 12 10
      bsp/x86/rtconfig.py
  43. 0 28
      bsp/x86/src/extract.sh
  44. 0 36
      bsp/x86/src/hello.c
  45. 0 18
      bsp/x86/src/stdio.h
  46. 0 55
      bsp/x86/x86_ram.lds
  47. 4 1
      components/lwp/SConscript
  48. 11 0
      components/lwp/arch/x86/i386/SConscript
  49. 351 0
      components/lwp/arch/x86/i386/lwp_arch.c
  50. 54 0
      components/lwp/arch/x86/i386/lwp_arch.h
  51. 73 0
      components/lwp/arch/x86/i386/lwp_gcc.S
  52. 41 0
      components/lwp/arch/x86/i386/reloc.c
  53. 2 0
      components/lwp/lwp_syscall.c
  54. 20 0
      libcpu/x86/SConscript
  55. 14 0
      libcpu/x86/i386/SConscript
  56. 43 0
      libcpu/x86/i386/backtrace.c
  57. 17 0
      libcpu/x86/i386/backtrace.h
  58. 117 0
      libcpu/x86/i386/bitmap.c
  59. 34 0
      libcpu/x86/i386/bitmap.h
  60. 68 0
      libcpu/x86/i386/boot_module.c
  61. 63 0
      libcpu/x86/i386/boot_module.h
  62. 64 0
      libcpu/x86/i386/cache.c
  63. 36 0
      libcpu/x86/i386/cache.h
  64. 51 0
      libcpu/x86/i386/context_gcc.S
  65. 147 0
      libcpu/x86/i386/cpuport.c
  66. 41 0
      libcpu/x86/i386/cpuport.h
  67. 101 0
      libcpu/x86/i386/dma.c
  68. 29 0
      libcpu/x86/i386/dma.h
  69. 156 0
      libcpu/x86/i386/gate.c
  70. 40 0
      libcpu/x86/i386/gate.h
  71. 94 0
      libcpu/x86/i386/i386.h
  72. 275 0
      libcpu/x86/i386/interrupt.c
  73. 43 0
      libcpu/x86/i386/interrupt.h
  74. 249 0
      libcpu/x86/i386/interrupt_gcc.S
  75. 684 0
      libcpu/x86/i386/mmu.c
  76. 149 0
      libcpu/x86/i386/mmu.h
  77. 401 0
      libcpu/x86/i386/multiboot2.h
  78. 489 0
      libcpu/x86/i386/page.c
  79. 34 0
      libcpu/x86/i386/page.h
  80. 67 0
      libcpu/x86/i386/pic.c
  81. 28 0
      libcpu/x86/i386/pic.h
  82. 80 0
      libcpu/x86/i386/segment.c
  83. 91 0
      libcpu/x86/i386/segment.h
  84. 71 0
      libcpu/x86/i386/stackframe.h
  85. 83 0
      libcpu/x86/i386/start_gcc.S
  86. 69 0
      libcpu/x86/i386/syscall_c.c
  87. 44 0
      libcpu/x86/i386/tss.c
  88. 56 0
      libcpu/x86/i386/tss.h
  89. 59 0
      libcpu/x86/i386/x86_gcc.S

+ 1 - 0
.gitignore

@@ -34,3 +34,4 @@ ncscope.*
 #ctag files
 tags
 
+.vscode/

+ 594 - 0
bsp/x86/.config

@@ -0,0 +1,594 @@
+#
+# 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
+
+#
+# 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

+ 31 - 0
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

+ 34 - 0
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"

+ 60 - 44
bsp/x86/Makefile

@@ -1,46 +1,62 @@
-
-CC = gcc -O0 -m32 -fno-builtin -fno-stack-protector -nostdinc -nostdlib
-LD = ld -melf_i386 -nostdlib
-
-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:
-	@scons
-
-rtsym:
-	@./src/extract.sh ./rtthread-ia32.map ./src/rt_thread_sym.h
-
-obj:
-	mkdir -p obj
-
-out:
-	mkdir -p out
-
-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
-
-disasm: obj out
-	$(CC) -shared -S -fPIC -Isrc src/hello.c -o obj/hello.s
-	cat obj/hello.s
-	objdump --disassemble out/hello.mo
-
-exe: obj out
-
+# tools 
+GRUB_DIR	:= grub-2.04
+OS_NAME		:= rtthread
+QEMU		:= qemu-system-i386
+GDB			:= gdb
+TRUNC		:= truncate
+MCOPY		:= mcopy
+
+# file name
+DISK0		:= disk0.img
+DISK1		:= disk1.img
+SZ_DISK0	:= 64M
+SZ_DISK1	:= 64M
+MKFS		:= mkfs.fat
+ROM_DIR		:= ../../../userapps/root
+
+RTTHREAD_ELF:= rtthread.elf
+
+# config graphic window ? (y/n)
+QEMU_WINDOW ?= n
+
+# 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
+
+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
+
+all: makeiso makedisk
+
+makeiso: $(RTTHREAD_ELF)
+	@$(MAKE) -s -C $(GRUB_DIR) KERNEL=$(RTTHREAD_ELF) OS_NAME=$(OS_NAME)
+
+makedisk:
+	$(TRUNC) --size $(SZ_DISK0) $(DISK0)
+	$(TRUNC) --size $(SZ_DISK1) $(DISK1)
+	$(MKFS) -F32 $(DISK0)
+	-$(MCOPY) -i $(DISK0) $(ROM_DIR)/bin/*.elf ::
+
+run: makedisk makeiso
+	$(QEMU) $(QEMU_ARGS)
+
+qemudbg:
+	$(QEMU) -S -gdb tcp::10001,ipv4 $(QEMU_ARGS)
+
+# 连接gdb server: target remote localhost:10001
+gdb:
+	$(GDB) $(RTTHREAD_ELF)
 
 clean:
-	scons -c clean
-	rm -fr build rtthread* out obj
-
-floppy.img:
-	wget https://github.com/bajdcc/tinix/raw/master/floppy.img
-
-# 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
+	@$(MAKE) -s -C $(GRUB_DIR) clean

+ 24 - 0
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
+```

+ 2 - 2
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)
 

+ 2 - 4
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)
 

+ 0 - 86
bsp/x86/applications/application.c

@@ -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 <rtthread.h>
-
-#ifdef RT_USING_DFS
-#include <dfs_fs.h>
-#include <dfs.h>
-#include "floppy.h"
-#ifdef RT_USING_MODULE
-#include <rtm.h>
-#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;
-}

+ 19 - 0
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 <rtthread.h>
+#include <rthw.h>
+#include <stdio.h>
+#include <string.h>
+
+int main(void)
+{
+    printf("Hello rtthread-smart x86!\n");
+    return 0;
+}

+ 37 - 0
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 <rtthread.h>
+
+#ifdef RT_USING_DFS
+#include <dfs_fs.h>
+#include <dfs_romfs.h>
+
+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

+ 21 - 0
bsp/x86/applications/romfs.c

@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2021-08-05     JasonHu      first version
+ */
+
+#include <dfs_romfs.h>
+
+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])};
+

+ 0 - 109
bsp/x86/applications/startup.c

@@ -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 <rtthread.h>
-#include <rthw.h>
-
-#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 ;
-}
-
-/*@}*/

+ 22 - 0
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

+ 95 - 48
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 <rtthread.h>
 #include <rthw.h>
+#include <rtthread.h>
+#include <rtdevice.h>
+#include <rtconfig.h>
+#include <rtdbg.h>
 
-#include <bsp.h>
+#include <cpuport.h>
+#include <board.h>
+#include <dma.h>
 
-/**
- * @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 <mmu.h>
+#include <page.h>
+#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.h>
-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
-/*@}*/

+ 74 - 7
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 <rtconfig.h>
+#include <interrupt.h>
+#include <cpuport.h>
+
+/* 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

+ 0 - 337
bsp/x86/drivers/console.c

@@ -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 <rtthread.h>
-#include <rthw.h>
-
-#include <bsp.h>
-
-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++);
-    }
-}
-
-/*@}*/

+ 191 - 0
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 <rtconfig.h>
+
+#ifdef BSP_USING_DIRECT_UART
+#include <rthw.h>
+#include <rtdevice.h>
+
+#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 */

+ 18 - 0
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__ */

+ 0 - 187
bsp/x86/drivers/dma.h

@@ -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
-

+ 852 - 0
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 <rtconfig.h>
+
+#ifdef BSP_DRV_AHCI
+
+#include <rtthread.h>
+#include <rtdef.h>
+#include <rtdbg.h>
+#include <rthw.h>
+#include <ioremap.h>
+#include <dma.h>
+#include <mmu.h>
+
+#include <board.h>
+
+#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 */

+ 356 - 0
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 <rtdef.h>
+
+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__ */

+ 148 - 0
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 <rthw.h>
+#include <rtthread.h>
+#include <rtconfig.h>
+
+#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;
+}

+ 16 - 0
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__ */

+ 302 - 0
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 <rtconfig.h>
+
+#ifdef BSP_DRV_UART
+#include <rthw.h>
+#include <rtdevice.h>
+#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 */

+ 16 - 0
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__ */

+ 0 - 360
bsp/x86/drivers/floppy.c

@@ -1,360 +0,0 @@
-
-#include <rtthread.h>
-#include <rthw.h>
-
-#include <bsp.h>
-
-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,&sector);
-
-    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);
-
-}

+ 0 - 71
bsp/x86/drivers/floppy.h

@@ -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

+ 0 - 148
bsp/x86/drivers/include/bsp.h

@@ -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 <i386.h>
-
-#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_ */

+ 0 - 93
bsp/x86/drivers/include/grub.h

@@ -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

+ 0 - 147
bsp/x86/drivers/include/i386.h

@@ -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

+ 0 - 366
bsp/x86/drivers/keyboard.c

@@ -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 <rtthread.h>
-#include <rthw.h>
-
-#include <bsp.h>
-#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;
-}
-
-/*@}*/

+ 0 - 132
bsp/x86/drivers/keyboard.h

@@ -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_ */

+ 0 - 239
bsp/x86/drivers/keymap.h

@@ -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_ */

+ 366 - 0
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 <rtthread.h>
+
+// #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 <finsh.h>
+MSH_CMD_EXPORT(list_pci_device, list PCI device on computer)
+#endif /* RT_USING_FINSH */

+ 127 - 0
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 <rtdef.h>
+
+#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__ */

+ 0 - 72
bsp/x86/drivers/serial.c

@@ -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 <rtthread.h>
-#include <rthw.h>
-
-#include <bsp.h>
-
-/**
- * @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);
-}
-
-/*@}*/

+ 6 - 0
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

+ 106 - 0
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 = .;
+}

+ 52 - 0
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                            |
+    +---------------------+-------------------------------------------+
+```

+ 167 - 150
bsp/x86/rtconfig.h

@@ -1,180 +1,197 @@
-/* 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
+
+/* 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

+ 12 - 10
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'

+ 0 - 28
bsp/x86/src/extract.sh

@@ -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

+ 0 - 36
bsp/x86/src/hello.c

@@ -1,36 +0,0 @@
-
-#include <stdio.h>
-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<argc; i++)
-	{
-		printf("argv[%d]='%s'\n", i, argv[i]);
-	}
-
-	printf(str);
-
-	printf("g_str address is %ph\n",g_str);
-	puts(g_str);
-
-	rt_kprintf("\nnative rt_kprintf a(%ph)=%d, b(%ph)=%d\n", &a, a, &b, b);
-
-	printf("%d+%d=%d\n", 4, 5, add(4, 5));
-
-	return 0xdeadbeef;
-}
-

+ 0 - 18
bsp/x86/src/stdio.h

@@ -1,18 +0,0 @@
-#ifndef __STDIO_H_H
-#define __STDIO_H_H
-
-#include <rt_thread_sym.h>
-
-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

+ 0 - 55
bsp/x86/x86_ram.lds

@@ -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 = .;
-}

+ 4 - 1
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

+ 11 - 0
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')

+ 351 - 0
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 <rthw.h>
+#include <stddef.h>
+#include <rtconfig.h>
+
+#ifdef RT_USING_USERSPACE
+
+#include <stackframe.h>
+#include <interrupt.h>
+#include <segment.h>
+
+#include <mmu.h>
+#include <page.h>
+#include <lwp_mm_area.h>
+#include <lwp_user_mm.h>
+#include <lwp_arch.h>
+#include <lwp_signal.h>
+
+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 */

+ 54 - 0
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 <lwp.h>
+#include <stackframe.h>
+
+#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__*/

+ 73 - 0
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 */

+ 41 - 0
components/lwp/arch/x86/i386/reloc.c

@@ -0,0 +1,41 @@
+/*
+ * 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
+ */
+
+#include <rtthread.h>
+#include <stdint.h>
+#include <string.h>
+#include <elf.h>
+#ifdef RT_USING_USERSPACE
+#include <mmu.h>
+#include <page.h>
+#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

+ 2 - 0
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)

+ 20 - 0
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')

+ 14 - 0
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')

+ 43 - 0
libcpu/x86/i386/backtrace.c

@@ -0,0 +1,43 @@
+/*
+ * 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
+ */
+
+#include <rtthread.h>
+#include <backtrace.h>
+
+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");
+}

+ 17 - 0
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__ */

+ 117 - 0
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 <bitmap.h>
+#include <rtdebug.h>
+#include <string.h>
+
+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;
+}

+ 34 - 0
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 <rtdef.h>
+
+#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__ */

+ 68 - 0
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 <string.h>
+
+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;
+}

+ 63 - 0
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 <rtdef.h>
+
+#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__ */

+ 64 - 0
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 <rthw.h>
+#include <rtdef.h>
+
+#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;
+}

+ 36 - 0
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 <rtdef.h>
+
+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__ */

+ 51 - 0
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 <rtconfig.h>
+
+.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

+ 147 - 0
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 <rthw.h>
+#include <rtthread.h>
+#include <rtdef.h>
+#include <rtdbg.h>
+
+#include "cpuport.h"
+#include "tss.h"
+#include "segment.h"
+#include "gate.h"
+#include "stackframe.h"
+#include "page.h"
+#include "mmu.h"
+#include <lwp.h>
+#include <lwp_arch.h>
+#include <interrupt.h>
+
+/**
+ * @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();
+}

+ 41 - 0
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 <rtconfig.h>
+#include <rtdef.h>
+
+#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__ */

+ 101 - 0
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 <rtthread.h>
+#include <rtdbg.h>
+#include <rtdef.h>
+#include <bitmap.h>
+#include <mmu.h>
+#include <dma.h>
+
+/**
+ * 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;
+}

+ 29 - 0
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 <rtdef.h>
+
+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__ */

+ 156 - 0
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 <rtdef.h>
+
+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);
+}

+ 40 - 0
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 <rtconfig.h>
+
+#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__ */

+ 94 - 0
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 <rtdef.h>
+
+#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__ */

+ 275 - 0
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 <rtthread.h>
+#include <rthw.h>
+#include <rtdbg.h>
+
+#include <interrupt.h>
+#include <stackframe.h>
+#include <backtrace.h>
+#include <pic.h>
+#include <lwp_arch.h>
+
+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();
+}

+ 43 - 0
libcpu/x86/i386/interrupt.h

@@ -0,0 +1,43 @@
+/*
+ * 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
+
+#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
+
+#include "i386.h"
+
+#endif  /* __INTERRUPT_H__ */

+ 249 - 0
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 <rtconfig.h>
+
+.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

+ 684 - 0
libcpu/x86/i386/mmu.c

@@ -0,0 +1,684 @@
+/*
+ * 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 <rtthread.h>
+#include <rthw.h>
+#include <stdlib.h>
+#include <string.h>
+#include <rtdbg.h>
+
+#include "mmu.h"
+#include "cache.h"
+#include "i386.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;
+}
+
+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);
+}

+ 149 - 0
libcpu/x86/i386/mmu.h

@@ -0,0 +1,149 @@
+/*
+ * 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 <stddef.h>
+#include <rtdef.h>
+#include <rtconfig.h>
+
+#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
+
+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_set_pagetable(rt_ubase_t addr);
+void mmu_enable_user_page_access();
+void mmu_disable_user_page_access();
+void mmu_enable();
+
+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

+ 401 - 0
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__ */

+ 489 - 0
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 <stdint.h>
+#include <rtthread.h>
+#include <rthw.h>
+#include <board.h>
+
+#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 */

+ 34 - 0
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 <rtdef.h>
+
+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

+ 67 - 0
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 <interrupt.h>
+
+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);
+}

+ 28 - 0
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         <Master> */
+#define PIC_MASTER_CTLMASK  0x21    /* setting bits in this port disables ints   <Master> */
+#define PIC_SLAVE_CTL       0xa0    /* I/O port for second interrupt controller  <Slave>  */
+#define PIC_SLAVE_CTLMASK   0xa1    /* setting bits in this port disables ints   <Slave>  */
+
+#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__ */

+ 80 - 0
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 <i386.h>
+#include <rtthread.h>
+
+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);
+}

+ 91 - 0
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 <rtconfig.h>
+
+/* 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 <rtdef.h>
+
+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__*/

+ 71 - 0
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 <rtdef.h>
+
+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__ */

+ 83 - 0
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

+ 69 - 0
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 <rthw.h>
+#include <rtthread.h>
+
+//#define DBG_LEVEL DBG_WARNING
+//#define DBG_LEVEL DBG_INFO
+#include <rtdbg.h>
+
+#ifdef RT_USING_USERSPACE
+
+#include <stdint.h>
+#include <mmu.h>
+#include <page.h>
+#include <lwp_mm_area.h>
+#include <lwp_user_mm.h>
+#include <lwp_arch.h>
+
+#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 */

+ 44 - 0
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 <string.h>
+#include <i386.h>
+#include <rtthread.h>
+
+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);
+}

+ 56 - 0
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 <rtdef.h>
+#include <rtconfig.h>
+
+#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__ */

+ 59 - 0
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