Hi ecm, 

> On Apr 24, 2023, at 12:57 PM, C. Masloch <pus...@ulukai.org> wrote:
> [..]
> 
>> 2) We could walk the device driver chain. Thats fairly straight forward and 
>> easy enough to implement. Lets do that… Hmmm, not all device drivers are 
>> showing up in the chain and logger is not being seen. Let’s not worry about 
>> that for now and do something else.
> 
> Don't know how you managed to do that, it is indeed straightforward.

I should have kept the original one that failed to work. So, I could look back 
and laugh at how I managed to mess it up. However, it could have been related 
to doing some of the testing inside DOSBox. Oh well, doesn’t matter now. 

>> [..]
>> I did consider walking the MCB chain to find it. But, that comes with its 
>> own set of problems. Some blocks contain sub-blocks.
> 
> SD "system data" blocks with sub-MCBs are a fact on most kernels, but they're 
> not terribly complicated to detect and handle. First two name bytes are "SD" 
> and the owner is 8. Sub-MCBs have signature letters indicating the type of 
> the block rather than "M" link / "Z" no link, and they always span the entire 
> space up to the end of the container SD block.
> 
>> The upper memory blocks may or may not be linked into the primary MCB chain.
> 
> This is more of a problem. You can ignore a "Z" (ie, treat it as if it is an 
> "M") if you know that the next block after the "Z" block is the first UMCB. 
> You can find the first UMCB by trying to call interrupt 2Fh, function 1261h, 
> CY; if it returns NC then ax = first UMCB. Or if the kernel does not support 
> that function, switch off the UMB link, walk until "Z", switch on the UMB 
> link, walk until you're past the MCB that was "Z" prior to this (but is now 
> "M"). Of course, you want to preserve the original UMB link state around 
> this. Example code is in my TSR example [1].
> 
> For a single search, it may be more efficient to just do the UMB link state 
> enabling around your MCB walker as is, and honor any "Z" as the final end 
> marker then.
> 
> 
> [1]: https://hg.pushbx.org/ecm/tsr/file/749e0f25364c/transien.asm#l96

Yup. Decades ago I wrote an MCB walker in Turbo Pascal. If it can be done in an 
HLL, it can be done in assembly. :-)

>> [..]
>> For “fun”, I implemented initial versions of both the 0x2b interrupt hook 
>> and a partial 0x2d implementation to locate the Logger device driver. The 
>> 0x2d version is very bare bones and does not include several functions 
>> required to be “fully compliant”. It only responds to the install check 
>> function for whichever multiplexer it allocates. Other function requests 
>> only respond with AL=0x00 which i guess is “not implemented”.
> 
> Yes, setting al to zero is the way to indicate a function is not implemented.

Looking at RBIL, it says that it returned al=zero for the “reserved” functions.

So, I assumed that would be the case for standard functions (0x01-0x06) that 
are not supported. 

Thanks for the clarification.

> 
>> As such, 0x2d uses 35 bytes more resident memory than 0x2b. (actually 49 
>> bytes more if you count a “title” string that is not required). If I spend 
>> the time making it fully compliant, it will require even more. It really 
>> would need function 04 (determine chained ints) and should have 06 (device 
>> driver info).
> 
> Why not show your examples? Perhaps we can point out some optimisations to 
> shave off a few bytes here and there. I have some ideas about how to write a 
> very small int 2Dh handler, eg:
> 
> int_2D:
>  ; IISP header here
> 
>  ; magic byte sequence common to Ralf Brown and ecm programs:
>  cmp ah, 0
> .multiplex_number: equ $ - 1
>  ; SMC, storing the multiplex number in the instruction immediate
>  je .handle
>  ; magic byte sequence end
>  jmp far [cs:.next]
> .handle:
>  cmp al, 0
>  ; check if installation check
>  mov al, 0
>  ; prepare "function not supported" return code
>  jne .iret
>  ; jump to iret if not installation check -->
>  ; (flags still as set from the compare instruction)
>  mov al, 0FFh
>  mov cx, 0100h
>  mov di, amis_signature
>  mov dx, cs
> .iret:
>  iret
> 
> 
> ETA: I found that you actually already uploaded your work! Nicely done. 
> Here's what I am referring to [2].
> 
> No need to reserve 15 bytes for the AMIS signature description, just let the 
> assembler do its job and allocate exactly as many bytes as needed.

I think I might drop the “optional” description completely to shave off 14 
bytes.

> The multiplex number, as in my example above, can be embedded into the code 
> of the handler. (I do not call this the "multiplexer" as you do here, rather, 
> "multiplexer" in my use refers to the resident program. The number is just 
> the "multiplex number".) This is what both Ralf Brown's examples and my 
> resident programs do.

Once set, it never changes. Great idea to save some bytes. :-)

> If you do put the multiplex number there at the end of the signatures, it may 
> save (very little) space to initialise it as zero rather than minus one, if 
> one were to compress your binary.
> 
> Preserving bx around the scan call is not needed; if someone uses int 2Dh in 
> a way incompatible to AMIS then this may not suffice to save you. At least in 
> my opinion, I just assume that only AMIS users handle it.

Sometimes, I suffer from a severe lack of trust in other programmers. I look at 
the "Install Check”  and see only specific registers are to be modified and no 
others are to be destroyed. But in my head, I think that someone out there may 
think it is a good idea to save some time by passing some additional 
information back in one of those registers. However, that would be their bug 
and not mine. So, I will remove them and not worry about it (very much). :-)

It’s kind of like the beginning of the interface program starts out with "push 
cs, pop ds, push cs, pop es" which is supposed to already be the case under 
DOS. I’ll comment them out to save 4 bytes. 

> The %%InvalidResponse branching is a good idea, as that indicates the 
> multiplex number is not "in use" by AMIS but also not "free" by AMIS. 
> However, I would have it branch to %%Next rather than to %%NotFound.

Thats a tricky one. If we get a bad response, something else is using the AMIS 
interrupt. Should it continue poking at it? I think it would have been lucky 
that the system didn’t crash and would be better to just abort. 

> 
> The cld is probably not needed here. A DOS application executable can assume 
> it is started with UP (direction flag clear). A DOS device driver usually can 
> assume as much too; if you are really afraid of DOS passing DN (direction 
> flag set) then put the cld at the beginning of your init handler.

Yeah, there are a bunch of extra CLDs in there that can go. It could/should be 
slimmed down to only 2 or 3 of them. 

It’s not in the resident portion. So, I’ll worry about that later. 

> 
> The actual interrupt handler does not have to preserve the flags it gets from 
> its entrypoint (your pushf / popf). If you drop those instructions, then 
> after the xor you can just put a single iret instruction instead of a short 
> jump.
> 
> The comment in the InstallHook macro wrongly refers to "int 0x2b" here, 
> should be 2Dh.
> 
> 
> In the common.inc file [3], in the macro CheckCompatible you can just change 
> this code sequence:
> 
> 
>       je      %%Compatible
>       stc
>       jmp     %%Done
> %%Compatible:
>       clc
> %%Done:
> 
> To this:
> 
>  je %%Done
>  ; flags are ZR NC if branching here
>  stc
>  ; insure CY if we didn't branch
> %%Done:
> 
> 
> In the log-sys.asm file [4], you can optimise the device entrypoints somewhat:
> 
> First, do not use a "Driver.Strategy" that saves away the request header 
> address. Instead, move all your processing (from "Driver.Routine") into the 
> strategy entrypoint and access the request header using es:bx. Your 
> "interrupt" entrypoint is just a single retf then (which you can share with 
> the resident handler's instruction that returns from your strategy 
> entrypoint). This is compatible with all common DOS kernels, certainly with 
> the FreeDOS kernel.
> 
> Second, you can write the resident device entrypoint to just always return 
> the status 8103h to the request header's status field. Make your entrypoint 
> code so that "Initialize" is called only initially, when command 0 is sent, 
> and later in the installation code patch your entrypoint to run the minimal 
> resident handler that only returns the error.

For simplicity, I moved and renamed the current Strategy/Entry routines after 
the the initialization section and created new ones. At startup, it points to 
the old versions, then during initialization, the header pointers are changed 
to the new tiny versions. The old larger ones are freed when initialization is 
completed. Reducing the footprint by another 3 paragraphs. 

> Finally, if you do *not* use the IISP headers (which I strongly recommend you 
> do use them), you can write the chain instruction as "jmp 0:0" and then 
> "BIOSInt10 equ $ - 4" after that instruction, so as to do SMC that patches 
> the immediate far jump instruction. That saves 4 bytes per chain instruction.

After implementing the previous optimizations and adding IISP (IBM Interrupt 
Sharing Protocol) the net savings with resident footprint is 1 paragraph for 
methods 2B and 2D, and 2 paragraphs for the Driver Chain walking. 

> I didn't check all the other resident code for optimisations yet, but I can 
> do so if you're interested.

That would be great.  

Much of the code was written as I worked through the problem of getting a 
stable and reliable capturing system up and running. I was constantly going 
back and changing and re-changing sections until the desired behavior was 
reached. There is little doubt it is not optimal and could probably use a 
complete rewrite of some sections for improved performance and size. But, it 
works and that may be good enough for version 1.

There are also a couple more things like that I should add. Like watching for 
changes to a VESA mode. At present, that will go unnoticed and the logging 
capture method does not switch. It is just a matter of hooking that interrupt 
function as well. 

I may also want to add a 3rd party interface to read, write and control the 
logging driver. But, I don’t know if that is really worth doing and would 
increase the resident footprint a lot. Maybe, I’ll hold off on that until 
version 2.

Once that stuff is done, it will be time for the  BETA version. 

> [..]
>> If it is made "fully compliant” with the AMIS protocol, it will add a 
>> minimum of 22 more bytes. Most likely, it will eventually be double or 
>> triple that. There are advantages to using AMIS. But, it requires calling 
>> the interrupt 255 times to check every multiplexer.
> 
> Up to 256 times, actually.

Yup. 0xff=255, 0x00 thru 0xff=256. 

I saw the typo after I sent the message and knew someone would point it out. 

LOL

> [..]
> 
> In any case, thanks for your work!
> 
> Regards,
> ecm
> 

You are welcome. 

It is not really work, I enjoy it. 

Thanks again for all the feedback.

:-)

Jerome

_______________________________________________
Freedos-devel mailing list
Freedos-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/freedos-devel

Reply via email to