Page 1 of 1

Help with int 0x13 in secondary boot loader.

Posted: Sun Feb 10, 2013 7:06 am
by Ariethenor
I am trying to writing a 16-bit OS, using C and assembly (bcc and as86)
I am having problems with secondary loader (places kernel into HiMem)
I have A20, check and enable routines that are working To the best of my knowlege (the function exits; and if A20 is not enabled it is designed to loop forever, however I have debugged enough to know that the loop is exiting so A20 must therefore be enabled).

the bootloader in the MBR uses a very similar structure and the exact same interupt routine. The bootloader in MBR works flawlessly.
the secondary loader sets carry flag after int 0x13 indicating an error, but I can't for the life of me figure out the error. Been debugging and testing for 3 days now before deciding to post. Any help would be great.

for refference this is my dap structure

Code: Select all

dap:	        db 0x10
		db 0x00
		dw 0x0010
ptr1:	
		dw 0x0010,0xFFFF
		db 0x03,0,0,0,0,0,0,0

MBR boots kernel
kernel runs init which reloads kernel into HiMem then transfers control
init then runs again, but if it is in HiMem or errors on HiMem load it just skips load stuff and exits back to main kernel program

Code: Select all

EXPORT _init
    ;cdelc convention header code here but not shown
    _checkSegment  ;some code to check if SS = 0xFFFF, indicating HiMem load was successful, (this has been debugged and works)
                           ;if successful skip all the loading stuff and jump to end init.
    _checkA20 ;some code follows but left out for space
    _enableA20 ;if nessesary, some code follows but left out for space
                    ;endlessly loops to _checkA20 till _checkA20 returns enabled

.loadHiMem:
		sti	          ;ensure interupts enabled
     ;reset regesters and segments used in previous procedures back to the known requred state
		xor ax, ax    ;ax = 0
		xor dx, dx    ;dx =0
		mov ds, ax   ;ds =0
;push "dap" onto stack (this was for debugging in case the dap structure was not being placed where i expected it durring as86 object file assembly)
;this way i know exactly where and how the dap is set up

		mov bx, sp		;save stack pointer to quickly remove the structure
		mov ax, ss
		mov es, ax		;set up index register

;maped out what the stack structure should look like using "grow down" and little endian. The pushed structure onto stack accordingly
		xor ax, ax
		push ax
		mov ax, #0x0003
		push ax
		mov ax, #0xFFFF
		push ax
		mov ax, #0x0010
		push ax
		mov di, sp               ;(ptr1) pointer to jump to after load points to HiMem
		push ax
		push ax
		
          ;exact same interupt routine used in bootloader in MBR, that bootloader works.
		mov si, sp                ;Already tested and proved as86 defaluts to ds seg reg for operations involving si index register
                                              ;sp should point to dap structure on stack.
		mov ah, #0x42
		mov	dl, #0x80
		int #0x13
		jc .error                   ;jump to "error handler" if problem durring load

		mov ax, #0xFFFF
		mov ss, ax               ;set up HiMem stack, for check segment routine, and for cdelc convention when kernel restarts in HiMem
		mov sp, #0x0FFF

;		mov [ptr1], word #0x0010      ;I may or may not have needed this in a past secondary bootloader written completely in assembly
                                                          ;using fasm, I know the loader isn't even getting this far, it is jumping to the error handler.
		seg es                                 ;when using index di, you must specify a segment this is how in as86
		jmp far dword [di]                 ;this was saved while pushing dap onto stack

.endinit:
;  cdelc convention footer
	pop si
	pop di
	mov sp, bp
	pop bp
	ret	;exit _init

.error:           ;"error handler"
	mov sp, bx			;remove dap from stack
	push #0x45                ;print "E" to screen (this is what is happening when init exits)
	push #0x8150
	push #0xB000
	call _putInMemory	;this works with no issues
	jmp .endinit                ; run kernel anyway, but not in HiMem, this is to ensure OS will boot even if HiMem is for whatever reason not available.
                                        ;but i already know that in my "Bochs" setup HiMem is available. This is Mark 2 for my OS, the first design was purely assmebly, this time i am trying to use mainly C for developement.

Any help is greatly appreciated, many thanks in advance.
I can't figure out why int 0x13 is producing an error.

ps, i know my code style may not be perfect, please offer advice, and don't criticize.

Re: Help with int 0x13 in secondary boot loader.

Posted: Sun Feb 10, 2013 8:53 am
by Brendan
Hi,

Code: Select all

;maped out what the stack structure should look like using "grow down" and little endian. The pushed structure onto stack accordingly
		xor ax, ax
		push ax
		mov ax, #0x0003
		push ax
		mov ax, #0xFFFF
		push ax
		mov ax, #0x0010
		push ax
		mov di, sp               ;(ptr1) pointer to jump to after load points to HiMem
		push ax
		push ax
The end result of this stupidity would look like this:

Code: Select all

es:si:
    db 0x10                ;Size of packet
    db 0x00                ;Reserved
    dw 0x0010              ;Number of blocks to transfer
    dw 0x0010              ;Offset to read data to
    dw 0xFFFF              ;Segment to read data to
    dq 0x????????00000003  ;Starting LBA ("undefined" as nothing was pushed/stored for the highest 32-bits)
Also note that I wouldn't expect loading data directly into the high memory area to work reliably on all computers (it's likely that some BIOSs have bugs that make a mess of it); and that you can do "push word 0x1234" and don't need to load the data into a register and push the register.


Cheers,

Brendan

Re: Help with int 0x13 in secondary boot loader.

Posted: Sun Feb 10, 2013 9:13 am
by Ariethenor
Brendan wrote:Hi,

Code: Select all

;maped out what the stack structure should look like using "grow down" and little endian. The pushed structure onto stack accordingly
		xor ax, ax
		push ax
		mov ax, #0x0003
		push ax
		mov ax, #0xFFFF
		push ax
		mov ax, #0x0010
		push ax
		mov di, sp               ;(ptr1) pointer to jump to after load points to HiMem
		push ax
		push ax
The end result of this stupidity would look like this:

Code: Select all

    dw 0x0010       ;Pointless?
    dw 0x0010       ;Pointless?
es:di:
    db 0x10         ;Size of packet
    db 0x00         ;Reserved
    dw 0xFFFF       ;Number of blocks to transfer (should not be greater than 0x007F)
    dw 0x0003       ;Offset to read data to (would trash the IVT)
    dw 0x0000       ;Segment to read data to (would trash the IVT)
    dq ?????        ;Starting LBA ("undefined" as nothing was pushed/stored)

Cheers,

Brendan
It's not "stupidity" i have checked(and am currently using) the "dap on stack setup" in my "WORKING" bootloader in the MBR(stage 1 is working flawlessly). sp points to DAP di points to the seg:offset to far jump to. Plus it is "upside down", cause stack grows down and "memory" goes up. But thanks for the try. Anyways the point is that int 0x13 is setting carry flag, and kernel is not being loaded into HiMem; and pushing the dap structure on the stack absolutely works correctly. It ensures that i know exactly where dap is durring debugging as i don't know exactly how as86 is organizing the object file i am linking to.

HiMem absolutely works on my setup... my OS mark 1 written entirely in assembly loads into HiMem without issues. It is the exact same "Bochs" so this operating system should have no problems either.

My code is not optimized, and my as86 assembler was being finiky (sp) about pushing constants onto the stack so i was removing that variable durring debugging. I will optimize when it is working. Like i said in my first post, i have been debugging and testing this very problem for 3 straight days now, been comparing bin outputs by fasm and as86 in hex editors to get it match identically as i know fasm syntax and wrote my entire first and working OS using fasm. I am rewriting in C to make it a little easier for myself. It is not like I am doing this for the first time.

Re: Help with int 0x13 in secondary boot loader.

Posted: Sun Feb 10, 2013 10:01 am
by Antti
Ariethenor wrote:I can't figure out why int 0x13 is producing an error
int 13h sets the carry flag because DAP is not sensible. It is that simple in this case. "DAP on the stack setup" could work if done correctly. I would also make sure that DAP is "nicely aligned" (e.g. 16-byte). However, I do not know whether it is strictly required.

Re: Help with int 0x13 in secondary boot loader.

Posted: Sun Feb 10, 2013 10:07 am
by Ariethenor
you might be on to something about the alignment issue...I remember reading something about that and totally forgot... i am just not quite sure how to make sure the stack is aligned... i will use some brute force for now and determine the issue, if it works then i will post the results and then look for a more elegent solution.

Re: Help with int 0x13 in secondary boot loader.

Posted: Sun Feb 10, 2013 11:34 am
by trinopoty
As Brendan suggested

Code: Select all

es:si:
    db 0x10                ;Size of packet
    db 0x00                ;Reserved
    dw 0x0010              ;Number of blocks to transfer
    dw 0x0010              ;Offset to read data to
    dw 0xFFFF              ;Segment to read data to
    dq 0x????????00000003  ;Starting LBA
Do not load directly to HiMem. Use a buffer and manually copy data to HiMem.
Make sure the DAP is aligned.
Push the full 64bit LBA onto stack.

It works on your MBR does not mean it is flawless. If it really was flawless, you would not be complaining about it not working.

Re: Help with int 0x13 in secondary boot loader.

Posted: Sun Feb 10, 2013 12:22 pm
by Ariethenor
********SOLVED*********

Thanks all, alignment, and not pushing the full quadword (i was getting lucky in my bootloader as the dap was the first, and only, thing on the stack, and the memory prior to the "bottom of stack" happened to initialize to zeros) was the answer. the working code looks like this.
I

Code: Select all


mov bx, sp		;save stack pointer
		mov ax, ss
		mov es, ax		;set up index registers
		mov ds, ax         ; *** had to add this line***

		sub sp, #16        ;*** force stack to allign *** more specifically the structure on the stack
		and sp, #0xFFF0

		push #0x0000
		push #0x0000
		push #0x0000
		push #0x0003     ;*** equals " dq 0x0000 0000 0000 0003 " ***
		push #0xFFFF      ;segment
		push #0x0010     ;offset
		mov di, sp          ;set di to point to seg:offset for far jmp
		push #0x0010     ;number of sectors to read
		push #0x0010     ;size of dap + unused word	

		mov si, sp          ;point si to dap structure on stack
		mov ah, #0x42
		mov	dl, #0x80
		int #0x13
		jc .error             ;error handler (this time it did not invoke... meaning successful HiMem boot)


Re: Help with int 0x13 in secondary boot loader.

Posted: Mon Feb 11, 2013 12:20 am
by Brendan
Hi,
Ariethenor wrote:It's not "stupidity" i have checked(and am currently using) the "dap on stack setup" in my "WORKING" bootloader in the MBR(stage 1 is working flawlessly).
Pushing the DAP on the stack is slower, increases the size of the executable, and makes it much harder to maintain and debug the code. Basically, regardless of whether it works perfectly, or works by accident despite bugs, or doesn't work at all; pushing the DAP on the stack is "stupidity".


Cheers,

Brendan

Re: Help with int 0x13 in secondary boot loader.

Posted: Mon Feb 11, 2013 12:40 am
by egos
You aren't absolutely right. This approach allows to make a code smaller if it is used correctly.

By the way, probably many people know about different behavior of the "push sp" on i8086 and on later processors. I have a question: what behaviour of the "pop sp" on different processors? Is it correct:

Code: Select all

  mov si,sp
  push si
  ...
  pop sp

Re: Help with int 0x13 in secondary boot loader.

Posted: Mon Feb 11, 2013 2:07 am
by Brendan
Hi,
egos wrote:By the way, probably many people know about different behavior of the "push sp" on i8086 and on later processors. I have a question: what behaviour of the "pop sp" on different processors? Is it correct:

Code: Select all

  mov si,sp
  push si
  ...
  pop sp
The "pop sp" instruction is always the reverse of "push sp". The code above would work on newer CPUs (final value of SP is the same as the original value of SP), but fail on 8086 (final value of SP is the original value + 2).


Cheers,

Brendan