0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

自作OS Windowを表示する為の準備2

0
Posted at

目的

Windowを表示したいと思っています。
以下の記事を3つ組み合わせて、VRAMを実機にも対応させ、タイトルバーっぽいものも追加しました。
今はただの試しです。ここから直して、Window毎に画面バッファを持たせたり、ドライバを作ってPS/2マウスに対応させたりしようと思っています。

自作OS Windowを表示する為の準備
x86 VBEのVRAM開始アドレスを調べる
x86 VBEのVRAM開始アドレスを取得

コード

图片.png

nasm -f bin boot.asm -o boot.bin
nasm -f elf32 entry.asm -o entry.o
#gcc -m32 -ffreestanding -c mainc.c -o mainc.o
gcc -O0 -m32 -ffreestanding -fno-pic -fno-stack-protector -c mainc.c -o mainc.o

ld -m elf_i386 -T linker.ld -o kernel.elf entry.o mainc.o 
objcopy -O binary kernel.elf kernel.bin
cat boot.bin kernel.bin > disk.img

qemu-system-i386 -drive format=raw,file=disk.img -monitor stdio
boot.asm
[org 0x7C00]
bits 16

start:
    cli
    xor ax, ax
    mov ds, ax
    mov es, ax
    mov ss, ax
    mov sp, 0x7C00
    sti
    
    ; BIOSに因るCS:IP=0x07C0:0x0000及び0x0000:0x7C00を統一する
    jmp 0x0000:real_start
real_start:

    ; VBEのVRAMをBIOSに聞く
    mov ax, 0x4F01
    mov cx, 0x115          ; 聞きたいモード
    mov di, modeinfo
    int 0x10
    
    ; 800x600 24bpp (モード 0115h) 
    mov ax, 0x4F02    ; VBE Set Mode
    mov bx, 0x4115    ; 0115h (24bpp) + ビット14
    int 0x10
    
    ; vbe_vram_addrへVBEのアドレスを置く
    mov eax, [modeinfo + 0x28] 
    mov [vbe_vram_addr], eax

    ; --- INT 13h CHS 読み込み ---
    mov ah, 0x02         ; BIOS: Read Sectors
    mov al, 2            ; 読み込むセクタ数
    mov ch, 0            ; シリンダ = 0
    mov dh, 0            ; ヘッド = 0
    mov cl, 2            ; セクタ = 2 (ブートローダの次)
    mov dl, 0x80         ; ドライブ番号=HDD
    mov bx, 0x7E00       ; ES:BX = 読み込み先
    int 0x13
    jc disk_error
    
    jmp 0x0000:0x7E00    ; 読み込んだコードへjmp   

disk_error:
    hlt
    jmp disk_error


; VBE返り値44バイト modeinfo + 0x28 = VRAM開始アドレス
modeinfo: resb 0x2C

times 506-($-$$) db 0
vbe_vram_addr: resd 1 ; VBE VRAM開始アドレス

times 510-($-$$) db 0
dw 0xAA55
entry.asm
entry.asm
bits 16
global start
extern kernel_main

start:
    cli
    xor ax, ax
    mov ds, ax
    mov es, ax
    mov ss, ax
    mov sp, 0x7C00
    
    ; GDTロード
    lgdt [gdt_descriptor]

    ; プロテクトモード有効化
    mov eax, cr0
    or eax, 1
    mov cr0, eax

    ; 32ビットコードへ移行
    jmp 0x08:pm_start

; -----------------------------
gdt_start:
    dq 0x0000000000000000            ; NULL

gdt_code:
    dw 0xFFFF                        ; limit 0-15
    dw 0x0000                        ; base 0-15
    db 0x00                          ; base 16-23
    db 0x9A                          ; code segment
    db 0xCF                          ; flags
    db 0x00                          ; base 24-31

gdt_data:
    dw 0xFFFF
    dw 0x0000
    db 0x00
    db 0x92                          ; data segment
    db 0xCF
    db 0x00
gdt_end:

gdt_descriptor:
    dw gdt_end - gdt_start - 1
    dd gdt_start

; -----------------------------
[bits 32]
pm_start:
    ; データセグメント設定
    mov ax, 0x10
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov ss, ax
    mov esp, 0x9FC00
    
    call kernel_main

.hlt_loop:
    hlt
    jmp .hlt_loop
mainc.c
typedef unsigned char  u8;
typedef unsigned short u16;
typedef unsigned int   u32;

#define SCREEN_W 800
#define SCREEN_H 600

// Windowの情報
typedef struct {
    int x, y; // window左上の座標
    int w, h; // windowの縦横の長さ
} window_t;

/*
 ピクセル描画
 *fb : VRAM
 x   : X座標
 y   : Y座標
 r   : 赤
 g   : 緑
 b   : 青
*/
static inline void put_pixel(volatile u8 *fb, int x, int y, u8 r, u8 g, u8 b) {
    int p = (y * SCREEN_W + x) * 3; // ポインタを描画するピクセルに合わせる
    fb[p]   = b;
    fb[p+1] = g;
    fb[p+2] = r;
}


/*
  Window描画
 *fb  : VRAM
 *win : Windows情報構造体
 r    : 赤 
 g    : 緑
 b    : 青
*/
void fill_rect(volatile u8 *fb, window_t *win, u8 r, u8 g, u8 b) {
    for (int y = win->y; y < win->y + win->h; y++) {
        for (int x = win->x; x < win->x + win->w; x++) {
            put_pixel(fb, x, y, r, g, b);
        }
    }
}


void draw_title_bar(volatile u8 *fb, window_t *win) {
    window_t bar = {win->x + 2, win->y + 2, win->w - 4, 20};
    fill_rect(fb, &bar, 160, 160, 160);
}

void kernel_main(void) {
    
    u32 fb_addr = *(volatile u32 *)0x7DFA; // VBEの開始VRAM(boot.asmで格納している)
    volatile u8 *fb = (volatile u8 *)fb_addr; // ピクセル毎に操作する為に8bitずつ操作(そもそも1ピクセル24bitだから8bit毎に操作するしかない)

    // 背景(黒)
    window_t bg = {0, 0, SCREEN_W, SCREEN_H};
    fill_rect(fb, &bg, 0, 0, 0);

    // 灰色window描画
    window_t win = {100, 80, 400, 300}; // x, y, 幅, 高さ
    fill_rect(fb, &win, 600, 600, 600); // 灰色
    draw_title_bar(fb, &win); 
    
    // 黄色window
    window_t win2 = {600, 100, 200, 150};
    fill_rect(fb, &win2, 255, 255, 0); // 黄色(R=255, G=255, B=0)
    draw_title_bar(fb, &win2); 

    while (1) asm volatile ("hlt");
}

大連に出張中で、ホテルで書いているので結構雑です。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?