OSDev.org
https://forum.osdev.org/

Assembly + INT 13 AH 42
https://forum.osdev.org/viewtopic.php?f=13&t=25807
Page 1 of 1

Author:  mark3094 [ Fri Sep 14, 2012 11:27 pm ]
Post subject:  Assembly + INT 13 AH 42

I've been working on my Kernel, but I've had to take a step back to look at my bootloader.
I have found out that my bootloader can load a 40KB kernel, but hangs if it tries to load anything over 40KB.

I am using INT 13, AH=42 in real mode to read from a FAT32 partition. I read the kernel to 0000:5500
After the jump to protected mode, the boot loader copies the kernel from 0x5500 to 0x100000

I have found that if the kernel is larger than 40KB, it will not fit into the real mode segment that I am using as the INT 13 buffer.

I have considered using 0550:0000 as the buffer (same physical memory location), which would give me up to 64KB for the Kernel before the segment is full, however, (1) I can't get this to work, and (2) I'll probably hit the limit for this again sometime in the near future.

I figure I can use 0550:0000 as the buffer, and when it gets full, move to the next segment. However, as I've said, I can't get it to work.

This is the DAP I'm using:
Code:
DAP:
   .Size      DB 0x10
   .NULL      DB 0x00
   .Sectors   DW 0x00
   .Offset      DW 0x00
   .Segment   DW 0x00
   .LBA      DD 0x00
   .LBA48      DD 0x00


If I use code like this, it works:
Code:
   mov word [DAP.Segment], 0x0000
   mov word [DAP.Offset], 0x5500


If I change it, I get problems:
Code:
   mov word [DAP.Segment], 0x0550
   mov word [DAP.Offset], 0x0000


I'm using VMWare Player to test with.


Any ideas what I may be doing wrong here?

Author:  Brendan [ Sat Sep 15, 2012 12:03 am ]
Post subject:  Re: Assembly + INT 13 AH 42

Hi,

mark3094 wrote:
I have found that if the kernel is larger than 40KB, it will not fit into the real mode segment that I am using as the INT 13 buffer.


If the kernel is larger than 64 KiB, then you have to split it into multiple reads (where each read is less than 64 KiB). If the kernel is larger than about 600 KiB (e.g. Linux is typically about 5 MiB) then you need a loop that reads (up to) 64 KiB then copies it somewhere else (e.g. to 0x00100000).

Also, for FAT32 the file may be fragmented, and you'd have to deal with that too.

The simplest way would be something like:

Code:
    while(not_all_loadeed) {
        find_next_cluster();
        read_cluster_into_buffer();
        copy_cluster_to_memory_above_0x00100000();
    }


You can improve performance a little by reading more than one cluster at a time (where possible):

Code:
    while(not_all_loadeed) {
        find_next_cluster();
        sectors = find_contiguous_clusters() * sectors_per_cluster;
        if(sectors > buffer_size / bytes_per_sector) {
            sectors = buffer_size / bytes_per_sector;
        }
        read_contiguous_sectors_into_buffer(count);
        copy_sectors_to_memory_above_0x00100000(count);
    }


Also, for the last cluster in the file you may be able to skip some sectors. For example, if a cluster is 2 KiB (4 sectors) and the end of the file only consumes 123 bytes of the last cluster, then you could only load 1 sector of the last cluster.


mark3094 wrote:
Any ideas what I may be doing wrong here?


Not really. 0x0550:0x0000 is the same physical address as 0x0000:0x5500, and there's no other information that we can check. :)


Cheers,

Brendan

Author:  mark3094 [ Sat Sep 15, 2012 1:12 am ]
Post subject:  Re: Assembly + INT 13 AH 42

I have found out why I was having problems with the Segment:Offset, and that is because another function was overwriting some values. I have put in some PUSH and POPs, and solved that part.

However, my Kernel still won't load if it's over 40KB. It seems to hang when INT 13 is called the 11th time (8 sectors per cluster, one read for each cluster, iw 4KB per INT 13).

Any thoughts on how I can troubleshoot this? I tried to read AH after INT is used, but it has already hung, so I can't print it to screen.


EDIT:
I have found that this problem happens as soon as I try to write 4KB to 0550:A000 (0xF500 linear). Does this overwrite reserved memory? As far as I can see I don't have anything loaded there.

Stage 2 is at 0x0500
Kernel (attempting) at 0x5500
Stack at 0x0050
Memory map at 0x3500
FAT/RD/etc at 0x2500

Can't see anything on the Wiki either
http://wiki.osdev.org/Memory_Map_%28x86%29


EDIT 2:
I have also found that I can use INT 13h AH 42h to store sectors in memory addresses up to 0x10499 (linear). As soon as I write to 0x104A0, it hangs or faults. Any idea what this means?

Author:  Brendan [ Sat Sep 15, 2012 4:23 am ]
Post subject:  Re: Assembly + INT 13 AH 42

Hi,

Is this right?
Code:
0x0050 to 0x04FF is Stack
0x0500 to 0x14FF is Stage 2
0x2500 to 0x34FF is FAT/RD/etc
0x3500 to 0x54FF is Memory map
0x5500 to ?????? is kernel


Now look at the first 4 rows of the memory map at http://wiki.osdev.org/Memory_Map_%28x86%29, and rearrange it a little:

Code:
0x0000 to 0x03FF is Real Mode IVT (Interrupt Vector Table)
0x0400 to 0x04FF is BDA (BIOS data area)
0x0500 to ?????? is Conventional memory


Now, let's merge these into one:

Code:
0x0050 to 0x04FF is Real Mode IVT that is TRASHED BY YOUR STACK
0x0400 to 0x04FF is BDA (BIOS data area) that is TRASHED BY YOUR STACK
0x0500 to 0x14FF is Stage 2
0x2500 to 0x34FF is FAT/RD/etc
0x3500 to 0x54FF is Memory map
0x5500 to ?????? is kernel


Cheers,

Brendan

Author:  mark3094 [ Sat Sep 15, 2012 4:33 am ]
Post subject:  Re: Assembly + INT 13 AH 42

Sorry, my mistake, my stack is not at 0x50, it is at 0xFFFF (not sure why I said 0x50... #-o )

Anyway, it appears I am trashing my stack with my Kernel, which is very bad of course.
I tried loading at 0x11000, and it worked just fine.


Thanks again for your help. Much appreciated

Page 1 of 1 All times are UTC - 6 hours
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
http://www.phpbb.com/