操作系统:内核的基本实现(一)屏幕输出与C语言支持

使用 C 语言

cdecl 约定

HimuOS Kernel 遵守 cdecl 约定,在32位操作系统上,

  • 函数实参在线程栈上按照从右至左的顺序依次压栈 (x86 cdecl 的参数总是在栈上)
  • 函数结果保存在寄存器EAX/AX/AL中
  • 浮点型结果存放在寄存器ST0中
  • 编译后的函数名前缀以一个下划线字符
  • 调用者负责清栈
  • 8比特或者16比特长的整形实参提升为32比特长
  • 受到函数调用影响的寄存器:EAX, ECX, EDX, ST0 - ST7, ES, GS

x86_64 的约定
在64位机器上约定有所不同,MSVC和GNU/GCC都有不同的约定。MSVC使用__fastcall,前四个整数或指针参数通过寄存器RCX, RDX, R8, R9传递,其余通过栈传递。GNU/GCC则使用System V ABI,前六个整数或指针参数通过RDI, RSI, RDX, RCX, R8, R9传递,返回值通过RAX

打印函数的实现

在保护模式中,一般使用 in/out 操作显卡有关I/O 端口完成图形操作(更新硬件光标位置等)

  1. 保存所有通用寄存器的值,以便函数结束时能够恢复原状态。
  2. 调用0x03d4/0x03d5 I/O 端口获取/更新硬件光标位置
  3. 检查是否是回车 (0x0d),换行 (0x0a),或退格 (0x08):
    • 回车和换行被视为相同的情况,跳转到 .key_lf 处理。
    • 退格字符减少光标位置并清除相应的字符。
  4. 若是普通字符,将光标位置乘以2(因为视频内存中每个字符占用2字节),把字符写入显存,并设置字符的颜色为 0x07(通常表示白色字符,黑色背景)。
  5. 若光标位置超出2000(超出屏幕区域),则跳转到滚动屏幕部分 .roll_screen
  6. 如果字符是回车或换行,计算新光标位置,换行后光标移动到下一行。
  7. 屏幕滚动:将前1-24行的缓存区全部向上到0-23行复制,最后一行用空格覆盖,并将光标置于最后一行的起始处。
;
; HIMU OPERATING SYSTEM
;
; File: krnlio.asm
; Kernel I/O functions
; Copyright (C) 2024 HimuOS Project, all rights reserved.

; All builtin functions has __himuos__ prefix to avoid conflicts with other functions

%include "osbase32.inc"

[bits 32]
section .text

; Function: getcrpos
; get current cursor position
; - return ax: cursor position
; ---------------------------------------------------------
global __himuos__getcrpos
__himuos__getcrpos:
    push edx
    mov dx, 0x03D4
    mov al, 0x0E
    out dx, al
    mov dx, 0x03D5
    in al, dx
    mov ah, al
    mov dx, 0x03D4
    mov al, 0x0F
    out dx, al
    mov dx, 0x03D5
    in al, dx
    pop edx
    ret

; Function: printc
; write a character in stack to the screen
; ---------------------------------------------------------
global __himuos__printc
__himuos__printc:
    pushad
    mov ax, SELECTOR_VIDEO
    mov gs, ax

    call __himuos__getcrpos
    mov bx, ax
    mov ecx, [esp + 36]

    cmp cl, 0xd
    jz .key_cr
    cmp cl, 0xa
    jz .key_lf
    cmp cl, 0x8
    jz .key_backspace
    jmp .key_other
.key_backspace:
    dec bx
    shl bx, 1
    mov byte [gs:bx], 0
    inc bx
    mov byte [gs:bx], 0x07
    shr bx, 1
    jmp .set_cursor
.key_other:
    shl bx, 1
    mov byte [gs:bx], cl
    inc bx
    mov byte [gs:bx], 0x07
    shr bx, 1
    inc bx
    cmp bx, 2000
    jl .set_cursor
; we consider carriage returns and line breaks as the same situation (CRLF)
.key_lf:
.key_cr:
    xor dx, dx
    mov ax, bx
    mov si, 80
    div si
    sub bx, dx
    add bx, 80
    cmp bx, 2000
    jl .set_cursor
.roll_screeen:
    cld 
    mov ecx, 960

    mov esi, 0xc00b80a0
    mov edi, 0xc00b8000
    rep movsd

    mov ebx, 3840
    mov ecx, 80

.cls:
    mov word [gs:ebx], 0x0720
    add ebx, 2
    loop .cls
    mov bx, 1920

.set_cursor:
    mov dx, 0x03d4
    mov al, 0x0e
    out dx, al
    mov dx, 0x03d5
    mov al, bh
    out dx, al

    mov dx, 0x03d4
    mov al, 0x0f
    out dx, al
    mov dx, 0x03d5
    mov al, bl
    out dx, al
.printc_end:
    popad
    ret

; Function: clscr
; clear the screen and set the cursor to the top left corner
; ---------------------------------------------------------
global __himuos__clscr
__himuos__clscr:
    pushad
    mov ax, SELECTOR_VIDEO
    mov gs, ax
    xor ebx, ebx
    mov ecx, 2000
.clscr_loop:
    mov word [gs:bx], 0x0720
    add ebx, 2
    loop .clscr_loop
    mov bx, 0
    mov dx, 0x03d4
    mov al, 0x0e
    out dx, al
    mov dx, 0x03d5
    mov al, bh
    out dx, al
    mov dx, 0x03d4
    mov al, 0x0f
    out dx, al
    mov dx, 0x03d5
    mov al, bl
    out dx, al
    popad
    ret

; Function: printstr
; print a string to the screen
; ---------------------------------------------------------
global __himuos__printstr
__himuos__printstr:
    push ebx
    push ecx
    mov ecx, 0
    mov ebx, [esp + 12]
.printstr_loop:
    mov cl, [ebx]
    cmp cl, 0
    jz .printstr_end
    push ecx
    call __himuos__printc
    add esp, 4
    inc ebx
    jmp .printstr_loop
.printstr_end:
    pop ecx
    pop ebx
    ret

posted on 2024-10-10 15:56  Himu  阅读(16)  评论(0编辑  收藏  举报