読者です 読者をやめる 読者になる 読者になる

_trampoline_pmの中身。

minix

こちらも基本的に詳細はコメントに書かれているのでわかりやすい!

!*===========================================================================*
!*                              trampoline_pm                                *
!*===========================================================================*
! This is the protected mode section of the trampoline 
! Load apropiate values into registers and jump to
!    ap_main c function to start execution 
_trampoline_pm:
        ! We are in protected mode. Load AP registers as in BSP
                mov     ax,     DS_SELECTOR
                mov     ds,     ax              ! load DS
                mov     ss,     ax              ! load SS
                mov     es,     ax              ! load ES
                mov     fs,     ax              ! load FS
                mov     gs,     ax              ! load GS
                mov     eax,    ( _esi_data )
                mov     esi,    eax             ! load ESI
                mov     eax,    ( _edi_data )
                mov     edi,    eax             ! load EDI
                mov     eax,    ( _ebp_data )
                mov     ebp,    eax             ! load EBP

ここら辺まではプロテクトモード用にレジスタの設定をしている。

        ! Load TSS of this ap
                THIS_CPU(eax)
                dec     eax                     ! AP# less 1
                shl     eax,    3               ! mult DESC_SIZE
                add     eax,    TSS_FIRST_AP_SELECTOR
                ltr     ax                      ! load TSS

ここはコメントで説明しているようにTSSを設定している部分。
TSSを「はじめて読む486]で調べると「Task State Segment」の略で、タスクの状態の保存・復元に利用するデータ領域のことと言う風に説明している。
OSDev.orgにも説明あります。Linuxはどうしているのかって説明が英語版のウィキペディアにありました。
ともかく、CPU自体がタスク切り替えの仕組みを提供しているので、それをminixで使うためには設定が必要。

TSSもgdt、idtのようにTSSディスクリプタの先頭アドレス、リミット値、属性を設定するテーブルの作成とTSSディスクリプタを作る必要がある。

THIS_CPUはxmp.hで定義しているマクロ。

/* This secuence provides in <reg> current cpu number from 0 to n-1
   Registers <reg>, EDX, DS are afected 
   SHORT version does not restores DS_SELECTOR in DS 
   <reg> can be EAX, EBX, ECX */

#define THIS_CPU_SHORT(reg)                             ;\
                mov     edx,    (_local_apic_base)      ;\
                add     edx,    0x20                    ;\
                mov     reg,    FLAT_DS_SELECTOR        ;\
                mov     ds,     reg                     ;\
                mov     reg,    (edx)                   ;\
                and     reg,    0x0F000000              ;\
                shr     reg,    6*4



#define THIS_CPU(reg)                                   ;\
                THIS_CPU_SHORT(reg)                     ;\
                mov     edx,    DS_SELECTOR             ;\
                mov     ds,     dx

TSS_FIRST_AP_SELECTORはprotect.hで定義しているマクロで、以下のように定義。

#define TSS_FIRST_AP_SELECTOR  0x70 /* TSS_AP_INDEX(1) * DESC_SIZE) */

コメント中に出てくる掛け算の内容はどういうことかと言うと、
protect.hにいる2個のマクロを使った掛け算で、

#define TSS_AP_INDEX(n) (13+n)  /* TSS for AP 1,2,3... */
#define DESC_SIZE        8      /* sizeof (struct segdesc_s) */

(13 + 1) * 8 = 112 = 0x70
って感じで、TSS_FIRST_AP_SELECTORが0x70として定義される。

ltr命令はTSSをTRレジスタに読み込むための命令。
TRレジスタは現在のTSSを保持するためのレジスタで、常にカレントTSSを保持する。

        ! Now we are ready to address as usual and execute normal
        ! kernel code, so, lets go
        ! Each CPU needs its own stack space inside kernel stack
        ! Make esp point to cpus stack top
                THIS_CPU(eax)
                SET_CPU_STK(eax)
        ! Enable AP cache
                call    _enable_cache
        ! Continue in C code
                call    _ap_main
hlt

TSSをTRレジスタに設定して、ついにcで書かれた関数をコールする準備ができてきた。

THIS_CPUは先ほども出てきたマクロなので飛ばして、次のSET_CPU_SKTを調べると・・
こんな感じのマクロがxmp.hに定義されている。
これもコメントのままだけど、カーネルで使うスタック領域の設定をしている部分。

/****************************************************************/
/* Macro definitions for kernel stack management                */
/****************************************************************/
#define K_STACK_BYTES_SH        10      /* log2 K_STACK_BYTES */
                                        /* K_STACK_BYTES MUST BE POWER OF 2 */

#if (K_STACK_BYTES != (1<<K_STACK_BYTES_SH))
#error "ERROR: K_STACK_BYTES_SH is not log2(K_STACK_BYTES)"
#endif

/* This secuence sets kernel stack to the top of kernel stack
   depending of current cpu number stored in <reg>
   Registers <reg>, EDX, ESP are afected
   <reg> can be EAX, EBX, ECX */

#define SET_CPU_STK(reg)                                ;\
                shl     reg,    K_STACK_BYTES_SH        ;\
                mov     edx,    k_stktop                ;\
                sub     edx,    reg                     ;\
                mov     esp,    edx

enable_caheはCR0レジスタの29,30ビット目のNWとCDビットを触ってると思う・・・
CDビットはCache Disableの略でCDとNWビットが両方0だとキャッシュが有効になるらしい。
NWはNow Write throughの略。

!*===========================================================================*
!*                              enable_cahe                                  *
!*===========================================================================*
! Enable cache on current cpu
_enable_cache:
                mov     ax,     cr0
                and     ax,     0x9FFFFFFF      ! 100111111111...111
                mov     cr0,    ax
                wbinv
                ret

TSS、キャッシュの設定が終わって最後にc言語で書かれたap_main()をコールする。(mp.c内に本体がいる)
"_"がついているのはお約束的なもの。

        ! Continue in C code
                call    _ap_main

続きはまた、