Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Assembly 在emu8086的另一个扇区中加载程序_Assembly_X86 - Fatal编程技术网

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

Assembly 在emu8086的另一个扇区中加载程序,assembly,x86,Assembly,X86,我使用了micro_os_loader,我制作了自己的内核,它工作得很好。内核必须在扇区2,这是可以的,我是这样做的,但我想在扇区4写一个程序,并想在内核中运行它作为一个子程序。但是我怎么能做到呢?在内核中,我应该怎么做才能使我的程序在扇区4中运行。这在很大程度上取决于内核的工作方式 你需要把程序代码读入内存,为它创建一个进程,然后。。。好。。。下一步已经相当依赖于设计 基本上你需要有CS:IP来指向程序的入口点 例如,如果您正在进行多任务处理,您可能会使用一个处理程序设置计时器中断,该处理程序

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

这在很大程度上取决于内核的工作方式

你需要把程序代码读入内存,为它创建一个进程,然后。。。好。。。下一步已经相当依赖于设计

基本上你需要有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
    ; ...
[/编辑]


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

这在很大程度上取决于内核的工作方式

你需要把程序代码读入内存,为它创建一个进程,然后。。。好。。。下一步已经相当依赖于设计

基本上你需要有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
    ; ...
[/编辑]


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

感谢您的回答,它非常有用。ı保存了所有寄存器,当ıbackı现在将它们加载回时,它工作得非常好。再次非常感谢much@Alparslanyk不客气!:)注意字面上保存所有内容(例如,通用regs、段、标志、8087寄存器(如果使用))以便单独运行的程序(和内核)不会相互干扰。如果出了什么问题,尽管问我。@Alparslanyk我知道你不接受这个解决方案。出什么事了?对不起,老兄,我是这里的新手,现在就接受吧,这样你就可以很好地工作了[:@Alparslanyk不用担心:)我只是想知道是否有什么问题需要解决……谢谢你的回答,它非常有用。保存了所有的寄存器,当返回时,它现在运行得很好。再次非常感谢你much@Alparslanyk不客气!:)注意保存一切(例如,通用寄存器、段、标志、8087寄存器(如果使用),以便程序(和内核)分开跑步不要互相干扰。如果有什么不对劲,请随时向我提问。@Alparslanyk我知道你没有接受这个解决方案。出了什么问题?对不起,伙计,我是这里的新手,现在就接受吧,谢谢你工作得很好[:@Alparslanyk不用担心:)我只是想知道是否有什么事情需要解决。。。