Read File on Floppy
Read File on Floppy
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
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
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
- 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
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.
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.
Last edited by Dex on Sun May 25, 2008 6:11 pm, edited 1 time in total.
_Dex: I used your VESA example to go back to Rmode like so:
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
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 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:vst_0201 wrote:_Dex: I used your VESA example to go back to Rmode like so:
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.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 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
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.
Thanks for the keyword, because of that I found v86mm.zip, it should be a great reference. thanks
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?
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?
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"
http://alexfru.chat.ru/epm.html
Take a look at "COFF UTILS" and "OS Development for Dummies - OS Loader"
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
Now you assemble it and then disassemble it again (you could also use a hex-editor).
With nasm you might get something like this
Now copy the opcode's over to a array or something.
Then just jump to it.
This is not the best solution, but ...
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
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
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));
This is not the best solution, but ...
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.
_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.
- Combuster
- Member
- Posts: 9301
- Joined: Wed Oct 18, 2006 3:45 am
- Libera.chat IRC: [com]buster
- Location: On the balcony, where I can actually keep 1½m distance
- Contact:
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)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.
This is exactly what we do in pedigree for interrupt vector handlers on PowerPC.Combuster wrote: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)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.
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