Page 1 of 1

How can I set 320x200x8 mode with grub?

Posted: Tue Apr 11, 2017 10:26 pm
by readlnh
hi
I switch back to Real Mode for setting the graphic video mode, but I meet a few problems,it just reboots back to GRUB in qemu.
Can someone give an example?

Re: How can I set 320x200x8 mode with grub?

Posted: Wed Apr 12, 2017 12:02 am
by FusT
Sounds like your code is triple-faulting the CPU.
Is your realmode IVT valid? Are your stack segments correct?
Can think of a couple of other ways this would fail, can you post some BOCHS output and a link to your source control repository?

Re: How can I set 320x200x8 mode with grub?

Posted: Wed Apr 12, 2017 7:48 am
by readlnh
FusT wrote:Sounds like your code is triple-faulting the CPU.
Is your realmode IVT valid? Are your stack segments correct?
Can think of a couple of other ways this would fail, can you post some BOCHS output and a link to your source control repository?
here is mycode

Code: Select all

MBOOT_HEADER_MAGIC  equ 0x1BADB002
MBOOT_PAGE_ALIGN    equ 1 << 0
MBOOT_MEM_INFO      equ 1 << 1
MBOOT_GRAPH_MODE    equ 1 << 2
MBOOT_HEADER_FLAGS  equ MBOOT_PAGE_ALIGN | MBOOT_MEM_INFO | MBOOT_GRAPH_MODE
MBOOT_CHECKSUM      equ -(MBOOT_HEADER_MAGIC + MBOOT_HEADER_FLAGS)

;magic flags checksum (magic + flags + checksum = 0)

[BITS 32]
section .text

dd MBOOT_HEADER_MAGIC
dd MBOOT_HEADER_FLAGS
dd MBOOT_CHECKSUM

dd 0
dd 0
dd 0
dd 0 
dd 0

dd 0
dd 640
dd 480
dd 16

[GLOBAL start]
[GLOBAL glb_mboot_ptr]
[EXTERN kern_entry]

start:
    cli

    mov esp, STACK_TOP
    mov ebp, 0
    and esp, 0FFFFFFF0H
    mov [glb_mboot_ptr] , ebx

	push ebx
    call kern_entry

stop:
    hlt
    jmp stop

section .bss
stack:
    resb 32768
glb_mboot_ptr:
    resb 4

STACK_TOP equ $ - stack - 1

Code: Select all

; 
; Protected Mode BIOS Call Functionailty v2.0 - by Napalm
; -------------------------------------------------------
; 
; This is code shows how its POSSIBLE to execute BIOS interrupts
; by switch out to real-mode and then back into protected mode.
; 
; If you wish to use all or part of this code you must agree
; to the license at the following URL.
; 
; License: http://creativecommons.org/licenses/by-sa/2.0/uk/
;         
; Notes: This file is in NASM syntax.
;        Turn off paging before calling these functions.
;        int32() resets all selectors.
;
; C Prototype:
;	void _cdelc int32(unsigned char intnum, regs16_t *regs);
; 
; Example of usage:
;   regs.ax = 0x0013;
;   int32(0x10, &regs);
;   memset((char *)0xA0000, 1, (320*200));
;   memset((char *)0xA0000 + (100*320+80), 14, 80);
;   regs.ax = 0x0000;
;   int32(0x16, &regs);
;   regs.ax = 0x0003;
;   int32(0x10, &regs);
; 
; 
[bits 32]

global int32, _int32

struc regs16_t
	.di	resw 1
	.si	resw 1
	.bp	resw 1
	.sp resw 1
	.bx	resw 1
	.dx	resw 1
	.cx	resw 1
	.ax	resw 1
	.gs	resw 1
	.fs	resw 1
	.es	resw 1
	.ds	resw 1
	.ef resw 1
endstruc

%define INT32_BASE                             0x7C00
%define REBASE(x)                              (((x) - reloc) + INT32_BASE)
%define GDTENTRY(x)                            ((x) << 3)
%define CODE32                                 GDTENTRY(1)	; 0x08
%define DATA32                                 GDTENTRY(2)	; 0x10
%define CODE16                                 GDTENTRY(3)	; 0x18
%define DATA16                                 GDTENTRY(4)	; 0x20
%define STACK16                                (INT32_BASE - regs16_t_size)


section .text
	int32: use32                               ; by Napalm
	_int32:
		cli                                    ; disable interrupts
		pusha                                  ; save register state to 32bit stack
		mov  esi, reloc                        ; set source to code below
		mov  edi, INT32_BASE                   ; set destination to new base address
		mov  ecx, (int32_end - reloc)          ; set copy size to our codes size
		cld                                    ; clear direction flag (so we copy forward)
		rep  movsb                             ; do the actual copy (relocate code to low 16bit space)
		jmp INT32_BASE                         ; jump to new code location
	reloc: use32                               ; by Napalm
		mov  [REBASE(stack32_ptr)], esp        ; save 32bit stack pointer
		sidt [REBASE(idt32_ptr)]               ; save 32bit idt pointer
		sgdt [REBASE(gdt32_ptr)]               ; save 32bit gdt pointer
		lgdt [REBASE(gdt16_ptr)]               ; load 16bit gdt pointer
		lea  esi, [esp+0x24]                   ; set position of intnum on 32bit stack
		lodsd                                  ; read intnum into eax
		mov  [REBASE(ib)], al                  ; set intrrupt immediate byte from our arguments 
		mov  esi, [esi]                        ; read regs pointer in esi as source
		mov  edi, STACK16                      ; set destination to 16bit stack
		mov  ecx, regs16_t_size                ; set copy size to our struct size
		mov  esp, edi                          ; save destination to as 16bit stack offset
		rep  movsb                             ; do the actual copy (32bit stack to 16bit stack)
		jmp  word CODE16:REBASE(p_mode16)      ; switch to 16bit selector (16bit protected mode)
	p_mode16: use16
		mov  ax, DATA16                        ; get our 16bit data selector
		mov  ds, ax                            ; set ds to 16bit selector
		mov  es, ax                            ; set es to 16bit selector
		mov  fs, ax                            ; set fs to 16bit selector
		mov  gs, ax                            ; set gs to 16bit selector
		mov  ss, ax                            ; set ss to 16bit selector
		mov  eax, cr0                          ; get cr0 so we can modify it
		and  al,  ~0x01                        ; mask off PE bit to turn off protected mode
		mov  cr0, eax                          ; set cr0 to result
		jmp  word 0x0000:REBASE(r_mode16)      ; finally set cs:ip to enter real-mode
	r_mode16: use16
		xor  ax, ax                            ; set ax to zero
		mov  ds, ax                            ; set ds so we can access idt16
		mov  ss, ax                            ; set ss so they the stack is valid
		lidt [REBASE(idt16_ptr)]               ; load 16bit idt
		mov  bx, 0x0870                        ; master 8 and slave 112
		call resetpic                          ; set pic's the to real-mode settings
		popa                                   ; load general purpose registers from 16bit stack
		pop  gs                                ; load gs from 16bit stack
		pop  fs                                ; load fs from 16bit stack
		pop  es                                ; load es from 16bit stack
		pop  ds                                ; load ds from 16bit stack
		sti                                    ; enable interrupts
		db 0xCD                                ; opcode of INT instruction with immediate byte
	ib: db 0x00
		cli                                    ; disable interrupts
		xor  sp, sp                            ; zero sp so we can reuse it
		mov  ss, sp                            ; set ss so the stack is valid
		mov  sp, INT32_BASE                    ; set correct stack position so we can copy back
		pushf                                  ; save eflags to 16bit stack
		push ds                                ; save ds to 16bit stack
		push es                                ; save es to 16bit stack
		push fs                                ; save fs to 16bit stack
		push gs                                ; save gs to 16bit stack
		pusha                                  ; save general purpose registers to 16bit stack
		mov  bx, 0x2028                        ; master 32 and slave 40
		call resetpic                          ; restore the pic's to protected mode settings
		mov  eax, cr0                          ; get cr0 so we can modify it
		inc  eax                               ; set PE bit to turn on protected mode
		mov  cr0, eax                          ; set cr0 to result
		jmp  dword CODE32:REBASE(p_mode32)     ; switch to 32bit selector (32bit protected mode)
	p_mode32: use32
		mov  ax, DATA32                        ; get our 32bit data selector
		mov  ds, ax                            ; reset ds selector
		mov  es, ax                            ; reset es selector
		mov  fs, ax                            ; reset fs selector
		mov  gs, ax                            ; reset gs selector
		mov  ss, ax                            ; reset ss selector
		lgdt [REBASE(gdt32_ptr)]               ; restore 32bit gdt pointer
		lidt [REBASE(idt32_ptr)]               ; restore 32bit idt pointer
		mov  esp, [REBASE(stack32_ptr)]        ; restore 32bit stack pointer
		mov  esi, STACK16                      ; set copy source to 16bit stack
		lea  edi, [esp+0x28]                   ; set position of regs pointer on 32bit stack
		mov  edi, [edi]                        ; use regs pointer in edi as copy destination
		mov  ecx, regs16_t_size                ; set copy size to our struct size
		cld                                    ; clear direction flag (so we copy forward)
		rep  movsb                             ; do the actual copy (16bit stack to 32bit stack)
		popa                                   ; restore registers
		sti                                    ; enable interrupts
		ret                                    ; return to caller
		
	resetpic:                                  ; reset's 8259 master and slave pic vectors
		push ax                                ; expects bh = master vector, bl = slave vector
		mov  al, 0x11                          ; 0x11 = ICW1_INIT | ICW1_ICW4
		out  0x20, al                          ; send ICW1 to master pic
		out  0xA0, al                          ; send ICW1 to slave pic
		mov  al, bh                            ; get master pic vector param
		out  0x21, al                          ; send ICW2 aka vector to master pic
		mov  al, bl                            ; get slave pic vector param
		out  0xA1, al                          ; send ICW2 aka vector to slave pic
		mov  al, 0x04                          ; 0x04 = set slave to IRQ2
		out  0x21, al                          ; send ICW3 to master pic
		shr  al, 1                             ; 0x02 = tell slave its on IRQ2 of master
		out  0xA1, al                          ; send ICW3 to slave pic
		shr  al, 1                             ; 0x01 = ICW4_8086
		out  0x21, al                          ; send ICW4 to master pic
		out  0xA1, al                          ; send ICW4 to slave pic
		pop  ax                                ; restore ax from stack
		ret                                    ; return to caller
		
	stack32_ptr:                               ; address in 32bit stack after we
		dd 0x00000000                          ;   save all general purpose registers
		
	idt32_ptr:                                 ; IDT table pointer for 32bit access
		dw 0x0000                              ; table limit (size)
		dd 0x00000000                          ; table base address
		
	gdt32_ptr:                                 ; GDT table pointer for 32bit access
		dw 0x0000                              ; table limit (size)
		dd 0x00000000                          ; table base address
		
	idt16_ptr:                                 ; IDT table pointer for 16bit access
		dw 0x03FF                              ; table limit (size)
		dd 0x00000000                          ; table base address
		
	gdt16_base:                                ; GDT descriptor table
		.null:                                 ; 0x00 - null segment descriptor
			dd 0x00000000                      ; must be left zero'd
			dd 0x00000000                      ; must be left zero'd
			
		.code32:                               ; 0x01 - 32bit code segment descriptor 0xFFFFFFFF
			dw 0xFFFF                          ; limit  0:15
			dw 0x0000                          ; base   0:15
			db 0x00                            ; base  16:23
			db 0x9A                            ; present, iopl/0, code, execute/read
			db 0xCF                            ; 4Kbyte granularity, 32bit selector; limit 16:19
			db 0x00                            ; base  24:31
			
		.data32:                               ; 0x02 - 32bit data segment descriptor 0xFFFFFFFF
			dw 0xFFFF                          ; limit  0:15
			dw 0x0000                          ; base   0:15
			db 0x00                            ; base  16:23
			db 0x92                            ; present, iopl/0, data, read/write
			db 0xCF                            ; 4Kbyte granularity, 32bit selector; limit 16:19
			db 0x00                            ; base  24:31
			
		.code16:                               ; 0x03 - 16bit code segment descriptor 0x000FFFFF
			dw 0xFFFF                          ; limit  0:15
			dw 0x0000                          ; base   0:15
			db 0x00                            ; base  16:23
			db 0x9A                            ; present, iopl/0, code, execute/read
			db 0x0F                            ; 1Byte granularity, 16bit selector; limit 16:19
			db 0x00                            ; base  24:31
			
		.data16:                               ; 0x04 - 16bit data segment descriptor 0x000FFFFF
			dw 0xFFFF                          ; limit  0:15
			dw 0x0000                          ; base   0:15
			db 0x00                            ; base  16:23
			db 0x92                            ; present, iopl/0, data, read/write
			db 0x0F                            ; 1Byte granularity, 16bit selector; limit 16:19
			db 0x00                            ; base  24:31
			
	gdt16_ptr:                                 ; GDT table pointer for 16bit access
		dw gdt16_ptr - gdt16_base - 1          ; table limit (size)
		dd gdt16_base                          ; table base address
		
	int32_end:                                 ; end marker (so we can copy the code)
	
	

Code: Select all

// define our structure
typedef struct __attribute__ ((packed)) {
	unsigned short di, si, bp, sp, bx, dx, cx, ax;
	unsigned short gs, fs, es, ds, eflags;
} regs16_t;

// tell compiler our int32 function is external
extern void int32(unsigned char intnum, regs16_t *regs);

// int32 test
void int32_test();

Code: Select all

#include "int32_test.h"
int kern_entry()
{
		
	regs16_t regs;	
	regs.ax = 0x0013;
	int32(0x10, &regs);
	//unsigned int* buffer = (unsigned int*) 0xA0000;
	int i;
	char *p;	
	for(i = 0xa0000; i < 0xaffff; i++) {
		p = i;
		*p = 1;	//blue color
	}   	
	/*for (int i = 0; i < 800 * 600; i++)
        buffer[i] = 15;*/
   	while (1) {}
}
I can see the full screen with blue color for just a moment in qemu,then it retuen back to grub...I don't konw what's wrong with it..

Re: How can I set 320x200x8 mode with grub?

Posted: Wed Apr 12, 2017 9:03 am
by Brendan
Hi,
readlnh wrote:I can see the full screen with blue color for just a moment in qemu,then it retuen back to grub...I don't konw what's wrong with it..
I'd assume that the code actually works (which is surprising given how bad it is); but after it has worked (in your "while(1)") an IRQ occurs, and you don't have an IDT so it blows up.

Note that the code you've "cut & pasted" reconfigures the PIC chips twice (which destroys all pending IRQs twice). For this reason it's incredibly broken for "early boot" (where there's no need to reconfigure PIC chips at all) and incredibly broken for "after boot" (where you can't just reconfigure PIC chips without breaking all device drivers).


Cheers,

Brendan

Re: How can I set 320x200x8 mode with grub?

Posted: Wed Apr 12, 2017 10:07 am
by readlnh
Brendan wrote:Hi,
readlnh wrote:I can see the full screen with blue color for just a moment in qemu,then it retuen back to grub...I don't konw what's wrong with it..
I'd assume that the code actually works (which is surprising given how bad it is); but after it has worked (in your "while(1)") an IRQ occurs, and you don't have an IDT so it blows up.

Note that the code you've "cut & pasted" reconfigures the PIC chips twice (which destroys all pending IRQs twice). For this reason it's incredibly broken for "early boot" (where there's no need to reconfigure PIC chips at all) and incredibly broken for "after boot" (where you can't just reconfigure PIC chips without breaking all device drivers).


Cheers,

Brendan
thank you very much,but i still don't know what should i do,can you give me some advice?

Re: How can I set 320x200x8 mode with grub?

Posted: Wed Apr 12, 2017 7:07 pm
by StudlyCaps
If nothing else replace the while(1) with inline asm for "cli" then "hlt"
This will stop the computer just rebooting immediately.

hlt stops the cpu from executing more instructions and cli makes sure that no interrupts will start it again.

Re: How can I set 320x200x8 mode with grub?

Posted: Wed Apr 12, 2017 7:21 pm
by Brendan
Hi,
readlnh wrote:
Brendan wrote:
readlnh wrote:I can see the full screen with blue color for just a moment in qemu,then it retuen back to grub...I don't konw what's wrong with it..
I'd assume that the code actually works (which is surprising given how bad it is); but after it has worked (in your "while(1)") an IRQ occurs, and you don't have an IDT so it blows up.

Note that the code you've "cut & pasted" reconfigures the PIC chips twice (which destroys all pending IRQs twice). For this reason it's incredibly broken for "early boot" (where there's no need to reconfigure PIC chips at all) and incredibly broken for "after boot" (where you can't just reconfigure PIC chips without breaking all device drivers).
thank you very much,but i still don't know what should i do,can you give me some advice?
For now; in the "_int32" routine, delete both "call resetpic" instructions (they aren't needed and do more harm than good) and also delete the last "sti" (which enables IRQs that you aren't ready for).


Cheers,

Brendan

Re: How can I set 320x200x8 mode with grub?

Posted: Wed Apr 12, 2017 8:19 pm
by readlnh
StudlyCaps wrote:If nothing else replace the while(1) with inline asm for "cli" then "hlt"
This will stop the computer just rebooting immediately.

hlt stops the cpu from executing more instructions and cli makes sure that no interrupts will start it again.
i tryed this

Code: Select all

#include "int32_test.h"
int kern_entry()
{
		
	regs16_t regs;	
	regs.ax = 0x0013;
	int32(0x10, &regs);
	//unsigned int* buffer = (unsigned int*) 0xA0000;
	int i;
	char *p;	
	for(i = 0xa0000; i < 0xaffff; i++) {
		p = i;
		*p = 1;	
	}   
	__asm__ __volatile__("hlt");
	__asm__ __volatile__("ret");
	return 0;	
}
but it still dosen't work...

Re: How can I set 320x200x8 mode with grub?

Posted: Wed Apr 12, 2017 8:57 pm
by StudlyCaps
The important thing is the "cli" command. You need to put the "cli" in.

Do you know about how interrupts work on the x86? Also do you know what the cli instruction does? These are very important concepts for low level programming. I can explain a bit if you would like me to.

Re: How can I set 320x200x8 mode with grub?

Posted: Sun Apr 16, 2017 11:28 pm
by readlnh
For now; in the "_int32" routine, delete both "call resetpic" instructions (they aren't needed and do more harm than good) and also delete the last "sti" (which enables IRQs that you aren't ready for).


Cheers,

Brendan
thank you very much, i have sloved the problem as what you told.

Re: How can I set 320x200x8 mode with grub?

Posted: Sun Apr 16, 2017 11:30 pm
by readlnh
than you all for your attention