feat(VGA): export cursor method from asm@@ -2,6 +2,82 @@ bits 32
extern kmain
+global set_cursor_pos
+global hide_cursor
+global show_cursor
+
+; Inputs: rdi = row, rsi = col
+set_cursor_pos:
+ push ebp
+ mov ebp, esp
+
+ mov eax, dword [ebp + 8] ; eax = row
+ mov ebx, 80
+ imul eax, ebx ; eax = row * 80
+ add eax, dword [ebp + 12] ; eax += col
+ mov bx, ax ; bx = position (16-bit)
+
+ ; outb(0x3D4, 0x0E);
+ mov dx, 0x3D4
+ mov al, 0x0E
+ out dx, al
+
+ ; outb(0x3D5, (position >> 8) & 0xFF);
+ mov dx, 0x3D5
+ mov al, bh
+ out dx, al
+
+ ; outb(0x3D4, 0x0F);
+ mov dx, 0x3D4
+ mov al, 0x0F
+ out dx, al
+
+ ; outb(0x3D5, position & 0xFF);
+ mov dx, 0x3D5
+ mov al, bl
+ out dx, al
+
+ mov esp, ebp
+ pop ebp
+ ret
+
+; void hide_cursor(void)
+hide_cursor:
+ ; Read: write index 0x0A, then write data with bit 5 set
+ ; For simplicity we don't read current value; we set start = 0x20 (disabled)
+ mov dx, 0x3D4
+ mov al, 0x0A
+ out dx, al
+
+ mov dx, 0x3D5
+ mov al, 0x20 ; set bit 5 to disable cursor
+ out dx, al
+
+ ret
+
+; void show_cursor(void)
+show_cursor:
+ ; Restore a typical cursor shape: start = 0 (scanline start)
+ mov dx, 0x3D4
+ mov al, 0x0A
+ out dx, al
+
+ mov dx, 0x3D5
+ mov al, 0x00 ; cursor start = 0
+ out dx, al
+
+ ; set cursor end (e.g., 15)
+ mov dx, 0x3D4
+ mov al, 0x0B
+ out dx, al
+
+ mov dx, 0x3D5
+ mov al, 0x0F ; cursor end = 15 (typical)
+ out dx, al
+
+ ret
+
+
section .entry
; void start()
@@ -27,19 +27,12 @@ fun kmain
VGA::Colors::BLACK_ON_CYAN,
)
VGA.puts("\n")
- VGA.puts("Hello world!\nWorks maybe?\n", line: 1)
- VGA.puts("Can print on multiple lines\n", line: 2)
+ VGA.puts("Hello world!\n\nWorks maybe?\n", line: 1)
+ VGA.puts("Can print on multiple lines\n", line: 2, color: VGA::Colors::BLACK_ON_LIME)
VGA.puts("But because we don't have a Heap, we need to set lines number in puts call for now...\n", line: 3)
- # VGA.puts(%(
- # Works well
- # multiline buffer?
- # ),
- # VGA::Colors::BLACK_ON_LIME,
- # )
- # VGA.puts("\n\n\n")
- # VGA.puts "hello world\n"
- #VGA.dump_cursor_and_cells
+ VGA.set_cursor(5, 4)
+ VGA.hide_cursor
while true
asm (%(hlt))
@@ -1,3 +1,13 @@
+lib KernelShim
+ # Definition in kernel/entry.asm
+ fun hide_cursor()
+ fun show_cursor()
+ fun set_cursor_pos(
+ row : UInt32,
+ col : UInt32
+ )
+end
+
struct VGACursor
col : Int32 = 0
row : Int32 = 0
@@ -66,83 +76,74 @@ module VGA
VGA_CURSOR.col = 0
VGA_CURSOR.row = 0
end
+
+ # Hide cursor
+ def self.hide_cursor
+ KernelShim.hide_cursor
+ end
+
+ # Show cursor
+ def self.show_cursor
+ KernelShim.show_cursor
+ end
+ # Set typing cursor position
+ def self.set_cursor(
+ col : Int32,
+ row : Int32
+ ) : Nil
+ KernelShim
+ .set_cursor_pos(row.to_u32, col.to_u32)
+ end
+
# Write a single character to the current cursor position
def self.putchar(
- ch : UInt8,
- i : Int32? = 0,
- line : Int32? = 0,
- color : UInt8? = Colors::DEFAULT
+ ch : UInt8,
+ i : Int32? = 0,
+ line : Int32? = 0,
+ color : UInt8? = Colors::DEFAULT
) : Nil
- VGA_CURSOR.col = i
- VGA_CURSOR.row = line
+ VGA_CURSOR.col = i
+ VGA_CURSOR.row = line
- # Simplified cursor handling (replace with actual cursor logic later)
- if ch == ("\n".to_unsafe).value # 0x0A_u8 # \n
- VGA_CURSOR.col = 0
- VGA_CURSOR.row += 1
- if VGA_CURSOR.row >= VGA_HEIGHT
- VGA_CURSOR.row = VGA_HEIGHT - 1
+ if ch == 0x0A_u8 # \n (not working...)
+ # VGA_CURSOR.col = 0
+ VGA_CURSOR.row += 1
+ if VGA_CURSOR.row >= VGA_HEIGHT
+ VGA_CURSOR.row = VGA_HEIGHT - 1
+ end
+ ch = " ".to_unsafe.value
end
- return
- end
-
- offset = (VGA_CURSOR.row * VGA_WIDTH + VGA_CURSOR.col) * 2
-
- (VGA_BUFFER + offset).value = ch
- (VGA_BUFFER + offset + 1).value = color
-
- VGA_CURSOR.col += 1
-
- if VGA_CURSOR.col >= VGA_WIDTH
- VGA_CURSOR.col = 0
- VGA_CURSOR.row += 1
-
- if VGA_CURSOR.row >= VGA_HEIGHT
- VGA_CURSOR.row = VGA_HEIGHT - 1
+
+ offset = (VGA_CURSOR.row * VGA_WIDTH + VGA_CURSOR.col) * 2
+
+ (VGA_BUFFER + offset).value = ch
+ (VGA_BUFFER + offset + 1).value = color
+
+ VGA_CURSOR.col += 1
+
+ # Wrap around if past screen
+ if VGA_CURSOR.col >= VGA_WIDTH
+ VGA_CURSOR.col = 0
+ VGA_CURSOR.row += 1
+ if VGA_CURSOR.row >= VGA_HEIGHT
+ VGA_CURSOR.row = VGA_HEIGHT - 1
+ end
end
end
-
- # Wrap around if past screen
- # i %= VGA_SIZE
- end
-
- # Write a string to VGA
- def self.puts(
- str : String,
- color : UInt8? = Colors::DEFAULT,
- line : Int32? = 0,
- ) : Nil
- i = 0
- while i < str.size - 1
- ch = (str.to_unsafe + i).value
- putchar(ch, i, line, color)
- i += 1
- end
- end
- def self.debug_write_at(r : Int32, c : Int32, s : String, color : UInt8 = Colors::DEFAULT)
- off = ((r * VGA_WIDTH) + c) * 2
- i = 0
- ptr = s.to_unsafe
- while i < s.bytesize
- (VGA_BUFFER + off + (i * 2)).value = (ptr + i).value
- (VGA_BUFFER + off + (i * 2) + 1).value = color
- i += 1
+ # Write a string to VGA
+ def self.puts(
+ str : String,
+ color : UInt8? = Colors::DEFAULT,
+ line : Int32? = 0,
+ ) : Nil
+ i = 0
+ while i < str.size - 1
+ ch = (str.to_unsafe + i).value
+ putchar(ch, i, line, color)
+ i += 1
+ end
end
- end
- def self.dump_cursor_and_cells
- # Write cursor state at row 2 col 0
- # debug_write_at(2, 0, ["CURSOR R:",VGA_CURSOR.row," C:",VGA_CURSOR.col].join(""), Colors::BLACK_ON_CYAN)
- # Also copy first 32 bytes of VGA buffer to row 3 for inspection
- i = 0
- while i < 32
- ch = (VGA_BUFFER + (i * 2)).value
- (VGA_BUFFER + ((3 * VGA_WIDTH + i) * 2)).value = ch
- (VGA_BUFFER + ((3 * VGA_WIDTH + i) * 2) + 1).value = Colors::BLACK_ON_LIME
- i += 1
- end
- end
-
end