Page 1 of 2

Read File on Floppy

Posted: Sun May 25, 2008 2:08 am
by Omega
Hi. I searched the board and all over the net looking for example code in C or NASM that will allow me to seek, locate, open, read, and print the contents of a file on a floppy disk; but I couldn't find any information at all.

Has anyone a link or example code to help me out with this? I would be in Protected mode when this needs to occur, thanks

Posted: Sun May 25, 2008 3:48 am
by svdmeer
You need two things:
- Software to read sectors
- Software that can search and read files with fileinformation. That software calls the routines to read sectors.

The way you implement it, depends on the place where you use the code.
In a bootsector, you read sectors with int 13h. Write a function ReadSector. There is enough info about int 13h-functions.

In a kernel, it's better to design the way drivers work and write a disk driver. In protectedmode you can't use 13h (without v86 mode or mode switching), but you can write a driver for the hardware. Just search, enough information. But it only reads sectors.

Sectorreading and filefinding/reading in one piece of code is inefficient, because every supported filesystem contains hardware-code and most OS-es work with different filesystems.

The way you find files and read the contents depends on the filesystem. The FAT filesystem is simple and about FAT is much information available.

There are many sector-reading examples!
Filereading is harder to find, but when you are able to read sectors it woudn't be hard to search and read files in a FAT filesystem when you get some documentation about it

Posted: Sun May 25, 2008 10:55 am
by Dex
Yes i wrote such a demo, it boots to PMode and demo fdd functions from pmode.
Its written in fasm very similar to nasm.
The pmode part is a very early DexOS kernel.
See here:
http://dex4u.com/demos/FddDemo.zip

PS: it also works fine in emulators.

Posted: Sun May 25, 2008 2:32 pm
by Omega
_Dex: Great example. Thanks for the PUSH. ;)

Posted: Sun May 25, 2008 11:10 pm
by Omega
_Dex: I used your VESA example to go back to Rmode like so:

Code: Select all

;Switches from Pmode to Rmode and Back
;example by Craig Bamford (Dex).  
[BITS 32]
[SECTION .data]
	GLOBAL _do_rm_switch
[SECTION .text]
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                      Headed back to Real mode from Pmode           
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
_do_rm_switch:
    cli
	
	mov   bx,[RealModeCS]		       ; push real-mode CS:IP
	push  bx
	lea   bx,[do_rm]
	push  bx
	
	; clear PE [protected mode enable] bit and return to real mode
	mov   eax,cr0
	and   al,0xFE
	mov   cr0,eax
	retf				       ; jumps to do_rm

;*******************
; 16-bit real mode again 
;*******************
do_rm: 
	mov   ax,cs			       ; restore real-mode segment register values
	mov   ds,ax
	mov   ss,ax
	nop
	mov   es,ax
	mov   fs,ax
	mov   gs,ax

	lidt  [ridtr]			       ; point to real-mode IDTR

	push  cs
	pop   ds
	push  ds
	pop   es
	mov   ax,0xB800
	mov   es,ax
       
	sti				       ; re-enable interrupts
	
;*******************
;  16-bit real mode int's   
;*******************
	mov   ax,0x0003   
	int   10h      
	
;*******************
;  real mode int's end      
;*******************
	cli				      ; Disable interrupts,
	lgdt  [gdtr]			      ; Load the GDTR with the base address and limit of the GDT

	;DO DISK READ FILE HERE
	
	jmp $ ;halt for now

;*******************
;  32-bit protected  mode
;*******************
do_pm_switch:
	mov   eax,cr0			      ; Set the PE [protected mode enable] bit in register CR0 
	or    al,1
	mov   cr0,eax
	
	sti
	
	mov   ax,sys_data
	mov   ds,ax
	mov   ss,ax
	nop
	mov   es,ax
	mov   fs,ax
	mov   gs,ax
	
	mov   ax,8h
	mov   es,ax
     
	popad
	
	ret    
	
	;*********************
	; Configurations Area, No Edit
	;*********************
	
	gdtr:	dw gdt_end - gdt - 1		   ; GDT limit
			dd gdt				   ; (GDT base gets set above)

	gdt:					   	   ; Address for the gdt 
			dw 0				   ; limit 15:0    (0h) Null Segment
			dw 0				   ; base 15:0
			db 0				   ; base 23:16
			db 0				   ; type
			db 0				   ; limit 19:16, flags
			db 0				   ; base 31:24

	linear_sel_1:	
			dw 0xFFFF			   ; (8h) linear Data segment, read/write, expand down
			dw 0					   
			db 0
			db 10010010b				   
			db 11001111b				  
			db 0

	sys_code_1:				   ; (10h) Code segment, read/execute, nonconforming
			dw 0FFFFh
			dw 0
			db 0
			db 10011010b
			db 11001111b
			db 0

	sys_data_1:				   ; (18h) Data segment, read/write, expand down
			dw 0FFFFh
			dw 0
			db 0
			db 10010010b
			db 11001111b
			db 0

	Real_code_1:				   ; (20h) Real mode code segment
			dw 0xFFFF
			dw 0						 
			db 0
			db 10011010b						  
			db 0						  
			db 0

	Real_data_1:				   ; (28h) Real mode data segment
			dw 0xFFFF
			dw 0						  
			db 0
			db 10010010b						  
			db 0						  
			db 0

	gdt_end:				   ; Used to calculate the size of the GDT
	
	linear_sel equ	linear_sel_1-gdt
	sys_code   equ	sys_code_1-gdt
	sys_data   equ	sys_data_1-gdt	  
	Real_code  equ	Real_code_1-gdt
	Real_data  equ	Real_data_1-gdt
	
	RealModeCS:
			dw 0

	ridtr:	
			dw 0xFFFF			    ; limit=0xFFFF
			dd 0				    ; base=0
	
	sMessage db "We have arrived in Real Mode!",13,10,0
I assemble it with NASM using the COFF format and that made it impossible to use the relocatable 16 bit instructions in your original demo, so I cut that and tried to replace some stuff with 32 Bit instructions but I am not sure if it is working because I couldn't get anything to work, such as your print functions.

I know it at least makes it to the jmp $ instruction because the application hangs as expected when the code is called from my C code, but I am not sure if I am in Rmode or Pmode. Just using this code makes my OS unstable (which I am 100% certain it is my fault not the demo), so I was wondering if you (or someone else) could look at the code above and tell me if you see anything I might change that I overlooked?

I also wonder if I need to enable A20 and re-do the GDT after I go and come back from Rmode?

I can't figure this one out, thanks

Posted: Mon May 26, 2008 12:49 am
by svdmeer
vst_0201 wrote:_Dex: I used your VESA example to go back to Rmode like so:

Code: Select all

;Switches from Pmode to Rmode and Back
;example by Craig Bamford (Dex).  
[BITS 32]
[SECTION .data]
	GLOBAL _do_rm_switch
[SECTION .text]
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
;                      Headed back to Real mode from Pmode           
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
_do_rm_switch:
    cli
	
	mov   bx,[RealModeCS]		       ; push real-mode CS:IP
	push  bx
	lea   bx,[do_rm]
	push  bx
	
	; clear PE [protected mode enable] bit and return to real mode
	mov   eax,cr0
	and   al,0xFE
	mov   cr0,eax
	retf				       ; jumps to do_rm

;*******************
; 16-bit real mode again 
;*******************
do_rm: 
	mov   ax,cs			       ; restore real-mode segment register values
	mov   ds,ax
	mov   ss,ax
	nop
	mov   es,ax
	mov   fs,ax
	mov   gs,ax

	lidt  [ridtr]			       ; point to real-mode IDTR

	push  cs
	pop   ds
	push  ds
	pop   es
	mov   ax,0xB800
	mov   es,ax
       
	sti				       ; re-enable interrupts
	
;*******************
;  16-bit real mode int's   
;*******************
	mov   ax,0x0003   
	int   10h      
	
;*******************
;  real mode int's end      
;*******************
	cli				      ; Disable interrupts,
	lgdt  [gdtr]			      ; Load the GDTR with the base address and limit of the GDT

	;DO DISK READ FILE HERE
	
	jmp $ ;halt for now

;*******************
;  32-bit protected  mode
;*******************
do_pm_switch:
	mov   eax,cr0			      ; Set the PE [protected mode enable] bit in register CR0 
	or    al,1
	mov   cr0,eax
	
	sti
	
	mov   ax,sys_data
	mov   ds,ax
	mov   ss,ax
	nop
	mov   es,ax
	mov   fs,ax
	mov   gs,ax
	
	mov   ax,8h
	mov   es,ax
     
	popad
	
	ret    
	
	;*********************
	; Configurations Area, No Edit
	;*********************
	
	gdtr:	dw gdt_end - gdt - 1		   ; GDT limit
			dd gdt				   ; (GDT base gets set above)

	gdt:					   	   ; Address for the gdt 
			dw 0				   ; limit 15:0    (0h) Null Segment
			dw 0				   ; base 15:0
			db 0				   ; base 23:16
			db 0				   ; type
			db 0				   ; limit 19:16, flags
			db 0				   ; base 31:24

	linear_sel_1:	
			dw 0xFFFF			   ; (8h) linear Data segment, read/write, expand down
			dw 0					   
			db 0
			db 10010010b				   
			db 11001111b				  
			db 0

	sys_code_1:				   ; (10h) Code segment, read/execute, nonconforming
			dw 0FFFFh
			dw 0
			db 0
			db 10011010b
			db 11001111b
			db 0

	sys_data_1:				   ; (18h) Data segment, read/write, expand down
			dw 0FFFFh
			dw 0
			db 0
			db 10010010b
			db 11001111b
			db 0

	Real_code_1:				   ; (20h) Real mode code segment
			dw 0xFFFF
			dw 0						 
			db 0
			db 10011010b						  
			db 0						  
			db 0

	Real_data_1:				   ; (28h) Real mode data segment
			dw 0xFFFF
			dw 0						  
			db 0
			db 10010010b						  
			db 0						  
			db 0

	gdt_end:				   ; Used to calculate the size of the GDT
	
	linear_sel equ	linear_sel_1-gdt
	sys_code   equ	sys_code_1-gdt
	sys_data   equ	sys_data_1-gdt	  
	Real_code  equ	Real_code_1-gdt
	Real_data  equ	Real_data_1-gdt
	
	RealModeCS:
			dw 0

	ridtr:	
			dw 0xFFFF			    ; limit=0xFFFF
			dd 0				    ; base=0
	
	sMessage db "We have arrived in Real Mode!",13,10,0
I assemble it with NASM using the COFF format and that made it impossible to use the relocatable 16 bit instructions in your original demo, so I cut that and tried to replace some stuff with 32 Bit instructions but I am not sure if it is working because I couldn't get anything to work, such as your print functions.

I know it at least makes it to the jmp $ instruction because the application hangs as expected when the code is called from my C code, but I am not sure if I am in Rmode or Pmode. Just using this code makes my OS unstable (which I am 100% certain it is my fault not the demo), so I was wondering if you (or someone else) could look at the code above and tell me if you see anything I might change that I overlooked?

I also wonder if I need to enable A20 and re-do the GDT after I go and come back from Rmode?

I can't figure this one out, thanks
What's better for calling a BIOS-function from protected mode:
1. Switch to realmode, calling BIOS, and switch back to protectedmode (like the example)
2. Or: Make a v86 mode task and call the BIOS from v86 mode.

Posted: Mon May 26, 2008 2:12 am
by Omega
Thanks for the keyword, because of that I found v86mm.zip, it should be a great reference. thanks

Posted: Tue May 27, 2008 2:49 am
by Omega
Hi. I never thought the v86 mode would be so involved to setup. I started condensing the project to 5 files (instead of like 20), but I am running into trouble and I know I will encounter this again down the line, so i better stop ignoring this issue; which is:

I need to produce a COFF object but in the ASM source it leaves Pmode using 16 BIT instructions, and so does every other tutorial/code I have looked at.

COFF does not allow for 16bit relocatable instructions, so you see my dilemma? Is there anything that I can do to work around this, yet still using COFF; maybe a switch or technique?

I can not place this global code in my my loader because I am assembling that as a BIN file, which I may be wrong for saying this, but I think you can not use globals in the BIN format. I am completely basing this assumption on failed experience and a vague recollection of the NASM manual.

I would hope that there might be a pure 32-BIT way of leaving Pmode for V86 so that I can use the BIOS INTs to read a floppy disk. Any help?

Posted: Tue May 27, 2008 7:00 am
by Dex
There is some good stuff on this web site, that may help ?.
http://alexfru.chat.ru/epm.html

Take a look at "COFF UTILS" and "OS Development for Dummies - OS Loader"

Posted: Tue May 27, 2008 7:52 am
by Combuster
the magic keyword is "position independent code"

Posted: Tue May 27, 2008 8:44 am
by cyr1x
Or another way (which is very tricky) would be "op-coding".
To make it easier you write your code, assemble it, then disasemble(that is: get the opcode's) it again and copy the opcode's into a table. Then you "memcpy" the table to the specific memory location.

Let's say you have an ASM file which looks like this

Code: Select all

ORG 0x1000

	jmp start

somedata:
	dd 0
	
start:
	jmp start 
Now you assemble it and then disassemble it again (you could also use a hex-editor).
With nasm you might get something like this

Code: Select all

00000000  E90400            jmp 0x7
00000003  0000              add [bx+si],al   
00000005  0000              add [bx+si],al
00000007  EBFE              jmp short 0x7
Now copy the opcode's over to a array or something.

Code: Select all

char some_code [] =
{
 0xE9, 0x04, 0x00,  // jmp 0x7
 0x00, 0x00,
 0x00, 0x00,
 0xEB, 0xFE            // jmp short 0x7
}

then we need to memcpy the code:
memcpy(/* here comes the value of "ORG" */ 
  (char*) 0x1000, some_code, sizeof(some_code));
Then just jump to it.

This is not the best solution, but ...

Posted: Tue May 27, 2008 3:18 pm
by Omega
_Dex: Thanks for the link. I will check it out immediately.

_ComBuster: Thanks for the keyword, I will start searching google.

_cyr1x: Nice. Now that's my kind of suggestion. ;)

Posted: Wed May 28, 2008 9:18 pm
by Omega
Update:

_Dex: Thanks for the links, however it seems that they will not solve my problem, because I must first have an .o file in order to convert it to .com, and since I cannot force NASM to assemble my code, then I can not produce an .o file to convert.

_Combuster: Great keyword. I found lots of stuff to read through. I am sure this advice will serve me better once I start improving the OS at a later date.

_cyr1x: Still loving your suggestion, but as you said, you are right op-coding something this complex would be insanity. Could probably grep the opcode to make it easier... nah, I'm going to do it the right way... thanks anyway: I saved this page to my HD for reference.

Posted: Thu May 29, 2008 5:30 am
by Combuster
vst_0201 wrote:_cyr1x: Still loving your suggestion, but as you said, you are right op-coding something this complex would be insanity. Could probably grep the opcode to make it easier... nah, I'm going to do it the right way... thanks anyway: I saved this page to my HD for reference.
My guess is that the final solution is somewhere inbetween - Cyr1x suggests you to put instructions somewhere and then copy them. You could just as well use the assembler and put some code in the data section for a similar effect - At least it is easier to debug that way. Example (look for .mpbootstub)

Posted: Thu May 29, 2008 6:33 am
by JamesM
Combuster wrote:
vst_0201 wrote:_cyr1x: Still loving your suggestion, but as you said, you are right op-coding something this complex would be insanity. Could probably grep the opcode to make it easier... nah, I'm going to do it the right way... thanks anyway: I saved this page to my HD for reference.
My guess is that the final solution is somewhere inbetween - Cyr1x suggests you to put instructions somewhere and then copy them. You could just as well use the assembler and put some code in the data section for a similar effect - At least it is easier to debug that way. Example (look for .mpbootstub)
This is exactly what we do in pedigree for interrupt vector handlers on PowerPC.

On MIPS we fully op-code - we generate a sequence of "lui","ori","j" and "nop" for every interrupt and memcpy them in place.

On PPC the interrupt handlers have to be a little more complex before they jump to the common stub, so we write them in assembly and link them somewhere (anywhere) in our kernel, making sure to use only opcodes that are not absolutely addressed - i.e. position independent, then memcpy them over to the correct location.

Cheers,

James