diff options
Diffstat (limited to 'arch/x86_64/boot')
-rw-r--r-- | arch/x86_64/boot/Makefile | 2 | ||||
-rw-r--r-- | arch/x86_64/boot/compressed/Makefile | 12 | ||||
-rw-r--r-- | arch/x86_64/boot/compressed/head.S | 339 | ||||
-rw-r--r-- | arch/x86_64/boot/compressed/misc.c | 247 | ||||
-rw-r--r-- | arch/x86_64/boot/compressed/vmlinux.lds | 44 | ||||
-rw-r--r-- | arch/x86_64/boot/compressed/vmlinux.scr | 9 | ||||
-rw-r--r-- | arch/x86_64/boot/setup.S | 85 | ||||
-rw-r--r-- | arch/x86_64/boot/video.S | 2043 |
8 files changed, 459 insertions, 2322 deletions
diff --git a/arch/x86_64/boot/Makefile b/arch/x86_64/boot/Makefile index deb063e7762d..ee6f6505f95f 100644 --- a/arch/x86_64/boot/Makefile +++ b/arch/x86_64/boot/Makefile | |||
@@ -36,7 +36,7 @@ subdir- := compressed/ #Let make clean descend in compressed/ | |||
36 | # --------------------------------------------------------------------------- | 36 | # --------------------------------------------------------------------------- |
37 | 37 | ||
38 | $(obj)/bzImage: IMAGE_OFFSET := 0x100000 | 38 | $(obj)/bzImage: IMAGE_OFFSET := 0x100000 |
39 | $(obj)/bzImage: EXTRA_AFLAGS := -traditional $(SVGA_MODE) $(RAMDISK) -D__BIG_KERNEL__ | 39 | $(obj)/bzImage: EXTRA_AFLAGS := $(SVGA_MODE) $(RAMDISK) -D__BIG_KERNEL__ |
40 | $(obj)/bzImage: BUILDFLAGS := -b | 40 | $(obj)/bzImage: BUILDFLAGS := -b |
41 | 41 | ||
42 | quiet_cmd_image = BUILD $@ | 42 | quiet_cmd_image = BUILD $@ |
diff --git a/arch/x86_64/boot/compressed/Makefile b/arch/x86_64/boot/compressed/Makefile index e70fa6e1da08..705a3e33d7e1 100644 --- a/arch/x86_64/boot/compressed/Makefile +++ b/arch/x86_64/boot/compressed/Makefile | |||
@@ -8,16 +8,14 @@ | |||
8 | 8 | ||
9 | targets := vmlinux vmlinux.bin vmlinux.bin.gz head.o misc.o piggy.o | 9 | targets := vmlinux vmlinux.bin vmlinux.bin.gz head.o misc.o piggy.o |
10 | EXTRA_AFLAGS := -traditional | 10 | EXTRA_AFLAGS := -traditional |
11 | AFLAGS := $(subst -m64,-m32,$(AFLAGS)) | ||
12 | 11 | ||
13 | # cannot use EXTRA_CFLAGS because base CFLAGS contains -mkernel which conflicts with | 12 | # cannot use EXTRA_CFLAGS because base CFLAGS contains -mkernel which conflicts with |
14 | # -m32 | 13 | # -m32 |
15 | CFLAGS := -m32 -D__KERNEL__ -Iinclude -O2 -fno-strict-aliasing | 14 | CFLAGS := -m64 -D__KERNEL__ -Iinclude -O2 -fno-strict-aliasing -fPIC -mcmodel=small -fno-builtin |
16 | LDFLAGS := -m elf_i386 | 15 | LDFLAGS := -m elf_x86_64 |
17 | 16 | ||
18 | LDFLAGS_vmlinux := -Ttext $(IMAGE_OFFSET) -e startup_32 -m elf_i386 | 17 | LDFLAGS_vmlinux := -T |
19 | 18 | $(obj)/vmlinux: $(src)/vmlinux.lds $(obj)/head.o $(obj)/misc.o $(obj)/piggy.o FORCE | |
20 | $(obj)/vmlinux: $(obj)/head.o $(obj)/misc.o $(obj)/piggy.o FORCE | ||
21 | $(call if_changed,ld) | 19 | $(call if_changed,ld) |
22 | @: | 20 | @: |
23 | 21 | ||
@@ -27,7 +25,7 @@ $(obj)/vmlinux.bin: vmlinux FORCE | |||
27 | $(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE | 25 | $(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE |
28 | $(call if_changed,gzip) | 26 | $(call if_changed,gzip) |
29 | 27 | ||
30 | LDFLAGS_piggy.o := -r --format binary --oformat elf32-i386 -T | 28 | LDFLAGS_piggy.o := -r --format binary --oformat elf64-x86-64 -T |
31 | 29 | ||
32 | $(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.gz FORCE | 30 | $(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.gz FORCE |
33 | $(call if_changed,ld) | 31 | $(call if_changed,ld) |
diff --git a/arch/x86_64/boot/compressed/head.S b/arch/x86_64/boot/compressed/head.S index 6f55565e4d42..f9d5692a0106 100644 --- a/arch/x86_64/boot/compressed/head.S +++ b/arch/x86_64/boot/compressed/head.S | |||
@@ -26,116 +26,279 @@ | |||
26 | 26 | ||
27 | #include <linux/linkage.h> | 27 | #include <linux/linkage.h> |
28 | #include <asm/segment.h> | 28 | #include <asm/segment.h> |
29 | #include <asm/pgtable.h> | ||
29 | #include <asm/page.h> | 30 | #include <asm/page.h> |
31 | #include <asm/msr.h> | ||
30 | 32 | ||
33 | .section ".text.head" | ||
31 | .code32 | 34 | .code32 |
32 | .globl startup_32 | 35 | .globl startup_32 |
33 | 36 | ||
34 | startup_32: | 37 | startup_32: |
35 | cld | 38 | cld |
36 | cli | 39 | cli |
37 | movl $(__KERNEL_DS),%eax | 40 | movl $(__KERNEL_DS), %eax |
38 | movl %eax,%ds | 41 | movl %eax, %ds |
39 | movl %eax,%es | 42 | movl %eax, %es |
40 | movl %eax,%fs | 43 | movl %eax, %ss |
41 | movl %eax,%gs | 44 | |
42 | 45 | /* Calculate the delta between where we were compiled to run | |
43 | lss stack_start,%esp | 46 | * at and where we were actually loaded at. This can only be done |
44 | xorl %eax,%eax | 47 | * with a short local call on x86. Nothing else will tell us what |
45 | 1: incl %eax # check that A20 really IS enabled | 48 | * address we are running at. The reserved chunk of the real-mode |
46 | movl %eax,0x000000 # loop forever if it isn't | 49 | * data at 0x34-0x3f are used as the stack for this calculation. |
47 | cmpl %eax,0x100000 | 50 | * Only 4 bytes are needed. |
48 | je 1b | 51 | */ |
52 | leal 0x40(%esi), %esp | ||
53 | call 1f | ||
54 | 1: popl %ebp | ||
55 | subl $1b, %ebp | ||
56 | |||
57 | /* setup a stack and make sure cpu supports long mode. */ | ||
58 | movl $user_stack_end, %eax | ||
59 | addl %ebp, %eax | ||
60 | movl %eax, %esp | ||
61 | |||
62 | call verify_cpu | ||
63 | testl %eax, %eax | ||
64 | jnz no_longmode | ||
65 | |||
66 | /* Compute the delta between where we were compiled to run at | ||
67 | * and where the code will actually run at. | ||
68 | */ | ||
69 | /* %ebp contains the address we are loaded at by the boot loader and %ebx | ||
70 | * contains the address where we should move the kernel image temporarily | ||
71 | * for safe in-place decompression. | ||
72 | */ | ||
73 | |||
74 | #ifdef CONFIG_RELOCATABLE | ||
75 | movl %ebp, %ebx | ||
76 | addl $(LARGE_PAGE_SIZE -1), %ebx | ||
77 | andl $LARGE_PAGE_MASK, %ebx | ||
78 | #else | ||
79 | movl $CONFIG_PHYSICAL_START, %ebx | ||
80 | #endif | ||
81 | |||
82 | /* Replace the compressed data size with the uncompressed size */ | ||
83 | subl input_len(%ebp), %ebx | ||
84 | movl output_len(%ebp), %eax | ||
85 | addl %eax, %ebx | ||
86 | /* Add 8 bytes for every 32K input block */ | ||
87 | shrl $12, %eax | ||
88 | addl %eax, %ebx | ||
89 | /* Add 32K + 18 bytes of extra slack and align on a 4K boundary */ | ||
90 | addl $(32768 + 18 + 4095), %ebx | ||
91 | andl $~4095, %ebx | ||
49 | 92 | ||
50 | /* | 93 | /* |
51 | * Initialize eflags. Some BIOS's leave bits like NT set. This would | 94 | * Prepare for entering 64 bit mode |
52 | * confuse the debugger if this code is traced. | ||
53 | * XXX - best to initialize before switching to protected mode. | ||
54 | */ | 95 | */ |
55 | pushl $0 | 96 | |
56 | popfl | 97 | /* Load new GDT with the 64bit segments using 32bit descriptor */ |
98 | leal gdt(%ebp), %eax | ||
99 | movl %eax, gdt+2(%ebp) | ||
100 | lgdt gdt(%ebp) | ||
101 | |||
102 | /* Enable PAE mode */ | ||
103 | xorl %eax, %eax | ||
104 | orl $(1 << 5), %eax | ||
105 | movl %eax, %cr4 | ||
106 | |||
107 | /* | ||
108 | * Build early 4G boot pagetable | ||
109 | */ | ||
110 | /* Initialize Page tables to 0*/ | ||
111 | leal pgtable(%ebx), %edi | ||
112 | xorl %eax, %eax | ||
113 | movl $((4096*6)/4), %ecx | ||
114 | rep stosl | ||
115 | |||
116 | /* Build Level 4 */ | ||
117 | leal pgtable + 0(%ebx), %edi | ||
118 | leal 0x1007 (%edi), %eax | ||
119 | movl %eax, 0(%edi) | ||
120 | |||
121 | /* Build Level 3 */ | ||
122 | leal pgtable + 0x1000(%ebx), %edi | ||
123 | leal 0x1007(%edi), %eax | ||
124 | movl $4, %ecx | ||
125 | 1: movl %eax, 0x00(%edi) | ||
126 | addl $0x00001000, %eax | ||
127 | addl $8, %edi | ||
128 | decl %ecx | ||
129 | jnz 1b | ||
130 | |||
131 | /* Build Level 2 */ | ||
132 | leal pgtable + 0x2000(%ebx), %edi | ||
133 | movl $0x00000183, %eax | ||
134 | movl $2048, %ecx | ||
135 | 1: movl %eax, 0(%edi) | ||
136 | addl $0x00200000, %eax | ||
137 | addl $8, %edi | ||
138 | decl %ecx | ||
139 | jnz 1b | ||
140 | |||
141 | /* Enable the boot page tables */ | ||
142 | leal pgtable(%ebx), %eax | ||
143 | movl %eax, %cr3 | ||
144 | |||
145 | /* Enable Long mode in EFER (Extended Feature Enable Register) */ | ||
146 | movl $MSR_EFER, %ecx | ||
147 | rdmsr | ||
148 | btsl $_EFER_LME, %eax | ||
149 | wrmsr | ||
150 | |||
151 | /* Setup for the jump to 64bit mode | ||
152 | * | ||
153 | * When the jump is performend we will be in long mode but | ||
154 | * in 32bit compatibility mode with EFER.LME = 1, CS.L = 0, CS.D = 1 | ||
155 | * (and in turn EFER.LMA = 1). To jump into 64bit mode we use | ||
156 | * the new gdt/idt that has __KERNEL_CS with CS.L = 1. | ||
157 | * We place all of the values on our mini stack so lret can | ||
158 | * used to perform that far jump. | ||
159 | */ | ||
160 | pushl $__KERNEL_CS | ||
161 | leal startup_64(%ebp), %eax | ||
162 | pushl %eax | ||
163 | |||
164 | /* Enter paged protected Mode, activating Long Mode */ | ||
165 | movl $0x80000001, %eax /* Enable Paging and Protected mode */ | ||
166 | movl %eax, %cr0 | ||
167 | |||
168 | /* Jump from 32bit compatibility mode into 64bit mode. */ | ||
169 | lret | ||
170 | |||
171 | no_longmode: | ||
172 | /* This isn't an x86-64 CPU so hang */ | ||
173 | 1: | ||
174 | hlt | ||
175 | jmp 1b | ||
176 | |||
177 | #include "../../kernel/verify_cpu.S" | ||
178 | |||
179 | /* Be careful here startup_64 needs to be at a predictable | ||
180 | * address so I can export it in an ELF header. Bootloaders | ||
181 | * should look at the ELF header to find this address, as | ||
182 | * it may change in the future. | ||
183 | */ | ||
184 | .code64 | ||
185 | .org 0x200 | ||
186 | ENTRY(startup_64) | ||
187 | /* We come here either from startup_32 or directly from a | ||
188 | * 64bit bootloader. If we come here from a bootloader we depend on | ||
189 | * an identity mapped page table being provied that maps our | ||
190 | * entire text+data+bss and hopefully all of memory. | ||
191 | */ | ||
192 | |||
193 | /* Setup data segments. */ | ||
194 | xorl %eax, %eax | ||
195 | movl %eax, %ds | ||
196 | movl %eax, %es | ||
197 | movl %eax, %ss | ||
198 | |||
199 | /* Compute the decompressed kernel start address. It is where | ||
200 | * we were loaded at aligned to a 2M boundary. %rbp contains the | ||
201 | * decompressed kernel start address. | ||
202 | * | ||
203 | * If it is a relocatable kernel then decompress and run the kernel | ||
204 | * from load address aligned to 2MB addr, otherwise decompress and | ||
205 | * run the kernel from CONFIG_PHYSICAL_START | ||
206 | */ | ||
207 | |||
208 | /* Start with the delta to where the kernel will run at. */ | ||
209 | #ifdef CONFIG_RELOCATABLE | ||
210 | leaq startup_32(%rip) /* - $startup_32 */, %rbp | ||
211 | addq $(LARGE_PAGE_SIZE - 1), %rbp | ||
212 | andq $LARGE_PAGE_MASK, %rbp | ||
213 | movq %rbp, %rbx | ||
214 | #else | ||
215 | movq $CONFIG_PHYSICAL_START, %rbp | ||
216 | movq %rbp, %rbx | ||
217 | #endif | ||
218 | |||
219 | /* Replace the compressed data size with the uncompressed size */ | ||
220 | movl input_len(%rip), %eax | ||
221 | subq %rax, %rbx | ||
222 | movl output_len(%rip), %eax | ||
223 | addq %rax, %rbx | ||
224 | /* Add 8 bytes for every 32K input block */ | ||
225 | shrq $12, %rax | ||
226 | addq %rax, %rbx | ||
227 | /* Add 32K + 18 bytes of extra slack and align on a 4K boundary */ | ||
228 | addq $(32768 + 18 + 4095), %rbx | ||
229 | andq $~4095, %rbx | ||
230 | |||
231 | /* Copy the compressed kernel to the end of our buffer | ||
232 | * where decompression in place becomes safe. | ||
233 | */ | ||
234 | leaq _end(%rip), %r8 | ||
235 | leaq _end(%rbx), %r9 | ||
236 | movq $_end /* - $startup_32 */, %rcx | ||
237 | 1: subq $8, %r8 | ||
238 | subq $8, %r9 | ||
239 | movq 0(%r8), %rax | ||
240 | movq %rax, 0(%r9) | ||
241 | subq $8, %rcx | ||
242 | jnz 1b | ||
243 | |||
244 | /* | ||
245 | * Jump to the relocated address. | ||
246 | */ | ||
247 | leaq relocated(%rbx), %rax | ||
248 | jmp *%rax | ||
249 | |||
250 | .section ".text" | ||
251 | relocated: | ||
252 | |||
57 | /* | 253 | /* |
58 | * Clear BSS | 254 | * Clear BSS |
59 | */ | 255 | */ |
60 | xorl %eax,%eax | 256 | xorq %rax, %rax |
61 | movl $_edata,%edi | 257 | leaq _edata(%rbx), %rdi |
62 | movl $_end,%ecx | 258 | leaq _end(%rbx), %rcx |
63 | subl %edi,%ecx | 259 | subq %rdi, %rcx |
64 | cld | 260 | cld |
65 | rep | 261 | rep |
66 | stosb | 262 | stosb |
263 | |||
264 | /* Setup the stack */ | ||
265 | leaq user_stack_end(%rip), %rsp | ||
266 | |||
267 | /* zero EFLAGS after setting rsp */ | ||
268 | pushq $0 | ||
269 | popfq | ||
270 | |||
67 | /* | 271 | /* |
68 | * Do the decompression, and jump to the new kernel.. | 272 | * Do the decompression, and jump to the new kernel.. |
69 | */ | 273 | */ |
70 | subl $16,%esp # place for structure on the stack | 274 | pushq %rsi # Save the real mode argument |
71 | movl %esp,%eax | 275 | movq %rsi, %rdi # real mode address |
72 | pushl %esi # real mode pointer as second arg | 276 | leaq _heap(%rip), %rsi # _heap |
73 | pushl %eax # address of structure as first arg | 277 | leaq input_data(%rip), %rdx # input_data |
74 | call decompress_kernel | 278 | movl input_len(%rip), %eax |
75 | orl %eax,%eax | 279 | movq %rax, %rcx # input_len |
76 | jnz 3f | 280 | movq %rbp, %r8 # output |
77 | addl $8,%esp | 281 | call decompress_kernel |
78 | xorl %ebx,%ebx | 282 | popq %rsi |
79 | ljmp $(__KERNEL_CS), $__PHYSICAL_START | ||
80 | 283 | ||
81 | /* | ||
82 | * We come here, if we were loaded high. | ||
83 | * We need to move the move-in-place routine down to 0x1000 | ||
84 | * and then start it with the buffer addresses in registers, | ||
85 | * which we got from the stack. | ||
86 | */ | ||
87 | 3: | ||
88 | movl %esi,%ebx | ||
89 | movl $move_routine_start,%esi | ||
90 | movl $0x1000,%edi | ||
91 | movl $move_routine_end,%ecx | ||
92 | subl %esi,%ecx | ||
93 | addl $3,%ecx | ||
94 | shrl $2,%ecx | ||
95 | cld | ||
96 | rep | ||
97 | movsl | ||
98 | |||
99 | popl %esi # discard the address | ||
100 | addl $4,%esp # real mode pointer | ||
101 | popl %esi # low_buffer_start | ||
102 | popl %ecx # lcount | ||
103 | popl %edx # high_buffer_start | ||
104 | popl %eax # hcount | ||
105 | movl $__PHYSICAL_START,%edi | ||
106 | cli # make sure we don't get interrupted | ||
107 | ljmp $(__KERNEL_CS), $0x1000 # and jump to the move routine | ||
108 | 284 | ||
109 | /* | 285 | /* |
110 | * Routine (template) for moving the decompressed kernel in place, | 286 | * Jump to the decompressed kernel. |
111 | * if we were high loaded. This _must_ PIC-code ! | ||
112 | */ | 287 | */ |
113 | move_routine_start: | 288 | jmp *%rbp |
114 | movl %ecx,%ebp | ||
115 | shrl $2,%ecx | ||
116 | rep | ||
117 | movsl | ||
118 | movl %ebp,%ecx | ||
119 | andl $3,%ecx | ||
120 | rep | ||
121 | movsb | ||
122 | movl %edx,%esi | ||
123 | movl %eax,%ecx # NOTE: rep movsb won't move if %ecx == 0 | ||
124 | addl $3,%ecx | ||
125 | shrl $2,%ecx | ||
126 | rep | ||
127 | movsl | ||
128 | movl %ebx,%esi # Restore setup pointer | ||
129 | xorl %ebx,%ebx | ||
130 | ljmp $(__KERNEL_CS), $__PHYSICAL_START | ||
131 | move_routine_end: | ||
132 | 289 | ||
133 | 290 | .data | |
134 | /* Stack for uncompression */ | 291 | gdt: |
135 | .align 32 | 292 | .word gdt_end - gdt |
136 | user_stack: | 293 | .long gdt |
294 | .word 0 | ||
295 | .quad 0x0000000000000000 /* NULL descriptor */ | ||
296 | .quad 0x00af9a000000ffff /* __KERNEL_CS */ | ||
297 | .quad 0x00cf92000000ffff /* __KERNEL_DS */ | ||
298 | gdt_end: | ||
299 | .bss | ||
300 | /* Stack for uncompression */ | ||
301 | .balign 4 | ||
302 | user_stack: | ||
137 | .fill 4096,4,0 | 303 | .fill 4096,4,0 |
138 | stack_start: | 304 | user_stack_end: |
139 | .long user_stack+4096 | ||
140 | .word __KERNEL_DS | ||
141 | |||
diff --git a/arch/x86_64/boot/compressed/misc.c b/arch/x86_64/boot/compressed/misc.c index 3755b2e394d0..f932b0e89096 100644 --- a/arch/x86_64/boot/compressed/misc.c +++ b/arch/x86_64/boot/compressed/misc.c | |||
@@ -9,10 +9,95 @@ | |||
9 | * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996 | 9 | * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996 |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #define _LINUX_STRING_H_ 1 | ||
13 | #define __LINUX_BITMAP_H 1 | ||
14 | |||
15 | #include <linux/linkage.h> | ||
12 | #include <linux/screen_info.h> | 16 | #include <linux/screen_info.h> |
13 | #include <asm/io.h> | 17 | #include <asm/io.h> |
14 | #include <asm/page.h> | 18 | #include <asm/page.h> |
15 | 19 | ||
20 | /* WARNING!! | ||
21 | * This code is compiled with -fPIC and it is relocated dynamically | ||
22 | * at run time, but no relocation processing is performed. | ||
23 | * This means that it is not safe to place pointers in static structures. | ||
24 | */ | ||
25 | |||
26 | /* | ||
27 | * Getting to provable safe in place decompression is hard. | ||
28 | * Worst case behaviours need to be analized. | ||
29 | * Background information: | ||
30 | * | ||
31 | * The file layout is: | ||
32 | * magic[2] | ||
33 | * method[1] | ||
34 | * flags[1] | ||
35 | * timestamp[4] | ||
36 | * extraflags[1] | ||
37 | * os[1] | ||
38 | * compressed data blocks[N] | ||
39 | * crc[4] orig_len[4] | ||
40 | * | ||
41 | * resulting in 18 bytes of non compressed data overhead. | ||
42 | * | ||
43 | * Files divided into blocks | ||
44 | * 1 bit (last block flag) | ||
45 | * 2 bits (block type) | ||
46 | * | ||
47 | * 1 block occurs every 32K -1 bytes or when there 50% compression has been achieved. | ||
48 | * The smallest block type encoding is always used. | ||
49 | * | ||
50 | * stored: | ||
51 | * 32 bits length in bytes. | ||
52 | * | ||
53 | * fixed: | ||
54 | * magic fixed tree. | ||
55 | * symbols. | ||
56 | * | ||
57 | * dynamic: | ||
58 | * dynamic tree encoding. | ||
59 | * symbols. | ||
60 | * | ||
61 | * | ||
62 | * The buffer for decompression in place is the length of the | ||
63 | * uncompressed data, plus a small amount extra to keep the algorithm safe. | ||
64 | * The compressed data is placed at the end of the buffer. The output | ||
65 | * pointer is placed at the start of the buffer and the input pointer | ||
66 | * is placed where the compressed data starts. Problems will occur | ||
67 | * when the output pointer overruns the input pointer. | ||
68 | * | ||
69 | * The output pointer can only overrun the input pointer if the input | ||
70 | * pointer is moving faster than the output pointer. A condition only | ||
71 | * triggered by data whose compressed form is larger than the uncompressed | ||
72 | * form. | ||
73 | * | ||
74 | * The worst case at the block level is a growth of the compressed data | ||
75 | * of 5 bytes per 32767 bytes. | ||
76 | * | ||
77 | * The worst case internal to a compressed block is very hard to figure. | ||
78 | * The worst case can at least be boundined by having one bit that represents | ||
79 | * 32764 bytes and then all of the rest of the bytes representing the very | ||
80 | * very last byte. | ||
81 | * | ||
82 | * All of which is enough to compute an amount of extra data that is required | ||
83 | * to be safe. To avoid problems at the block level allocating 5 extra bytes | ||
84 | * per 32767 bytes of data is sufficient. To avoind problems internal to a block | ||
85 | * adding an extra 32767 bytes (the worst case uncompressed block size) is | ||
86 | * sufficient, to ensure that in the worst case the decompressed data for | ||
87 | * block will stop the byte before the compressed data for a block begins. | ||
88 | * To avoid problems with the compressed data's meta information an extra 18 | ||
89 | * bytes are needed. Leading to the formula: | ||
90 | * | ||
91 | * extra_bytes = (uncompressed_size >> 12) + 32768 + 18 + decompressor_size. | ||
92 | * | ||
93 | * Adding 8 bytes per 32K is a bit excessive but much easier to calculate. | ||
94 | * Adding 32768 instead of 32767 just makes for round numbers. | ||
95 | * Adding the decompressor_size is necessary as it musht live after all | ||
96 | * of the data as well. Last I measured the decompressor is about 14K. | ||
97 | * 10K of actuall data and 4K of bss. | ||
98 | * | ||
99 | */ | ||
100 | |||
16 | /* | 101 | /* |
17 | * gzip declarations | 102 | * gzip declarations |
18 | */ | 103 | */ |
@@ -28,15 +113,20 @@ typedef unsigned char uch; | |||
28 | typedef unsigned short ush; | 113 | typedef unsigned short ush; |
29 | typedef unsigned long ulg; | 114 | typedef unsigned long ulg; |
30 | 115 | ||
31 | #define WSIZE 0x8000 /* Window size must be at least 32k, */ | 116 | #define WSIZE 0x80000000 /* Window size must be at least 32k, |
32 | /* and a power of two */ | 117 | * and a power of two |
118 | * We don't actually have a window just | ||
119 | * a huge output buffer so I report | ||
120 | * a 2G windows size, as that should | ||
121 | * always be larger than our output buffer. | ||
122 | */ | ||
33 | 123 | ||
34 | static uch *inbuf; /* input buffer */ | 124 | static uch *inbuf; /* input buffer */ |
35 | static uch window[WSIZE]; /* Sliding window buffer */ | 125 | static uch *window; /* Sliding window buffer, (and final output buffer) */ |
36 | 126 | ||
37 | static unsigned insize = 0; /* valid bytes in inbuf */ | 127 | static unsigned insize; /* valid bytes in inbuf */ |
38 | static unsigned inptr = 0; /* index of next byte to be processed in inbuf */ | 128 | static unsigned inptr; /* index of next byte to be processed in inbuf */ |
39 | static unsigned outcnt = 0; /* bytes in output buffer */ | 129 | static unsigned outcnt; /* bytes in output buffer */ |
40 | 130 | ||
41 | /* gzip flag byte */ | 131 | /* gzip flag byte */ |
42 | #define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */ | 132 | #define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */ |
@@ -87,8 +177,6 @@ extern unsigned char input_data[]; | |||
87 | extern int input_len; | 177 | extern int input_len; |
88 | 178 | ||
89 | static long bytes_out = 0; | 179 | static long bytes_out = 0; |
90 | static uch *output_data; | ||
91 | static unsigned long output_ptr = 0; | ||
92 | 180 | ||
93 | static void *malloc(int size); | 181 | static void *malloc(int size); |
94 | static void free(void *where); | 182 | static void free(void *where); |
@@ -98,17 +186,10 @@ static void *memcpy(void *dest, const void *src, unsigned n); | |||
98 | 186 | ||
99 | static void putstr(const char *); | 187 | static void putstr(const char *); |
100 | 188 | ||
101 | extern int end; | 189 | static long free_mem_ptr; |
102 | static long free_mem_ptr = (long)&end; | ||
103 | static long free_mem_end_ptr; | 190 | static long free_mem_end_ptr; |
104 | 191 | ||
105 | #define INPLACE_MOVE_ROUTINE 0x1000 | 192 | #define HEAP_SIZE 0x7000 |
106 | #define LOW_BUFFER_START 0x2000 | ||
107 | #define LOW_BUFFER_MAX 0x90000 | ||
108 | #define HEAP_SIZE 0x3000 | ||
109 | static unsigned int low_buffer_end, low_buffer_size; | ||
110 | static int high_loaded =0; | ||
111 | static uch *high_buffer_start /* = (uch *)(((ulg)&end) + HEAP_SIZE)*/; | ||
112 | 193 | ||
113 | static char *vidmem = (char *)0xb8000; | 194 | static char *vidmem = (char *)0xb8000; |
114 | static int vidport; | 195 | static int vidport; |
@@ -218,58 +299,31 @@ static void* memcpy(void* dest, const void* src, unsigned n) | |||
218 | */ | 299 | */ |
219 | static int fill_inbuf(void) | 300 | static int fill_inbuf(void) |
220 | { | 301 | { |
221 | if (insize != 0) { | 302 | error("ran out of input data"); |
222 | error("ran out of input data"); | 303 | return 0; |
223 | } | ||
224 | |||
225 | inbuf = input_data; | ||
226 | insize = input_len; | ||
227 | inptr = 1; | ||
228 | return inbuf[0]; | ||
229 | } | 304 | } |
230 | 305 | ||
231 | /* =========================================================================== | 306 | /* =========================================================================== |
232 | * Write the output window window[0..outcnt-1] and update crc and bytes_out. | 307 | * Write the output window window[0..outcnt-1] and update crc and bytes_out. |
233 | * (Used for the decompressed data only.) | 308 | * (Used for the decompressed data only.) |
234 | */ | 309 | */ |
235 | static void flush_window_low(void) | ||
236 | { | ||
237 | ulg c = crc; /* temporary variable */ | ||
238 | unsigned n; | ||
239 | uch *in, *out, ch; | ||
240 | |||
241 | in = window; | ||
242 | out = &output_data[output_ptr]; | ||
243 | for (n = 0; n < outcnt; n++) { | ||
244 | ch = *out++ = *in++; | ||
245 | c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8); | ||
246 | } | ||
247 | crc = c; | ||
248 | bytes_out += (ulg)outcnt; | ||
249 | output_ptr += (ulg)outcnt; | ||
250 | outcnt = 0; | ||
251 | } | ||
252 | |||
253 | static void flush_window_high(void) | ||
254 | { | ||
255 | ulg c = crc; /* temporary variable */ | ||
256 | unsigned n; | ||
257 | uch *in, ch; | ||
258 | in = window; | ||
259 | for (n = 0; n < outcnt; n++) { | ||
260 | ch = *output_data++ = *in++; | ||
261 | if ((ulg)output_data == low_buffer_end) output_data=high_buffer_start; | ||
262 | c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8); | ||
263 | } | ||
264 | crc = c; | ||
265 | bytes_out += (ulg)outcnt; | ||
266 | outcnt = 0; | ||
267 | } | ||
268 | |||
269 | static void flush_window(void) | 310 | static void flush_window(void) |
270 | { | 311 | { |
271 | if (high_loaded) flush_window_high(); | 312 | /* With my window equal to my output buffer |
272 | else flush_window_low(); | 313 | * I only need to compute the crc here. |
314 | */ | ||
315 | ulg c = crc; /* temporary variable */ | ||
316 | unsigned n; | ||
317 | uch *in, ch; | ||
318 | |||
319 | in = window; | ||
320 | for (n = 0; n < outcnt; n++) { | ||
321 | ch = *in++; | ||
322 | c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8); | ||
323 | } | ||
324 | crc = c; | ||
325 | bytes_out += (ulg)outcnt; | ||
326 | outcnt = 0; | ||
273 | } | 327 | } |
274 | 328 | ||
275 | static void error(char *x) | 329 | static void error(char *x) |
@@ -281,57 +335,8 @@ static void error(char *x) | |||
281 | while(1); /* Halt */ | 335 | while(1); /* Halt */ |
282 | } | 336 | } |
283 | 337 | ||
284 | static void setup_normal_output_buffer(void) | 338 | asmlinkage void decompress_kernel(void *rmode, unsigned long heap, |
285 | { | 339 | uch *input_data, unsigned long input_len, uch *output) |
286 | #ifdef STANDARD_MEMORY_BIOS_CALL | ||
287 | if (RM_EXT_MEM_K < 1024) error("Less than 2MB of memory"); | ||
288 | #else | ||
289 | if ((RM_ALT_MEM_K > RM_EXT_MEM_K ? RM_ALT_MEM_K : RM_EXT_MEM_K) < 1024) error("Less than 2MB of memory"); | ||
290 | #endif | ||
291 | output_data = (unsigned char *)__PHYSICAL_START; /* Normally Points to 1M */ | ||
292 | free_mem_end_ptr = (long)real_mode; | ||
293 | } | ||
294 | |||
295 | struct moveparams { | ||
296 | uch *low_buffer_start; int lcount; | ||
297 | uch *high_buffer_start; int hcount; | ||
298 | }; | ||
299 | |||
300 | static void setup_output_buffer_if_we_run_high(struct moveparams *mv) | ||
301 | { | ||
302 | high_buffer_start = (uch *)(((ulg)&end) + HEAP_SIZE); | ||
303 | #ifdef STANDARD_MEMORY_BIOS_CALL | ||
304 | if (RM_EXT_MEM_K < (3*1024)) error("Less than 4MB of memory"); | ||
305 | #else | ||
306 | if ((RM_ALT_MEM_K > RM_EXT_MEM_K ? RM_ALT_MEM_K : RM_EXT_MEM_K) < (3*1024)) error("Less than 4MB of memory"); | ||
307 | #endif | ||
308 | mv->low_buffer_start = output_data = (unsigned char *)LOW_BUFFER_START; | ||
309 | low_buffer_end = ((unsigned int)real_mode > LOW_BUFFER_MAX | ||
310 | ? LOW_BUFFER_MAX : (unsigned int)real_mode) & ~0xfff; | ||
311 | low_buffer_size = low_buffer_end - LOW_BUFFER_START; | ||
312 | high_loaded = 1; | ||
313 | free_mem_end_ptr = (long)high_buffer_start; | ||
314 | if ( (__PHYSICAL_START + low_buffer_size) > ((ulg)high_buffer_start)) { | ||
315 | high_buffer_start = (uch *)(__PHYSICAL_START + low_buffer_size); | ||
316 | mv->hcount = 0; /* say: we need not to move high_buffer */ | ||
317 | } | ||
318 | else mv->hcount = -1; | ||
319 | mv->high_buffer_start = high_buffer_start; | ||
320 | } | ||
321 | |||
322 | static void close_output_buffer_if_we_run_high(struct moveparams *mv) | ||
323 | { | ||
324 | if (bytes_out > low_buffer_size) { | ||
325 | mv->lcount = low_buffer_size; | ||
326 | if (mv->hcount) | ||
327 | mv->hcount = bytes_out - low_buffer_size; | ||
328 | } else { | ||
329 | mv->lcount = bytes_out; | ||
330 | mv->hcount = 0; | ||
331 | } | ||
332 | } | ||
333 | |||
334 | int decompress_kernel(struct moveparams *mv, void *rmode) | ||
335 | { | 340 | { |
336 | real_mode = rmode; | 341 | real_mode = rmode; |
337 | 342 | ||
@@ -346,13 +351,21 @@ int decompress_kernel(struct moveparams *mv, void *rmode) | |||
346 | lines = RM_SCREEN_INFO.orig_video_lines; | 351 | lines = RM_SCREEN_INFO.orig_video_lines; |
347 | cols = RM_SCREEN_INFO.orig_video_cols; | 352 | cols = RM_SCREEN_INFO.orig_video_cols; |
348 | 353 | ||
349 | if (free_mem_ptr < 0x100000) setup_normal_output_buffer(); | 354 | window = output; /* Output buffer (Normally at 1M) */ |
350 | else setup_output_buffer_if_we_run_high(mv); | 355 | free_mem_ptr = heap; /* Heap */ |
356 | free_mem_end_ptr = heap + HEAP_SIZE; | ||
357 | inbuf = input_data; /* Input buffer */ | ||
358 | insize = input_len; | ||
359 | inptr = 0; | ||
360 | |||
361 | if ((ulg)output & (__KERNEL_ALIGN - 1)) | ||
362 | error("Destination address not 2M aligned"); | ||
363 | if ((ulg)output >= 0xffffffffffUL) | ||
364 | error("Destination address too large"); | ||
351 | 365 | ||
352 | makecrc(); | 366 | makecrc(); |
353 | putstr(".\nDecompressing Linux..."); | 367 | putstr(".\nDecompressing Linux..."); |
354 | gunzip(); | 368 | gunzip(); |
355 | putstr("done.\nBooting the kernel.\n"); | 369 | putstr("done.\nBooting the kernel.\n"); |
356 | if (high_loaded) close_output_buffer_if_we_run_high(mv); | 370 | return; |
357 | return high_loaded; | ||
358 | } | 371 | } |
diff --git a/arch/x86_64/boot/compressed/vmlinux.lds b/arch/x86_64/boot/compressed/vmlinux.lds new file mode 100644 index 000000000000..94c13e557fb4 --- /dev/null +++ b/arch/x86_64/boot/compressed/vmlinux.lds | |||
@@ -0,0 +1,44 @@ | |||
1 | OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64") | ||
2 | OUTPUT_ARCH(i386:x86-64) | ||
3 | ENTRY(startup_64) | ||
4 | SECTIONS | ||
5 | { | ||
6 | /* Be careful parts of head.S assume startup_32 is at | ||
7 | * address 0. | ||
8 | */ | ||
9 | . = 0; | ||
10 | .text : { | ||
11 | _head = . ; | ||
12 | *(.text.head) | ||
13 | _ehead = . ; | ||
14 | *(.text.compressed) | ||
15 | _text = .; /* Text */ | ||
16 | *(.text) | ||
17 | *(.text.*) | ||
18 | _etext = . ; | ||
19 | } | ||
20 | .rodata : { | ||
21 | _rodata = . ; | ||
22 | *(.rodata) /* read-only data */ | ||
23 | *(.rodata.*) | ||
24 | _erodata = . ; | ||
25 | } | ||
26 | .data : { | ||
27 | _data = . ; | ||
28 | *(.data) | ||
29 | *(.data.*) | ||
30 | _edata = . ; | ||
31 | } | ||
32 | .bss : { | ||
33 | _bss = . ; | ||
34 | *(.bss) | ||
35 | *(.bss.*) | ||
36 | *(COMMON) | ||
37 | . = ALIGN(8); | ||
38 | _end = . ; | ||
39 | . = ALIGN(4096); | ||
40 | pgtable = . ; | ||
41 | . = . + 4096 * 6; | ||
42 | _heap = .; | ||
43 | } | ||
44 | } | ||
diff --git a/arch/x86_64/boot/compressed/vmlinux.scr b/arch/x86_64/boot/compressed/vmlinux.scr index 1ed9d791f863..bd1429ce193e 100644 --- a/arch/x86_64/boot/compressed/vmlinux.scr +++ b/arch/x86_64/boot/compressed/vmlinux.scr | |||
@@ -1,9 +1,10 @@ | |||
1 | SECTIONS | 1 | SECTIONS |
2 | { | 2 | { |
3 | .data : { | 3 | .text.compressed : { |
4 | input_len = .; | 4 | input_len = .; |
5 | LONG(input_data_end - input_data) input_data = .; | 5 | LONG(input_data_end - input_data) input_data = .; |
6 | *(.data) | 6 | *(.data) |
7 | input_data_end = .; | 7 | output_len = . - 4; |
8 | input_data_end = .; | ||
8 | } | 9 | } |
9 | } | 10 | } |
diff --git a/arch/x86_64/boot/setup.S b/arch/x86_64/boot/setup.S index 770940cc0108..e9e33f949697 100644 --- a/arch/x86_64/boot/setup.S +++ b/arch/x86_64/boot/setup.S | |||
@@ -51,6 +51,7 @@ | |||
51 | #include <asm/boot.h> | 51 | #include <asm/boot.h> |
52 | #include <asm/e820.h> | 52 | #include <asm/e820.h> |
53 | #include <asm/page.h> | 53 | #include <asm/page.h> |
54 | #include <asm/setup.h> | ||
54 | 55 | ||
55 | /* Signature words to ensure LILO loaded us right */ | 56 | /* Signature words to ensure LILO loaded us right */ |
56 | #define SIG1 0xAA55 | 57 | #define SIG1 0xAA55 |
@@ -80,7 +81,7 @@ start: | |||
80 | # This is the setup header, and it must start at %cs:2 (old 0x9020:2) | 81 | # This is the setup header, and it must start at %cs:2 (old 0x9020:2) |
81 | 82 | ||
82 | .ascii "HdrS" # header signature | 83 | .ascii "HdrS" # header signature |
83 | .word 0x0204 # header version number (>= 0x0105) | 84 | .word 0x0206 # header version number (>= 0x0105) |
84 | # or else old loadlin-1.5 will fail) | 85 | # or else old loadlin-1.5 will fail) |
85 | realmode_swtch: .word 0, 0 # default_switch, SETUPSEG | 86 | realmode_swtch: .word 0, 0 # default_switch, SETUPSEG |
86 | start_sys_seg: .word SYSSEG | 87 | start_sys_seg: .word SYSSEG |
@@ -155,7 +156,20 @@ cmd_line_ptr: .long 0 # (Header version 0x0202 or later) | |||
155 | # low memory 0x10000 or higher. | 156 | # low memory 0x10000 or higher. |
156 | 157 | ||
157 | ramdisk_max: .long 0xffffffff | 158 | ramdisk_max: .long 0xffffffff |
158 | 159 | kernel_alignment: .long 0x200000 # physical addr alignment required for | |
160 | # protected mode relocatable kernel | ||
161 | #ifdef CONFIG_RELOCATABLE | ||
162 | relocatable_kernel: .byte 1 | ||
163 | #else | ||
164 | relocatable_kernel: .byte 0 | ||
165 | #endif | ||
166 | pad2: .byte 0 | ||
167 | pad3: .word 0 | ||
168 | |||
169 | cmdline_size: .long COMMAND_LINE_SIZE-1 #length of the command line, | ||
170 | #added with boot protocol | ||
171 | #version 2.06 | ||
172 | |||
159 | trampoline: call start_of_setup | 173 | trampoline: call start_of_setup |
160 | .align 16 | 174 | .align 16 |
161 | # The offset at this point is 0x240 | 175 | # The offset at this point is 0x240 |
@@ -290,64 +304,10 @@ loader_ok: | |||
290 | movw %cs,%ax | 304 | movw %cs,%ax |
291 | movw %ax,%ds | 305 | movw %ax,%ds |
292 | 306 | ||
293 | /* minimum CPUID flags for x86-64 */ | 307 | call verify_cpu |
294 | /* see http://www.x86-64.org/lists/discuss/msg02971.html */ | 308 | testl %eax,%eax |
295 | #define SSE_MASK ((1<<25)|(1<<26)) | 309 | jz sse_ok |
296 | #define REQUIRED_MASK1 ((1<<0)|(1<<3)|(1<<4)|(1<<5)|(1<<6)|(1<<8)|\ | 310 | |
297 | (1<<13)|(1<<15)|(1<<24)) | ||
298 | #define REQUIRED_MASK2 (1<<29) | ||
299 | |||
300 | pushfl /* standard way to check for cpuid */ | ||
301 | popl %eax | ||
302 | movl %eax,%ebx | ||
303 | xorl $0x200000,%eax | ||
304 | pushl %eax | ||
305 | popfl | ||
306 | pushfl | ||
307 | popl %eax | ||
308 | cmpl %eax,%ebx | ||
309 | jz no_longmode /* cpu has no cpuid */ | ||
310 | movl $0x0,%eax | ||
311 | cpuid | ||
312 | cmpl $0x1,%eax | ||
313 | jb no_longmode /* no cpuid 1 */ | ||
314 | xor %di,%di | ||
315 | cmpl $0x68747541,%ebx /* AuthenticAMD */ | ||
316 | jnz noamd | ||
317 | cmpl $0x69746e65,%edx | ||
318 | jnz noamd | ||
319 | cmpl $0x444d4163,%ecx | ||
320 | jnz noamd | ||
321 | mov $1,%di /* cpu is from AMD */ | ||
322 | noamd: | ||
323 | movl $0x1,%eax | ||
324 | cpuid | ||
325 | andl $REQUIRED_MASK1,%edx | ||
326 | xorl $REQUIRED_MASK1,%edx | ||
327 | jnz no_longmode | ||
328 | movl $0x80000000,%eax | ||
329 | cpuid | ||
330 | cmpl $0x80000001,%eax | ||
331 | jb no_longmode /* no extended cpuid */ | ||
332 | movl $0x80000001,%eax | ||
333 | cpuid | ||
334 | andl $REQUIRED_MASK2,%edx | ||
335 | xorl $REQUIRED_MASK2,%edx | ||
336 | jnz no_longmode | ||
337 | sse_test: | ||
338 | movl $1,%eax | ||
339 | cpuid | ||
340 | andl $SSE_MASK,%edx | ||
341 | cmpl $SSE_MASK,%edx | ||
342 | je sse_ok | ||
343 | test %di,%di | ||
344 | jz no_longmode /* only try to force SSE on AMD */ | ||
345 | movl $0xc0010015,%ecx /* HWCR */ | ||
346 | rdmsr | ||
347 | btr $15,%eax /* enable SSE */ | ||
348 | wrmsr | ||
349 | xor %di,%di /* don't loop */ | ||
350 | jmp sse_test /* try again */ | ||
351 | no_longmode: | 311 | no_longmode: |
352 | call beep | 312 | call beep |
353 | lea long_mode_panic,%si | 313 | lea long_mode_panic,%si |
@@ -357,7 +317,8 @@ no_longmode_loop: | |||
357 | long_mode_panic: | 317 | long_mode_panic: |
358 | .string "Your CPU does not support long mode. Use a 32bit distribution." | 318 | .string "Your CPU does not support long mode. Use a 32bit distribution." |
359 | .byte 0 | 319 | .byte 0 |
360 | 320 | ||
321 | #include "../kernel/verify_cpu.S" | ||
361 | sse_ok: | 322 | sse_ok: |
362 | popw %ds | 323 | popw %ds |
363 | 324 | ||
@@ -846,7 +807,7 @@ gdt_48: | |||
846 | 807 | ||
847 | # Include video setup & detection code | 808 | # Include video setup & detection code |
848 | 809 | ||
849 | #include "video.S" | 810 | #include "../../i386/boot/video.S" |
850 | 811 | ||
851 | # Setup signature -- must be last | 812 | # Setup signature -- must be last |
852 | setup_sig1: .word SIG1 | 813 | setup_sig1: .word SIG1 |
diff --git a/arch/x86_64/boot/video.S b/arch/x86_64/boot/video.S deleted file mode 100644 index 6090516c9c7f..000000000000 --- a/arch/x86_64/boot/video.S +++ /dev/null | |||
@@ -1,2043 +0,0 @@ | |||
1 | /* video.S | ||
2 | * | ||
3 | * Display adapter & video mode setup, version 2.13 (14-May-99) | ||
4 | * | ||
5 | * Copyright (C) 1995 -- 1998 Martin Mares <mj@ucw.cz> | ||
6 | * Based on the original setup.S code (C) Linus Torvalds and Mats Anderson | ||
7 | * | ||
8 | * Rewritten to use GNU 'as' by Chris Noe <stiker@northlink.com> May 1999 | ||
9 | * | ||
10 | * For further information, look at Documentation/svga.txt. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | /* Enable autodetection of SVGA adapters and modes. */ | ||
15 | #undef CONFIG_VIDEO_SVGA | ||
16 | |||
17 | /* Enable autodetection of VESA modes */ | ||
18 | #define CONFIG_VIDEO_VESA | ||
19 | |||
20 | /* Enable compacting of mode table */ | ||
21 | #define CONFIG_VIDEO_COMPACT | ||
22 | |||
23 | /* Retain screen contents when switching modes */ | ||
24 | #define CONFIG_VIDEO_RETAIN | ||
25 | |||
26 | /* Enable local mode list */ | ||
27 | #undef CONFIG_VIDEO_LOCAL | ||
28 | |||
29 | /* Force 400 scan lines for standard modes (hack to fix bad BIOS behaviour */ | ||
30 | #undef CONFIG_VIDEO_400_HACK | ||
31 | |||
32 | /* Hack that lets you force specific BIOS mode ID and specific dimensions */ | ||
33 | #undef CONFIG_VIDEO_GFX_HACK | ||
34 | #define VIDEO_GFX_BIOS_AX 0x4f02 /* 800x600 on ThinkPad */ | ||
35 | #define VIDEO_GFX_BIOS_BX 0x0102 | ||
36 | #define VIDEO_GFX_DUMMY_RESOLUTION 0x6425 /* 100x37 */ | ||
37 | |||
38 | /* This code uses an extended set of video mode numbers. These include: | ||
39 | * Aliases for standard modes | ||
40 | * NORMAL_VGA (-1) | ||
41 | * EXTENDED_VGA (-2) | ||
42 | * ASK_VGA (-3) | ||
43 | * Video modes numbered by menu position -- NOT RECOMMENDED because of lack | ||
44 | * of compatibility when extending the table. These are between 0x00 and 0xff. | ||
45 | */ | ||
46 | #define VIDEO_FIRST_MENU 0x0000 | ||
47 | |||
48 | /* Standard BIOS video modes (BIOS number + 0x0100) */ | ||
49 | #define VIDEO_FIRST_BIOS 0x0100 | ||
50 | |||
51 | /* VESA BIOS video modes (VESA number + 0x0200) */ | ||
52 | #define VIDEO_FIRST_VESA 0x0200 | ||
53 | |||
54 | /* Video7 special modes (BIOS number + 0x0900) */ | ||
55 | #define VIDEO_FIRST_V7 0x0900 | ||
56 | |||
57 | /* Special video modes */ | ||
58 | #define VIDEO_FIRST_SPECIAL 0x0f00 | ||
59 | #define VIDEO_80x25 0x0f00 | ||
60 | #define VIDEO_8POINT 0x0f01 | ||
61 | #define VIDEO_80x43 0x0f02 | ||
62 | #define VIDEO_80x28 0x0f03 | ||
63 | #define VIDEO_CURRENT_MODE 0x0f04 | ||
64 | #define VIDEO_80x30 0x0f05 | ||
65 | #define VIDEO_80x34 0x0f06 | ||
66 | #define VIDEO_80x60 0x0f07 | ||
67 | #define VIDEO_GFX_HACK 0x0f08 | ||
68 | #define VIDEO_LAST_SPECIAL 0x0f09 | ||
69 | |||
70 | /* Video modes given by resolution */ | ||
71 | #define VIDEO_FIRST_RESOLUTION 0x1000 | ||
72 | |||
73 | /* The "recalculate timings" flag */ | ||
74 | #define VIDEO_RECALC 0x8000 | ||
75 | |||
76 | /* Positions of various video parameters passed to the kernel */ | ||
77 | /* (see also include/linux/tty.h) */ | ||
78 | #define PARAM_CURSOR_POS 0x00 | ||
79 | #define PARAM_VIDEO_PAGE 0x04 | ||
80 | #define PARAM_VIDEO_MODE 0x06 | ||
81 | #define PARAM_VIDEO_COLS 0x07 | ||
82 | #define PARAM_VIDEO_EGA_BX 0x0a | ||
83 | #define PARAM_VIDEO_LINES 0x0e | ||
84 | #define PARAM_HAVE_VGA 0x0f | ||
85 | #define PARAM_FONT_POINTS 0x10 | ||
86 | |||
87 | #define PARAM_LFB_WIDTH 0x12 | ||
88 | #define PARAM_LFB_HEIGHT 0x14 | ||
89 | #define PARAM_LFB_DEPTH 0x16 | ||
90 | #define PARAM_LFB_BASE 0x18 | ||
91 | #define PARAM_LFB_SIZE 0x1c | ||
92 | #define PARAM_LFB_LINELENGTH 0x24 | ||
93 | #define PARAM_LFB_COLORS 0x26 | ||
94 | #define PARAM_VESAPM_SEG 0x2e | ||
95 | #define PARAM_VESAPM_OFF 0x30 | ||
96 | #define PARAM_LFB_PAGES 0x32 | ||
97 | #define PARAM_VESA_ATTRIB 0x34 | ||
98 | #define PARAM_CAPABILITIES 0x36 | ||
99 | |||
100 | /* Define DO_STORE according to CONFIG_VIDEO_RETAIN */ | ||
101 | #ifdef CONFIG_VIDEO_RETAIN | ||
102 | #define DO_STORE call store_screen | ||
103 | #else | ||
104 | #define DO_STORE | ||
105 | #endif /* CONFIG_VIDEO_RETAIN */ | ||
106 | |||
107 | # This is the main entry point called by setup.S | ||
108 | # %ds *must* be pointing to the bootsector | ||
109 | video: pushw %ds # We use different segments | ||
110 | pushw %ds # FS contains original DS | ||
111 | popw %fs | ||
112 | pushw %cs # DS is equal to CS | ||
113 | popw %ds | ||
114 | pushw %cs # ES is equal to CS | ||
115 | popw %es | ||
116 | xorw %ax, %ax | ||
117 | movw %ax, %gs # GS is zero | ||
118 | cld | ||
119 | call basic_detect # Basic adapter type testing (EGA/VGA/MDA/CGA) | ||
120 | #ifdef CONFIG_VIDEO_SELECT | ||
121 | movw %fs:(0x01fa), %ax # User selected video mode | ||
122 | cmpw $ASK_VGA, %ax # Bring up the menu | ||
123 | jz vid2 | ||
124 | |||
125 | call mode_set # Set the mode | ||
126 | jc vid1 | ||
127 | |||
128 | leaw badmdt, %si # Invalid mode ID | ||
129 | call prtstr | ||
130 | vid2: call mode_menu | ||
131 | vid1: | ||
132 | #ifdef CONFIG_VIDEO_RETAIN | ||
133 | call restore_screen # Restore screen contents | ||
134 | #endif /* CONFIG_VIDEO_RETAIN */ | ||
135 | call store_edid | ||
136 | #endif /* CONFIG_VIDEO_SELECT */ | ||
137 | call mode_params # Store mode parameters | ||
138 | popw %ds # Restore original DS | ||
139 | ret | ||
140 | |||
141 | # Detect if we have CGA, MDA, EGA or VGA and pass it to the kernel. | ||
142 | basic_detect: | ||
143 | movb $0, %fs:(PARAM_HAVE_VGA) | ||
144 | movb $0x12, %ah # Check EGA/VGA | ||
145 | movb $0x10, %bl | ||
146 | int $0x10 | ||
147 | movw %bx, %fs:(PARAM_VIDEO_EGA_BX) # Identifies EGA to the kernel | ||
148 | cmpb $0x10, %bl # No, it's a CGA/MDA/HGA card. | ||
149 | je basret | ||
150 | |||
151 | incb adapter | ||
152 | movw $0x1a00, %ax # Check EGA or VGA? | ||
153 | int $0x10 | ||
154 | cmpb $0x1a, %al # 1a means VGA... | ||
155 | jne basret # anything else is EGA. | ||
156 | |||
157 | incb %fs:(PARAM_HAVE_VGA) # We've detected a VGA | ||
158 | incb adapter | ||
159 | basret: ret | ||
160 | |||
161 | # Store the video mode parameters for later usage by the kernel. | ||
162 | # This is done by asking the BIOS except for the rows/columns | ||
163 | # parameters in the default 80x25 mode -- these are set directly, | ||
164 | # because some very obscure BIOSes supply insane values. | ||
165 | mode_params: | ||
166 | #ifdef CONFIG_VIDEO_SELECT | ||
167 | cmpb $0, graphic_mode | ||
168 | jnz mopar_gr | ||
169 | #endif | ||
170 | movb $0x03, %ah # Read cursor position | ||
171 | xorb %bh, %bh | ||
172 | int $0x10 | ||
173 | movw %dx, %fs:(PARAM_CURSOR_POS) | ||
174 | movb $0x0f, %ah # Read page/mode/width | ||
175 | int $0x10 | ||
176 | movw %bx, %fs:(PARAM_VIDEO_PAGE) | ||
177 | movw %ax, %fs:(PARAM_VIDEO_MODE) # Video mode and screen width | ||
178 | cmpb $0x7, %al # MDA/HGA => segment differs | ||
179 | jnz mopar0 | ||
180 | |||
181 | movw $0xb000, video_segment | ||
182 | mopar0: movw %gs:(0x485), %ax # Font size | ||
183 | movw %ax, %fs:(PARAM_FONT_POINTS) # (valid only on EGA/VGA) | ||
184 | movw force_size, %ax # Forced size? | ||
185 | orw %ax, %ax | ||
186 | jz mopar1 | ||
187 | |||
188 | movb %ah, %fs:(PARAM_VIDEO_COLS) | ||
189 | movb %al, %fs:(PARAM_VIDEO_LINES) | ||
190 | ret | ||
191 | |||
192 | mopar1: movb $25, %al | ||
193 | cmpb $0, adapter # If we are on CGA/MDA/HGA, the | ||
194 | jz mopar2 # screen must have 25 lines. | ||
195 | |||
196 | movb %gs:(0x484), %al # On EGA/VGA, use the EGA+ BIOS | ||
197 | incb %al # location of max lines. | ||
198 | mopar2: movb %al, %fs:(PARAM_VIDEO_LINES) | ||
199 | ret | ||
200 | |||
201 | #ifdef CONFIG_VIDEO_SELECT | ||
202 | # Fetching of VESA frame buffer parameters | ||
203 | mopar_gr: | ||
204 | leaw modelist+1024, %di | ||
205 | movb $0x23, %fs:(PARAM_HAVE_VGA) | ||
206 | movw 16(%di), %ax | ||
207 | movw %ax, %fs:(PARAM_LFB_LINELENGTH) | ||
208 | movw 18(%di), %ax | ||
209 | movw %ax, %fs:(PARAM_LFB_WIDTH) | ||
210 | movw 20(%di), %ax | ||
211 | movw %ax, %fs:(PARAM_LFB_HEIGHT) | ||
212 | movb 25(%di), %al | ||
213 | movb $0, %ah | ||
214 | movw %ax, %fs:(PARAM_LFB_DEPTH) | ||
215 | movb 29(%di), %al | ||
216 | movb $0, %ah | ||
217 | movw %ax, %fs:(PARAM_LFB_PAGES) | ||
218 | movl 40(%di), %eax | ||
219 | movl %eax, %fs:(PARAM_LFB_BASE) | ||
220 | movl 31(%di), %eax | ||
221 | movl %eax, %fs:(PARAM_LFB_COLORS) | ||
222 | movl 35(%di), %eax | ||
223 | movl %eax, %fs:(PARAM_LFB_COLORS+4) | ||
224 | movw 0(%di), %ax | ||
225 | movw %ax, %fs:(PARAM_VESA_ATTRIB) | ||
226 | |||
227 | # get video mem size | ||
228 | leaw modelist+1024, %di | ||
229 | movw $0x4f00, %ax | ||
230 | int $0x10 | ||
231 | xorl %eax, %eax | ||
232 | movw 18(%di), %ax | ||
233 | movl %eax, %fs:(PARAM_LFB_SIZE) | ||
234 | |||
235 | # store mode capabilities | ||
236 | movl 10(%di), %eax | ||
237 | movl %eax, %fs:(PARAM_CAPABILITIES) | ||
238 | |||
239 | # switching the DAC to 8-bit is for <= 8 bpp only | ||
240 | movw %fs:(PARAM_LFB_DEPTH), %ax | ||
241 | cmpw $8, %ax | ||
242 | jg dac_done | ||
243 | |||
244 | # get DAC switching capability | ||
245 | xorl %eax, %eax | ||
246 | movb 10(%di), %al | ||
247 | testb $1, %al | ||
248 | jz dac_set | ||
249 | |||
250 | # attempt to switch DAC to 8-bit | ||
251 | movw $0x4f08, %ax | ||
252 | movw $0x0800, %bx | ||
253 | int $0x10 | ||
254 | cmpw $0x004f, %ax | ||
255 | jne dac_set | ||
256 | movb %bh, dac_size # store actual DAC size | ||
257 | |||
258 | dac_set: | ||
259 | # set color size to DAC size | ||
260 | movb dac_size, %al | ||
261 | movb %al, %fs:(PARAM_LFB_COLORS+0) | ||
262 | movb %al, %fs:(PARAM_LFB_COLORS+2) | ||
263 | movb %al, %fs:(PARAM_LFB_COLORS+4) | ||
264 | movb %al, %fs:(PARAM_LFB_COLORS+6) | ||
265 | |||
266 | # set color offsets to 0 | ||
267 | movb $0, %fs:(PARAM_LFB_COLORS+1) | ||
268 | movb $0, %fs:(PARAM_LFB_COLORS+3) | ||
269 | movb $0, %fs:(PARAM_LFB_COLORS+5) | ||
270 | movb $0, %fs:(PARAM_LFB_COLORS+7) | ||
271 | |||
272 | dac_done: | ||
273 | # get protected mode interface informations | ||
274 | movw $0x4f0a, %ax | ||
275 | xorw %bx, %bx | ||
276 | xorw %di, %di | ||
277 | int $0x10 | ||
278 | cmp $0x004f, %ax | ||
279 | jnz no_pm | ||
280 | |||
281 | movw %es, %fs:(PARAM_VESAPM_SEG) | ||
282 | movw %di, %fs:(PARAM_VESAPM_OFF) | ||
283 | no_pm: ret | ||
284 | |||
285 | # The video mode menu | ||
286 | mode_menu: | ||
287 | leaw keymsg, %si # "Return/Space/Timeout" message | ||
288 | call prtstr | ||
289 | call flush | ||
290 | nokey: call getkt | ||
291 | |||
292 | cmpb $0x0d, %al # ENTER ? | ||
293 | je listm # yes - manual mode selection | ||
294 | |||
295 | cmpb $0x20, %al # SPACE ? | ||
296 | je defmd1 # no - repeat | ||
297 | |||
298 | call beep | ||
299 | jmp nokey | ||
300 | |||
301 | defmd1: ret # No mode chosen? Default 80x25 | ||
302 | |||
303 | listm: call mode_table # List mode table | ||
304 | listm0: leaw name_bann, %si # Print adapter name | ||
305 | call prtstr | ||
306 | movw card_name, %si | ||
307 | orw %si, %si | ||
308 | jnz an2 | ||
309 | |||
310 | movb adapter, %al | ||
311 | leaw old_name, %si | ||
312 | orb %al, %al | ||
313 | jz an1 | ||
314 | |||
315 | leaw ega_name, %si | ||
316 | decb %al | ||
317 | jz an1 | ||
318 | |||
319 | leaw vga_name, %si | ||
320 | jmp an1 | ||
321 | |||
322 | an2: call prtstr | ||
323 | leaw svga_name, %si | ||
324 | an1: call prtstr | ||
325 | leaw listhdr, %si # Table header | ||
326 | call prtstr | ||
327 | movb $0x30, %dl # DL holds mode number | ||
328 | leaw modelist, %si | ||
329 | lm1: cmpw $ASK_VGA, (%si) # End? | ||
330 | jz lm2 | ||
331 | |||
332 | movb %dl, %al # Menu selection number | ||
333 | call prtchr | ||
334 | call prtsp2 | ||
335 | lodsw | ||
336 | call prthw # Mode ID | ||
337 | call prtsp2 | ||
338 | movb 0x1(%si), %al | ||
339 | call prtdec # Rows | ||
340 | movb $0x78, %al # the letter 'x' | ||
341 | call prtchr | ||
342 | lodsw | ||
343 | call prtdec # Columns | ||
344 | movb $0x0d, %al # New line | ||
345 | call prtchr | ||
346 | movb $0x0a, %al | ||
347 | call prtchr | ||
348 | incb %dl # Next character | ||
349 | cmpb $0x3a, %dl | ||
350 | jnz lm1 | ||
351 | |||
352 | movb $0x61, %dl | ||
353 | jmp lm1 | ||
354 | |||
355 | lm2: leaw prompt, %si # Mode prompt | ||
356 | call prtstr | ||
357 | leaw edit_buf, %di # Editor buffer | ||
358 | lm3: call getkey | ||
359 | cmpb $0x0d, %al # Enter? | ||
360 | jz lment | ||
361 | |||
362 | cmpb $0x08, %al # Backspace? | ||
363 | jz lmbs | ||
364 | |||
365 | cmpb $0x20, %al # Printable? | ||
366 | jc lm3 | ||
367 | |||
368 | cmpw $edit_buf+4, %di # Enough space? | ||
369 | jz lm3 | ||
370 | |||
371 | stosb | ||
372 | call prtchr | ||
373 | jmp lm3 | ||
374 | |||
375 | lmbs: cmpw $edit_buf, %di # Backspace | ||
376 | jz lm3 | ||
377 | |||
378 | decw %di | ||
379 | movb $0x08, %al | ||
380 | call prtchr | ||
381 | call prtspc | ||
382 | movb $0x08, %al | ||
383 | call prtchr | ||
384 | jmp lm3 | ||
385 | |||
386 | lment: movb $0, (%di) | ||
387 | leaw crlft, %si | ||
388 | call prtstr | ||
389 | leaw edit_buf, %si | ||
390 | cmpb $0, (%si) # Empty string = default mode | ||
391 | jz lmdef | ||
392 | |||
393 | cmpb $0, 1(%si) # One character = menu selection | ||
394 | jz mnusel | ||
395 | |||
396 | cmpw $0x6373, (%si) # "scan" => mode scanning | ||
397 | jnz lmhx | ||
398 | |||
399 | cmpw $0x6e61, 2(%si) | ||
400 | jz lmscan | ||
401 | |||
402 | lmhx: xorw %bx, %bx # Else => mode ID in hex | ||
403 | lmhex: lodsb | ||
404 | orb %al, %al | ||
405 | jz lmuse1 | ||
406 | |||
407 | subb $0x30, %al | ||
408 | jc lmbad | ||
409 | |||
410 | cmpb $10, %al | ||
411 | jc lmhx1 | ||
412 | |||
413 | subb $7, %al | ||
414 | andb $0xdf, %al | ||
415 | cmpb $10, %al | ||
416 | jc lmbad | ||
417 | |||
418 | cmpb $16, %al | ||
419 | jnc lmbad | ||
420 | |||
421 | lmhx1: shlw $4, %bx | ||
422 | orb %al, %bl | ||
423 | jmp lmhex | ||
424 | |||
425 | lmuse1: movw %bx, %ax | ||
426 | jmp lmuse | ||
427 | |||
428 | mnusel: lodsb # Menu selection | ||
429 | xorb %ah, %ah | ||
430 | subb $0x30, %al | ||
431 | jc lmbad | ||
432 | |||
433 | cmpb $10, %al | ||
434 | jc lmuse | ||
435 | |||
436 | cmpb $0x61-0x30, %al | ||
437 | jc lmbad | ||
438 | |||
439 | subb $0x61-0x30-10, %al | ||
440 | cmpb $36, %al | ||
441 | jnc lmbad | ||
442 | |||
443 | lmuse: call mode_set | ||
444 | jc lmdef | ||
445 | |||
446 | lmbad: leaw unknt, %si | ||
447 | call prtstr | ||
448 | jmp lm2 | ||
449 | lmscan: cmpb $0, adapter # Scanning only on EGA/VGA | ||
450 | jz lmbad | ||
451 | |||
452 | movw $0, mt_end # Scanning of modes is | ||
453 | movb $1, scanning # done as new autodetection. | ||
454 | call mode_table | ||
455 | jmp listm0 | ||
456 | lmdef: ret | ||
457 | |||
458 | # Additional parts of mode_set... (relative jumps, you know) | ||
459 | setv7: # Video7 extended modes | ||
460 | DO_STORE | ||
461 | subb $VIDEO_FIRST_V7>>8, %bh | ||
462 | movw $0x6f05, %ax | ||
463 | int $0x10 | ||
464 | stc | ||
465 | ret | ||
466 | |||
467 | _setrec: jmp setrec # Ugly... | ||
468 | _set_80x25: jmp set_80x25 | ||
469 | |||
470 | # Aliases for backward compatibility. | ||
471 | setalias: | ||
472 | movw $VIDEO_80x25, %ax | ||
473 | incw %bx | ||
474 | jz mode_set | ||
475 | |||
476 | movb $VIDEO_8POINT-VIDEO_FIRST_SPECIAL, %al | ||
477 | incw %bx | ||
478 | jnz setbad # Fall-through! | ||
479 | |||
480 | # Setting of user mode (AX=mode ID) => CF=success | ||
481 | mode_set: | ||
482 | movw %ax, %fs:(0x01fa) # Store mode for use in acpi_wakeup.S | ||
483 | movw %ax, %bx | ||
484 | cmpb $0xff, %ah | ||
485 | jz setalias | ||
486 | |||
487 | testb $VIDEO_RECALC>>8, %ah | ||
488 | jnz _setrec | ||
489 | |||
490 | cmpb $VIDEO_FIRST_RESOLUTION>>8, %ah | ||
491 | jnc setres | ||
492 | |||
493 | cmpb $VIDEO_FIRST_SPECIAL>>8, %ah | ||
494 | jz setspc | ||
495 | |||
496 | cmpb $VIDEO_FIRST_V7>>8, %ah | ||
497 | jz setv7 | ||
498 | |||
499 | cmpb $VIDEO_FIRST_VESA>>8, %ah | ||
500 | jnc check_vesa | ||
501 | |||
502 | orb %ah, %ah | ||
503 | jz setmenu | ||
504 | |||
505 | decb %ah | ||
506 | jz setbios | ||
507 | |||
508 | setbad: clc | ||
509 | movb $0, do_restore # The screen needn't be restored | ||
510 | ret | ||
511 | |||
512 | setvesa: | ||
513 | DO_STORE | ||
514 | subb $VIDEO_FIRST_VESA>>8, %bh | ||
515 | movw $0x4f02, %ax # VESA BIOS mode set call | ||
516 | int $0x10 | ||
517 | cmpw $0x004f, %ax # AL=4f if implemented | ||
518 | jnz setbad # AH=0 if OK | ||
519 | |||
520 | stc | ||
521 | ret | ||
522 | |||
523 | setbios: | ||
524 | DO_STORE | ||
525 | int $0x10 # Standard BIOS mode set call | ||
526 | pushw %bx | ||
527 | movb $0x0f, %ah # Check if really set | ||
528 | int $0x10 | ||
529 | popw %bx | ||
530 | cmpb %bl, %al | ||
531 | jnz setbad | ||
532 | |||
533 | stc | ||
534 | ret | ||
535 | |||
536 | setspc: xorb %bh, %bh # Set special mode | ||
537 | cmpb $VIDEO_LAST_SPECIAL-VIDEO_FIRST_SPECIAL, %bl | ||
538 | jnc setbad | ||
539 | |||
540 | addw %bx, %bx | ||
541 | jmp *spec_inits(%bx) | ||
542 | |||
543 | setmenu: | ||
544 | orb %al, %al # 80x25 is an exception | ||
545 | jz _set_80x25 | ||
546 | |||
547 | pushw %bx # Set mode chosen from menu | ||
548 | call mode_table # Build the mode table | ||
549 | popw %ax | ||
550 | shlw $2, %ax | ||
551 | addw %ax, %si | ||
552 | cmpw %di, %si | ||
553 | jnc setbad | ||
554 | |||
555 | movw (%si), %ax # Fetch mode ID | ||
556 | _m_s: jmp mode_set | ||
557 | |||
558 | setres: pushw %bx # Set mode chosen by resolution | ||
559 | call mode_table | ||
560 | popw %bx | ||
561 | xchgb %bl, %bh | ||
562 | setr1: lodsw | ||
563 | cmpw $ASK_VGA, %ax # End of the list? | ||
564 | jz setbad | ||
565 | |||
566 | lodsw | ||
567 | cmpw %bx, %ax | ||
568 | jnz setr1 | ||
569 | |||
570 | movw -4(%si), %ax # Fetch mode ID | ||
571 | jmp _m_s | ||
572 | |||
573 | check_vesa: | ||
574 | #ifdef CONFIG_FIRMWARE_EDID | ||
575 | leaw modelist+1024, %di | ||
576 | movw $0x4f00, %ax | ||
577 | int $0x10 | ||
578 | cmpw $0x004f, %ax | ||
579 | jnz setbad | ||
580 | |||
581 | movw 4(%di), %ax | ||
582 | movw %ax, vbe_version | ||
583 | #endif | ||
584 | leaw modelist+1024, %di | ||
585 | subb $VIDEO_FIRST_VESA>>8, %bh | ||
586 | movw %bx, %cx # Get mode information structure | ||
587 | movw $0x4f01, %ax | ||
588 | int $0x10 | ||
589 | addb $VIDEO_FIRST_VESA>>8, %bh | ||
590 | cmpw $0x004f, %ax | ||
591 | jnz setbad | ||
592 | |||
593 | movb (%di), %al # Check capabilities. | ||
594 | andb $0x19, %al | ||
595 | cmpb $0x09, %al | ||
596 | jz setvesa # This is a text mode | ||
597 | |||
598 | movb (%di), %al # Check capabilities. | ||
599 | andb $0x99, %al | ||
600 | cmpb $0x99, %al | ||
601 | jnz _setbad # Doh! No linear frame buffer. | ||
602 | |||
603 | subb $VIDEO_FIRST_VESA>>8, %bh | ||
604 | orw $0x4000, %bx # Use linear frame buffer | ||
605 | movw $0x4f02, %ax # VESA BIOS mode set call | ||
606 | int $0x10 | ||
607 | cmpw $0x004f, %ax # AL=4f if implemented | ||
608 | jnz _setbad # AH=0 if OK | ||
609 | |||
610 | movb $1, graphic_mode # flag graphic mode | ||
611 | movb $0, do_restore # no screen restore | ||
612 | stc | ||
613 | ret | ||
614 | |||
615 | _setbad: jmp setbad # Ugly... | ||
616 | |||
617 | # Recalculate vertical display end registers -- this fixes various | ||
618 | # inconsistencies of extended modes on many adapters. Called when | ||
619 | # the VIDEO_RECALC flag is set in the mode ID. | ||
620 | |||
621 | setrec: subb $VIDEO_RECALC>>8, %ah # Set the base mode | ||
622 | call mode_set | ||
623 | jnc rct3 | ||
624 | |||
625 | movw %gs:(0x485), %ax # Font size in pixels | ||
626 | movb %gs:(0x484), %bl # Number of rows | ||
627 | incb %bl | ||
628 | mulb %bl # Number of visible | ||
629 | decw %ax # scan lines - 1 | ||
630 | movw $0x3d4, %dx | ||
631 | movw %ax, %bx | ||
632 | movb $0x12, %al # Lower 8 bits | ||
633 | movb %bl, %ah | ||
634 | outw %ax, %dx | ||
635 | movb $0x07, %al # Bits 8 and 9 in the overflow register | ||
636 | call inidx | ||
637 | xchgb %al, %ah | ||
638 | andb $0xbd, %ah | ||
639 | shrb %bh | ||
640 | jnc rct1 | ||
641 | orb $0x02, %ah | ||
642 | rct1: shrb %bh | ||
643 | jnc rct2 | ||
644 | orb $0x40, %ah | ||
645 | rct2: movb $0x07, %al | ||
646 | outw %ax, %dx | ||
647 | stc | ||
648 | rct3: ret | ||
649 | |||
650 | # Table of routines for setting of the special modes. | ||
651 | spec_inits: | ||
652 | .word set_80x25 | ||
653 | .word set_8pixel | ||
654 | .word set_80x43 | ||
655 | .word set_80x28 | ||
656 | .word set_current | ||
657 | .word set_80x30 | ||
658 | .word set_80x34 | ||
659 | .word set_80x60 | ||
660 | .word set_gfx | ||
661 | |||
662 | # Set the 80x25 mode. If already set, do nothing. | ||
663 | set_80x25: | ||
664 | movw $0x5019, force_size # Override possibly broken BIOS | ||
665 | use_80x25: | ||
666 | #ifdef CONFIG_VIDEO_400_HACK | ||
667 | movw $0x1202, %ax # Force 400 scan lines | ||
668 | movb $0x30, %bl | ||
669 | int $0x10 | ||
670 | #else | ||
671 | movb $0x0f, %ah # Get current mode ID | ||
672 | int $0x10 | ||
673 | cmpw $0x5007, %ax # Mode 7 (80x25 mono) is the only one available | ||
674 | jz st80 # on CGA/MDA/HGA and is also available on EGAM | ||
675 | |||
676 | cmpw $0x5003, %ax # Unknown mode, force 80x25 color | ||
677 | jnz force3 | ||
678 | |||
679 | st80: cmpb $0, adapter # CGA/MDA/HGA => mode 3/7 is always 80x25 | ||
680 | jz set80 | ||
681 | |||
682 | movb %gs:(0x0484), %al # This is EGA+ -- beware of 80x50 etc. | ||
683 | orb %al, %al # Some buggy BIOS'es set 0 rows | ||
684 | jz set80 | ||
685 | |||
686 | cmpb $24, %al # It's hopefully correct | ||
687 | jz set80 | ||
688 | #endif /* CONFIG_VIDEO_400_HACK */ | ||
689 | force3: DO_STORE | ||
690 | movw $0x0003, %ax # Forced set | ||
691 | int $0x10 | ||
692 | set80: stc | ||
693 | ret | ||
694 | |||
695 | # Set the 80x50/80x43 8-pixel mode. Simple BIOS calls. | ||
696 | set_8pixel: | ||
697 | DO_STORE | ||
698 | call use_80x25 # The base is 80x25 | ||
699 | set_8pt: | ||
700 | movw $0x1112, %ax # Use 8x8 font | ||
701 | xorb %bl, %bl | ||
702 | int $0x10 | ||
703 | movw $0x1200, %ax # Use alternate print screen | ||
704 | movb $0x20, %bl | ||
705 | int $0x10 | ||
706 | movw $0x1201, %ax # Turn off cursor emulation | ||
707 | movb $0x34, %bl | ||
708 | int $0x10 | ||
709 | movb $0x01, %ah # Define cursor scan lines 6-7 | ||
710 | movw $0x0607, %cx | ||
711 | int $0x10 | ||
712 | set_current: | ||
713 | stc | ||
714 | ret | ||
715 | |||
716 | # Set the 80x28 mode. This mode works on all VGA's, because it's a standard | ||
717 | # 80x25 mode with 14-point fonts instead of 16-point. | ||
718 | set_80x28: | ||
719 | DO_STORE | ||
720 | call use_80x25 # The base is 80x25 | ||
721 | set14: movw $0x1111, %ax # Use 9x14 font | ||
722 | xorb %bl, %bl | ||
723 | int $0x10 | ||
724 | movb $0x01, %ah # Define cursor scan lines 11-12 | ||
725 | movw $0x0b0c, %cx | ||
726 | int $0x10 | ||
727 | stc | ||
728 | ret | ||
729 | |||
730 | # Set the 80x43 mode. This mode is works on all VGA's. | ||
731 | # It's a 350-scanline mode with 8-pixel font. | ||
732 | set_80x43: | ||
733 | DO_STORE | ||
734 | movw $0x1201, %ax # Set 350 scans | ||
735 | movb $0x30, %bl | ||
736 | int $0x10 | ||
737 | movw $0x0003, %ax # Reset video mode | ||
738 | int $0x10 | ||
739 | jmp set_8pt # Use 8-pixel font | ||
740 | |||
741 | # Set the 80x30 mode (all VGA's). 480 scanlines, 16-pixel font. | ||
742 | set_80x30: | ||
743 | call use_80x25 # Start with real 80x25 | ||
744 | DO_STORE | ||
745 | movw $0x3cc, %dx # Get CRTC port | ||
746 | inb %dx, %al | ||
747 | movb $0xd4, %dl | ||
748 | rorb %al # Mono or color? | ||
749 | jc set48a | ||
750 | |||
751 | movb $0xb4, %dl | ||
752 | set48a: movw $0x0c11, %ax # Vertical sync end (also unlocks CR0-7) | ||
753 | call outidx | ||
754 | movw $0x0b06, %ax # Vertical total | ||
755 | call outidx | ||
756 | movw $0x3e07, %ax # (Vertical) overflow | ||
757 | call outidx | ||
758 | movw $0xea10, %ax # Vertical sync start | ||
759 | call outidx | ||
760 | movw $0xdf12, %ax # Vertical display end | ||
761 | call outidx | ||
762 | movw $0xe715, %ax # Vertical blank start | ||
763 | call outidx | ||
764 | movw $0x0416, %ax # Vertical blank end | ||
765 | call outidx | ||
766 | pushw %dx | ||
767 | movb $0xcc, %dl # Misc output register (read) | ||
768 | inb %dx, %al | ||
769 | movb $0xc2, %dl # (write) | ||
770 | andb $0x0d, %al # Preserve clock select bits and color bit | ||
771 | orb $0xe2, %al # Set correct sync polarity | ||
772 | outb %al, %dx | ||
773 | popw %dx | ||
774 | movw $0x501e, force_size | ||
775 | stc # That's all. | ||
776 | ret | ||
777 | |||
778 | # Set the 80x34 mode (all VGA's). 480 scans, 14-pixel font. | ||
779 | set_80x34: | ||
780 | call set_80x30 # Set 480 scans | ||
781 | call set14 # And 14-pt font | ||
782 | movw $0xdb12, %ax # VGA vertical display end | ||
783 | movw $0x5022, force_size | ||
784 | setvde: call outidx | ||
785 | stc | ||
786 | ret | ||
787 | |||
788 | # Set the 80x60 mode (all VGA's). 480 scans, 8-pixel font. | ||
789 | set_80x60: | ||
790 | call set_80x30 # Set 480 scans | ||
791 | call set_8pt # And 8-pt font | ||
792 | movw $0xdf12, %ax # VGA vertical display end | ||
793 | movw $0x503c, force_size | ||
794 | jmp setvde | ||
795 | |||
796 | # Special hack for ThinkPad graphics | ||
797 | set_gfx: | ||
798 | #ifdef CONFIG_VIDEO_GFX_HACK | ||
799 | movw $VIDEO_GFX_BIOS_AX, %ax | ||
800 | movw $VIDEO_GFX_BIOS_BX, %bx | ||
801 | int $0x10 | ||
802 | movw $VIDEO_GFX_DUMMY_RESOLUTION, force_size | ||
803 | stc | ||
804 | #endif | ||
805 | ret | ||
806 | |||
807 | #ifdef CONFIG_VIDEO_RETAIN | ||
808 | |||
809 | # Store screen contents to temporary buffer. | ||
810 | store_screen: | ||
811 | cmpb $0, do_restore # Already stored? | ||
812 | jnz stsr | ||
813 | |||
814 | testb $CAN_USE_HEAP, loadflags # Have we space for storing? | ||
815 | jz stsr | ||
816 | |||
817 | pushw %ax | ||
818 | pushw %bx | ||
819 | pushw force_size # Don't force specific size | ||
820 | movw $0, force_size | ||
821 | call mode_params # Obtain params of current mode | ||
822 | popw force_size | ||
823 | movb %fs:(PARAM_VIDEO_LINES), %ah | ||
824 | movb %fs:(PARAM_VIDEO_COLS), %al | ||
825 | movw %ax, %bx # BX=dimensions | ||
826 | mulb %ah | ||
827 | movw %ax, %cx # CX=number of characters | ||
828 | addw %ax, %ax # Calculate image size | ||
829 | addw $modelist+1024+4, %ax | ||
830 | cmpw heap_end_ptr, %ax | ||
831 | jnc sts1 # Unfortunately, out of memory | ||
832 | |||
833 | movw %fs:(PARAM_CURSOR_POS), %ax # Store mode params | ||
834 | leaw modelist+1024, %di | ||
835 | stosw | ||
836 | movw %bx, %ax | ||
837 | stosw | ||
838 | pushw %ds # Store the screen | ||
839 | movw video_segment, %ds | ||
840 | xorw %si, %si | ||
841 | rep | ||
842 | movsw | ||
843 | popw %ds | ||
844 | incb do_restore # Screen will be restored later | ||
845 | sts1: popw %bx | ||
846 | popw %ax | ||
847 | stsr: ret | ||
848 | |||
849 | # Restore screen contents from temporary buffer. | ||
850 | restore_screen: | ||
851 | cmpb $0, do_restore # Has the screen been stored? | ||
852 | jz res1 | ||
853 | |||
854 | call mode_params # Get parameters of current mode | ||
855 | movb %fs:(PARAM_VIDEO_LINES), %cl | ||
856 | movb %fs:(PARAM_VIDEO_COLS), %ch | ||
857 | leaw modelist+1024, %si # Screen buffer | ||
858 | lodsw # Set cursor position | ||
859 | movw %ax, %dx | ||
860 | cmpb %cl, %dh | ||
861 | jc res2 | ||
862 | |||
863 | movb %cl, %dh | ||
864 | decb %dh | ||
865 | res2: cmpb %ch, %dl | ||
866 | jc res3 | ||
867 | |||
868 | movb %ch, %dl | ||
869 | decb %dl | ||
870 | res3: movb $0x02, %ah | ||
871 | movb $0x00, %bh | ||
872 | int $0x10 | ||
873 | lodsw # Display size | ||
874 | movb %ah, %dl # DL=number of lines | ||
875 | movb $0, %ah # BX=phys. length of orig. line | ||
876 | movw %ax, %bx | ||
877 | cmpb %cl, %dl # Too many? | ||
878 | jc res4 | ||
879 | |||
880 | pushw %ax | ||
881 | movb %dl, %al | ||
882 | subb %cl, %al | ||
883 | mulb %bl | ||
884 | addw %ax, %si | ||
885 | addw %ax, %si | ||
886 | popw %ax | ||
887 | movb %cl, %dl | ||
888 | res4: cmpb %ch, %al # Too wide? | ||
889 | jc res5 | ||
890 | |||
891 | movb %ch, %al # AX=width of src. line | ||
892 | res5: movb $0, %cl | ||
893 | xchgb %ch, %cl | ||
894 | movw %cx, %bp # BP=width of dest. line | ||
895 | pushw %es | ||
896 | movw video_segment, %es | ||
897 | xorw %di, %di # Move the data | ||
898 | addw %bx, %bx # Convert BX and BP to _bytes_ | ||
899 | addw %bp, %bp | ||
900 | res6: pushw %si | ||
901 | pushw %di | ||
902 | movw %ax, %cx | ||
903 | rep | ||
904 | movsw | ||
905 | popw %di | ||
906 | popw %si | ||
907 | addw %bp, %di | ||
908 | addw %bx, %si | ||
909 | decb %dl | ||
910 | jnz res6 | ||
911 | |||
912 | popw %es # Done | ||
913 | res1: ret | ||
914 | #endif /* CONFIG_VIDEO_RETAIN */ | ||
915 | |||
916 | # Write to indexed VGA register (AL=index, AH=data, DX=index reg. port) | ||
917 | outidx: outb %al, %dx | ||
918 | pushw %ax | ||
919 | movb %ah, %al | ||
920 | incw %dx | ||
921 | outb %al, %dx | ||
922 | decw %dx | ||
923 | popw %ax | ||
924 | ret | ||
925 | |||
926 | # Build the table of video modes (stored after the setup.S code at the | ||
927 | # `modelist' label. Each video mode record looks like: | ||
928 | # .word MODE-ID (our special mode ID (see above)) | ||
929 | # .byte rows (number of rows) | ||
930 | # .byte columns (number of columns) | ||
931 | # Returns address of the end of the table in DI, the end is marked | ||
932 | # with a ASK_VGA ID. | ||
933 | mode_table: | ||
934 | movw mt_end, %di # Already filled? | ||
935 | orw %di, %di | ||
936 | jnz mtab1x | ||
937 | |||
938 | leaw modelist, %di # Store standard modes: | ||
939 | movl $VIDEO_80x25 + 0x50190000, %eax # The 80x25 mode (ALL) | ||
940 | stosl | ||
941 | movb adapter, %al # CGA/MDA/HGA -- no more modes | ||
942 | orb %al, %al | ||
943 | jz mtabe | ||
944 | |||
945 | decb %al | ||
946 | jnz mtabv | ||
947 | |||
948 | movl $VIDEO_8POINT + 0x502b0000, %eax # The 80x43 EGA mode | ||
949 | stosl | ||
950 | jmp mtabe | ||
951 | |||
952 | mtab1x: jmp mtab1 | ||
953 | |||
954 | mtabv: leaw vga_modes, %si # All modes for std VGA | ||
955 | movw $vga_modes_end-vga_modes, %cx | ||
956 | rep # I'm unable to use movsw as I don't know how to store a half | ||
957 | movsb # of the expression above to cx without using explicit shr. | ||
958 | |||
959 | cmpb $0, scanning # Mode scan requested? | ||
960 | jz mscan1 | ||
961 | |||
962 | call mode_scan | ||
963 | mscan1: | ||
964 | |||
965 | #ifdef CONFIG_VIDEO_LOCAL | ||
966 | call local_modes | ||
967 | #endif /* CONFIG_VIDEO_LOCAL */ | ||
968 | |||
969 | #ifdef CONFIG_VIDEO_VESA | ||
970 | call vesa_modes # Detect VESA VGA modes | ||
971 | #endif /* CONFIG_VIDEO_VESA */ | ||
972 | |||
973 | #ifdef CONFIG_VIDEO_SVGA | ||
974 | cmpb $0, scanning # Bypass when scanning | ||
975 | jnz mscan2 | ||
976 | |||
977 | call svga_modes # Detect SVGA cards & modes | ||
978 | mscan2: | ||
979 | #endif /* CONFIG_VIDEO_SVGA */ | ||
980 | |||
981 | mtabe: | ||
982 | |||
983 | #ifdef CONFIG_VIDEO_COMPACT | ||
984 | leaw modelist, %si | ||
985 | movw %di, %dx | ||
986 | movw %si, %di | ||
987 | cmt1: cmpw %dx, %si # Scan all modes | ||
988 | jz cmt2 | ||
989 | |||
990 | leaw modelist, %bx # Find in previous entries | ||
991 | movw 2(%si), %cx | ||
992 | cmt3: cmpw %bx, %si | ||
993 | jz cmt4 | ||
994 | |||
995 | cmpw 2(%bx), %cx # Found => don't copy this entry | ||
996 | jz cmt5 | ||
997 | |||
998 | addw $4, %bx | ||
999 | jmp cmt3 | ||
1000 | |||
1001 | cmt4: movsl # Copy entry | ||
1002 | jmp cmt1 | ||
1003 | |||
1004 | cmt5: addw $4, %si # Skip entry | ||
1005 | jmp cmt1 | ||
1006 | |||
1007 | cmt2: | ||
1008 | #endif /* CONFIG_VIDEO_COMPACT */ | ||
1009 | |||
1010 | movw $ASK_VGA, (%di) # End marker | ||
1011 | movw %di, mt_end | ||
1012 | mtab1: leaw modelist, %si # SI=mode list, DI=list end | ||
1013 | ret0: ret | ||
1014 | |||
1015 | # Modes usable on all standard VGAs | ||
1016 | vga_modes: | ||
1017 | .word VIDEO_8POINT | ||
1018 | .word 0x5032 # 80x50 | ||
1019 | .word VIDEO_80x43 | ||
1020 | .word 0x502b # 80x43 | ||
1021 | .word VIDEO_80x28 | ||
1022 | .word 0x501c # 80x28 | ||
1023 | .word VIDEO_80x30 | ||
1024 | .word 0x501e # 80x30 | ||
1025 | .word VIDEO_80x34 | ||
1026 | .word 0x5022 # 80x34 | ||
1027 | .word VIDEO_80x60 | ||
1028 | .word 0x503c # 80x60 | ||
1029 | #ifdef CONFIG_VIDEO_GFX_HACK | ||
1030 | .word VIDEO_GFX_HACK | ||
1031 | .word VIDEO_GFX_DUMMY_RESOLUTION | ||
1032 | #endif | ||
1033 | |||
1034 | vga_modes_end: | ||
1035 | # Detect VESA modes. | ||
1036 | |||
1037 | #ifdef CONFIG_VIDEO_VESA | ||
1038 | vesa_modes: | ||
1039 | cmpb $2, adapter # VGA only | ||
1040 | jnz ret0 | ||
1041 | |||
1042 | movw %di, %bp # BP=original mode table end | ||
1043 | addw $0x200, %di # Buffer space | ||
1044 | movw $0x4f00, %ax # VESA Get card info call | ||
1045 | int $0x10 | ||
1046 | movw %bp, %di | ||
1047 | cmpw $0x004f, %ax # Successful? | ||
1048 | jnz ret0 | ||
1049 | |||
1050 | cmpw $0x4556, 0x200(%di) | ||
1051 | jnz ret0 | ||
1052 | |||
1053 | cmpw $0x4153, 0x202(%di) | ||
1054 | jnz ret0 | ||
1055 | |||
1056 | movw $vesa_name, card_name # Set name to "VESA VGA" | ||
1057 | pushw %gs | ||
1058 | lgsw 0x20e(%di), %si # GS:SI=mode list | ||
1059 | movw $128, %cx # Iteration limit | ||
1060 | vesa1: | ||
1061 | # gas version 2.9.1, using BFD version 2.9.1.0.23 buggers the next inst. | ||
1062 | # XXX: lodsw %gs:(%si), %ax # Get next mode in the list | ||
1063 | gs; lodsw | ||
1064 | cmpw $0xffff, %ax # End of the table? | ||
1065 | jz vesar | ||
1066 | |||
1067 | cmpw $0x0080, %ax # Check validity of mode ID | ||
1068 | jc vesa2 | ||
1069 | |||
1070 | orb %ah, %ah # Valid IDs: 0x0000-0x007f/0x0100-0x07ff | ||
1071 | jz vesan # Certain BIOSes report 0x80-0xff! | ||
1072 | |||
1073 | cmpw $0x0800, %ax | ||
1074 | jnc vesae | ||
1075 | |||
1076 | vesa2: pushw %cx | ||
1077 | movw %ax, %cx # Get mode information structure | ||
1078 | movw $0x4f01, %ax | ||
1079 | int $0x10 | ||
1080 | movw %cx, %bx # BX=mode number | ||
1081 | addb $VIDEO_FIRST_VESA>>8, %bh | ||
1082 | popw %cx | ||
1083 | cmpw $0x004f, %ax | ||
1084 | jnz vesan # Don't report errors (buggy BIOSES) | ||
1085 | |||
1086 | movb (%di), %al # Check capabilities. We require | ||
1087 | andb $0x19, %al # a color text mode. | ||
1088 | cmpb $0x09, %al | ||
1089 | jnz vesan | ||
1090 | |||
1091 | cmpw $0xb800, 8(%di) # Standard video memory address required | ||
1092 | jnz vesan | ||
1093 | |||
1094 | testb $2, (%di) # Mode characteristics supplied? | ||
1095 | movw %bx, (%di) # Store mode number | ||
1096 | jz vesa3 | ||
1097 | |||
1098 | xorw %dx, %dx | ||
1099 | movw 0x12(%di), %bx # Width | ||
1100 | orb %bh, %bh | ||
1101 | jnz vesan | ||
1102 | |||
1103 | movb %bl, 0x3(%di) | ||
1104 | movw 0x14(%di), %ax # Height | ||
1105 | orb %ah, %ah | ||
1106 | jnz vesan | ||
1107 | |||
1108 | movb %al, 2(%di) | ||
1109 | mulb %bl | ||
1110 | cmpw $8193, %ax # Small enough for Linux console driver? | ||
1111 | jnc vesan | ||
1112 | |||
1113 | jmp vesaok | ||
1114 | |||
1115 | vesa3: subw $0x8108, %bx # This mode has no detailed info specified, | ||
1116 | jc vesan # so it must be a standard VESA mode. | ||
1117 | |||
1118 | cmpw $5, %bx | ||
1119 | jnc vesan | ||
1120 | |||
1121 | movw vesa_text_mode_table(%bx), %ax | ||
1122 | movw %ax, 2(%di) | ||
1123 | vesaok: addw $4, %di # The mode is valid. Store it. | ||
1124 | vesan: loop vesa1 # Next mode. Limit exceeded => error | ||
1125 | vesae: leaw vesaer, %si | ||
1126 | call prtstr | ||
1127 | movw %bp, %di # Discard already found modes. | ||
1128 | vesar: popw %gs | ||
1129 | ret | ||
1130 | |||
1131 | # Dimensions of standard VESA text modes | ||
1132 | vesa_text_mode_table: | ||
1133 | .byte 60, 80 # 0108 | ||
1134 | .byte 25, 132 # 0109 | ||
1135 | .byte 43, 132 # 010A | ||
1136 | .byte 50, 132 # 010B | ||
1137 | .byte 60, 132 # 010C | ||
1138 | #endif /* CONFIG_VIDEO_VESA */ | ||
1139 | |||
1140 | # Scan for video modes. A bit dirty, but should work. | ||
1141 | mode_scan: | ||
1142 | movw $0x0100, %cx # Start with mode 0 | ||
1143 | scm1: movb $0, %ah # Test the mode | ||
1144 | movb %cl, %al | ||
1145 | int $0x10 | ||
1146 | movb $0x0f, %ah | ||
1147 | int $0x10 | ||
1148 | cmpb %cl, %al | ||
1149 | jnz scm2 # Mode not set | ||
1150 | |||
1151 | movw $0x3c0, %dx # Test if it's a text mode | ||
1152 | movb $0x10, %al # Mode bits | ||
1153 | call inidx | ||
1154 | andb $0x03, %al | ||
1155 | jnz scm2 | ||
1156 | |||
1157 | movb $0xce, %dl # Another set of mode bits | ||
1158 | movb $0x06, %al | ||
1159 | call inidx | ||
1160 | shrb %al | ||
1161 | jc scm2 | ||
1162 | |||
1163 | movb $0xd4, %dl # Cursor location | ||
1164 | movb $0x0f, %al | ||
1165 | call inidx | ||
1166 | orb %al, %al | ||
1167 | jnz scm2 | ||
1168 | |||
1169 | movw %cx, %ax # Ok, store the mode | ||
1170 | stosw | ||
1171 | movb %gs:(0x484), %al # Number of rows | ||
1172 | incb %al | ||
1173 | stosb | ||
1174 | movw %gs:(0x44a), %ax # Number of columns | ||
1175 | stosb | ||
1176 | scm2: incb %cl | ||
1177 | jns scm1 | ||
1178 | |||
1179 | movw $0x0003, %ax # Return back to mode 3 | ||
1180 | int $0x10 | ||
1181 | ret | ||
1182 | |||
1183 | tstidx: outw %ax, %dx # OUT DX,AX and inidx | ||
1184 | inidx: outb %al, %dx # Read from indexed VGA register | ||
1185 | incw %dx # AL=index, DX=index reg port -> AL=data | ||
1186 | inb %dx, %al | ||
1187 | decw %dx | ||
1188 | ret | ||
1189 | |||
1190 | # Try to detect type of SVGA card and supply (usually approximate) video | ||
1191 | # mode table for it. | ||
1192 | |||
1193 | #ifdef CONFIG_VIDEO_SVGA | ||
1194 | svga_modes: | ||
1195 | leaw svga_table, %si # Test all known SVGA adapters | ||
1196 | dosvga: lodsw | ||
1197 | movw %ax, %bp # Default mode table | ||
1198 | orw %ax, %ax | ||
1199 | jz didsv1 | ||
1200 | |||
1201 | lodsw # Pointer to test routine | ||
1202 | pushw %si | ||
1203 | pushw %di | ||
1204 | pushw %es | ||
1205 | movw $0xc000, %bx | ||
1206 | movw %bx, %es | ||
1207 | call *%ax # Call test routine | ||
1208 | popw %es | ||
1209 | popw %di | ||
1210 | popw %si | ||
1211 | orw %bp, %bp | ||
1212 | jz dosvga | ||
1213 | |||
1214 | movw %bp, %si # Found, copy the modes | ||
1215 | movb svga_prefix, %ah | ||
1216 | cpsvga: lodsb | ||
1217 | orb %al, %al | ||
1218 | jz didsv | ||
1219 | |||
1220 | stosw | ||
1221 | movsw | ||
1222 | jmp cpsvga | ||
1223 | |||
1224 | didsv: movw %si, card_name # Store pointer to card name | ||
1225 | didsv1: ret | ||
1226 | |||
1227 | # Table of all known SVGA cards. For each card, we store a pointer to | ||
1228 | # a table of video modes supported by the card and a pointer to a routine | ||
1229 | # used for testing of presence of the card. The video mode table is always | ||
1230 | # followed by the name of the card or the chipset. | ||
1231 | svga_table: | ||
1232 | .word ati_md, ati_test | ||
1233 | .word oak_md, oak_test | ||
1234 | .word paradise_md, paradise_test | ||
1235 | .word realtek_md, realtek_test | ||
1236 | .word s3_md, s3_test | ||
1237 | .word chips_md, chips_test | ||
1238 | .word video7_md, video7_test | ||
1239 | .word cirrus5_md, cirrus5_test | ||
1240 | .word cirrus6_md, cirrus6_test | ||
1241 | .word cirrus1_md, cirrus1_test | ||
1242 | .word ahead_md, ahead_test | ||
1243 | .word everex_md, everex_test | ||
1244 | .word genoa_md, genoa_test | ||
1245 | .word trident_md, trident_test | ||
1246 | .word tseng_md, tseng_test | ||
1247 | .word 0 | ||
1248 | |||
1249 | # Test routines and mode tables: | ||
1250 | |||
1251 | # S3 - The test algorithm was taken from the SuperProbe package | ||
1252 | # for XFree86 1.2.1. Report bugs to Christoph.Niemann@linux.org | ||
1253 | s3_test: | ||
1254 | movw $0x0f35, %cx # we store some constants in cl/ch | ||
1255 | movw $0x03d4, %dx | ||
1256 | movb $0x38, %al | ||
1257 | call inidx | ||
1258 | movb %al, %bh # store current CRT-register 0x38 | ||
1259 | movw $0x0038, %ax | ||
1260 | call outidx # disable writing to special regs | ||
1261 | movb %cl, %al # check whether we can write special reg 0x35 | ||
1262 | call inidx | ||
1263 | movb %al, %bl # save the current value of CRT reg 0x35 | ||
1264 | andb $0xf0, %al # clear bits 0-3 | ||
1265 | movb %al, %ah | ||
1266 | movb %cl, %al # and write it to CRT reg 0x35 | ||
1267 | call outidx | ||
1268 | call inidx # now read it back | ||
1269 | andb %ch, %al # clear the upper 4 bits | ||
1270 | jz s3_2 # the first test failed. But we have a | ||
1271 | |||
1272 | movb %bl, %ah # second chance | ||
1273 | movb %cl, %al | ||
1274 | call outidx | ||
1275 | jmp s3_1 # do the other tests | ||
1276 | |||
1277 | s3_2: movw %cx, %ax # load ah with 0xf and al with 0x35 | ||
1278 | orb %bl, %ah # set the upper 4 bits of ah with the orig value | ||
1279 | call outidx # write ... | ||
1280 | call inidx # ... and reread | ||
1281 | andb %cl, %al # turn off the upper 4 bits | ||
1282 | pushw %ax | ||
1283 | movb %bl, %ah # restore old value in register 0x35 | ||
1284 | movb %cl, %al | ||
1285 | call outidx | ||
1286 | popw %ax | ||
1287 | cmpb %ch, %al # setting lower 4 bits was successful => bad | ||
1288 | je no_s3 # writing is allowed => this is not an S3 | ||
1289 | |||
1290 | s3_1: movw $0x4838, %ax # allow writing to special regs by putting | ||
1291 | call outidx # magic number into CRT-register 0x38 | ||
1292 | movb %cl, %al # check whether we can write special reg 0x35 | ||
1293 | call inidx | ||
1294 | movb %al, %bl | ||
1295 | andb $0xf0, %al | ||
1296 | movb %al, %ah | ||
1297 | movb %cl, %al | ||
1298 | call outidx | ||
1299 | call inidx | ||
1300 | andb %ch, %al | ||
1301 | jnz no_s3 # no, we can't write => no S3 | ||
1302 | |||
1303 | movw %cx, %ax | ||
1304 | orb %bl, %ah | ||
1305 | call outidx | ||
1306 | call inidx | ||
1307 | andb %ch, %al | ||
1308 | pushw %ax | ||
1309 | movb %bl, %ah # restore old value in register 0x35 | ||
1310 | movb %cl, %al | ||
1311 | call outidx | ||
1312 | popw %ax | ||
1313 | cmpb %ch, %al | ||
1314 | jne no_s31 # writing not possible => no S3 | ||
1315 | movb $0x30, %al | ||
1316 | call inidx # now get the S3 id ... | ||
1317 | leaw idS3, %di | ||
1318 | movw $0x10, %cx | ||
1319 | repne | ||
1320 | scasb | ||
1321 | je no_s31 | ||
1322 | |||
1323 | movb %bh, %ah | ||
1324 | movb $0x38, %al | ||
1325 | jmp s3rest | ||
1326 | |||
1327 | no_s3: movb $0x35, %al # restore CRT register 0x35 | ||
1328 | movb %bl, %ah | ||
1329 | call outidx | ||
1330 | no_s31: xorw %bp, %bp # Detection failed | ||
1331 | s3rest: movb %bh, %ah | ||
1332 | movb $0x38, %al # restore old value of CRT register 0x38 | ||
1333 | jmp outidx | ||
1334 | |||
1335 | idS3: .byte 0x81, 0x82, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95 | ||
1336 | .byte 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa8, 0xb0 | ||
1337 | |||
1338 | s3_md: .byte 0x54, 0x2b, 0x84 | ||
1339 | .byte 0x55, 0x19, 0x84 | ||
1340 | .byte 0 | ||
1341 | .ascii "S3" | ||
1342 | .byte 0 | ||
1343 | |||
1344 | # ATI cards. | ||
1345 | ati_test: | ||
1346 | leaw idati, %si | ||
1347 | movw $0x31, %di | ||
1348 | movw $0x09, %cx | ||
1349 | repe | ||
1350 | cmpsb | ||
1351 | je atiok | ||
1352 | |||
1353 | xorw %bp, %bp | ||
1354 | atiok: ret | ||
1355 | |||
1356 | idati: .ascii "761295520" | ||
1357 | |||
1358 | ati_md: .byte 0x23, 0x19, 0x84 | ||
1359 | .byte 0x33, 0x2c, 0x84 | ||
1360 | .byte 0x22, 0x1e, 0x64 | ||
1361 | .byte 0x21, 0x19, 0x64 | ||
1362 | .byte 0x58, 0x21, 0x50 | ||
1363 | .byte 0x5b, 0x1e, 0x50 | ||
1364 | .byte 0 | ||
1365 | .ascii "ATI" | ||
1366 | .byte 0 | ||
1367 | |||
1368 | # AHEAD | ||
1369 | ahead_test: | ||
1370 | movw $0x200f, %ax | ||
1371 | movw $0x3ce, %dx | ||
1372 | outw %ax, %dx | ||
1373 | incw %dx | ||
1374 | inb %dx, %al | ||
1375 | cmpb $0x20, %al | ||
1376 | je isahed | ||
1377 | |||
1378 | cmpb $0x21, %al | ||
1379 | je isahed | ||
1380 | |||
1381 | xorw %bp, %bp | ||
1382 | isahed: ret | ||
1383 | |||
1384 | ahead_md: | ||
1385 | .byte 0x22, 0x2c, 0x84 | ||
1386 | .byte 0x23, 0x19, 0x84 | ||
1387 | .byte 0x24, 0x1c, 0x84 | ||
1388 | .byte 0x2f, 0x32, 0xa0 | ||
1389 | .byte 0x32, 0x22, 0x50 | ||
1390 | .byte 0x34, 0x42, 0x50 | ||
1391 | .byte 0 | ||
1392 | .ascii "Ahead" | ||
1393 | .byte 0 | ||
1394 | |||
1395 | # Chips & Tech. | ||
1396 | chips_test: | ||
1397 | movw $0x3c3, %dx | ||
1398 | inb %dx, %al | ||
1399 | orb $0x10, %al | ||
1400 | outb %al, %dx | ||
1401 | movw $0x104, %dx | ||
1402 | inb %dx, %al | ||
1403 | movb %al, %bl | ||
1404 | movw $0x3c3, %dx | ||
1405 | inb %dx, %al | ||
1406 | andb $0xef, %al | ||
1407 | outb %al, %dx | ||
1408 | cmpb $0xa5, %bl | ||
1409 | je cantok | ||
1410 | |||
1411 | xorw %bp, %bp | ||
1412 | cantok: ret | ||
1413 | |||
1414 | chips_md: | ||
1415 | .byte 0x60, 0x19, 0x84 | ||
1416 | .byte 0x61, 0x32, 0x84 | ||
1417 | .byte 0 | ||
1418 | .ascii "Chips & Technologies" | ||
1419 | .byte 0 | ||
1420 | |||
1421 | # Cirrus Logic 5X0 | ||
1422 | cirrus1_test: | ||
1423 | movw $0x3d4, %dx | ||
1424 | movb $0x0c, %al | ||
1425 | outb %al, %dx | ||
1426 | incw %dx | ||
1427 | inb %dx, %al | ||
1428 | movb %al, %bl | ||
1429 | xorb %al, %al | ||
1430 | outb %al, %dx | ||
1431 | decw %dx | ||
1432 | movb $0x1f, %al | ||
1433 | outb %al, %dx | ||
1434 | incw %dx | ||
1435 | inb %dx, %al | ||
1436 | movb %al, %bh | ||
1437 | xorb %ah, %ah | ||
1438 | shlb $4, %al | ||
1439 | movw %ax, %cx | ||
1440 | movb %bh, %al | ||
1441 | shrb $4, %al | ||
1442 | addw %ax, %cx | ||
1443 | shlw $8, %cx | ||
1444 | addw $6, %cx | ||
1445 | movw %cx, %ax | ||
1446 | movw $0x3c4, %dx | ||
1447 | outw %ax, %dx | ||
1448 | incw %dx | ||
1449 | inb %dx, %al | ||
1450 | andb %al, %al | ||
1451 | jnz nocirr | ||
1452 | |||
1453 | movb %bh, %al | ||
1454 | outb %al, %dx | ||
1455 | inb %dx, %al | ||
1456 | cmpb $0x01, %al | ||
1457 | je iscirr | ||
1458 | |||
1459 | nocirr: xorw %bp, %bp | ||
1460 | iscirr: movw $0x3d4, %dx | ||
1461 | movb %bl, %al | ||
1462 | xorb %ah, %ah | ||
1463 | shlw $8, %ax | ||
1464 | addw $0x0c, %ax | ||
1465 | outw %ax, %dx | ||
1466 | ret | ||
1467 | |||
1468 | cirrus1_md: | ||
1469 | .byte 0x1f, 0x19, 0x84 | ||
1470 | .byte 0x20, 0x2c, 0x84 | ||
1471 | .byte 0x22, 0x1e, 0x84 | ||
1472 | .byte 0x31, 0x25, 0x64 | ||
1473 | .byte 0 | ||
1474 | .ascii "Cirrus Logic 5X0" | ||
1475 | .byte 0 | ||
1476 | |||
1477 | # Cirrus Logic 54XX | ||
1478 | cirrus5_test: | ||
1479 | movw $0x3c4, %dx | ||
1480 | movb $6, %al | ||
1481 | call inidx | ||
1482 | movb %al, %bl # BL=backup | ||
1483 | movw $6, %ax | ||
1484 | call tstidx | ||
1485 | cmpb $0x0f, %al | ||
1486 | jne c5fail | ||
1487 | |||
1488 | movw $0x1206, %ax | ||
1489 | call tstidx | ||
1490 | cmpb $0x12, %al | ||
1491 | jne c5fail | ||
1492 | |||
1493 | movb $0x1e, %al | ||
1494 | call inidx | ||
1495 | movb %al, %bh | ||
1496 | movb %bh, %ah | ||
1497 | andb $0xc0, %ah | ||
1498 | movb $0x1e, %al | ||
1499 | call tstidx | ||
1500 | andb $0x3f, %al | ||
1501 | jne c5xx | ||
1502 | |||
1503 | movb $0x1e, %al | ||
1504 | movb %bh, %ah | ||
1505 | orb $0x3f, %ah | ||
1506 | call tstidx | ||
1507 | xorb $0x3f, %al | ||
1508 | andb $0x3f, %al | ||
1509 | c5xx: pushf | ||
1510 | movb $0x1e, %al | ||
1511 | movb %bh, %ah | ||
1512 | outw %ax, %dx | ||
1513 | popf | ||
1514 | je c5done | ||
1515 | |||
1516 | c5fail: xorw %bp, %bp | ||
1517 | c5done: movb $6, %al | ||
1518 | movb %bl, %ah | ||
1519 | outw %ax, %dx | ||
1520 | ret | ||
1521 | |||
1522 | cirrus5_md: | ||
1523 | .byte 0x14, 0x19, 0x84 | ||
1524 | .byte 0x54, 0x2b, 0x84 | ||
1525 | .byte 0 | ||
1526 | .ascii "Cirrus Logic 54XX" | ||
1527 | .byte 0 | ||
1528 | |||
1529 | # Cirrus Logic 64XX -- no known extra modes, but must be identified, because | ||
1530 | # it's misidentified by the Ahead test. | ||
1531 | cirrus6_test: | ||
1532 | movw $0x3ce, %dx | ||
1533 | movb $0x0a, %al | ||
1534 | call inidx | ||
1535 | movb %al, %bl # BL=backup | ||
1536 | movw $0xce0a, %ax | ||
1537 | call tstidx | ||
1538 | orb %al, %al | ||
1539 | jne c2fail | ||
1540 | |||
1541 | movw $0xec0a, %ax | ||
1542 | call tstidx | ||
1543 | cmpb $0x01, %al | ||
1544 | jne c2fail | ||
1545 | |||
1546 | movb $0xaa, %al | ||
1547 | call inidx # 4X, 5X, 7X and 8X are valid 64XX chip ID's. | ||
1548 | shrb $4, %al | ||
1549 | subb $4, %al | ||
1550 | jz c6done | ||
1551 | |||
1552 | decb %al | ||
1553 | jz c6done | ||
1554 | |||
1555 | subb $2, %al | ||
1556 | jz c6done | ||
1557 | |||
1558 | decb %al | ||
1559 | jz c6done | ||
1560 | |||
1561 | c2fail: xorw %bp, %bp | ||
1562 | c6done: movb $0x0a, %al | ||
1563 | movb %bl, %ah | ||
1564 | outw %ax, %dx | ||
1565 | ret | ||
1566 | |||
1567 | cirrus6_md: | ||
1568 | .byte 0 | ||
1569 | .ascii "Cirrus Logic 64XX" | ||
1570 | .byte 0 | ||
1571 | |||
1572 | # Everex / Trident | ||
1573 | everex_test: | ||
1574 | movw $0x7000, %ax | ||
1575 | xorw %bx, %bx | ||
1576 | int $0x10 | ||
1577 | cmpb $0x70, %al | ||
1578 | jne noevrx | ||
1579 | |||
1580 | shrw $4, %dx | ||
1581 | cmpw $0x678, %dx | ||
1582 | je evtrid | ||
1583 | |||
1584 | cmpw $0x236, %dx | ||
1585 | jne evrxok | ||
1586 | |||
1587 | evtrid: leaw trident_md, %bp | ||
1588 | evrxok: ret | ||
1589 | |||
1590 | noevrx: xorw %bp, %bp | ||
1591 | ret | ||
1592 | |||
1593 | everex_md: | ||
1594 | .byte 0x03, 0x22, 0x50 | ||
1595 | .byte 0x04, 0x3c, 0x50 | ||
1596 | .byte 0x07, 0x2b, 0x64 | ||
1597 | .byte 0x08, 0x4b, 0x64 | ||
1598 | .byte 0x0a, 0x19, 0x84 | ||
1599 | .byte 0x0b, 0x2c, 0x84 | ||
1600 | .byte 0x16, 0x1e, 0x50 | ||
1601 | .byte 0x18, 0x1b, 0x64 | ||
1602 | .byte 0x21, 0x40, 0xa0 | ||
1603 | .byte 0x40, 0x1e, 0x84 | ||
1604 | .byte 0 | ||
1605 | .ascii "Everex/Trident" | ||
1606 | .byte 0 | ||
1607 | |||
1608 | # Genoa. | ||
1609 | genoa_test: | ||
1610 | leaw idgenoa, %si # Check Genoa 'clues' | ||
1611 | xorw %ax, %ax | ||
1612 | movb %es:(0x37), %al | ||
1613 | movw %ax, %di | ||
1614 | movw $0x04, %cx | ||
1615 | decw %si | ||
1616 | decw %di | ||
1617 | l1: incw %si | ||
1618 | incw %di | ||
1619 | movb (%si), %al | ||
1620 | testb %al, %al | ||
1621 | jz l2 | ||
1622 | |||
1623 | cmpb %es:(%di), %al | ||
1624 | l2: loope l1 | ||
1625 | orw %cx, %cx | ||
1626 | je isgen | ||
1627 | |||
1628 | xorw %bp, %bp | ||
1629 | isgen: ret | ||
1630 | |||
1631 | idgenoa: .byte 0x77, 0x00, 0x99, 0x66 | ||
1632 | |||
1633 | genoa_md: | ||
1634 | .byte 0x58, 0x20, 0x50 | ||
1635 | .byte 0x5a, 0x2a, 0x64 | ||
1636 | .byte 0x60, 0x19, 0x84 | ||
1637 | .byte 0x61, 0x1d, 0x84 | ||
1638 | .byte 0x62, 0x20, 0x84 | ||
1639 | .byte 0x63, 0x2c, 0x84 | ||
1640 | .byte 0x64, 0x3c, 0x84 | ||
1641 | .byte 0x6b, 0x4f, 0x64 | ||
1642 | .byte 0x72, 0x3c, 0x50 | ||
1643 | .byte 0x74, 0x42, 0x50 | ||
1644 | .byte 0x78, 0x4b, 0x64 | ||
1645 | .byte 0 | ||
1646 | .ascii "Genoa" | ||
1647 | .byte 0 | ||
1648 | |||
1649 | # OAK | ||
1650 | oak_test: | ||
1651 | leaw idoakvga, %si | ||
1652 | movw $0x08, %di | ||
1653 | movw $0x08, %cx | ||
1654 | repe | ||
1655 | cmpsb | ||
1656 | je isoak | ||
1657 | |||
1658 | xorw %bp, %bp | ||
1659 | isoak: ret | ||
1660 | |||
1661 | idoakvga: .ascii "OAK VGA " | ||
1662 | |||
1663 | oak_md: .byte 0x4e, 0x3c, 0x50 | ||
1664 | .byte 0x4f, 0x3c, 0x84 | ||
1665 | .byte 0x50, 0x19, 0x84 | ||
1666 | .byte 0x51, 0x2b, 0x84 | ||
1667 | .byte 0 | ||
1668 | .ascii "OAK" | ||
1669 | .byte 0 | ||
1670 | |||
1671 | # WD Paradise. | ||
1672 | paradise_test: | ||
1673 | leaw idparadise, %si | ||
1674 | movw $0x7d, %di | ||
1675 | movw $0x04, %cx | ||
1676 | repe | ||
1677 | cmpsb | ||
1678 | je ispara | ||
1679 | |||
1680 | xorw %bp, %bp | ||
1681 | ispara: ret | ||
1682 | |||
1683 | idparadise: .ascii "VGA=" | ||
1684 | |||
1685 | paradise_md: | ||
1686 | .byte 0x41, 0x22, 0x50 | ||
1687 | .byte 0x47, 0x1c, 0x84 | ||
1688 | .byte 0x55, 0x19, 0x84 | ||
1689 | .byte 0x54, 0x2c, 0x84 | ||
1690 | .byte 0 | ||
1691 | .ascii "Paradise" | ||
1692 | .byte 0 | ||
1693 | |||
1694 | # Trident. | ||
1695 | trident_test: | ||
1696 | movw $0x3c4, %dx | ||
1697 | movb $0x0e, %al | ||
1698 | outb %al, %dx | ||
1699 | incw %dx | ||
1700 | inb %dx, %al | ||
1701 | xchgb %al, %ah | ||
1702 | xorb %al, %al | ||
1703 | outb %al, %dx | ||
1704 | inb %dx, %al | ||
1705 | xchgb %ah, %al | ||
1706 | movb %al, %bl # Strange thing ... in the book this wasn't | ||
1707 | andb $0x02, %bl # necessary but it worked on my card which | ||
1708 | jz setb2 # is a trident. Without it the screen goes | ||
1709 | # blurred ... | ||
1710 | andb $0xfd, %al | ||
1711 | jmp clrb2 | ||
1712 | |||
1713 | setb2: orb $0x02, %al | ||
1714 | clrb2: outb %al, %dx | ||
1715 | andb $0x0f, %ah | ||
1716 | cmpb $0x02, %ah | ||
1717 | je istrid | ||
1718 | |||
1719 | xorw %bp, %bp | ||
1720 | istrid: ret | ||
1721 | |||
1722 | trident_md: | ||
1723 | .byte 0x50, 0x1e, 0x50 | ||
1724 | .byte 0x51, 0x2b, 0x50 | ||
1725 | .byte 0x52, 0x3c, 0x50 | ||
1726 | .byte 0x57, 0x19, 0x84 | ||
1727 | .byte 0x58, 0x1e, 0x84 | ||
1728 | .byte 0x59, 0x2b, 0x84 | ||
1729 | .byte 0x5a, 0x3c, 0x84 | ||
1730 | .byte 0 | ||
1731 | .ascii "Trident" | ||
1732 | .byte 0 | ||
1733 | |||
1734 | # Tseng. | ||
1735 | tseng_test: | ||
1736 | movw $0x3cd, %dx | ||
1737 | inb %dx, %al # Could things be this simple ! :-) | ||
1738 | movb %al, %bl | ||
1739 | movb $0x55, %al | ||
1740 | outb %al, %dx | ||
1741 | inb %dx, %al | ||
1742 | movb %al, %ah | ||
1743 | movb %bl, %al | ||
1744 | outb %al, %dx | ||
1745 | cmpb $0x55, %ah | ||
1746 | je istsen | ||
1747 | |||
1748 | isnot: xorw %bp, %bp | ||
1749 | istsen: ret | ||
1750 | |||
1751 | tseng_md: | ||
1752 | .byte 0x26, 0x3c, 0x50 | ||
1753 | .byte 0x2a, 0x28, 0x64 | ||
1754 | .byte 0x23, 0x19, 0x84 | ||
1755 | .byte 0x24, 0x1c, 0x84 | ||
1756 | .byte 0x22, 0x2c, 0x84 | ||
1757 | .byte 0x21, 0x3c, 0x84 | ||
1758 | .byte 0 | ||
1759 | .ascii "Tseng" | ||
1760 | .byte 0 | ||
1761 | |||
1762 | # Video7. | ||
1763 | video7_test: | ||
1764 | movw $0x3cc, %dx | ||
1765 | inb %dx, %al | ||
1766 | movw $0x3b4, %dx | ||
1767 | andb $0x01, %al | ||
1768 | jz even7 | ||
1769 | |||
1770 | movw $0x3d4, %dx | ||
1771 | even7: movb $0x0c, %al | ||
1772 | outb %al, %dx | ||
1773 | incw %dx | ||
1774 | inb %dx, %al | ||
1775 | movb %al, %bl | ||
1776 | movb $0x55, %al | ||
1777 | outb %al, %dx | ||
1778 | inb %dx, %al | ||
1779 | decw %dx | ||
1780 | movb $0x1f, %al | ||
1781 | outb %al, %dx | ||
1782 | incw %dx | ||
1783 | inb %dx, %al | ||
1784 | movb %al, %bh | ||
1785 | decw %dx | ||
1786 | movb $0x0c, %al | ||
1787 | outb %al, %dx | ||
1788 | incw %dx | ||
1789 | movb %bl, %al | ||
1790 | outb %al, %dx | ||
1791 | movb $0x55, %al | ||
1792 | xorb $0xea, %al | ||
1793 | cmpb %bh, %al | ||
1794 | jne isnot | ||
1795 | |||
1796 | movb $VIDEO_FIRST_V7>>8, svga_prefix # Use special mode switching | ||
1797 | ret | ||
1798 | |||
1799 | video7_md: | ||
1800 | .byte 0x40, 0x2b, 0x50 | ||
1801 | .byte 0x43, 0x3c, 0x50 | ||
1802 | .byte 0x44, 0x3c, 0x64 | ||
1803 | .byte 0x41, 0x19, 0x84 | ||
1804 | .byte 0x42, 0x2c, 0x84 | ||
1805 | .byte 0x45, 0x1c, 0x84 | ||
1806 | .byte 0 | ||
1807 | .ascii "Video 7" | ||
1808 | .byte 0 | ||
1809 | |||
1810 | # Realtek VGA | ||
1811 | realtek_test: | ||
1812 | leaw idrtvga, %si | ||
1813 | movw $0x45, %di | ||
1814 | movw $0x0b, %cx | ||
1815 | repe | ||
1816 | cmpsb | ||
1817 | je isrt | ||
1818 | |||
1819 | xorw %bp, %bp | ||
1820 | isrt: ret | ||
1821 | |||
1822 | idrtvga: .ascii "REALTEK VGA" | ||
1823 | |||
1824 | realtek_md: | ||
1825 | .byte 0x1a, 0x3c, 0x50 | ||
1826 | .byte 0x1b, 0x19, 0x84 | ||
1827 | .byte 0x1c, 0x1e, 0x84 | ||
1828 | .byte 0x1d, 0x2b, 0x84 | ||
1829 | .byte 0x1e, 0x3c, 0x84 | ||
1830 | .byte 0 | ||
1831 | .ascii "REALTEK" | ||
1832 | .byte 0 | ||
1833 | |||
1834 | #endif /* CONFIG_VIDEO_SVGA */ | ||
1835 | |||
1836 | # User-defined local mode table (VGA only) | ||
1837 | #ifdef CONFIG_VIDEO_LOCAL | ||
1838 | local_modes: | ||
1839 | leaw local_mode_table, %si | ||
1840 | locm1: lodsw | ||
1841 | orw %ax, %ax | ||
1842 | jz locm2 | ||
1843 | |||
1844 | stosw | ||
1845 | movsw | ||
1846 | jmp locm1 | ||
1847 | |||
1848 | locm2: ret | ||
1849 | |||
1850 | # This is the table of local video modes which can be supplied manually | ||
1851 | # by the user. Each entry consists of mode ID (word) and dimensions | ||
1852 | # (byte for column count and another byte for row count). These modes | ||
1853 | # are placed before all SVGA and VESA modes and override them if table | ||
1854 | # compacting is enabled. The table must end with a zero word followed | ||
1855 | # by NUL-terminated video adapter name. | ||
1856 | local_mode_table: | ||
1857 | .word 0x0100 # Example: 40x25 | ||
1858 | .byte 25,40 | ||
1859 | .word 0 | ||
1860 | .ascii "Local" | ||
1861 | .byte 0 | ||
1862 | #endif /* CONFIG_VIDEO_LOCAL */ | ||
1863 | |||
1864 | # Read a key and return the ASCII code in al, scan code in ah | ||
1865 | getkey: xorb %ah, %ah | ||
1866 | int $0x16 | ||
1867 | ret | ||
1868 | |||
1869 | # Read a key with a timeout of 30 seconds. | ||
1870 | # The hardware clock is used to get the time. | ||
1871 | getkt: call gettime | ||
1872 | addb $30, %al # Wait 30 seconds | ||
1873 | cmpb $60, %al | ||
1874 | jl lminute | ||
1875 | |||
1876 | subb $60, %al | ||
1877 | lminute: | ||
1878 | movb %al, %cl | ||
1879 | again: movb $0x01, %ah | ||
1880 | int $0x16 | ||
1881 | jnz getkey # key pressed, so get it | ||
1882 | |||
1883 | call gettime | ||
1884 | cmpb %cl, %al | ||
1885 | jne again | ||
1886 | |||
1887 | movb $0x20, %al # timeout, return `space' | ||
1888 | ret | ||
1889 | |||
1890 | # Flush the keyboard buffer | ||
1891 | flush: movb $0x01, %ah | ||
1892 | int $0x16 | ||
1893 | jz empty | ||
1894 | |||
1895 | xorb %ah, %ah | ||
1896 | int $0x16 | ||
1897 | jmp flush | ||
1898 | |||
1899 | empty: ret | ||
1900 | |||
1901 | # Print hexadecimal number. | ||
1902 | prthw: pushw %ax | ||
1903 | movb %ah, %al | ||
1904 | call prthb | ||
1905 | popw %ax | ||
1906 | prthb: pushw %ax | ||
1907 | shrb $4, %al | ||
1908 | call prthn | ||
1909 | popw %ax | ||
1910 | andb $0x0f, %al | ||
1911 | prthn: cmpb $0x0a, %al | ||
1912 | jc prth1 | ||
1913 | |||
1914 | addb $0x07, %al | ||
1915 | prth1: addb $0x30, %al | ||
1916 | jmp prtchr | ||
1917 | |||
1918 | # Print decimal number in al | ||
1919 | prtdec: pushw %ax | ||
1920 | pushw %cx | ||
1921 | xorb %ah, %ah | ||
1922 | movb $0x0a, %cl | ||
1923 | idivb %cl | ||
1924 | cmpb $0x09, %al | ||
1925 | jbe lt100 | ||
1926 | |||
1927 | call prtdec | ||
1928 | jmp skip10 | ||
1929 | |||
1930 | lt100: addb $0x30, %al | ||
1931 | call prtchr | ||
1932 | skip10: movb %ah, %al | ||
1933 | addb $0x30, %al | ||
1934 | call prtchr | ||
1935 | popw %cx | ||
1936 | popw %ax | ||
1937 | ret | ||
1938 | |||
1939 | store_edid: | ||
1940 | #ifdef CONFIG_FIRMWARE_EDID | ||
1941 | pushw %es # just save all registers | ||
1942 | pushw %ax | ||
1943 | pushw %bx | ||
1944 | pushw %cx | ||
1945 | pushw %dx | ||
1946 | pushw %di | ||
1947 | |||
1948 | pushw %fs | ||
1949 | popw %es | ||
1950 | |||
1951 | movl $0x13131313, %eax # memset block with 0x13 | ||
1952 | movw $32, %cx | ||
1953 | movw $0x140, %di | ||
1954 | cld | ||
1955 | rep | ||
1956 | stosl | ||
1957 | |||
1958 | cmpw $0x0200, vbe_version # only do EDID on >= VBE2.0 | ||
1959 | jl no_edid | ||
1960 | |||
1961 | pushw %es # save ES | ||
1962 | xorw %di, %di # Report Capability | ||
1963 | pushw %di | ||
1964 | popw %es # ES:DI must be 0:0 | ||
1965 | movw $0x4f15, %ax | ||
1966 | xorw %bx, %bx | ||
1967 | xorw %cx, %cx | ||
1968 | int $0x10 | ||
1969 | popw %es # restore ES | ||
1970 | |||
1971 | cmpb $0x00, %ah # call successful | ||
1972 | jne no_edid | ||
1973 | |||
1974 | cmpb $0x4f, %al # function supported | ||
1975 | jne no_edid | ||
1976 | |||
1977 | movw $0x4f15, %ax # do VBE/DDC | ||
1978 | movw $0x01, %bx | ||
1979 | movw $0x00, %cx | ||
1980 | movw $0x01, %dx | ||
1981 | movw $0x140, %di | ||
1982 | int $0x10 | ||
1983 | |||
1984 | no_edid: | ||
1985 | popw %di # restore all registers | ||
1986 | popw %dx | ||
1987 | popw %cx | ||
1988 | popw %bx | ||
1989 | popw %ax | ||
1990 | popw %es | ||
1991 | #endif | ||
1992 | ret | ||
1993 | |||
1994 | # VIDEO_SELECT-only variables | ||
1995 | mt_end: .word 0 # End of video mode table if built | ||
1996 | edit_buf: .space 6 # Line editor buffer | ||
1997 | card_name: .word 0 # Pointer to adapter name | ||
1998 | scanning: .byte 0 # Performing mode scan | ||
1999 | do_restore: .byte 0 # Screen contents altered during mode change | ||
2000 | svga_prefix: .byte VIDEO_FIRST_BIOS>>8 # Default prefix for BIOS modes | ||
2001 | graphic_mode: .byte 0 # Graphic mode with a linear frame buffer | ||
2002 | dac_size: .byte 6 # DAC bit depth | ||
2003 | vbe_version: .word 0 # VBE bios version | ||
2004 | |||
2005 | # Status messages | ||
2006 | keymsg: .ascii "Press <RETURN> to see video modes available, " | ||
2007 | .ascii "<SPACE> to continue or wait 30 secs" | ||
2008 | .byte 0x0d, 0x0a, 0 | ||
2009 | |||
2010 | listhdr: .byte 0x0d, 0x0a | ||
2011 | .ascii "Mode: COLSxROWS:" | ||
2012 | |||
2013 | crlft: .byte 0x0d, 0x0a, 0 | ||
2014 | |||
2015 | prompt: .byte 0x0d, 0x0a | ||
2016 | .asciz "Enter mode number or `scan': " | ||
2017 | |||
2018 | unknt: .asciz "Unknown mode ID. Try again." | ||
2019 | |||
2020 | badmdt: .ascii "You passed an undefined mode number." | ||
2021 | .byte 0x0d, 0x0a, 0 | ||
2022 | |||
2023 | vesaer: .ascii "Error: Scanning of VESA modes failed. Please " | ||
2024 | .ascii "report to <mj@ucw.cz>." | ||
2025 | .byte 0x0d, 0x0a, 0 | ||
2026 | |||
2027 | old_name: .asciz "CGA/MDA/HGA" | ||
2028 | |||
2029 | ega_name: .asciz "EGA" | ||
2030 | |||
2031 | svga_name: .ascii " " | ||
2032 | |||
2033 | vga_name: .asciz "VGA" | ||
2034 | |||
2035 | vesa_name: .asciz "VESA" | ||
2036 | |||
2037 | name_bann: .asciz "Video adapter: " | ||
2038 | #endif /* CONFIG_VIDEO_SELECT */ | ||
2039 | |||
2040 | # Other variables: | ||
2041 | adapter: .byte 0 # Video adapter: 0=CGA/MDA/HGA,1=EGA,2=VGA | ||
2042 | video_segment: .word 0xb800 # Video memory segment | ||
2043 | force_size: .word 0 # Use this size instead of the one in BIOS vars | ||