我使用了micro_os_loader,我制作了自己的内核,它运行得很好。内核必须在第2扇区,我可以这样做,但我想在第4扇区编写一个程序,并希望在内核中作为子程序运行它。但我怎么能这样做?在内核中,我应该怎样做才能让我的程序在第4区运行。
答案 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的代码示例。