Portál AbcLinuxu, 10. června 2026 07:28
int 10h mov bh,0xb8 mov ds,bx L: lodsb sub si,byte 57 xor [si],al out 61h,al jmp short LHow it works:
/*
Build: gcc -x assembler-with-cpp -D__KERNEL__ -DMODULE \
-I/usr/lib/modules/$(uname -r)/build/include \
-c pok.asm -o pok.o
Link: ld -r -o pok.ko pok.o
Load: sudo insmod pok.ko
Unload: sudo rmmod pok
Note: Requires legacy VGA text mode exposed and root. Use in VM.
*/
#define ASM_EXPORTED 1
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
#include <linux/kthread.h>
#include <asm/io.h>
#define VGA_PHYS 0xB8000
#define VGA_SIZE 0x4000
#define OFFSET 57
.intel_syntax noprefix
.section .data
vga_ptr: .quad 0
task_ptr: .quad 0
.section .text
.globl xor_init
.globl xor_exit
.type xor_init,@function
.type xor_exit,@function
.globl worker
.type worker,@function
worker:
push rbp
mov rbp, rsp
push rbx r12 r13
xor r12d, r12d /* i = 0 */
.loop:
call kthread_should_stop
test eax, eax
jnz .done
mov rbx, [vga_ptr]
movzx eax, byte ptr [rbx + r12] /* al = vram[i] */
/* j = (i + VGA_SIZE - OFFSET) % VGA_SIZE */
mov r13d, r12d
add r13d, VGA_SIZE - OFFSET
cmp r13d, VGA_SIZE
jb .mod_ok
sub r13d, VGA_SIZE
.mod_ok:
mov dl, byte ptr [rbx + r13]
xor dl, al
mov byte ptr [rbx + r13], dl /* vram[j] ^= al */
/* Program PIT channel 2 frequency from al (square wave) */
mov dx, 0x43
mov al, 0b10110110 /* ch2, lobyte/hibyte, mode 3 */
out dx, al
mov dx, 0x42
mov al, byte ptr [rbx + r12]
and al, 0x3F /* limit range */
add ax, 0x0100 /* base pitch */
out dx, al /* low byte */
mov ah, 0x04
out dx, ah /* high byte */
/* Enable speaker gate bits 0 and 1 */
mov dx, 0x61
in al, dx
or al, 0x03
out dx, al
inc r12d
cmp r12d, VGA_SIZE
jb .loop
xor r12d, r12d
jmp .loop
.done:
pop r13 r12 rbx
pop rbp
xor eax, eax
ret
.size worker, .-worker
xor_init:
push rbp
mov rbp, rsp
/* request_region(0x61,1,"pok") */
mov edi, 0x61
mov esi, 1
lea rdx, port_name[rip]
call request_region
test rax, rax
jz .fail_busy
/* vga = ioremap(VGA_PHYS, VGA_SIZE) */
mov edi, VGA_PHYS
mov esi, VGA_SIZE
call ioremap
test rax, rax
jz .fail_map
mov [vga_ptr], rax
/* task = kthread_run(worker,NULL,"pok") */
lea rdi, worker
xor esi, esi
lea rdx, th_name[rip]
call kthread_run
mov [task_ptr], rax
cmp rax, -4095
jae .fail_thread
lea rdi, msg_load[rip]
xor eax, eax
call printk
xor eax, eax
pop rbp
ret
.fail_thread:
mov rdi, [vga_ptr]
call iounmap
.fail_map:
mov edi, 0x61
mov esi, 1
lea rdx, port_name[rip]
call release_region
.fail_busy:
mov eax, -16 /* -EBUSY */
pop rbp
ret
.size xor_init, .-xor_init
xor_exit:
push rbp
mov rbp, rsp
mov rdi, [task_ptr]
test rdi, rdi
jz .skip_stop
call kthread_stop
.skip_stop:
mov rdi, [vga_ptr]
test rdi, rdi
jz .skip_map
call iounmap
.skip_map:
mov edi, 0x61
mov esi, 1
lea rdx, port_name[rip]
call release_region
lea rdi, msg_unload[rip]
xor eax, eax
call printk
pop rbp
ret
.size xor_exit, .-xor_exit
.section .rodata
port_name: .asciz "pok"
th_name: .asciz "pok"
msg_load: .asciz "pok loaded\n"
msg_unload: .asciz "pok unloaded\n"
.section .modinfo
.asciz "license=GPL"
Tiskni
Sdílej:
ISSN 1214-1267, (c) 1999-2007 Stickfish s.r.o.