仍在开发x86 NASM程序集操作系统。
跟我的上一个问题(CLI and STI are not working):
在我意识到CLI和STI指令正确关闭了所有中断之后,我不久之后才意识到系统定时器& RTC时钟本身就是中断(参见Wikipedia - IRQ : x86 IRQs : Master PIC)。这就是为什么时钟不起作用的原因 - 它将等待并等待(并等待)永远,直到系统计时器开始更新。这显然从未发生过,因为更新的中断已关闭!
不幸的是,知道这一点并不能解决我的原子性问题:在没有中断的情况下无法读取系统时钟。但是,中断将无法确保原子性。
我听说有办法掩盖一些中断,但不是全部。我想知道如何屏蔽除0和8之外的所有中断(参见维基百科链接)。我想在Wait_Clk_Ticks
函数中实现它。
这让我想到了这段代码 - 这段代码加载到启动设备(在我的情况下是软盘)时会显示“下降的雨滴”效果。红色,2像素长的部分将沿屏幕缓慢移动,然后从顶部重新开始。这是应该做的。
然而,有3个问题,所有问题都与时钟有关(我相信):
当按下某个键时,计算机会发出令人讨厌的声音,雨滴会缓慢下降。我认为这是因为按一个键导致中断,这就是延迟定时器功能。
计时器没有原子性。
过了一会儿,雨滴就会完全停止(这可能是导致问题的中断)
如何解决这些问题?
编辑:我添加了Set_IRQ_Mask函数。但是现在我的操作系统在启动时挂起。
编辑2:已修复,请参阅答案。
[BITS 16] ; 16 bit code
[ORG 0x7C00] ; Start to load at 0x7c00
; OS to create 'falling raindrop' effect
jmp Code_Start
Set_IRQ_Mask: ; see http://wiki.osdev.org/8259_PIC and http://cs.smith.edu/~thiebaut/ArtOfAssembly/CH17/CH17-3.html
in al, 21h ; Read existing bits.
or al, 00010000b ; Disable IRQ4 (serial port com1)
out 21h, al
mov al, 0x20 ; Send end of interrupt signal
out 0x20, al
ret
Wait_Clk_Ticks:
; MASK CERTAIN INTERRUPTS
push ax ; Store current values.
push bx
mov ax, 0 ; Reset 'ds' (destination pointer).
mov ds, ax
mov bx, [46Ch] ; Tick status is at 0:46Ch.
; Store into 'bx'.
_WCT_Get_Tick: ; Gets new tick.
mov ax, [46Ch] ; Update current time into 'ax'.
cmp ax, bx ; If 'current' == 'older' ticks,
je _WCT_Get_Tick
; Then clock tick isn't over: reset.
mov bx, ax ; If the clock tick is over,
; put 'current' into 'older'.
sub cx, 1 ; Decrement number of ticks till exit.
jnz _WCT_Get_Tick;
; If 'cx' (ticks till exit) is zero,
pop bx ; Restore current values.
pop ax
; UNMASK CERTAIN INTERRUPTS
ret ; Return.
Set_Video_Mode:
mov ax, 13h ; VGA mode (320x200) 256 color
int 10h ; sets vga mode SEE: http://www.wagemakers.be/english/doc/vga
ret
Write_Pixel:
push ax ; push variables used here onto the stack
push bx
push cx
mov cx, 320 ; puts 320 (how many rows there are) into a register
mul cx ; multiplies 320 by AX (# of rows) and stores into AX
add ax, bx ; adds rows and cols to make the location, puts into ax
mov si, ax ; move ax into si
mov bx, 0a000h ; this puts 0a000h (starting register) as the beginning
mov es, bx ; move bx into es
pop cx
mov word [es:si], cx ; move the color attribute (cx) into the memory location es+si
pop bx ; restore variables from stack
pop ax
ret
Code_Start:
mov bx, 40 ; work on COLUMN 40 solely
call Set_Video_Mode
call Set_IRQ_Mask
Reset:
mov ax, 0 ; Reset row to 0
Loop:
mov cx, 40 ; Write head in in RED (40)
call Write_Pixel
cmp ax, 0 ; Are we at row 1?
je Next_Zero ; Go to special conditions
cmp ax, 1 ; Are we at row 2?
je Next_One ; Go to special conditions
jmp Next_Norm ; Otherwise, no special conditions
Next_Zero: ; Make the cover spot 197 if the current dot is 0
push ax
mov ax, 197
jmp Cover_Black
Next_One: ; Make the cover spot 198 if the current dot is 1
push ax
mov ax, 198
jmp Cover_Black
Next_Norm: ; Otherwise, make the cover spot 'ax - 2'
push ax
sub ax, 2
Cover_Black: ; Set color to black
mov cx, 0
call Write_Pixel
pop ax ; Restore AX to the RED location.
mov cx, 1 ; Set to wait for a clock tick
call Wait_Clk_Ticks
inc ax ; Increment the row
cmp ax, 199 ; If pixel has reached the bottom of the screen, reset AX
je Reset
jmp Loop ; Otherwise, continue downwards.
End:
jmp $ ; Run this line over and over again- stops excecution.
times 510-($-$$) db 0 ; Fill the rest of the 512 byte sector with zeros
dw 0xAA55 ; Boot magic number
答案 0 :(得分:1)
假设您还没有尝试处理任何多处理内容,可以对8259 Programmable Interrupt Controller进行编程以屏蔽某些IRQ。
答案 1 :(得分:1)
......好吧,似乎修复是在ret
函数之后添加Set_IRQ_Mask
...
这是一行5小时的调试...... :)感谢您的帮助!
答案 2 :(得分:0)
您根本不需要为正在执行的操作禁用中断。我不确定你认为什么是原子的,但唯一需要原子化的是内存中滴答计数器的16位读取。由于对齐的16位读取保证是原子的,并且由于滴答计数器适当对齐,因此您不需要禁用中断。即使没有保证(例如,计数器位于奇数地址),您需要做的就是禁用执行读取的指令的中断。
以下是我实施Wait_Clk_Ticks
功能的方法:
Wait_Clk_Tics:
push ds
push ax
push bx
xor ax, ax
mov ds, ax
; cli
mov ax, [0x46c]
; sti
.loop:
hlt
; cli
mov bx, [0x46c]
; sti
sub bx, ax
cmp bx, cx
jb .loop
pop bx
pop ax
pop ds
ret
如果定时器计数器未正确对齐,我已经显示了CLI / STI指令的位置。我还简化了代码,因此它不计算计数器更改,它只是从原始值中减去计数器的当前值。最后我插入了HLT指令。这将导致CPU等待中断。在相对较新的CPU上,这也会导致处理器进入低功耗状态,并且应该具有明显的功率使用效果和CPU风扇产生的噪声。
答案 3 :(得分:-1)
or al, 00010000b ; Disable IRQ4 (serial port com1)
前一行不如您的正确,或者不会屏蔽串口com1 !!!
and al, 11101111b