在emu8086上加载另一个扇区的程序

时间:2013-03-26 00:40:35

标签: assembly x86

我使用了micro_os_loader,我制作了自己的内核,它运行得很好。内核必须在第2扇区,我可以这样做,但我想在第4扇区编写一个程序,并希望在内核中作为子程序运行它。但我怎么能这样做?在内核中,我应该怎样做才能让我的程序在第4区运行。

1 个答案:

答案 0 :(得分:1)

这很大程度上取决于你的内核是如何工作的。

你需要将程序代码读入内存,为它创建一个过程......好吧......下一步已经完全取决于设计。

基本上你需要让CS:IP指向程序的入口点。

例如,如果您是多任务处理,则可能使用处理程序设置定时器中断,该处理程序将所有寄存器保存在PCB中并从进程队列中选择另一个进程。然后它从属于该进程的PCB加载寄存器,篡改堆栈上的返回地址以指向从该进程执行的下一条指令以及问题 iret 以给出进程控制。

同时,内核在循环中空闲 - 例如:

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
    ; ...

[/编辑]

Here 您可以找到重新编程PIT的代码示例。