2013-03-26 2 views
1

Я использовал micro_os_loader, и я создал свое собственное ядро, и все работает отлично. Ядро должно быть в секторе 2, это нормально, я сделал это таким образом, но я хочу написать программу в секторе 4 и хочу запустить ее в ядре в качестве подпрограммы. но как я могу это сделать? В ядре что делать, чтобы моя программа работала в секторе 4.Загрузка программы в другой сектор на emu8086

ответ

1

Это в значительной степени зависит от того, как работает ваше ядро.

Вам необходимо прочитать программный код в памяти, создать процесс для него и ... ну ... следующий шаг уже в значительной степени зависит от дизайна.

В основном вам необходимо, чтобы CS: IP указывал на точку входа программы.

Например, если вы многозадачность, вы, вероятно, настроили прерывание таймера с помощью обработчика, который сохраняет все регистры на печатной плате и выбирает другой процесс из очереди процессов. Затем он загружает регистры из печатной платы, принадлежащей этому процессу, подталкивает обратный адрес в стеке, чтобы указать на следующую команду для выполнения из этого процесса и проблемы iret, чтобы дать управление процессом.

Между тем, ядро ​​работает на холостом ходу в цикле - например:

idle: 
    hlt 
    jmp idle 

здесь, ядро ​​не имеет никакой линейной работы. Вместо этого он сидит в режиме ожидания, ожидая системных вызовов от процессов и прерываний от аппаратного обеспечения. Системные вызовы обычно реализуются в виде обработчиков (-ов) прерываний, поэтому все виды асинхронных событий, которые происходят в системе, могут рассматриваться единообразно.

[EDIT]

Для дополнительного примера, мы пойдем с вытесняющей многозадачностью, сдуру жестко прописывать планировщик в обработчик таймера IRQ и, не вдаваясь в детали. Например, реализация очереди процессов зависит от вас (это всего лишь список печатных плат где-то в памяти). Мы не будем перепрограммировать таймер, поскольку он не является существенным (он уже работает и генерирует 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 
    ; ... 

[/ EDIT]

Here вы можете найти примеры кода, перепрограммировать PIT.

+0

Спасибо за ваш ответ, это очень помогло. ı сохранил все регистры, и когда ı назад ı загрузил их обратно, теперь он работает очень хорошо. еще раз большое спасибо – Alparslanyk

+0

@Alparslanyk Добро пожаловать! :) Обратите внимание на буквально сохранение всего (например, общие регистры, сегменты, флаги, регистры 8087, если они используются), так что программы (и ядро), работающие отдельно, не мешают друг другу. Если что-то пойдет не так, не стесняйтесь задавать мне вопрос. – Powerslave

+0

@Alparslanyk Я вижу, что вы не приняли решение. Что пошло не так? – Powerslave

Смежные вопросы