VESA编程初步试验


  
读京山游侠《使用 GCC 和 GNU Binutils 编写能在 x86 实模式运行的 16 位代码》一文之后,进行了VESA编程试验。
试验在bochs下以软盘启动通过:(环境为Ubuntu18(64bit),apt-get install bochs bochs-x hexedit)
boot3.S( for bochs ):
.code16gcc
.global _start
.text
.align 4
_start:

###### A20 ########

     pushl  %eax
     pushl  %ecx            # needed to save, (demo code is like this)

     cli
     

     xor  %eax,  %eax 

     movw $0x2401 ,  %ax
     int  $0x15             #al 00-disabled 01-enabled

     movw $0x2402 ,  %ax
     int  $0x15             #al 00-disabled 01-enabled


     sti

     popl   %ecx
     popl   %eax


###################

##### VESA #######

     pushw %di
     pushl %eax
     pushl %ecx
     pushw %bx

     movw  $0x8000, %di

     movw  $0x4115, %bx
     movw $0x4f02, %ax

     int  $0x10

     movb  %ah,  number

     popw %bx
     popl %ecx
     popl %eax
     popw %di
 
#########################

########  protected mode ########
     cli
 
     lgdt   gdt_48
     movl   %cr0,  %eax
     orl    $1 , %eax
     movl   %eax, %cr0

     ljmp     $0x8, $protcseg
#################################

####### write video ram ####
.code32
write_vram:

     sti

     pushl  %eax
     pushw  %ds
     pushw  %di


#.byte 0x66  
     movl $0xe0000000, %eax
     addl $720000,      %eax
     movw   %fs,  %cx
     movw   %cx,  %di

     calll  main2          
     jmp .                 # remove these two lines to show assembly drawing


     movl $800, %ecx
loop:

     movl $0x00ff0000, (%eax)

     addl $3,   %eax
     subl $1,   %ecx
     cmp  $0,   %ecx
     jnz  loop
 
     popw  %di
     popw  %ds
     popl  %eax

     jmp .

##################


.code16gcc
##### base code ###
base:
   pushw %ds
   pushw %es
   pushw %ss

   movw %cs, %ax
   movw %ax, %ds
   movw %ax, %es
   movw %ax, %ss

    pushw %sp   

    movw $stack, %ax
    movw  %ax, %sp

    calll  main2

    popw %sp
    movw $stack, %sp

    popw %ss
    popw %es
    popw %ds


    hlt 


message:
   .string "Hello, world!\n\0"

.global display_str
display_str:
  pushl        %ebp
  movl   %esp, %ebp

  and 0xfffffff0, %esp

  pushl %ebp              

  pushl %ebx
  pushl %ecx
  pushl %edx

 
   movw    0x0c(%ebp) , %cx       # 15
   movw     0x8(%ebp),  %bp       #  movw  $message, %bp
  movw $0x1301, %ax
  movw $0x000c, %bx
  movw  $0x0,   %dx

  int $0x10

   popl %edx
   popl %ecx
   popl %ebx

  popl %ebp

#   movl %ebp, %esp   
#   popl %ebp
   leavel
   retl


.org  .+0x40
stack:


.code32
protcseg:
 
     sti


     movw  $0x10,  %ax
     movw %ax, %ds        # this is indispensable


######### return to real mode ######
.code16gcc
     cli

     movl   %cr0,  %eax
     andl    $0xfffffffe , %eax
     movl   %eax, %cr0



#DATA32 ADDR32
     jmp     $0x0, $write_vram    #ljmp $0x08, $write_vram #jmp  write_vram

####################################
.code32
gdt:   .word 0,0,0,0
    .word  0xffff
    .word  0x0000
    .word  0x9a00
    .word  0x00cf

    .word  0xffff
    .word  0x0000
    .word  0x9200
    .word  0x00cf

#    .word  0xffff
#    .word  0x0000
#    .word  0x9200
#    .word  0xe0cf

      .word 0,0,0,0  
#      .word 0,0,0,0  

gdt_48:    .word  0x1f
           .long  gdt
 
boot3.c( for bochs ):
__asm__(".code32\n");


void display_str(char* str, short length);

int number ;
int number2;

void main2()
{
   char* str;

   number2 = number;
      char* pAddress = (char*)0xe0000000;
      pAddress +=300*800 + 100*3;
      for(int i = 0; i < 2400-200*3; i++)   
      {
         *pAddress = 255;
	 pAddress += 1;
      }
      while(1)
	 ;
}
 
编译脚本如下:(注意然后要手动dd到空白软盘镜像和用hexedit改最后两个字节为0xAA55)
make3.sh(for bochs):
#!/bin/bash
   rm -f boot *.o *.out boot.img    disassem.asm

   as --32 boot3.S -o boot3_S.o  
   gcc -c -m32 boot3.c  -o boot3_c.o
   ld -Ttext 0x7c00  -m elf_i386  boot3_S.o  boot3_c.o   -o  boot.elf
     objdump -D -m i8086   boot.elf  >  disassem.asm
   objcopy -j .text  -j .rodata   -O binary  boot.elf  boot.out
     dd if=/dev/zero of=boot.img bs=512 count=1
 #    dd if=boot.out of=boot.img bs=96 count=1 conv=notrunc
 
运行bochs配置文件如下:
bochsrc(for bochs):
config_interface: textconfig
#display_library: sdl
#romimage: file=/usr/share/bochs/BIOS-bochs-latest, address=0xf0000
romimage: file=/usr/share/bochs/BIOS-bochs-latest
megs: 32
vgaromimage: file=/usr/share/vgabios/vgabios.bin
floppya: type=1_44, 1_44="boot.img", status=inserted
ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
ata1: enabled=0, ioaddr1=0x170, ioaddr2=0x370, irq=15
ata2: enabled=0, ioaddr1=0x1e8, ioaddr2=0x3e0, irq=11
ata3: enabled=0, ioaddr1=0x168, ioaddr2=0x360, irq=9
#ata0-master: type=disk, path="", mode=flat, cylinders=1024, heads=16, spt=63
ata0-slave: type=cdrom, path="/dev/cdrom", status=inserted

boot: floppy

#ips: 1000000
floppy_bootsig_check: disabled=0
log: /dev/stdout
panic: action=ask
error: action=report
info: action=report
debug: action=ignore
debugger_log: -
com1: enabled=1, dev=/dev/ttyS0
parport1: enabled=1, file="/dev/lp0"
sb16: midimode=1, midi=/dev/midi00, wavemode=1, wave=/dev/dsp, loglevel=2, log=/dev/stdout, dmatimer=600000
vga_update_interval: 300000
keyboard_serial_delay: 250
keyboard_paste_delay: 100000
#floppy_command_delay: 500
mouse: enabled=1
private_colormap: enabled=0
#ne2k: ioaddr=0x240, irq=9, mac=b0:c4:20:00:00:00, ethmod=linux, ethdev=eth0
#keyboard_mapping: enabled=0, map=/usr/share/bochs/keymaps/x11-pc-de.map
#keyboard_type: mf
#user_shortcut: keys=ctrlaltdel
#magic_break: enabled=1
#cmosimage: cmos.img
#load32bitOSImage: os=nullkernel, path=../kernel.img, iolog=../vga_io.log
#load32bitOSImage: os=linux, path=../linux.img, iolog=../vga_io.log, initrd=../initrd.img
#i440fxsupport: enabled=1
#usb1: enabled=1, ioaddr=0xFF80, irq=10
#text_snapshot_check: enable
 
运行命令:bochs -f ./bochsrc
效果如图:
(汇编版)

(c语言版)


至此试验初步就告完成。结论是:从16位实模式进了32位保护模式然后又返回实模式可以访问4GB内存,可写0xe0000000物理地址的VESA (LFB模式的)显存。 参阅了《vbe3标准》和《操作系统实现之路》《Linux内核完全剖析》《一个64位操作系统的设计与实现》《最新VESA/SVGA图形图像编程秘技》 《simple_os_book》等和一些网文, 表示谢意。
源文件打包在此:bochs软盘启动版:boot3_bochs_0.9992.tgz

  

More powered by