1

micro_os_loaderを使用し、独自のカーネルを作成しましたが、問題なく動作します。カーネルはセクター2にある必要があります。そのようにしたのは問題ありませんが、セクター4でプログラムを作成し、カーネルでサブプログラムとして実行したいと思います。しかし、どうすればそれを行うことができますか?カーネルでは、プログラムをセクター4で実行するにはどうすればよいですか。

4

1 に答える 1

1

これは、カーネルがどのように機能するかに大きく依存します。

プログラムコードをメモリに読み込み、そのプロセスを作成する必要があります。そして...まあ...次のステップはすでにほとんど設計に依存しています。

基本的に、プログラムのエントリポイントを指すにはCS:IPが必要です。

たとえば、マルチタスクを実行している場合は、PCB内のすべてのレジスタを保存し、プロセスキューから別のプロセスを選択するハンドラを使用してタイマー割り込みを設定する可能性があります。次に、そのプロセスに属するPCBからレジスタをロードし、スタック上のリターンアドレスを改ざんして、そのプロセスから実行する次の命令をポイントし、プロセス制御を与えるために問題を発行します。

その間、カーネルはループでアイドリングしています-例:

idle:
    hlt
    jmp idle

ここから、カーネルには線形の作業はありません。代わりに、プロセスからのシステムコールと、ハードウェアからの割り込みを処理するためにアイドル状態になります。システムコールは通常、割り込みハンドラの形式で実装されるため、システムで発生するすべての種類の非同期イベントを均一に処理できます。

[編集]

追加の例として、プリエンプティブマルチタスクを使用し、スケジューラーをタイマーIRQハンドラーに愚かにハードコーディングしますが、詳細については説明しません。たとえば、プロセスキューの実装はあなた次第です(これはメモリ内のどこかにあるPCBのリストにすぎません)。タイマーは必須ではないため、再プログラムしません(すでに実行され、IRQ 0を生成しています)。ただし、デフォルトの8253/8254セットアップで提供される速度以外の速度でタスクを切り替えることができるように、必要に応じて再プログラムすることができます。また、IRLではFPUの状態やその他のものも保存する必要があることに注意してください...

; cdecl calling convention
; ugly pieces of code appear! DO NOT COPY-PASTE OR OTHERWISE USE THIS! this is just for illustration


proc timerInterruptHandler
    cli                     ; disabling interrupts so they don't mess up anything. no need to worry about re-enabling them as FLAGS is implicitly saved on the stack
    push ax                 ; let's first save our current CPU state on the stack
    push cx
    push dx
    push bx
    push bp
    push sp
    push si
    push di
    push es
    push ss
    push ds

    push bp
    mov bp,sp

    call getCurrentProcess    ; get the current process instance. let's now assume that the context is simply saved at relative address 0
    mov di,ax
    lea si,[bp + 2]
    mov cx,14
    rep movsw                 ; save the contents of each register to the buffer

    call selectNextProcess    ; we'll select the next process from the queue (or the first when the current is the last one).
    mov si,ax
    lea di,[bp + 2]
    mov cx,14
    rep movsw                 ; overwrite the saved registers on the stack with the saved state of our new process
                              ; upon returning from the handler (the next steps), the state of the new process will be loaded

    mov sp,bp
    pop bp

    pop ds
    pop ss
    pop es
    pop di
    pop si
    pop sp
    pop bp
    pop bx
    pop dx
    pop cx
    call acknowledgeMasterPICInterrupt  ; every IRQ must be acknowledged to the corresponding PIC (both if the IRQ is triggered by the salve PIC, i.e. IRQ8+)
    pop ax
    iret
endp timerInterruptHandler


; void setUpTaskScheduler(void)
proc setUpTaskScheduler                ; here we assume that no IRQ remapping is done, thus IRQ 0 (timer) is at INT 8.
    pushf
    cli
    push bx
    push ds

    mov cx,2                           ; multiplying the interrupt number by 4 gives you the address of the IVT record to modify
    mov bx,8
    shl bx,cx

    xor ax,ax
    mov ds,ax

    lea ax,[cs:timerInterruptHandler]   ; write the offset first
    mov [word ptr ds:bx + 0],ax
    mov ax,cs
    mov [word ptr ds:bx + 2],ax         ; then the segment


    pop ds
    pop bx
    popf
    ret
endp setUpTaskScheduler


; void acknowledgeMasterPICInterrupt(void)
proc acknowledgeMasterPICInterrupt
    mov al,20h
    out 20h,al
    ret
endp acknowledgeMasterPICInterrupt


; void acknowledgeSlavePICInterrupt(void)
proc acknowledgeSlavePICInterrupt
    mov al,20h
    out 0A0h,al
    call acknowledgeMasterPICInterrupt
    ret
endp acknowledgeSlavePICInterrupt

_main:
    ; ...
    call setUpTaskScheduler
    ; Once interrupts are enabled the scheduler will start doing its work
    ; ...

[/編集]

ここでは、PITを再プログラムするコード例を見つけることができます。

于 2013-04-13T16:42:14.380 に答える