1 / 32

uC/OS-II Porting to Intel X86 Platform

uC/OS-II Porting to Intel X86 Platform. 2010/04/29 Yufeng Lin. Outline. uC/OS-II Porting Multicore Boot Demo SMP uC/OS-II. uC/OS-II. uC/OS-II Porting Limit. Hardware limit 處理器的 C 編譯器能產生可重入程式碼。 用 C 語言就可以打開和關閉中斷。

wyatt
Download Presentation

uC/OS-II Porting to Intel X86 Platform

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. uC/OS-II Porting to Intel X86 Platform 2010/04/29 Yufeng Lin

  2. Outline • uC/OS-II Porting • Multicore Boot • Demo SMP uC/OS-II 2/32

  3. uC/OS-II 3/32

  4. uC/OS-II Porting Limit • Hardware limit • 處理器的 C 編譯器能產生可重入程式碼。 • 用 C 語言就可以打開和關閉中斷。 • 處理器支援中斷,並且能產生定時中斷 (通常在 10 至 100Hz 之間)。 • 處理器支援能夠容納一定數量的資料的硬體堆疊 (可能是幾千位元組)。 • 處理器有將堆疊指標和其他 CPU 暫存器讀出和儲存到堆疊或記憶體中的指令。 4/32

  5. uC/OS-II Porting main OSInit OSStartHigeReady OSStart Task create Do something Task 1 OSStatrt TimeDly Context switch Other Tasks 5/32 1. 裝置啟動後,執行完硬體的初始設定或是硬體狀態檢查,就直接跳轉到 AP 執行的位置 2. uC/OS-II 一般啟動流程

  6. uC/OS-II Porting • Porting = bootloader + OS • Bootloader • Initialize hardware, vectors, memory, stack, register value • There are two ways • 分開成兩個檔案(bin),bootloader裡面要設定OS Image存放的位址(OS入口),需要兩者一致方可成功啟動OS • 合成一個bin檔,在bootloader執行完以後,透過跳轉__main進入OS入口 • … 6/32

  7. uC/OS-II Porting --- Bootloader 47 16 15 0 Reset 32 bit Linear Base Address 16 bit Table Limit EntryPoint32 PROC NEAR ; Initialize all segment registers to 10h (entry #2 in the GDT) mov ax,10h ; entry #2 in GDT mov ds,ax ; ds = 10h mov es,ax ; es = 10h mov fs,ax ; fs = 10h mov gs,ax ; gs = 10h mov ss,ax ; ss = 10h ; Set the top of stack to allow stack operations. mov esp,8000h ; arbitrary top of stack ; Call main(), which is not expected to return. call _main 16 bit LDT(Local Descriptor Table) is the same GDTR GDT = Global Descriptor Table Real mode _Gdt: DD 0 ; GDT[0]: Null entry, never used. DD 0 ; GDT[1]: Executable, read-only code, base address of 0, ;limit of FFFFFh, granularity bit (G) set (making the limit 4GB) DW 0FFFFh ; Limit[15..0] DW 0000h ; Base[15..0] DB 00h ; Base[23..16] DB 10011010b ; P(1) DPL(00) S(1) 1 C(0) R(1) A(0) DB 11001111b ; G(1) D(1) 0 0 Limit[19..16] DB 00h ; Base[31..24] ; GDT[2]: Writable data segment DW 0FFFFh ; Limit[15..0] DW 0000h ; Base[15..0] DB 00h ; Base[23..16] DB 10010010b ; P(1) DPL(00) S(1) 0 E(0) W(1) A(0) DB 11001111b ; G(1) B(1) 0 0 Limit[19..16] DB 00h ; Base[31..24] mov eax,cr0 or eax,1 mov cr0,eax Build GDT GDT address GDT Size 32 bit Set PE in CR0 .386p 16 bit Protected mode Jump could clear instruction queue LGDT GDT Clear instr. queue Jmp EntryPoint32 uC/OS-II Main Function Protected mode 7/32

  8. uC/OS-II Porting --- Hardware Init. (1/4) • The rest of the hardware initialization is performed in the application. Once in main(), a call is done to OsCpuInit(), in order to perform the following: • Enable the address line 20 • Relocate the IRQ interrupts • Initialize the interrupt table • The clock handler is installed as the interrupt 20h handler • The uC/OS-II context switch handler is installed as the interrupt 30h handler 8/32

  9. uC/OS-II Porting --- Hardware Init. (2/4) • void OSCpuInit() • { • int IntNo; • InitA20(); // Enable address line 20 • InitPIC(); // Relocate IRQs to 0x20-0x2F • // Install a default handler for all supported interrupts: • // a) 0x00-0x1F: Intel-reserved • // b) 0x20-0x2F: IRQ (relocated) • // c) 0x30-0x3F: Available for uCOS and application. • for (IntNo = 0; IntNo < 0x40; IntNo++) • SetIntVector(IntNo, DefIntHandler); • SetIntVector(0x20, OSTickISR); // Install the tick handler • SetIntVector(0x30, OSCtxSw); // Install uCOS-II's context switch handler • } 9/32

  10. uC/OS-II Porting --- Hardware Init. (3/4) • The A20 line is enabled by sending a few commands to the Intel 8042 keyboard controller. • InitA20 • do {status = inportb(0x64);} while (status & 2); • // Wait until i8042 can receive the command. • outportb(0x64, 0xd1); // Send the 'write' command to the i8042. • do { status = inportb(0x64);} while (status & 2); • // Wait until i8042 can receive the command. • outportb(0x60, 0xdf); // Send the new set-up. • do { status = inportb(0x64);} while (status & 2); • // Wait until i8042 has received the command. 10/32

  11. uC/OS-II Porting --- Hardware Init. (4/4) • Relocate the IRQ lanes from 0x00 to 0x20 to prevent conflicts between IRQ and CPU's exceptions • InitPIC • // Reprogram the master 8259. • outportb(I8259_A0, 0x11); • outportb(I8259_A1, 0x20); • outportb(I8259_A1, 0x04); • outportb(I8259_A1, 0x01); • outportb(I8259_A1, 0x00); • // Reprogram the slave 8259. • outportb(I8259_B0, 0x11); • outportb(I8259_B1, 0x28); • outportb(I8259_B1, 0x02); • outportb(I8259_B1, 0x01); • outportb(I8259_B1, 0x00); 11/32

  12. uC/OS-II Porting 12/32 • OS_CPU.h • Define Data type & register value depend on hardware specification & compiler • OS_CPU_A.asm • OSStartHighRdy() • OSCtwSw() • OSTickISR() • OSIntCtxSw()

  13. uC/OS-II Porting 13/32 • OS_CPU_C.c • OSTaskStkInit() • OSTaskCreateHook() • OSTaskDelHook() • OSTaskSwHook() • OSTaskStatHook() • OSTimeTickHook()

  14. OS_CPU.h (1/2) 14/32 • Compiler dependent(請查看compiler手冊) • typedef unsigned char BOOLEAN; • typedef unsigned char INT8U; • typedef char INT8S; • typedef unsigned short INT16U; • typedef short INT16S; • typedef unsigned long INT32U; • typedef long INT32S; • typedef float FP32; • typedef double FP64; • typedef INT32U OS_STK;

  15. OS_CPU.h (2/2) 15/32 • Processor dependent • #define OS_ENTER_CRITICAL() __asm PUSHFD __asm CLI • #define OS_EXIT_CRITICAL() __asm POPFD • #define OS_STK_GROWTH 1 • #define OS_TASK_SW() __asm INT 0x30

  16. OS_CPU_A.asm 16/32 一般寫完bootloader後,常要觀察其與OS搭配後,是否可以順利進入OS 為了往後可以測試task context switch 是否成功,因此建立2個task,不同的priority,分別進行不同動作,例如輸出不同字元 taskA priority 5 並在while迴圈中加入OSTimeDly taskB priority 10並在while迴圈中加入OSTimeDly

  17. OS_CPU_A.asm --- OSStartHighRdy(1/3) 17/32 • OSStartHighRdy() • 由於OSstart()後,會去執行schedule,並且挑出最高priority的task執行 • Pseudo code • void OSStartHighRdy (void) • { • Call user definable OSTaskSwHook();  • Get the stack pointer of the task to resume: • Stack pointer = OSTCBHighRdy->OSTCBStkPtr;  • OSRunning = TRUE;  • Restore all processor registers from the new task's stack;  • Execute a return from interrupt instruction; • }

  18. OS_CPU_A.asm --- OSStartHighRdy(2/3) • OSStartHighRdy • call _OSTaskSwHook ; Call OSTaskSwHook(); • OSRunning = TRUE • mov eax, 1h • mov [ _OSRunning ], eax • Load the processor stack pointer with OSTCBHighRdy->OSTCBStkPtr • mov eax,[_OSTCBHighRdy] • mov esp,[eax] • Pop all the processor registers from the stack • popad • Execute a Return from interrupt intruction • iretd 18/32

  19. OS_CPU_A.asm --- OSStartHighRdy(3/3) • 若是此函式完成後 • 可以觀察到taskA的動作 • 若是沒有預期動作,則表示先前的準備工作尚未全部完成 • Ex.bootloader、OS_CPU.h…… 19/32

  20. OS_CPU_A.asm --- OSCtxSw(1/4) 20/32 • OSCtxSw() • 若是目前task ready queue中有更高priority的task,則使用此函式將目前正在執行的task與之交換 • Pseudo code • void OSCtxSw(void) • { • 保存處理器暫存器;  • 將當前 task 的堆疊指標保存到當前 task 的 OS_TCB 中:  • OSTCBCur->OSTCBStkPtr = Stack pointer;  • 呼叫使用者定義的 OSTaskSwHook();  • OSTCBCur = OSTCBHighRdy;  • OSPrioCur = OSPrioHighRdy;  • 得到需要恢復的 task 的堆疊指標:  • Stack pointer = OSTCBHighRdy->OSTCBStkPtr;  • 將所有處理器暫存器從新 task 的堆疊中恢復出來;  • 執行中斷返回指令; • }

  21. OS_CPU_A.asm --- OSCtxSw(2/4) 21/32 • OSCtxSw • 保存處理器暫存器 • pushad • OSTCBCur->OSTCBStkPtr = Stack pointer • mov eax,[_OSTCBCur] • mov [eax],esp ; Stack pointer is ESP

  22. OS_CPU_A.asm --- OSCtxSw(3/4) 22/32 • 呼叫使用者定義的 OSTaskSwHook() • call _OSTaskSwHook • OSTCBCur = OSTCBHighRdy  • mov al,[_OSPrioHighRdy] ; AL is OSPrioHighRdy • mov [_OSPrioCur],al • OSPrioCur = OSTCBHighRdy • mov eax,[_OSTCBHighRdy] ; EAX is OSTCBHighRdy • mov [_OSTCBCur],eax

  23. OS_CPU_A.asm --- OSCtxSw(4/4) 23/32 • Stack pointer = OSTCBHighRdy->OSTCBStkPtr • mov esp,[eax] ; ESP = OSTCBHighRdy->OSTCBStkPtr • 將所有處理器暫存器從新 task 的堆疊中恢復出來 • 執行中斷返回指令 • popad • iretd • 此函式成功,則在taskA動作結束後,taskB會隨之動作

  24. OS_CPU_A.asm --- OSTickISR 24/32 • OSTickISR • 保存處理器暫存器 • pushad • Send an end-of-interrupt to the i8259 • mov al,20h • out 20h,al • 呼叫 OSIntEnter() 或者直接將 OSIntNesting 加 1 • call _OSIntEnter • 呼叫 OSTimeTick() • call _OSTimeTick • 呼叫 OSIntExit() • call _OSIntExit • 恢復處理器暫存器 • popad • 執行中斷返回指令 • iretd • 此函式完成後,可以在此函式中加入輸出, 若是此輸出可以依照interval持續到來,表示成功

  25. Multicore Boot • Multicore • BSP (Bootstrap Processor) • AP (Application Processor) • How to boot AP (Application Processor) ? • Disable 8259 • Initialize Local APIC • Initialize I/O APIC 25/32

  26. BSP AP AP CPU 1 CPU 2 CPU 3 PIC Mode IMCR Local APIC 0 Local APIC 1 Local APIC 2 NMI LINTIN1 LINTIN0 RESET ICC BUS I/O APIC 8259 Interrupt INT 26/32

  27. Interrupt Mode BSP AP AP CPU 1 CPU 2 CPU 3 IMCR APIC Mode Local APIC 0 Local APIC 1 Local APIC 2 NMI LINTIN1 LINTIN0 RESET ICC BUS I/O APIC 8259 Interrupt INT` 27/32

  28. Multicore Boot • Disable 8259 • It means leave PIC mode • IMCR ( Interrupt Mode Control Register) • Write 0x70 on 0x22 (choose IMCR) • Write 0x01 on 0x23 (not use PIC mode) • Disable(mask) 8259 all IRQ pins 28/32

  29. Multicore Boot BSP初始化過程1. 初始化memory2. Load microcode到處理器3. 初始化內存範圍寄存器(MTRRs)4. enable cache5. 確定BSP是否是"GenuineIntel"6. 執行CPUID,保存CPU信息為將來使用7. load AP的啟動代碼到低1M的一個4K的頁裡8. 切換到保護模式9. 轉換4K的頁基址為一個8位的向量. 例如0x000BD000H --> 0xBDH10.設置APIC的SVR的bit8來enable local APIC11.建立錯誤處理handler12.初始化鎖信號量13.探測系統中的AP, 方法如下:- 設置處理器COUNT為1   - 啟動一個timer,BSP開始等待- 此時AP開始初始化,並將COUNT加1   - timer到期,BSP檢查COUNT,如果沒有增加,就表示系統中沒有AP.14. 等timer中斷,檢查COUNT並建立處理器數目 AP初始化1. 獲取信號量,開始初始化2. load microcode到處理器3. 初始化內存範圍寄存器(MTRRs)4. enable cache5. 檢查AP是否是"GenuineIntel"6. 保存CPUID信息,為將來使用7. 切換到保護模式8. 配置AP的共存內存接口執行環境9. 將處理器個數加110.釋放信號量11. 執行CLI並且進入halt狀態12.等待INIT IPI 29/32 Intel spec

  30. Multicore Boot 30/32 • Broadcasts an INIT-SIPI-SIPI IPI sequence to the APs to wake them up and initialize • send twice IPI (Inter-Processor Interrupt) (INIT) • make AP initialize • set AP Arb ID register • broadcast SIPI (start-up IPI) • Number of times depend on CPU • Tell AP the address where it start execute

  31. Demo 31/32

  32. Questions? 32/32

More Related