mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-08-09 03:10:27 +00:00
[metal] Let user choose video mode after pressing Shift on boot
This commit is contained in:
parent
596f7d1ed4
commit
e6e56a74e4
1 changed files with 129 additions and 43 deletions
|
@ -89,48 +89,18 @@ _rlinit_vesa:
|
||||||
.do_vesa_rlinit:
|
.do_vesa_rlinit:
|
||||||
push %eax
|
push %eax
|
||||||
push %bx
|
push %bx
|
||||||
push %cx
|
|
||||||
push %edx
|
push %edx
|
||||||
push %esi
|
|
||||||
push %bp
|
push %bp
|
||||||
push %es
|
|
||||||
sub $2+MAX_VESA_MODES_TO_TRACK*"mi::sizeof",%sp
|
sub $2+MAX_VESA_MODES_TO_TRACK*"mi::sizeof",%sp
|
||||||
mov %sp,%bp
|
mov %sp,%bp
|
||||||
call .gather_vesa_modes # gather list of VESA modes
|
call .gather_vesa_modes # gather list of VESA modes
|
||||||
jc 8f
|
jc 8f
|
||||||
mov (%bp),%cx # loop through VESA modes & find one
|
call .get_default_mode # choose a default mode to use
|
||||||
test %cx,%cx # which we like
|
jc 6f
|
||||||
jz 6f
|
call .choose_mode # allow user to select different mode
|
||||||
inc %bp
|
movw %bx,%bp
|
||||||
inc %bp
|
|
||||||
or $-1,%esi # %esi = best fit screen size
|
|
||||||
xor %bx,%bx # %bx = pointer to best info. struct.
|
|
||||||
# (start with NULL)
|
|
||||||
1: cmpb $PC_VIDEO_BGR565,"mi::type"(%bp)
|
|
||||||
jnz 2f
|
|
||||||
movzwl "mi::width"(%bp),%eax
|
|
||||||
cmp $VGA_PREFER_GRAPH_WIDTH,%ax
|
|
||||||
jb 2f
|
|
||||||
movzwl "mi::height"(%bp),%edx
|
|
||||||
cmp $VGA_PREFER_GRAPH_HEIGHT,%dx
|
|
||||||
jb 2f
|
|
||||||
imul %edx,%eax
|
|
||||||
cmp %esi,%eax
|
|
||||||
jnb 2f
|
|
||||||
mov %eax,%esi
|
|
||||||
mov %bp,%bx
|
|
||||||
2: add $"mi::sizeof",%bp
|
|
||||||
loop 1b
|
|
||||||
3: test %bx,%bx # if no good video mode found,
|
|
||||||
jz 6f # bail out
|
|
||||||
movw %bx,%bp # otherwise...
|
|
||||||
mov $REAL(str.use_mode),%si
|
|
||||||
call .puts
|
|
||||||
mov "mi::mode_num"(%bp),%ax
|
|
||||||
mov %ax,%bx
|
|
||||||
call .putx
|
|
||||||
call .putnl
|
|
||||||
call .snooze
|
call .snooze
|
||||||
|
mov "mi::mode_num"(%bp),%bx
|
||||||
mov $0x4f02,%ax
|
mov $0x4f02,%ax
|
||||||
int $0x10
|
int $0x10
|
||||||
cmp $0x004f,%ax
|
cmp $0x004f,%ax
|
||||||
|
@ -155,11 +125,8 @@ _rlinit_vesa:
|
||||||
5: lahf
|
5: lahf
|
||||||
add $2+MAX_VESA_MODES_TO_TRACK*"mi::sizeof",%sp
|
add $2+MAX_VESA_MODES_TO_TRACK*"mi::sizeof",%sp
|
||||||
sahf
|
sahf
|
||||||
pop %es
|
|
||||||
pop %bp
|
pop %bp
|
||||||
pop %esi
|
|
||||||
pop %edx
|
pop %edx
|
||||||
pop %cx
|
|
||||||
pop %bx
|
pop %bx
|
||||||
pop %eax
|
pop %eax
|
||||||
ret
|
ret
|
||||||
|
@ -170,6 +137,116 @@ _rlinit_vesa:
|
||||||
jmp 5b
|
jmp 5b
|
||||||
9: mov $REAL(str.bad_mode),%si
|
9: mov $REAL(str.bad_mode),%si
|
||||||
jmp 7b
|
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:
|
.snooze:
|
||||||
push %ax
|
push %ax
|
||||||
|
@ -311,8 +388,10 @@ _rlinit_vesa:
|
||||||
call .putdb
|
call .putdb
|
||||||
mov %es:0x10(%di),%ax # - mode stride
|
mov %es:0x10(%di),%ax # - mode stride
|
||||||
mov %ax,%ss:("mi::stride")(%bx)
|
mov %ax,%ss:("mi::stride")(%bx)
|
||||||
mov %es:0x28(%di),%eax # - frame buffer address
|
testb $0b00010000,%cl
|
||||||
mov %eax,%ss:("mi::fb")(%bx)
|
jz .txt
|
||||||
|
mov %es:0x28(%di),%eax
|
||||||
|
.fb: mov %eax,%ss:("mi::fb")(%bx) # - frame buffer address
|
||||||
clc
|
clc
|
||||||
.done3: lea 0x100(%esp),%sp
|
.done3: lea 0x100(%esp),%sp
|
||||||
pop %di
|
pop %di
|
||||||
|
@ -323,6 +402,9 @@ _rlinit_vesa:
|
||||||
ret
|
ret
|
||||||
.fail3: stc
|
.fail3: stc
|
||||||
jmp .done3
|
jmp .done3
|
||||||
|
.txt: movzwl %es:8(%di),%eax # for text mode, use window A as
|
||||||
|
shl $4,%eax # frame buffer
|
||||||
|
jmp .fb
|
||||||
.endfn .munge
|
.endfn .munge
|
||||||
|
|
||||||
// Check if the given video mode information uses a video buffer type
|
// Check if the given video mode information uses a video buffer type
|
||||||
|
@ -491,12 +573,16 @@ _rlinit_vesa:
|
||||||
str.no_vesa:
|
str.no_vesa:
|
||||||
.asciz "info: no VESA\r\n"
|
.asciz "info: no VESA\r\n"
|
||||||
.endobj str.no_vesa
|
.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:
|
str.no_mode:
|
||||||
.asciz "info: no usable video mode\r\n"
|
.asciz "info: no usable video mode\r\n"
|
||||||
.endobj str.no_mode
|
.endobj str.no_mode
|
||||||
str.use_mode:
|
|
||||||
.asciz "info: switching to video mode "
|
|
||||||
.endobj str.use_mode
|
|
||||||
str.bad_mode:
|
str.bad_mode:
|
||||||
.asciz "info: mode switch fail\r\n"
|
.asciz "info: mode switch fail\r\n"
|
||||||
.endobj str.bad_mode
|
.endobj str.bad_mode
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue