mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 11:37:35 +00:00
Start exploring graphical video modes for VGA console (#637)
This commit is contained in:
parent
304cf8869c
commit
ecb2ef7c39
8 changed files with 964 additions and 70 deletions
|
@ -112,19 +112,34 @@ static noasan textreal void __normalize_e820(struct mman *mm) {
|
|||
mm->e820n = n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Identity maps an area of physical memory to its negative address.
|
||||
*/
|
||||
noasan textreal void __invert_memory_area(struct mman *mm, uint64_t *pml4t,
|
||||
uint64_t ps, uint64_t size,
|
||||
uint64_t pte_flags) {
|
||||
uint64_t pe = ps + size, p, *m;
|
||||
ps = ROUNDDOWN(ps, 4096);
|
||||
pe = ROUNDUP(pe, 4096);
|
||||
for (p = ps; p != pe; p += 4096) {
|
||||
m = __get_virtual(mm, pml4t, BANE + p, true);
|
||||
if (m && !(*m & PAGE_V)) {
|
||||
*m = p | PAGE_V | pte_flags;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Identity maps all usable physical memory to its negative address.
|
||||
*/
|
||||
static noasan textreal void __invert_memory(struct mman *mm, uint64_t *pml4t) {
|
||||
uint64_t i, j, *m, p, pe;
|
||||
for (i = 0; i < mm->e820n; ++i) {
|
||||
for (p = mm->e820[i].addr, pe = mm->e820[i].addr + mm->e820[i].size;
|
||||
p != pe + 0x200000; p += 4096) {
|
||||
m = __get_virtual(mm, pml4t, BANE + p, true);
|
||||
if (m && !(*m & PAGE_V)) {
|
||||
*m = p | PAGE_V | PAGE_RW;
|
||||
}
|
||||
}
|
||||
uint64_t ps = mm->e820[i].addr, size = mm->e820[i].size;
|
||||
/* ape/ape.S has already mapped the first 2 MiB of physical memory. */
|
||||
if (ps < 0x200000 && ps + size <= 0x200000)
|
||||
continue;
|
||||
__invert_memory_area(mm, pml4t, ps, size, PAGE_RW);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -148,6 +163,12 @@ noasan textreal void __setup_mman(struct mman *mm, uint64_t *pml4t) {
|
|||
export_offsetof(struct mman, e820);
|
||||
export_offsetof(struct mman, e820_end);
|
||||
export_offsetof(struct mman, bad_idt);
|
||||
export_offsetof(struct mman, pc_video_type);
|
||||
export_offsetof(struct mman, pc_video_stride);
|
||||
export_offsetof(struct mman, pc_video_width);
|
||||
export_offsetof(struct mman, pc_video_height);
|
||||
export_offsetof(struct mman, pc_video_framebuffer);
|
||||
export_offsetof(struct mman, pc_video_framebuffer_size);
|
||||
__normalize_e820(mm);
|
||||
__invert_memory(mm, pml4t);
|
||||
}
|
||||
|
|
|
@ -18,8 +18,27 @@ struct mman {
|
|||
unsigned char pc_drive_last_head; /* 0x1d21 */
|
||||
unsigned char pc_drive; /* 0x1d22 */
|
||||
char bad_idt[6]; /* 0x1d23 */
|
||||
unsigned char pc_video_type; /* 0x1d29 */
|
||||
unsigned short pc_video_stride; /* 0x1d2a — line width, including any
|
||||
invisible "pixels" — in
|
||||
bytes (NOTE) */
|
||||
unsigned short pc_video_width; /* 0x1d2c — width in chars. (text)
|
||||
or pixels (graphics) */
|
||||
unsigned short pc_video_height; /* 0x1d2e — height in chars. (text)
|
||||
or pixels (graphics) */
|
||||
uint64_t pc_video_framebuffer; /* 0x1d30 — physical address of
|
||||
video frame buffer */
|
||||
uint64_t pc_video_framebuffer_size; /* 0x1d38 */
|
||||
};
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
||||
/* Values for mman::pc_video_type. TODO: implement graphics modes. */
|
||||
#define PC_VIDEO_TEXT 0
|
||||
#define PC_VIDEO_BGR565 1
|
||||
#define PC_VIDEO_BGR555 2
|
||||
#define PC_VIDEO_BGRX8888 3
|
||||
#define PC_VIDEO_RGBX8888 4
|
||||
|
||||
#endif /* COSMOPOLITAN_LIBC_RUNTIME_MMAN_H_ */
|
||||
|
|
|
@ -186,6 +186,8 @@ struct IdtDescriptor {
|
|||
uint64_t *__get_virtual(struct mman *, uint64_t *, int64_t, bool);
|
||||
uint64_t __clear_page(uint64_t);
|
||||
uint64_t __new_page(struct mman *);
|
||||
void __invert_memory_area(struct mman *, uint64_t *, uint64_t, uint64_t,
|
||||
uint64_t);
|
||||
void __map_phdrs(struct mman *, uint64_t *, uint64_t);
|
||||
|
||||
forceinline unsigned char inb(unsigned short port) {
|
||||
|
|
611
libc/vga/rlinit-vesa.S
Normal file
611
libc/vga/rlinit-vesa.S
Normal file
|
@ -0,0 +1,611 @@
|
|||
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
||||
│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ This is free and unencumbered software released into the public domain. │
|
||||
│ │
|
||||
│ Anyone is free to copy, modify, publish, use, compile, sell, or │
|
||||
│ distribute this software, either in source code form or as a compiled │
|
||||
│ binary, for any purpose, commercial or non-commercial, and by any │
|
||||
│ means. │
|
||||
│ │
|
||||
│ In jurisdictions that recognize copyright laws, the author or authors │
|
||||
│ of this software dedicate any and all copyright interest in the │
|
||||
│ software to the public domain. We make this dedication for the benefit │
|
||||
│ of the public at large and to the detriment of our heirs and │
|
||||
│ successors. We intend this dedication to be an overt act of │
|
||||
│ relinquishment in perpetuity of all present and future rights to this │
|
||||
│ software under copyright law. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │
|
||||
│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │
|
||||
│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │
|
||||
│ IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR │
|
||||
│ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, │
|
||||
│ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR │
|
||||
│ OTHER DEALINGS IN THE SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "ape/relocations.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/runtime/mman.internal.h"
|
||||
#include "libc/vga/vga.internal.h"
|
||||
|
||||
#define VGA_PREFER_GRAPH_HEIGHT \
|
||||
(VGA_PREFER_TTY_HEIGHT * VGA_ASSUME_CHAR_HEIGHT_PX)
|
||||
#define VGA_PREFER_GRAPH_WIDTH \
|
||||
(VGA_PREFER_TTY_WIDTH * VGA_ASSUME_CHAR_WIDTH_PX)
|
||||
#define MAX_VESA_MODES_TO_TRACK 64
|
||||
|
||||
// Mode information data structure, used internally.
|
||||
.set "mi::type",0
|
||||
.set "mi::bpp",1
|
||||
.set "mi::width",2
|
||||
.set "mi::height",4
|
||||
.set "mi::mode_num",6
|
||||
.set "mi::stride",8
|
||||
.set "mi::fb",10
|
||||
.set "mi::sizeof",14
|
||||
|
||||
// Routine to activate additional VESA functionality if the user holds
|
||||
// down a magic key, when booting from bare metal. Currently this just
|
||||
// dumps a list of all usable VESA VBE video modes on the console.
|
||||
//
|
||||
// TODO: allow user to select a video mode and switch to it
|
||||
// TODO: implement character drawing in graphics modes
|
||||
//
|
||||
// @return CF = 0 if we decided to set a new video mode, CF = 1 otherwise
|
||||
|
||||
.real
|
||||
.code16
|
||||
_rlinit_vesa:
|
||||
push %es
|
||||
pushw $0
|
||||
testb $0b00000011,0x0417 # read keyboard shift state (as
|
||||
jnz .doit # given by BIOS's IRQ 1); if Shift
|
||||
# key pressed, activate code below
|
||||
mov $0x8300,%ax # wait for the magic key for a short
|
||||
mov $(250000>>16),%cx # period of time...
|
||||
mov $(250000&0xffff),%dx
|
||||
push %ss
|
||||
pop %es
|
||||
mov %sp,%bx
|
||||
int $0x15
|
||||
jc .done
|
||||
.wait: pause
|
||||
testb $0b00000011,0x0417
|
||||
jnz .doit2
|
||||
cmpb $0,%es:(%bx)
|
||||
jz .wait
|
||||
stc
|
||||
.done: pop %ax
|
||||
pop %es
|
||||
ret
|
||||
.doit2: mov $0x8301,%ax # we got the magic key; cancel the
|
||||
int $0x15 # wait timer
|
||||
.doit: pop %ax # we got the magic key; do stuff
|
||||
pop %es
|
||||
// fall through
|
||||
.endfn _rlinit_vesa,globl,hidden
|
||||
|
||||
.do_vesa_rlinit:
|
||||
push %eax
|
||||
push %bx
|
||||
push %edx
|
||||
push %bp
|
||||
sub $2+MAX_VESA_MODES_TO_TRACK*"mi::sizeof",%sp
|
||||
mov %sp,%bp
|
||||
call .gather_vesa_modes # gather list of VESA modes
|
||||
jc 8f
|
||||
call .get_default_mode # choose a default mode to use
|
||||
jc 6f
|
||||
call .choose_mode # allow user to select different mode
|
||||
movw %bx,%bp
|
||||
call .snooze
|
||||
mov "mi::mode_num"(%bp),%bx
|
||||
mov $0x4f02,%ax
|
||||
int $0x10
|
||||
cmp $0x004f,%ax
|
||||
jnz 9f
|
||||
mov "mi::type"(%bp),%al
|
||||
.set mm,0x0500
|
||||
mov %al,mm+"struct mman::pc_video_type"
|
||||
mov "mi::width"(%bp),%ax
|
||||
mov %ax,mm+"struct mman::pc_video_width"
|
||||
movzwl "mi::height"(%bp),%edx
|
||||
mov %dx,mm+"struct mman::pc_video_height"
|
||||
mov "mi::fb"(%bp),%eax
|
||||
mov %eax,mm+"struct mman::pc_video_framebuffer"
|
||||
movzwl "mi::stride"(%bp),%eax
|
||||
mov %ax,mm+"struct mman::pc_video_stride"
|
||||
imul %edx,%eax
|
||||
mov %eax,mm+"struct mman::pc_video_framebuffer_size"
|
||||
xor %eax,%eax
|
||||
mov %eax,mm+"struct mman::pc_video_framebuffer"+4
|
||||
mov %eax,mm+"struct mman::pc_video_framebuffer_size"+4
|
||||
clc
|
||||
5: lahf
|
||||
add $2+MAX_VESA_MODES_TO_TRACK*"mi::sizeof",%sp
|
||||
sahf
|
||||
pop %bp
|
||||
pop %edx
|
||||
pop %bx
|
||||
pop %eax
|
||||
ret
|
||||
6: mov $REAL(str.no_mode),%si
|
||||
7: call .puts
|
||||
8: call .snooze
|
||||
stc
|
||||
jmp 5b
|
||||
9: mov $REAL(str.bad_mode),%si
|
||||
jmp 7b
|
||||
.endfn .do_vesa_rlinit
|
||||
|
||||
// Preliminarily choose a "default" VESA screen mode from a list of
|
||||
// gathered screen modes.
|
||||
//
|
||||
// @return %bx is such that %ss:(%bx) = internal struc. for default mode
|
||||
// @return CF = 1 if no available modes, CF = 0 otherwise
|
||||
.get_default_mode:
|
||||
push %eax
|
||||
push %cx
|
||||
push %edx
|
||||
push %edi
|
||||
push %bp
|
||||
mov (%bp),%cx
|
||||
jcxz 8f
|
||||
inc %bp
|
||||
inc %bp
|
||||
or $-1,%esi # %esi = best fit screen size + penalty
|
||||
# (to be recalculated later)
|
||||
mov %bp,%bx # %bx = pointer to best info. struct.
|
||||
1: mov "mi::type"(%bp),%ax # load mode type & bits per pixel
|
||||
ror %ah # convert bpp into penalty value:
|
||||
movzbl %ah,%edi # fewer bpp are better, but prefer
|
||||
# 16 bpp over 15 bpp
|
||||
cmp $PC_VIDEO_TEXT,%al # handle text modes specially
|
||||
jz 9f
|
||||
movzwl "mi::width"(%bp),%eax
|
||||
jz 9f
|
||||
cmp $VGA_PREFER_GRAPH_WIDTH,%ax # calculate screen size
|
||||
jb 3f
|
||||
movzwl "mi::height"(%bp),%edx
|
||||
cmp $VGA_PREFER_GRAPH_HEIGHT,%dx
|
||||
jb 3f
|
||||
imul %edx,%eax
|
||||
2: add %edi,%eax
|
||||
jc 3f
|
||||
cmp %esi,%eax
|
||||
jnb 3f
|
||||
mov %eax,%esi
|
||||
mov %bp,%bx
|
||||
3: add $"mi::sizeof",%bp
|
||||
loop 1b
|
||||
clc
|
||||
7: pop %bp
|
||||
pop %edi
|
||||
pop %edx
|
||||
pop %cx
|
||||
pop %eax
|
||||
ret
|
||||
8: stc
|
||||
jmp 7b
|
||||
9: imul $VGA_ASSUME_CHAR_WIDTH_PX,%eax
|
||||
cmp $VGA_PREFER_GRAPH_WIDTH,%eax
|
||||
jb 2b
|
||||
movzwl "mi::height"(%bp),%edx
|
||||
imul $VGA_ASSUME_CHAR_HEIGHT_PX,%edx
|
||||
cmp $VGA_PREFER_GRAPH_HEIGHT,%edx
|
||||
jb 3b
|
||||
imul %edx,%eax
|
||||
jo 3b
|
||||
mov $1<<31,%edi # severely disparage text modes
|
||||
jmp 2b
|
||||
.endfn .get_default_mode
|
||||
|
||||
// Allow the user to choose a VESA screen mode to use.
|
||||
//
|
||||
// @return %bx is such that ss:(%bx) = internal struc. for chosen mode
|
||||
.choose_mode:
|
||||
push %ax
|
||||
push %si
|
||||
push %di
|
||||
mov (%bp),%di
|
||||
imul $"mi::sizeof",%di
|
||||
lea 2(%bp,%di),%di
|
||||
1: mov $REAL(str.choose_mode),%si
|
||||
call .puts
|
||||
mov %ss:("mi::mode_num")(%bx),%ax
|
||||
call .putx
|
||||
mov %ss:("mi::width")(%bx),%ax
|
||||
call .putd
|
||||
mov %ss:("mi::height")(%bx),%ax
|
||||
call .putd
|
||||
mov %ss:("mi::bpp")(%bx),%al
|
||||
call .putdb
|
||||
mov $0,%ah
|
||||
int $0x16
|
||||
#define UPSCN 0x48
|
||||
#define DNSCN 0x50
|
||||
#define CRSCN 0x1c
|
||||
cmp $DNSCN,%ah
|
||||
jz 3f
|
||||
cmp $CRSCN,%ah
|
||||
jz 4f
|
||||
cmp $UPSCN,%ah
|
||||
jnz 1b
|
||||
lea 2(%bp),%ax # up arrow pressed
|
||||
cmp %ax,%bx
|
||||
jz 1b
|
||||
2: sub $"mi::sizeof",%bx
|
||||
jmp 1b
|
||||
3: add $"mi::sizeof",%bx # down arrow pressed
|
||||
cmp %di,%bx
|
||||
jnz 1b
|
||||
jmp 2b
|
||||
4: call .putnl # Enter pressed
|
||||
pop %di
|
||||
pop %si
|
||||
pop %ax
|
||||
ret
|
||||
.endfn .choose_mode
|
||||
|
||||
.snooze:
|
||||
push %ax
|
||||
push %cx
|
||||
push %dx
|
||||
mov $0x86,%ah # do a(nother) short few-second wait
|
||||
mov $(2000000>>16),%cx
|
||||
mov $(2000000&0xffff),%dx
|
||||
int $0x15
|
||||
pop %dx
|
||||
pop %cx
|
||||
pop %ax
|
||||
ret
|
||||
.endfn .snooze
|
||||
|
||||
// Dump a list of all the VESA VBE video modes that are usable on the
|
||||
// target machine. Also gather a list of video modes and basic
|
||||
// information about these modes at %ss:(%bp).
|
||||
.gather_vesa_modes:
|
||||
push %ds
|
||||
push %es
|
||||
push %si
|
||||
push %di
|
||||
push %ss # allocate 0x200 bytes on stack
|
||||
pop %es # for general VESA information
|
||||
sub $0x200,%sp
|
||||
mov $0x200/2,%cx
|
||||
mov %sp,%di
|
||||
cld
|
||||
xor %ax,%ax
|
||||
rep stosw
|
||||
mov $0x4f00,%ax # get general VESA information
|
||||
mov %sp,%di
|
||||
movl $/*"VBE2"*/0x32454256,%es:(%di)
|
||||
int $0x10
|
||||
cmp $0x004f,%ax # if this fails, complain
|
||||
jnz .fail2
|
||||
mov $REAL(str.mode_list_start),%si
|
||||
call .puts # otherwise start iterating through
|
||||
lds %es:0xe(%di),%si # the returned video mode list
|
||||
movw $0,(%bp)
|
||||
cld
|
||||
.iter1: lodsw
|
||||
inc %ax
|
||||
jz .done2
|
||||
dec %ax
|
||||
call .munge # process mode number
|
||||
jc .iter1
|
||||
.iter2: lodsw
|
||||
inc %ax
|
||||
jz .nl
|
||||
dec %ax
|
||||
call .munge # process another mode number
|
||||
jc .iter2
|
||||
.iter3: lodsw
|
||||
inc %ax
|
||||
jz .nl
|
||||
dec %ax
|
||||
call .munge # process another mode number
|
||||
jc .iter3
|
||||
call .putnl
|
||||
jmp .iter1 # ...and so on
|
||||
.nl: call .putnl
|
||||
clc
|
||||
.done2: add $0x200,%sp # OK, we are finally done
|
||||
pop %di
|
||||
pop %si
|
||||
pop %es
|
||||
pop %ds
|
||||
ret
|
||||
.fail2: mov $REAL(str.no_vesa),%si
|
||||
call .puts
|
||||
stc
|
||||
jmp .done2
|
||||
.endfn .gather_vesa_modes
|
||||
|
||||
// Display information on one video mode number, which should be in %ax.
|
||||
// If %ax is a mode which we can use, also update the mode information
|
||||
// buffer at %ss:(%bp). Assume %es = %ss.
|
||||
//
|
||||
// @return CF = 0 if video mode is usable, CF = 1 otherwise
|
||||
.munge: push %ax
|
||||
push %bx
|
||||
push %cx
|
||||
push %si
|
||||
push %di
|
||||
or $1<<14,%ax # force frame buffer mode
|
||||
xchg %ax,%si # remember mode number
|
||||
sub $0x100,%sp # allocate 0x100 stack bytes for
|
||||
mov $0x100/2,%cx # information on this mode; clear
|
||||
mov %sp,%di # the bytes
|
||||
cld
|
||||
xor %ax,%ax
|
||||
rep stosw
|
||||
mov %si,%cx # get information on one mode
|
||||
mov $0x4f01,%ax
|
||||
mov %sp,%di
|
||||
int $0x10
|
||||
cmp $0x004f,%ax # if error, skip mode
|
||||
jnz .fail3
|
||||
mov %es:(%di),%al
|
||||
mov %al,%cl
|
||||
and $0b00001011,%al # also skip if mode is unusable, or
|
||||
cmp $0b00001011,%al # extra information unavailable, or
|
||||
jnz .fail3 # is monochrome, or is graphics w/o
|
||||
mov %cl,%al # linear frame buffer
|
||||
and $0b10010000,%al
|
||||
cmp $0b00010000,%al
|
||||
jz .fail3
|
||||
call .video_type # check if we know about the video
|
||||
jc .fail3 # buffer type, & what exact type it is
|
||||
mov (%bp),%bx # if we are already tracking too
|
||||
cmp $MAX_VESA_MODES_TO_TRACK,%bx # VESA modes, also skip
|
||||
jnb .fail3
|
||||
inc %bx # otherwise start noting down mode
|
||||
mov %bx,(%bp) # information...
|
||||
imul $"mi::sizeof",%bx
|
||||
lea 2-"mi::sizeof"(%ebp,%ebx),%bx
|
||||
mov %al,%ss:("mi::type")(%bx) # ...starting from frame buffer type
|
||||
call .putsp # echo and remember mode information
|
||||
call .putsp
|
||||
test $0b00010000,%cl # first, echo mode attributes
|
||||
setnz %al
|
||||
imul $'G'-'T',%ax,%ax # - 'G': graphics; 'T': text mode
|
||||
add $'T',%al
|
||||
call .putc
|
||||
call .putsp
|
||||
xchg %ax,%si # then process
|
||||
mov %ax,%ss:("mi::mode_num")(%bx) # - mode number
|
||||
call .putx
|
||||
mov %es:0x12(%di),%ax # - mode width
|
||||
mov %ax,%ss:("mi::width")(%bx)
|
||||
call .putd
|
||||
mov %es:0x14(%di),%ax # - mode height
|
||||
mov %ax,%ss:("mi::height")(%bx)
|
||||
call .putd
|
||||
mov %es:0x19(%di),%al # - bits per pixel
|
||||
mov %al,%ss:("mi::bpp")(%bx)
|
||||
call .putdb
|
||||
mov %es:0x10(%di),%ax # - mode stride
|
||||
mov %ax,%ss:("mi::stride")(%bx)
|
||||
testb $0b00010000,%cl
|
||||
jz .txt
|
||||
mov %es:0x28(%di),%eax
|
||||
.fb: mov %eax,%ss:("mi::fb")(%bx) # - frame buffer address
|
||||
clc
|
||||
.done3: lea 0x100(%esp),%sp
|
||||
pop %di
|
||||
pop %si
|
||||
pop %cx
|
||||
pop %bx
|
||||
pop %ax
|
||||
ret
|
||||
.fail3: stc
|
||||
jmp .done3
|
||||
.txt: movzwl %es:8(%di),%eax # for text mode, use window A as
|
||||
shl $4,%eax # frame buffer
|
||||
jmp .fb
|
||||
.endfn .munge
|
||||
|
||||
// Check if the given video mode information uses a video buffer type
|
||||
// we know about, and say what type of video buffer it is.
|
||||
//
|
||||
// @param %es:(%di) = video mode information from int 0x10, %ax = 0x4f01
|
||||
// @param %cl = low byte of video mode attributes (= %es:(%di))
|
||||
// @return %al = video buffer type (for mman::pc_video_type)
|
||||
// @return CF = 0 if video mode is usable, CF = 1 otherwise
|
||||
.video_type:
|
||||
push %bx
|
||||
push %cx
|
||||
push %edx
|
||||
mov $PC_VIDEO_TEXT,%al # if text mode, simply say so
|
||||
test $0b00010000,%cl
|
||||
jz .ok4
|
||||
cmp $6,%es:0x1b(%di) # if graphics mode, check if direct
|
||||
jnz .fail4 # color; bail out if not
|
||||
mov %es:0x19(%di),%cl # check actual color fields & bits
|
||||
mov %es:0x1f(%di),%ax # per pixel, against a list
|
||||
mov %es:0x21(%di),%edx
|
||||
mov $REAL(.type_list),%bx
|
||||
.iter4: cmp %edx,%cs:4(%bx)
|
||||
jnz .next
|
||||
cmp %cl,%cs:1(%bx)
|
||||
jnz .next
|
||||
cmp %ax,%cs:2(%bx)
|
||||
jz .found
|
||||
.next: add $8,%bx
|
||||
cmp $REAL(.type_list_end),%bx
|
||||
jnz .iter4
|
||||
.fail4: stc # unsupported mode; return failure
|
||||
jmp .done4
|
||||
.found: mov %cs:(%bx),%al # this mode is supported; return the
|
||||
.ok4: clc # corresponding type code
|
||||
.done4: pop %edx
|
||||
pop %cx
|
||||
pop %bx
|
||||
ret
|
||||
|
||||
// Output a string via BIOS.
|
||||
.puts: cld
|
||||
push %si
|
||||
0: lodsb
|
||||
test %al,%al
|
||||
jz 1f
|
||||
call .putc
|
||||
jmp 0b
|
||||
1: pop %si
|
||||
ret
|
||||
.endfn .puts
|
||||
|
||||
// Output a 16-bit number in decimal via BIOS.
|
||||
.putd: push %ax
|
||||
push %cx
|
||||
push %dx
|
||||
push %si
|
||||
push %ds
|
||||
push %ss
|
||||
pop %ds
|
||||
sub $8,%sp
|
||||
lea 4(%esp),%si
|
||||
mov $10,%cx
|
||||
xor %dx,%dx
|
||||
div %cx
|
||||
add $'0'|' '<<8,%dx
|
||||
mov %dx,(%si)
|
||||
movb $0,2(%si)
|
||||
1: mov $' ',%dl
|
||||
test %ax,%ax
|
||||
jz 2f
|
||||
xor %dx,%dx
|
||||
div %cx
|
||||
add $'0',%dl
|
||||
2: dec %si
|
||||
mov %dl,(%si)
|
||||
cmp %sp,%si
|
||||
jnz 1b
|
||||
call .puts
|
||||
add $8,%sp
|
||||
pop %ds
|
||||
pop %si
|
||||
pop %dx
|
||||
pop %cx
|
||||
pop %ax
|
||||
ret
|
||||
.endfn .putd
|
||||
|
||||
// Output an 8-bit number in decimal via BIOS.
|
||||
.putdb: push %ax
|
||||
mov %al,%ah
|
||||
cmp $100,%al
|
||||
jnb 3f
|
||||
mov $' ',%al
|
||||
1: call .putc
|
||||
mov %ah,%al
|
||||
aam
|
||||
testb %ah,%ah
|
||||
jz 5f
|
||||
add $'0'|'0'<<8,%ax
|
||||
2: xchg %al,%ah
|
||||
call .putc
|
||||
mov %ah,%al
|
||||
call .putc
|
||||
pop %ax
|
||||
ret
|
||||
3: cmp $200,%al
|
||||
jnb 4f
|
||||
sub $100,%ah
|
||||
mov $'1',%al
|
||||
jmp 1b
|
||||
4: sub $200,%ah
|
||||
mov $'2',%al
|
||||
jmp 1b
|
||||
5: add $'0'|' '<<8,%ax
|
||||
jmp 2b
|
||||
|
||||
// Output a number in hexadecimal via BIOS.
|
||||
.putx: push %ax
|
||||
push %bx
|
||||
push %cx
|
||||
xchg %ax,%bx
|
||||
mov $'0',%al
|
||||
call .putc
|
||||
mov $'x',%al
|
||||
call .putc
|
||||
mov $4,%cx
|
||||
0: rol $4,%bx
|
||||
mov %bl,%al
|
||||
and $0b00001111,%al
|
||||
add $'0',%al
|
||||
cmp $'9',%al
|
||||
jna 1f
|
||||
add $'a'-'9'-1,%al
|
||||
1: call .putc
|
||||
loop 0b
|
||||
pop %cx
|
||||
pop %bx
|
||||
pop %ax
|
||||
.endfn .putx
|
||||
// fall through
|
||||
|
||||
// Output a character via BIOS.
|
||||
.putsp: mov $' ',%al
|
||||
.endfn .putsp
|
||||
// fall through
|
||||
|
||||
.putc: push %ax
|
||||
push %bx
|
||||
mov $7,%bx
|
||||
mov $0x0e,%ah
|
||||
int $0x10
|
||||
pop %bx
|
||||
pop %ax
|
||||
ret
|
||||
.endfn .putc
|
||||
|
||||
.putnl:
|
||||
mov $'\r',%al
|
||||
call .putc
|
||||
mov $'\n',%al
|
||||
jmp .putc
|
||||
.endfn .putnl
|
||||
.previous
|
||||
|
||||
str.no_vesa:
|
||||
.asciz "info: no VESA\r\n"
|
||||
.endobj str.no_vesa
|
||||
str.choose_mode:
|
||||
#define UPGLYPH "\x18"
|
||||
#define DNGLYPH "\x19"
|
||||
#define CRGLYPH "\x1b\xd9"
|
||||
.ascii "\rchoose video mode (",UPGLYPH," ",DNGLYPH," ",CRGLYPH
|
||||
.asciz "): "
|
||||
.endobj str.choose_mode
|
||||
str.no_mode:
|
||||
.asciz "info: no usable video mode\r\n"
|
||||
.endobj str.no_mode
|
||||
str.bad_mode:
|
||||
.asciz "info: mode switch fail\r\n"
|
||||
.endobj str.bad_mode
|
||||
str.mode_list_start:
|
||||
.ascii "info: VESA video modes:\r\n"
|
||||
.ascii " mode# X Y bpp"
|
||||
.ascii " mode# X Y bpp"
|
||||
.asciz " mode# X Y bpp\r\n"
|
||||
.endobj str.mode_list_start
|
||||
|
||||
.type_list:
|
||||
// ┌value to use for mman::pc_video_type
|
||||
// │ ┌bits per pixel
|
||||
// │ │ ┌red field size (in bits)
|
||||
// │ │ │ ┌red field position (bits)
|
||||
// │ │ │ │ ┌green field size
|
||||
// │ │ │ │ │ ┌green field position
|
||||
// │ │ │ │ │ │ ┌blue field size
|
||||
// │ │ │ │ │ │ │ ┌blue field position
|
||||
// │ │ │ │ │ │ │ │
|
||||
.byte PC_VIDEO_BGR565, 16, 5,11, 6, 5, 5, 0
|
||||
.byte PC_VIDEO_BGR555, 15, 5,10, 5, 5, 5, 0
|
||||
.byte PC_VIDEO_BGR555, 16, 5,10, 5, 5, 5, 0
|
||||
.byte PC_VIDEO_RGBX8888,32, 8, 0, 8, 8, 8,16
|
||||
.byte PC_VIDEO_BGRX8888,32, 8,16, 8, 8, 8, 0
|
||||
.type_list_end:
|
|
@ -25,6 +25,7 @@
|
|||
│ OTHER DEALINGS IN THE SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/runtime/mman.internal.h"
|
||||
#include "libc/vga/vga.internal.h"
|
||||
|
||||
// Code snippet for initializing the VGA video mode for bare metal.
|
||||
|
@ -42,6 +43,8 @@
|
|||
// @see sys_writev_vga (libc/vga/writev-vga.c)
|
||||
.section .sort.text.real.init.2,"ax",@progbits
|
||||
.code16
|
||||
call _rlinit_vesa
|
||||
jnc 9f
|
||||
mov $0x4f03,%ax # get current video mode via VESA
|
||||
int $0x10
|
||||
cmp $0x004f,%ax # is VESA a thing here?
|
||||
|
@ -58,6 +61,16 @@
|
|||
mov $0x0500,%ax # just make sure we are on display
|
||||
# page 0
|
||||
2: int $0x10 # otherwise, change the video mode
|
||||
.set mm,0x0500 # note down video mode parameters
|
||||
movb $PC_VIDEO_TEXT,mm+"struct mman::pc_video_type"
|
||||
movw $160,mm+"struct mman::pc_video_stride"
|
||||
movw $80,mm+"struct mman::pc_video_width"
|
||||
movw $25,mm+"struct mman::pc_video_height"
|
||||
movl $0xb8000,mm+"struct mman::pc_video_framebuffer"
|
||||
movl $0x8000,mm+"struct mman::pc_video_framebuffer_size"
|
||||
xor %eax,%eax
|
||||
mov %eax,mm+"struct mman::pc_video_framebuffer"+4
|
||||
mov %eax,mm+"struct mman::pc_video_framebuffer_size"+4
|
||||
mov $0x1003,%ax # enable/disable VGA text blinking
|
||||
#ifdef VGA_USE_BLINK
|
||||
mov $1,%bx
|
||||
|
@ -65,6 +78,7 @@
|
|||
xor %bx,%bx
|
||||
#endif
|
||||
int $0x10
|
||||
9:
|
||||
.previous
|
||||
.code64
|
||||
.section .rodata,"a",@progbits
|
|
@ -240,7 +240,7 @@ static uint8_t TtyGetVgaAttr(struct Tty *tty) {
|
|||
return attr;
|
||||
}
|
||||
|
||||
void _TtyErase(struct Tty *tty, size_t dst, size_t n) {
|
||||
static void TtyErase(struct Tty *tty, size_t dst, size_t n) {
|
||||
uint8_t attr = TtyGetVgaAttr(tty);
|
||||
size_t i;
|
||||
for (i = 0; i < n; ++i)
|
||||
|
@ -248,11 +248,32 @@ void _TtyErase(struct Tty *tty, size_t dst, size_t n) {
|
|||
if (Wcs(tty)) wmemset(Wcs(tty) + dst, L' ', n);
|
||||
}
|
||||
|
||||
void _TtyMemmove(struct Tty *tty, size_t dst, size_t src, size_t n) {
|
||||
void _TtyEraseLineCells(struct Tty *tty, size_t dsty, size_t dstx, size_t n) {
|
||||
size_t xn = Xn(tty);
|
||||
TtyErase(tty, dsty * xn + dstx, n);
|
||||
}
|
||||
|
||||
void _TtyEraseLines(struct Tty *tty, size_t dsty, size_t n) {
|
||||
size_t xn = Xn(tty);
|
||||
TtyErase(tty, dsty * xn, n * xn);
|
||||
}
|
||||
|
||||
static void TtyMemmove(struct Tty *tty, size_t dst, size_t src, size_t n) {
|
||||
memmove(tty->ccs + dst, tty->ccs + src, n * sizeof(struct VgaTextCharCell));
|
||||
if (Wcs(tty)) wmemmove(Wcs(tty) + dst, Wcs(tty) + src, n);
|
||||
}
|
||||
|
||||
void _TtyMoveLineCells(struct Tty *tty, size_t dsty, size_t dstx,
|
||||
size_t srcy, size_t srcx, size_t n) {
|
||||
size_t xn = Xn(tty);
|
||||
TtyMemmove(tty, dsty * xn + dstx, srcy * xn + srcx, n);
|
||||
}
|
||||
|
||||
void _TtyMoveLines(struct Tty *tty, size_t dsty, size_t srcy, size_t n) {
|
||||
size_t xn = Xn(tty);
|
||||
TtyMemmove(tty, dsty * xn, srcy * xn, n * xn);
|
||||
}
|
||||
|
||||
void _TtyResetOutputMode(struct Tty *tty) {
|
||||
tty->pr = 0;
|
||||
tty->fg = DEFAULT_FG;
|
||||
|
@ -272,7 +293,7 @@ void _TtyFullReset(struct Tty *tty) {
|
|||
_TtyResetOutputMode(tty);
|
||||
tty->y = 0;
|
||||
tty->x = 0;
|
||||
_TtyErase(tty, 0, Yn(tty) * Xn(tty));
|
||||
_TtyEraseLines(tty, 0, Yn(tty));
|
||||
}
|
||||
|
||||
void _TtySetY(struct Tty *tty, unsigned short y) {
|
||||
|
@ -286,13 +307,13 @@ void _TtySetX(struct Tty *tty, unsigned short x) {
|
|||
}
|
||||
|
||||
static void TtyScroll(struct Tty *tty) {
|
||||
_TtyMemmove(tty, 0, Xn(tty), Xn(tty) * (Yn(tty) - 1));
|
||||
_TtyErase(tty, Xn(tty) * (Yn(tty) - 1), Xn(tty));
|
||||
_TtyMoveLines(tty, 0, 1, Yn(tty) - 1);
|
||||
_TtyEraseLines(tty, Yn(tty) - 1, 1);
|
||||
}
|
||||
|
||||
static void TtyReverse(struct Tty *tty) {
|
||||
_TtyMemmove(tty, Xn(tty), 0, Xn(tty) * (Yn(tty) - 1));
|
||||
_TtyErase(tty, 0, Xn(tty));
|
||||
_TtyMoveLines(tty, 1, 0, Yn(tty) - 1);
|
||||
_TtyEraseLines(tty, 0, 1);
|
||||
}
|
||||
|
||||
static void TtyIndex(struct Tty *tty) {
|
||||
|
@ -464,15 +485,16 @@ static void TtyRestoreCursorPosition(struct Tty *tty) {
|
|||
static void TtyEraseDisplay(struct Tty *tty) {
|
||||
switch (TtyAtoi(tty->esc.s, NULL)) {
|
||||
case 0:
|
||||
_TtyErase(tty, tty->y * Xn(tty) + tty->x,
|
||||
Yn(tty) * Xn(tty) - (tty->y * Xn(tty) + tty->x));
|
||||
_TtyEraseLineCells(tty, tty->y, tty->x, Xn(tty) - tty->x);
|
||||
_TtyEraseLines(tty, tty->y + 1, Yn(tty) - tty->y - 1);
|
||||
break;
|
||||
case 1:
|
||||
_TtyErase(tty, 0, tty->y * Xn(tty) + tty->x);
|
||||
_TtyEraseLines(tty, 0, tty->y);
|
||||
_TtyEraseLineCells(tty, tty->y, 0, tty->x);
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
_TtyErase(tty, 0, Yn(tty) * Xn(tty));
|
||||
_TtyEraseLines(tty, 0, Yn(tty));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -482,13 +504,13 @@ static void TtyEraseDisplay(struct Tty *tty) {
|
|||
static void TtyEraseLine(struct Tty *tty) {
|
||||
switch (TtyAtoi(tty->esc.s, NULL)) {
|
||||
case 0:
|
||||
_TtyErase(tty, tty->y * Xn(tty) + tty->x, Xn(tty) - tty->x);
|
||||
_TtyEraseLineCells(tty, tty->y, tty->x, Xn(tty) - tty->x);
|
||||
break;
|
||||
case 1:
|
||||
_TtyErase(tty, tty->y * Xn(tty), tty->x);
|
||||
_TtyEraseLineCells(tty, tty->y, 0, tty->x);
|
||||
break;
|
||||
case 2:
|
||||
_TtyErase(tty, tty->y * Xn(tty), Xn(tty));
|
||||
_TtyEraseLines(tty, tty->y, 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -496,11 +518,23 @@ static void TtyEraseLine(struct Tty *tty) {
|
|||
}
|
||||
|
||||
static void TtyEraseCells(struct Tty *tty) {
|
||||
int i, n, x;
|
||||
i = tty->y * Xn(tty) + tty->x;
|
||||
n = Yn(tty) * Xn(tty);
|
||||
x = min(max(TtyAtoi(tty->esc.s, NULL), 1), n - i);
|
||||
_TtyErase(tty, i, x);
|
||||
int yn, xn, yi, xi, n, left;
|
||||
yn = Yn(tty);
|
||||
xn = Xn(tty);
|
||||
yi = tty->y;
|
||||
xi = tty->x;
|
||||
left = min(max(TtyAtoi(tty->esc.s, NULL), 1), yn * xn - (yi * xn + xi));
|
||||
while (left) {
|
||||
if (left >= xn - xi) {
|
||||
_TtyEraseLineCells(tty, yi, xi, xn - xi);
|
||||
left -= xn - xi;
|
||||
++yi;
|
||||
xi = 0;
|
||||
} else {
|
||||
_TtyEraseLineCells(tty, yi, xi, left);
|
||||
left = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int TtyArg1(struct Tty *tty) {
|
||||
|
@ -509,30 +543,28 @@ static int TtyArg1(struct Tty *tty) {
|
|||
|
||||
static void TtyInsertCells(struct Tty *tty) {
|
||||
int n = min(Xn(tty) - tty->x, TtyArg1(tty));
|
||||
_TtyMemmove(tty, tty->y * Xn(tty) + tty->x + n, tty->y * Xn(tty) + tty->x,
|
||||
Xn(tty) - (tty->x + n));
|
||||
_TtyErase(tty, tty->y * Xn(tty) + tty->x, n);
|
||||
_TtyMoveLineCells(tty, tty->y, tty->x + n, tty->y, tty->x,
|
||||
Xn(tty) - (tty->x + n));
|
||||
_TtyEraseLineCells(tty, tty->y, tty->x, n);
|
||||
}
|
||||
|
||||
static void TtyInsertLines(struct Tty *tty) {
|
||||
int n = min(Yn(tty) - tty->y, TtyArg1(tty));
|
||||
_TtyMemmove(tty, (tty->y + n) * Xn(tty), tty->y * Xn(tty),
|
||||
(Yn(tty) - tty->y - n) * Xn(tty));
|
||||
_TtyErase(tty, tty->y * Xn(tty), n * Xn(tty));
|
||||
_TtyMoveLines(tty, tty->y + n, tty->y, Yn(tty) - tty->y - n);
|
||||
_TtyEraseLines(tty, tty->y, n);
|
||||
}
|
||||
|
||||
static void TtyDeleteCells(struct Tty *tty) {
|
||||
int n = min(Xn(tty) - tty->x, TtyArg1(tty));
|
||||
_TtyMemmove(tty, tty->y * Xn(tty) + tty->x, tty->y * Xn(tty) + tty->x + n,
|
||||
Xn(tty) - (tty->x + n));
|
||||
_TtyErase(tty, tty->y * Xn(tty) + tty->x, n);
|
||||
_TtyMoveLineCells(tty, tty->y, tty->x, tty->y, tty->x + n,
|
||||
Xn(tty) - (tty->x + n));
|
||||
_TtyEraseLineCells(tty, tty->y, tty->x, n);
|
||||
}
|
||||
|
||||
static void TtyDeleteLines(struct Tty *tty) {
|
||||
int n = min(Yn(tty) - tty->y, TtyArg1(tty));
|
||||
_TtyMemmove(tty, tty->y * Xn(tty), (tty->y + n) * Xn(tty),
|
||||
(Yn(tty) - tty->y - n) * Xn(tty));
|
||||
_TtyErase(tty, (tty->y + n) * Xn(tty), n * Xn(tty));
|
||||
_TtyMoveLines(tty, tty->y, tty->y + n, Yn(tty) - tty->y - n);
|
||||
_TtyEraseLines(tty, tty->y + n, n);
|
||||
}
|
||||
|
||||
static void TtyReportDeviceStatus(struct Tty *tty) {
|
||||
|
|
|
@ -1,22 +1,21 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_VGA_VGA_INTERNAL_H_
|
||||
#define COSMOPOLITAN_LIBC_VGA_VGA_INTERNAL_H_
|
||||
|
||||
/** Preferred width of the video screen, in character units. */
|
||||
#define VGA_PREFER_TTY_HEIGHT 30
|
||||
/** Preferred width of the video screen, in character units. */
|
||||
#define VGA_PREFER_TTY_WIDTH 80
|
||||
/** Assumed height of each character in pixels, in graphics modes. */
|
||||
#define VGA_ASSUME_CHAR_HEIGHT_PX 16
|
||||
/** Assumed width of each character in pixels, in graphics modes. */
|
||||
#define VGA_ASSUME_CHAR_WIDTH_PX 8
|
||||
|
||||
/*
|
||||
* VGA_TTY_HEIGHT, VGA_TTY_WIDTH, VGA_USE_WCS, & VGA_PERSNICKETY_STATUS are
|
||||
* configuration knobs which can potentially be used to tweak the features
|
||||
* to be compiled into our VGA teletypewriter support.
|
||||
* VGA_USE_WCS, VGA_USE_BLINK, & VGA_PERSNICKETY_STATUS are configuration
|
||||
* knobs which can potentially be used to tweak the features to be compiled
|
||||
* into our VGA teletypewriter support.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Height of the video screen, in character units. Undefine if the height
|
||||
* may vary at runtime.
|
||||
*/
|
||||
#define VGA_TTY_HEIGHT 25
|
||||
/**
|
||||
* Width of the video screen, in character units. Undefine if the width may
|
||||
* vary at runtime.
|
||||
*/
|
||||
#define VGA_TTY_WIDTH 80
|
||||
/**
|
||||
* If VGA_USE_WCS is defined, the tty code can maintain an array of the
|
||||
* Unicode characters "underlying" the 8-bit (or 9-bit) characters that are
|
||||
|
@ -113,13 +112,22 @@ struct VgaTextCharCell {
|
|||
};
|
||||
|
||||
struct Tty {
|
||||
/**
|
||||
* Cursor position. (y, x) = (0, 0) means the cursor is on the top left
|
||||
* character cell of the terminal.
|
||||
*/
|
||||
unsigned short y, x;
|
||||
#ifndef VGA_TTY_HEIGHT
|
||||
unsigned short yn;
|
||||
#endif
|
||||
#ifndef VGA_TTY_WIDTH
|
||||
unsigned short xn;
|
||||
#endif
|
||||
/** Height and width of terminal, in character units. */
|
||||
unsigned short yn, xn;
|
||||
/** Height and width of terminal, in pixels (if in graphics video mode). */
|
||||
unsigned short yp, xp;
|
||||
/**
|
||||
* Number of bytes (NOTE) occupied by each row of pixels, including any
|
||||
* invisible "pixels".
|
||||
*/
|
||||
unsigned short xs;
|
||||
/** Type of video buffer (from mman::pc_video_type). */
|
||||
unsigned char type;
|
||||
uint32_t u8;
|
||||
uint32_t n8;
|
||||
uint32_t pr;
|
||||
|
@ -155,8 +163,10 @@ ssize_t _TtyWrite(struct Tty *, const void *, size_t);
|
|||
ssize_t _TtyWriteInput(struct Tty *, const void *, size_t);
|
||||
void _TtyResetOutputMode(struct Tty *);
|
||||
void _TtyFullReset(struct Tty *);
|
||||
void _TtyMemmove(struct Tty *, size_t, size_t, size_t);
|
||||
void _TtyErase(struct Tty *, size_t, size_t);
|
||||
void _TtyMoveLineCells(struct Tty *, size_t, size_t, size_t, size_t, size_t);
|
||||
void _TtyMoveLines(struct Tty *, size_t, size_t, size_t);
|
||||
void _TtyEraseLineCells(struct Tty *, size_t, size_t, size_t);
|
||||
void _TtyEraseLines(struct Tty *, size_t, size_t);
|
||||
void _TtySetY(struct Tty *, unsigned short);
|
||||
void _TtySetX(struct Tty *, unsigned short);
|
||||
|
||||
|
|
|
@ -32,12 +32,6 @@
|
|||
#include "libc/runtime/pc.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
#ifdef VGA_USE_WCS
|
||||
static wchar_t vga_wcs[VGA_TTY_HEIGHT * VGA_TTY_WIDTH];
|
||||
#else
|
||||
static wchar_t * const vga_wcs = NULL;
|
||||
#endif
|
||||
|
||||
struct Tty _vga_tty;
|
||||
|
||||
ssize_t sys_writev_vga(struct Fd *fd, const struct iovec *iov, int iovlen) {
|
||||
|
@ -58,9 +52,194 @@ ssize_t sys_writev_vga(struct Fd *fd, const struct iovec *iov, int iovlen) {
|
|||
return wrote;
|
||||
}
|
||||
|
||||
static void _vga_init_test(void *vid_buf, unsigned char vid_type,
|
||||
size_t stride) {
|
||||
switch (vid_type) {
|
||||
case PC_VIDEO_TEXT:
|
||||
break;
|
||||
case PC_VIDEO_BGR565:
|
||||
{
|
||||
char *row_buf = (char *)vid_buf + stride * 100;
|
||||
uint16_t *row_pix = (uint16_t *)row_buf;
|
||||
unsigned i;
|
||||
row_pix[0] = 0x0000;
|
||||
row_pix[1] = 0x0000;
|
||||
row_pix[2] = 0x07fc;
|
||||
row_pix[3] = 0x07fc;
|
||||
row_pix[4] = 0x07fc;
|
||||
row_pix[5] = 0x0000;
|
||||
row_pix[6] = 0x0000;
|
||||
row_pix[7] = 0x0000;
|
||||
row_buf += stride;
|
||||
row_pix = (uint16_t *)row_buf;
|
||||
row_pix[0] = 0x0000;
|
||||
row_pix[1] = 0x07fc;
|
||||
row_pix[2] = 0x07fc;
|
||||
row_pix[3] = 0x07fc;
|
||||
row_pix[4] = 0x07fc;
|
||||
row_pix[5] = 0x07fc;
|
||||
row_pix[6] = 0x0000;
|
||||
row_pix[7] = 0x0000;
|
||||
row_buf += stride;
|
||||
row_pix = (uint16_t *)row_buf;
|
||||
row_pix[0] = 0x07fc;
|
||||
row_pix[1] = 0x07fc;
|
||||
row_pix[2] = 0x0000;
|
||||
row_pix[3] = 0x0000;
|
||||
row_pix[4] = 0x0000;
|
||||
row_pix[5] = 0x07fc;
|
||||
row_pix[6] = 0x07fc;
|
||||
row_pix[7] = 0x0000;
|
||||
row_buf += stride;
|
||||
row_pix = (uint16_t *)row_buf;
|
||||
row_pix[0] = 0x07fc;
|
||||
row_pix[1] = 0x07fc;
|
||||
row_pix[2] = 0x07fc;
|
||||
row_pix[3] = 0x07fc;
|
||||
row_pix[4] = 0x07fc;
|
||||
row_pix[5] = 0x07fc;
|
||||
row_pix[6] = 0x07fc;
|
||||
row_pix[7] = 0x0000;
|
||||
for (i = 0; i < 4; ++i) {
|
||||
row_buf += stride;
|
||||
row_pix = (uint16_t *)row_buf;
|
||||
row_pix[0] = 0xf81f;
|
||||
row_pix[1] = 0xf81f;
|
||||
row_pix[2] = 0x0000;
|
||||
row_pix[3] = 0x0000;
|
||||
row_pix[4] = 0x0000;
|
||||
row_pix[5] = 0xf81f;
|
||||
row_pix[6] = 0xf81f;
|
||||
row_pix[7] = 0x0000;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PC_VIDEO_BGR555:
|
||||
{
|
||||
char *row_buf = (char *)vid_buf + stride * 100;
|
||||
uint16_t *row_pix = (uint16_t *)row_buf;
|
||||
unsigned i;
|
||||
row_pix[0] = 0x8000;
|
||||
row_pix[1] = 0x8000;
|
||||
row_pix[2] = 0x83fc;
|
||||
row_pix[3] = 0x83fc;
|
||||
row_pix[4] = 0x83fc;
|
||||
row_pix[5] = 0x8000;
|
||||
row_pix[6] = 0x8000;
|
||||
row_pix[7] = 0x8000;
|
||||
row_buf += stride;
|
||||
row_pix = (uint16_t *)row_buf;
|
||||
row_pix[0] = 0x8000;
|
||||
row_pix[1] = 0x83fc;
|
||||
row_pix[2] = 0x83fc;
|
||||
row_pix[3] = 0x83fc;
|
||||
row_pix[4] = 0x83fc;
|
||||
row_pix[5] = 0x83fc;
|
||||
row_pix[6] = 0x8000;
|
||||
row_pix[7] = 0x8000;
|
||||
row_buf += stride;
|
||||
row_pix = (uint16_t *)row_buf;
|
||||
row_pix[0] = 0x83fc;
|
||||
row_pix[1] = 0x83fc;
|
||||
row_pix[2] = 0x8000;
|
||||
row_pix[3] = 0x8000;
|
||||
row_pix[4] = 0x8000;
|
||||
row_pix[5] = 0x83fc;
|
||||
row_pix[6] = 0x83fc;
|
||||
row_pix[7] = 0x8000;
|
||||
row_buf += stride;
|
||||
row_pix = (uint16_t *)row_buf;
|
||||
row_pix[0] = 0x83fc;
|
||||
row_pix[1] = 0x83fc;
|
||||
row_pix[2] = 0x83fc;
|
||||
row_pix[3] = 0x83fc;
|
||||
row_pix[4] = 0x83fc;
|
||||
row_pix[5] = 0x83fc;
|
||||
row_pix[6] = 0x83fc;
|
||||
row_pix[7] = 0x8000;
|
||||
for (i = 0; i < 4; ++i) {
|
||||
row_buf += stride;
|
||||
row_pix = (uint16_t *)row_buf;
|
||||
row_pix[0] = 0xfc1f;
|
||||
row_pix[1] = 0xfc1f;
|
||||
row_pix[2] = 0x8000;
|
||||
row_pix[3] = 0x8000;
|
||||
row_pix[4] = 0x8000;
|
||||
row_pix[5] = 0xfc1f;
|
||||
row_pix[6] = 0xfc1f;
|
||||
row_pix[7] = 0x8000;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
char *row_buf = (char *)vid_buf + stride * 100;
|
||||
uint32_t *row_pix = (uint32_t *)row_buf;
|
||||
unsigned i;
|
||||
row_pix[0] = 0xff000000;
|
||||
row_pix[1] = 0xff000000;
|
||||
row_pix[2] = 0xff00ffe0;
|
||||
row_pix[3] = 0xff00ffe0;
|
||||
row_pix[4] = 0xff00ffe0;
|
||||
row_pix[5] = 0xff000000;
|
||||
row_pix[6] = 0xff000000;
|
||||
row_pix[7] = 0xff000000;
|
||||
row_buf += stride;
|
||||
row_pix = (uint32_t *)row_buf;
|
||||
row_pix[0] = 0xff000000;
|
||||
row_pix[1] = 0xff00ffe0;
|
||||
row_pix[2] = 0xff00ffe0;
|
||||
row_pix[3] = 0xff00ffe0;
|
||||
row_pix[4] = 0xff00ffe0;
|
||||
row_pix[5] = 0xff00ffe0;
|
||||
row_pix[6] = 0xff000000;
|
||||
row_pix[7] = 0xff000000;
|
||||
row_buf += stride;
|
||||
row_pix = (uint32_t *)row_buf;
|
||||
row_pix[0] = 0xff00ffe0;
|
||||
row_pix[1] = 0xff00ffe0;
|
||||
row_pix[2] = 0xff000000;
|
||||
row_pix[3] = 0xff000000;
|
||||
row_pix[4] = 0xff000000;
|
||||
row_pix[5] = 0xff00ffe0;
|
||||
row_pix[6] = 0xff00ffe0;
|
||||
row_pix[7] = 0xff000000;
|
||||
row_buf += stride;
|
||||
row_pix = (uint32_t *)row_buf;
|
||||
row_pix[0] = 0xff00ffe0;
|
||||
row_pix[1] = 0xff00ffe0;
|
||||
row_pix[2] = 0xff00ffe0;
|
||||
row_pix[3] = 0xff00ffe0;
|
||||
row_pix[4] = 0xff00ffe0;
|
||||
row_pix[5] = 0xff00ffe0;
|
||||
row_pix[6] = 0xff00ffe0;
|
||||
row_pix[7] = 0xff000000;
|
||||
for (i = 0; i < 4; ++i) {
|
||||
row_buf += stride;
|
||||
row_pix = (uint32_t *)row_buf;
|
||||
row_pix[0] = 0xffff00ff;
|
||||
row_pix[1] = 0xffff00ff;
|
||||
row_pix[2] = 0xff000000;
|
||||
row_pix[3] = 0xff000000;
|
||||
row_pix[4] = 0xff000000;
|
||||
row_pix[5] = 0xffff00ff;
|
||||
row_pix[6] = 0xffff00ff;
|
||||
row_pix[7] = 0xff000000;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__((__constructor__)) static textstartup void _vga_init(void) {
|
||||
if (IsMetal()) {
|
||||
void * const vid_buf = (void *)(BANE + 0xb8000ull);
|
||||
struct mman *mm = (struct mman *)(BANE + 0x0500);
|
||||
unsigned char vid_type = mm->pc_video_type;
|
||||
unsigned short height = mm->pc_video_height, width = mm->pc_video_width,
|
||||
stride = mm->pc_video_stride;
|
||||
uint64_t vid_buf_phy = mm->pc_video_framebuffer;
|
||||
void *vid_buf = (void *)(BANE + vid_buf_phy);
|
||||
size_t vid_buf_sz = mm->pc_video_framebuffer_size;
|
||||
/*
|
||||
* Get the initial cursor position from the BIOS data area. Also get
|
||||
* the height (in scan lines) of each character; this is used to set the
|
||||
|
@ -74,11 +253,17 @@ __attribute__((__constructor__)) static textstartup void _vga_init(void) {
|
|||
chr_ht_hi = *(uint8_t *)(BANE + 0x0486ull);
|
||||
if (chr_ht_hi != 0 || chr_ht > 32)
|
||||
chr_ht = 32;
|
||||
/* Make sure the video buffer is mapped into virtual memory. */
|
||||
__invert_memory_area(mm, __get_pml4t(), vid_buf_phy, vid_buf_sz, PAGE_RW);
|
||||
#if 1
|
||||
/* Test video frame buffer output. */
|
||||
_vga_init_test(vid_buf, vid_type, stride);
|
||||
#endif
|
||||
/*
|
||||
* Initialize our tty structure from the current screen contents,
|
||||
* current cursor position, & character height.
|
||||
* Initialize our tty structure from the current screen geometry,
|
||||
* screen contents, cursor position, & character height.
|
||||
*/
|
||||
_StartTty(&_vga_tty, VGA_TTY_HEIGHT, VGA_TTY_WIDTH, pos.row, pos.col,
|
||||
chr_ht, vid_buf, vga_wcs);
|
||||
_StartTty(&_vga_tty, height, width, pos.row, pos.col, chr_ht,
|
||||
vid_buf, NULL);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue