*work_area_start = WorkAreaBase;
*work_area_size = ram_end - (uintptr_t) WorkAreaBase;
*heap_start = BSP_BOOTCARD_HEAP_USES_WORK_AREA;
*heap_size = (uintptr_t) HeapSize;
這些變量是在連接腳本中
_sdram_base = DEFINED(_sdram_base) ? _sdram_base : 0x30000000;
_sdram_size = DEFINED(_sdram_size) ? _sdram_size : 64M;
RamBase = _sdram_base;
RamSize = _sdram_size;
HeapSize = DEFINED(HeapSize) ? HeapSize : 0x0;
_end = . ;
__end__ = . ;
PROVIDE (end = _end);
WorkAreaBase = .;
可見,work are 是在 ZI 段之後沒有用的內存。大小就是根據配置的RAM的總大小減去已經佔用的大小。
HeapSize 則需要根據是否有定義,沒有的話就是0了。應該是通過makefile等手段去指定的,目前暫時查找不到根源
這個 work area 和配置中的 ram需求大小做判斷,如果需求大於供給,則會錯誤
if ( work_area_size <= Configuration.work_space_size ) {
printk(
"bootcard: work space too big for work area: %p > %p\n",
(void *) Configuration.work_space_size,
(void *) work_area_size
);
bsp_cleanup();
return -1;
}
rtems_configuration_table Configuration = {
NULL, /* filled in by BSP */
CONFIGURE_EXECUTIVE_RAM_SIZE,
CONFIGURE_EXECUTIVE_RAM_SIZE 是用戶定義的,默認是根據自動計算的。一般一些網絡應用應該至少給 256K 以上的 RAM
bootcard_bsp_libc_helper 函數中先設置 heap ,如果 CONFIGURE_UNIFIED_WORK_AREAS ,表示 work area 和 heap
使用統一的空間,則初始化爲 heap 的 work area 開始
如果爲獨立空間,則 heap 跟在 work area 的後面的所有配置空間
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
LIBIO 是設備的輸入輸出接口
CONFIGURE_LIBIO_MAXIMUM_FILE_DESCRIPTORS 可以由用戶配置,默認 3個
有全局變量去保存
uint32_t rtems_libio_number_iops = CONFIGURE_LIBIO_MAXIMUM_FILE_DESCRIPTORS;
很簡單,維護3個全局變量,信號量,指向這塊內存的,空的。
rtems_id rtems_libio_semaphore;
rtems_libio_t *rtems_libio_iops;
rtems_libio_t *rtems_libio_iop_freelist;
void rtems_libio_init( void )
{
rtems_status_code rc;
uint32_t i;
rtems_libio_t *iop;
if (rtems_libio_number_iops > 0)
{
rtems_libio_iops = (rtems_libio_t *) calloc(rtems_libio_number_iops,
sizeof(rtems_libio_t));
if (rtems_libio_iops == NULL)
rtems_fatal_error_occurred(RTEMS_NO_MEMORY);
iop = rtems_libio_iop_freelist = rtems_libio_iops;
for (i = 0 ; (i + 1) < rtems_libio_number_iops ; i++, iop++)
iop->data1 = iop + 1;
iop->data1 = NULL;
}
很簡單,分配 N 個(由用戶配置)描述符結構體,然後初始化連接起來,連接到 rtems_libio_iop_freelist
上面。這樣做的好處是不會隨便的分配,固定分配,更加穩定。這個和 UCOS 的 TCB 是一樣的。
rc = rtems_semaphore_create(
RTEMS_LIBIO_SEM,
1,
RTEMS_BINARY_SEMAPHORE | RTEMS_INHERIT_PRIORITY | RTEMS_PRIORITY,
RTEMS_NO_PRIORITY,
&rtems_libio_semaphore
);
if ( rc != RTEMS_SUCCESSFUL )
rtems_fatal_error_occurred( rc );
接着佔用一個信號量使用。
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
device driver 的初始化
首先,有多少個驅動支持是用戶指定的,沒有的話自動根據 Device_drivers 配置,裏面放的是靜態
的驅動
CONFIGURE_MAXIMUM_DRIVERS, /* maximum device drivers */
CONFIGURE_NUMBER_OF_DRIVERS, /* static device drivers */
Device_drivers,
在初始化函數 _IO_Manager_initialization 的時候賦值到全局變量中了。
_IO_Driver_address_table = driver_table;
_IO_Number_of_drivers = number_of_drivers;
在 _IO_Initialize_all_drivers 函數中將會根據這個表中的驅動進行初始化。
可以看看這個表,根據配置支持哪些驅動都在裏面了
rtems_driver_address_table Device_drivers[] = {
#ifdef CONFIGURE_BSP_PREREQUISITE_DRIVERS
CONFIGURE_BSP_PREREQUISITE_DRIVERS,
#endif
#ifdef CONFIGURE_APPLICATION_PREREQUISITE_DRIVERS
CONFIGURE_APPLICATION_PREREQUISITE_DRIVERS,
#endif
#ifdef CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
CONSOLE_DRIVER_TABLE_ENTRY,
#endif
#ifdef CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
CLOCK_DRIVER_TABLE_ENTRY,
#endif
#ifdef CONFIGURE_APPLICATION_NEEDS_RTC_DRIVER
RTC_DRIVER_TABLE_ENTRY,
#endif
#ifdef CONFIGURE_APPLICATION_NEEDS_WATCHDOG_DRIVER
WATCHDOG_DRIVER_TABLE_ENTRY,
#endif
.........
};
比較關心的是console 驅動和clock驅動
#define CLOCK_DRIVER_TABLE_ENTRY \
{ Clock_initialize, NULL, NULL, NULL, NULL, NULL }
Clock_initialize 裏面初始化時鐘,由BSP中做了
Clock_driver_support_install_isr( Clock_isr, Old_ticker );
按照 中斷處理句柄,最終是會調用 rtems_clock_tick ,這個比較重要
是操作系統知道一個 tick,會發生任務切換的。
rtems_status_code rtems_clock_tick( void )
{
}
所以不知道爲什麼,這麼重要的,爲什麼可以配置爲不使用,或者是用戶自己去調用 rtems_clock_tick
又或者是根本不需要任務切換。
#define CONSOLE_DRIVER_TABLE_ENTRY \
{ console_initialize, console_open, console_close, \
console_read, console_write, console_control }
console_initialize
根據全局變量 Console_Port_Count 確定有多少個端口,Console_Port_Tbl 確定具體的設備,這個設備表
是由具體的bsp去實現的,例如 gp32/console 裏面的文件,最後註冊爲設備 /dev/console
console_open 打開
cptr = &Console_Port_Tbl[minor];
Callbacks.firstOpen = cptr->pDeviceFns->deviceFirstOpen;
Callbacks.lastClose = cptr->pDeviceFns->deviceLastClose;
......
打開設備,則從之前的全局變量中找到已經註冊到的串口設備,然後構造callback
調用爲設備自己提供的函數
status = rtems_termios_open ( major, minor, arg, &Callbacks );
/*
* Set callbacks
*/
tty->device = *callbacks;
最後將用戶自己提供的串口函數,連接爲 termios 的回調函數,那麼 termios就能輸入輸出了。
這樣能基本解釋怎麼使用BSP提供的串口函數了。
最後我覺得 termios 是有必要好好的讀讀源代碼,這串口實現比較有意思。以後再搞了。