Skip to contentSkip to conversation

Searching for string problems

DISCUSSION Andrew Kirilenko 3 participants 14 messages Apr 23, 2003

lore
Share & tools
lore
#0 lore raw

Hello!

OK. I've solved my problems with storing data (problem was with improper DS setup - thanks to all, pointed me to this). And now I should perform a search in the BIOS are for particular string (version of BIOS ). Here is my code (it's located in the setup.S, so executes in the real mode, not ptotected).

-->
start_of_setup:
jmp cl_start
cl_id_str: .string "BIOS 0.1"
cl_start:

        movb    $0, %al
        movw    $0xe000, %bx
cl_compare:
        incw    %bx
        movw    %bx, %si
        cmpw    $0xefff, %si
        je      cl_compare_done
        movw    $cl_id_str, %di
cl_compare_inner:
        movb    (%di), %ah
        cmpb    $0, %ah
        je      cl_compare_done_good
        cmpb    (%si), %ah
        jne     cl_compare
        incw    %si
        incw    %di
        jmp     cl_compare_inner
cl_compare_done_good:
        movb    $1, %al

cl_compare_done:
<--

This code don't work... I'm sure, that's because of inproper registers setup (or maybe address range is wrong). Please help me.

Best regards,
Andrew.

#1 lore raw
Quoted 31 lines · Andrew Kirilenko

Hello!

OK. I've solved my problems with storing data (problem was with improper DS setup - thanks to all, pointed me to this). And now I should perform a search in the BIOS are for particular string (version of BIOS ). Here is my code (it's located in the setup.S, so executes in the real mode, not ptotected).

-->
start_of_setup:
jmp cl_start
cl_id_str: .string "BIOS 0.1"
cl_start:

        movb    $0, %al
        movw    $0xe000, %bx
cl_compare:
        incw    %bx
        movw    %bx, %si
        cmpw    $0xefff, %si
        je      cl_compare_done
        movw    $cl_id_str, %di
cl_compare_inner:
        movb    (%di), %ah
        cmpb    $0, %ah
        je      cl_compare_done_good
        cmpb    (%si), %ah
        jne     cl_compare
        incw    %si
        incw    %di
        jmp     cl_compare_inner
cl_compare_done_good:
        movb    $1, %al
Quoted 6 lines

cl_compare_done:
<--

This code don't work... I'm sure, that's because of inproper registers setup (or maybe address range is wrong). Please help me.

Hmm, maybe you should just learn assembly off-line.

cl_id_str: .string "BIOS 0.1"
cl_id_end:

scan: movw %cs, %ax # Get code-segment
movw %ax, %ds # Set into data segment
movw %ax, %es # Set into extra segment CS=ES=DS
cld # Compare forwards
movw $cl_id_str, %si # String to compare
movw $were_in_the_bios_you_expect_to_find_it, %di
movw $cl_id_end, %cx # Offset to this label
subw %si, %cx # CX = length of string
decw %cx # Don't compare \0
repz cmpsb # Continue as long as they compare
jz found # String was found
# Not found here
found:

If you need to search the whole BIOS for that string, you need to set up an outer loop using an unused register which starts at the offset of the BIOS and increments by one byte everytime you can't find the string. This value gets put into %di, instead of the absolute number specified above.

Like:

scan: movw %cs, %ax

	movw	%ax, %ds
	movw	%ax, %es
	movw	$where_in_BIOS_to_start, %bx
	cld

1: movw $cl_id_str, %si # Offset of search string
movw $cl_id_end, %cx # Offset of string end + 1
subw %si, %cx # String length
decw %cx # Don't look for the \0
movw %bx, %di # ES:DI = where to look
repz cmpsb # Loop while the same
jz found # Found the string
incb %bx # Next starting offset
cmpb $_BIOS_END, %bx # Check for limit
jb 1b # Continue
never_found_anywhere:

found:

Note that the gas .string macro puts in a '\0', assuming it's a 'C' string. You don't want to put that in the comparison. That's why you search one-less than the allocation length. There are predefined macros available for 'len', also.

Cheers,
Dick Johnson
Penguin : Linux version 2.4.20 on an i686 machine (797.90 BogoMips). Why is the government concerned about the lunatic fringe? Think about it.

#2 lore raw

Hello!

Quoted 25 lines

If you need to search the whole BIOS for that string, you need to set up an outer loop using an unused register which starts at the offset of the BIOS and increments by one byte everytime you can't find the string. This value gets put into %di, instead of the absolute number specified above.

Like:

scan: movw %cs, %ax

	movw	%ax, %ds
	movw	%ax, %es
	movw	$where_in_BIOS_to_start, %bx
	cld

1: movw $cl_id_str, %si # Offset of search string
movw $cl_id_end, %cx # Offset of string end + 1
subw %si, %cx # String length
decw %cx # Don't look for the \0
movw %bx, %di # ES:DI = where to look
repz cmpsb # Loop while the same
jz found # Found the string
incb %bx # Next starting offset
cmpb $_BIOS_END, %bx # Check for limit
jb 1b # Continue
never_found_anywhere:

Quoted 1 line

found:

I've written something similar to this before - and it wont' work, so I've reimplemented it. The problem is, that I don't know how to set ES properly. I only know, that BIOS data (and code) is located in 0xe000..0xf000 (real address).

Best regards,
Andrew.

#3 lore raw
Quoted 27 lines · Andrew Kirilenko

Hello!

Quoted 25 lines

If you need to search the whole BIOS for that string, you need to set up an outer loop using an unused register which starts at the offset of the BIOS and increments by one byte everytime you can't find the string. This value gets put into %di, instead of the absolute number specified above.

Like:

scan: movw %cs, %ax

	movw	%ax, %ds
	movw	%ax, %es
	movw	$where_in_BIOS_to_start, %bx
	cld

1: movw $cl_id_str, %si # Offset of search string
movw $cl_id_end, %cx # Offset of string end + 1
subw %si, %cx # String length
decw %cx # Don't look for the \0
movw %bx, %di # ES:DI = where to look
repz cmpsb # Loop while the same
jz found # Found the string
incb %bx # Next starting offset
cmpb $_BIOS_END, %bx # Check for limit
jb 1b # Continue
never_found_anywhere:

Quoted 7 lines
Quoted 1 line

found:

I've written something similar to this before - and it wont' work, so I've reimplemented it. The problem is, that I don't know how to set ES properly. I only know, that BIOS data (and code) is located in 0xe000..0xf000 (real address).

Yeah. So. I set ES and DS to be exactly where CS is. This means that if your &!)(^$&_ code executes it will work. So, instead of trying it, you just blindly ignore it and state that it won't work.

Bullshit. I do this for a living and I gave you some valuable time which you rejected out-of-hand. Have fun.

Cheers,
Dick Johnson
Penguin : Linux version 2.4.20 on an i686 machine (797.90 BogoMips). Why is the government concerned about the lunatic fringe? Think about it.

#4 lore raw

Hello!

Quoted 24 lines
Quoted 17 lines
Quoted 17 lines

scan: movw %cs, %ax

	movw	%ax, %ds
	movw	%ax, %es
	movw	$where_in_BIOS_to_start, %bx
	cld

1: movw $cl_id_str, %si # Offset of search string
movw $cl_id_end, %cx # Offset of string end + 1
subw %si, %cx # String length
decw %cx # Don't look for the \0
movw %bx, %di # ES:DI = where to look
repz cmpsb # Loop while the same
jz found # Found the string
incb %bx # Next starting offset
cmpb $_BIOS_END, %bx # Check for limit
jb 1b # Continue
never_found_anywhere:

Quoted 6 lines
Quoted 1 line

found:

I've written something similar to this before - and it wont' work, so I've reimplemented it. The problem is, that I don't know how to set ES properly. I only know, that BIOS data (and code) is located in 0xe000..0xf000 (real address).

Quoted 6 lines

Yeah. So. I set ES and DS to be exactly where CS is. This means that if your &!)(^$&_ code executes it will work. So, instead of trying it, you just blindly ignore it and state that it won't work.

Bullshit. I do this for a living and I gave you some valuable time which you rejected out-of-hand. Have fun.

Of course, I've tried your code as well - the same result! Sorry, if you haven't understand me.

The problem is, that I don't know where this BIOS code is relative to current code segment (CS). I only know (hope), that it should be in 0x0:0xe000...0x0:0xf000. I have tried to set ES to 0 (xor %ax, %ax; mov %ax, %es) - no luck as well. BTW, strings /dev/mem | grep "REQUESTED STRING" founds it perfectly...

Best regards,
Andrew.

#5 lore raw
Quoted 42 lines · Andrew Kirilenko

Hello!

Quoted 24 lines
Quoted 17 lines
Quoted 17 lines

scan: movw %cs, %ax

	movw	%ax, %ds
	movw	%ax, %es
	movw	$where_in_BIOS_to_start, %bx
	cld

1: movw $cl_id_str, %si # Offset of search string
movw $cl_id_end, %cx # Offset of string end + 1
subw %si, %cx # String length
decw %cx # Don't look for the \0
movw %bx, %di # ES:DI = where to look
repz cmpsb # Loop while the same
jz found # Found the string
incw %bx # Next starting offset
cmpw $_BIOS_END, %bx # Check for limit
jb 1b # Continue
never_found_anywhere:

Quoted 6 lines
Quoted 1 line

found:

I've written something similar to this before - and it wont' work, so I've reimplemented it. The problem is, that I don't know how to set ES properly. I only know, that BIOS data (and code) is located in 0xe000..0xf000 (real address).

Quoted 6 lines

Yeah. So. I set ES and DS to be exactly where CS is. This means that if your &!)(^$&_ code executes it will work. So, instead of trying it, you just blindly ignore it and state that it won't work.

Bullshit. I do this for a living and I gave you some valuable time which you rejected out-of-hand. Have fun.

Of course, I've tried your code as well - the same result! Sorry, if you haven't understand me.

The problem is, that I don't know where this BIOS code is relative to current code segment (CS). I only know (hope), that it should be in 0x0:0xe000...0x0:0xf000. I have tried to set ES to 0 (xor %ax, %ax; mov %ax, %es) - no luck as well. BTW, strings /dev/mem | grep "REQUESTED STRING" founds it perfectly...

Quoted 3 lines

Best regards,
Andrew.
-

The bios is in segment 0xf000. You set ES to that area. ES:DI will start at 0 if bx=0 in the code shown. The BIOS is only 64k. This means that where bx is being incremented (it should be incw, not incb). It would generate an assembly error with incb which is why I knew you didn't even try it. -- you just jnz back to 1b, without any additional test.

Cheers,
Dick Johnson
Penguin : Linux version 2.4.20 on an i686 machine (797.90 BogoMips). Why is the government concerned about the lunatic fringe? Think about it.

#6 lore raw

Hello!

Quoted 25 lines
Quoted 21 lines
Quoted 11 lines
Quoted 4 lines

I've written something similar to this before - and it wont' work, so I've reimplemented it. The problem is, that I don't know how to set ES properly. I only know, that BIOS data (and code) is located in 0xe000..0xf000 (real address).

Yeah. So. I set ES and DS to be exactly where CS is. This means that if your &!)(^$&_ code executes it will work. So, instead of trying it, you just blindly ignore it and state that it won't work.

Bullshit. I do this for a living and I gave you some valuable time which you rejected out-of-hand. Have fun.

Of course, I've tried your code as well - the same result! Sorry, if you haven't understand me.

The problem is, that I don't know where this BIOS code is relative to current code segment (CS). I only know (hope), that it should be in 0x0:0xe000...0x0:0xf000. I have tried to set ES to 0 (xor %ax, %ax; mov %ax, %es) - no luck as well. BTW, strings /dev/mem | grep "REQUESTED STRING" founds it perfectly...

Quoted 3 lines

Best regards,
Andrew.
-

Quoted 6 lines

The bios is in segment 0xf000. You set ES to that area. ES:DI will start at 0 if bx=0 in the code shown. The BIOS is only 64k. This means that where bx is being incremented (it should be incw, not incb). It would generate an assembly error with incb which is why I knew you didn't even try it. -- you just jnz back to 1b, without any additional test.

1. How to set ES to this area? "movw $0xf000, %ax ; movw %ax, %es" will be enough?
2. Is the are really starts from 0xf000? Or 0xe000?
3. I'm smart enough to correct "incb %bx" to "incw %bx" ;)

Best regards,
Andrew.

#7 lore raw

On Wed, 23 Apr 2003 22:00:20 +0300 Andrew Kirilenko <[email protected]> wrote:

| Hello!
| 
| > > > > I've written something similar to this before - and it wont' work, so
| > > > > I've reimplemented it. The problem is, that I don't know how to set
| > > > > ES properly. I only know, that BIOS data (and code) is located in
| > > > > 0xe000..0xf000 (real address).
| > > >
| > > > Yeah. So. I set ES and DS to be exactly where CS is. This means that
| > > > if your &!)(^$&_ code executes it will work. So, instead of trying
| > > > it, you just blindly ignore it and state that it won't work.
| > > >
| > > > Bullshit. I do this for a living and I gave you some valuable time
| > > > which you rejected out-of-hand. Have fun.
| > >
| > > Of course, I've tried your code as well - the same result! Sorry, if you
| > > haven't understand me.
| > >
| > > The problem is, that I don't know where this BIOS code is relative to
| > > current code segment (CS). I only know (hope), that it should be in
| > > 0x0:0xe000...0x0:0xf000. I have tried to set ES to 0 (xor %ax, %ax; mov
| > > %ax, %es) - no luck as well. BTW, `strings /dev/mem | grep "REQUESTED
| > > STRING"` founds it perfectly...
| > >
| > > Best regards,
| > > Andrew.
| > > -
| >
| > The bios is in segment 0xf000. You set ES to that area. ES:DI will
| > start at 0 if bx=0 in the code shown. The BIOS is only 64k.
| > This means that where bx is being incremented (it should be incw, not
| > incb). It would generate an assembly error with incb which is why
| > I knew you didn't even try it.  -- you just jnz back to 1b, without
| > any additional test.
| 
| 1. How to set ES to this area? "movw $0xf000, %ax ; movw %ax, %es" will be 
| enough?

That should do it.

| 2. Is the are really starts from 0xf000? Or 0xe000?

Most current ones that I know of are 128 KB, so start at segment 0xe000:0 thru 0xf000:ffff.
Just boot DOS, run debug, and display those areas. That will answer it for you. :)

| 3. I'm smart enough to correct "incb %bx" to "incw %bx" ;)

--
~Randy

#8 lore raw
In reply to Andrew Kirilenko
Quoted 34 lines · Andrew Kirilenko

Hello!

Quoted 25 lines
Quoted 21 lines
Quoted 11 lines
Quoted 4 lines

I've written something similar to this before - and it wont' work, so I've reimplemented it. The problem is, that I don't know how to set ES properly. I only know, that BIOS data (and code) is located in 0xe000..0xf000 (real address).

Yeah. So. I set ES and DS to be exactly where CS is. This means that if your &!)(^$&_ code executes it will work. So, instead of trying it, you just blindly ignore it and state that it won't work.

Bullshit. I do this for a living and I gave you some valuable time which you rejected out-of-hand. Have fun.

Of course, I've tried your code as well - the same result! Sorry, if you haven't understand me.

The problem is, that I don't know where this BIOS code is relative to current code segment (CS). I only know (hope), that it should be in 0x0:0xe000...0x0:0xf000. I have tried to set ES to 0 (xor %ax, %ax; mov %ax, %es) - no luck as well. BTW, strings /dev/mem | grep "REQUESTED STRING" founds it perfectly...

Quoted 3 lines

Best regards,
Andrew.
-

Quoted 6 lines

The bios is in segment 0xf000. You set ES to that area. ES:DI will start at 0 if bx=0 in the code shown. The BIOS is only 64k. This means that where bx is being incremented (it should be incw, not incb). It would generate an assembly error with incb which is why I knew you didn't even try it. -- you just jnz back to 1b, without any additional test.

Quoted 2 lines

1. How to set ES to this area? "movw $0xf000, %ax ; movw %ax, %es" will be enough?

Yes.

Quoted 1 line

2. Is the are really starts from 0xf000? Or 0xe000?

The stuff used to boot, usually the relocated and shadowed BIOS ROM, always exists at absolute address 0x000f0000. Since a 'segment' is a 16-byte thing, the appropriate segment is 0xf000. The code must be there because the 'reset-vector' is (must be) 16 bytes from the end of this segment. That's the code that first gets control during the startup sequence.

The BIOS setup menus and other stuff is (typically) put down at 0xe000. However many new BIOS uncompress some stuff from NVRAM and put it anywhere they want because they 'own' all the RAM in the system until an attempted boot.

Quoted 4 lines

3. I'm smart enough to correct "incb %bx" to "incw %bx" ;)

Best regards,
Andrew.

If you use the string search primative I show, it will work.

Cheers,
Dick Johnson
Penguin : Linux version 2.4.20 on an i686 machine (797.90 BogoMips). Why is the government concerned about the lunatic fringe? Think about it.

#9 lore raw

Hello!

Big thanks to all of you. Now I'm starting to understand how it's working. Here is current version of my code:

-->
jmp cl_start
cl_id_str: .string "STRING"
cl_start:
cld
movw %cs, %ax
movw %ax, %ds
movw $0xe000, %ax
movw %ax, %es
movb $0, %al
xor %bx, %bx # start of segment
cl_compare:

        movw    $cl_id_str, %si
        movw    $cl_start, %cx
        subw    %si, %cx
        decw    %cx
        movw    %bx, %di
        repz    cmpsb
        je      cl_compare_done_good
        incw    %bx
        cmpw    $0xffff, %bx  # are we at the end of segment
        je      cl_compare_done
        jmp     cl_compare
cl_compare_done_good:
       movb $1, %al

cl_compare_done:
<--

And this code won't work as well :(

Unfortunately, I can't start DOS and check, cause there is no video and keyboard controller on that PC.

Best reagrds,
Andrew.

#10 lore raw
Quoted 33 lines · Andrew Kirilenko

Hello!

Big thanks to all of you. Now I'm starting to understand how it's working. Here is current version of my code:

-->
jmp cl_start
cl_id_str: .string "STRING"
cl_start:
cld
movw %cs, %ax
movw %ax, %ds
movw $0xe000, %ax
movw %ax, %es
movb $0, %al
xor %bx, %bx # start of segment
cl_compare:

        movw    $cl_id_str, %si
        movw    $cl_start, %cx
        subw    %si, %cx
        decw    %cx
        movw    %bx, %di
        repz    cmpsb
        je      cl_compare_done_good
        incw    %bx
        cmpw    $0xffff, %bx  # are we at the end of segment
        je      cl_compare_done
        jmp     cl_compare
cl_compare_done_good:
       movb $1, %al

cl_compare_done:
<--

Quoted 7 lines

And this code won't work as well :(

Unfortunately, I can't start DOS and check, cause there is no video and keyboard controller on that PC.

Best reagrds,
Andrew.

Change this:

         movw    $0xe000, %ax

To:

         movw    $0xf000, %ax

... like I told you. The BIOS ROM contents, the stuff that has the serial number _must_ start where I told you.

Cheers,
Dick Johnson
Penguin : Linux version 2.4.20 on an i686 machine (797.90 BogoMips). Why is the government concerned about the lunatic fringe? Think about it.

#11 lore raw

Hello!

Quoted 9 lines
Quoted 6 lines

And this code won't work as well :(

Unfortunately, I can't start DOS and check, cause there is no video and keyboard controller on that PC.

Change this:

Quoted 7 lines
         movw    $0xe000, %ax

To:

         movw    $0xf000, %ax

... like I told you. The BIOS ROM contents, the stuff that has the serial number _must_ start where I told you.

Already solved the problem. AX was overwritten, before storing it's value (0 or 1) into memory. The most stupid mistake, I've seen last year. 20 hours of kernel programming without breaks isn't really good.

Thanks too all of you, once again. You really saved my life.

Best regards,
Andrew.

#12 lore raw
In reply to Andrew Kirilenko

On Wed, 23 Apr 2003 22:48:35 +0300 Andrew Kirilenko <[email protected]> wrote:

| Hello!
| 
| Big thanks to all of you. Now I'm starting to understand how it's working. 
| Here is current version of my code:
| 
| -->
|        jmp         cl_start
| cl_id_str:      .string "STRING"
| cl_start:
|         cld
|         movw    %cs, %ax
|         movw    %ax, %ds
|         movw    $0xe000, %ax
|         movw    %ax, %es
|         movb    $0, %al
|         xor         %bx, %bx  # start of segment
| cl_compare:
|         movw    $cl_id_str, %si
|         movw    $cl_start, %cx
|         subw    %si, %cx
|         decw    %cx
|         movw    %bx, %di
|         repz    cmpsb
|         je      cl_compare_done_good
|         incw    %bx
|         cmpw    $0xffff, %bx  # are we at the end of segment
|         je      cl_compare_done
|         jmp     cl_compare
| cl_compare_done_good:
|        movb $1, %al
| cl_compare_done:
# here the code needs to do something like this,
# to check the second 64 KB block of memory:
	movw	%es, %bx
	cmpw	%bx, $0xe000
	je	all_done
	movw	$0xf000, %bx
	movw	%bx, %es
	xor	%bx, %bx
	jmp	cl_compare
| <--
| 
| And this code won't work as well :(

Do you understand x86 real-mode segment registers? They can only address a "segment" of 64 KB (roughly).

| Unfortunately, I can't start DOS and check, cause there is no video and | keyboard controller on that PC.

oh yes.

--
~Randy

#13 lore raw
In reply to Andrew Kirilenko

On Wed, 23 Apr 2003 21:25:22 +0300 Andrew Kirilenko <[email protected]> wrote:

| Hello!
| 
| > > > scan:	movw	%cs, %ax
| > > > 	movw	%ax, %ds
| > > > 	movw	%ax, %es
| > > > 	movw	$where_in_BIOS_to_start, %bx
| > > > 	cld
| > > > 1:	movw	$cl_id_str, %si		# Offset of search string
| > > > 	movw	$cl_id_end, %cx		# Offset of string end + 1
| > > > 	subw	%si, %cx		# String length
| > > > 	decw	%cx			# Don't look for the \0
| > > > 	movw	%bx, %di		# ES:DI = where to look
| > > > 	repz	cmpsb			# Loop while the same
| > > > 	jz	found			# Found the string
| > > > 	incb	%bx			# Next starting offset
| > > > 	cmpb	$_BIOS_END, %bx		# Check for limit
| > > > 	jb	1b			# Continue
| > > > never_found_anywhere:
| > > >
| > > > found:
| > >
| > > I've written something similar to this before - and it wont' work, so
| > > I've reimplemented it. The problem is, that I don't know how to set ES
| > > properly. I only know, that BIOS data (and code) is located in
| > > 0xe000..0xf000 (real address).
| >
| > Yeah. So. I set ES and DS to be exactly where CS is. This means that
| > if your &!)(^$&_ code executes it will work. So, instead of trying
| > it, you just blindly ignore it and state that it won't work.
| >
| > Bullshit. I do this for a living and I gave you some valuable time
| > which you rejected out-of-hand. Have fun.
| 
| Of course, I've tried your code as well - the same result! Sorry, if you 
| haven't understand me.
| 
| The problem is, that I don't know where this BIOS code is relative to current 
| code segment (CS). I only know (hope), that it should be in 
| 0x0:0xe000...0x0:0xf000. I have tried to set ES to 0 (xor %ax, %ax; mov %ax, 
| %es) - no luck as well. BTW, `strings /dev/mem | grep "REQUESTED STRING"` 
| founds it perfectly...

You shouldn't need to know where the BIOS code is "relative to current code segment." It "should be" in hex 0:e000-ffff. You should be able to use some segment reg. = 0 to search.

I see that Dick just corrected this, just as I was about to do:
Typical PC BIOSen are at segment 0xe000:0 thru 0xf000:ffff, not segment 0 and offsets as you have them listed. Are you using a typical PC BIOS or something else?

--
~Randy