On 2015/11/24 22:42, Laszlo Ersek wrote:
On 11/24/15 15:27, Zeng, Star wrote:
On 2015/11/24 21:17, Laszlo Ersek wrote:
On 11/24/15 02:01, Zeng, Star wrote:
On 2015/11/23 22:01, Laszlo Ersek wrote:

[snip]

(2) although I see that you unified the GetControl / SetControl /
SetAttributes implementations between
- EarlyFdtPL011SerialPortLib and
- FdtPL011SerialPortLib,

the actual implementations are incorrect, plus this doesn't seem to be
what we agreed upon.

Please refer to:

http://thread.gmane.org/gmane.comp.bios.edk2.devel/4370/focus=4408

You wrote "Even the SerialDxe may not work for ConsoleIn (ConsoleOut
should work well) with the functions return RETURN_UNSUPPORTED
(especially SerialPortGetControl())."

So I think that that *all six* functions should return RETURN_SUCCESS.
(And both GetControl functions should also set *Control to zero.)

Again, please just do what
"EmbeddedPkg/Library/SerialPortExtLibNull/SerialPortExtLibNull.c" does.


There will be no difference to return RETURN_SUCCESS or
RETURN_UNSUPPORTED if the interfaces are not to do the real get/set
operation.

The matter what I said is that the value return from
SerialPortGetControl() with *EFI_SERIAL_INPUT_BUFFER_EMPTY*, you can see
the line 568 in TerminalConIn.c.

Okay, thank you for that location. I've been wondering where these
functions are actually called.

So, the code in question is in the TerminalConInTimerHandler() function
-- leading comment: "Timer handler to poll the key from serial" --; it
goes like:

    //
    // Check whether serial buffer is empty.
    //
    Status = SerialIo->GetControl (SerialIo, &Control);

    if ((Control & EFI_SERIAL_INPUT_BUFFER_EMPTY) == 0) {
      //
      // Fetch all the keys in the serial buffer,
      // and insert the byte stream into RawFIFO.
      //
      while (!IsRawFiFoFull (TerminalDevice)) {

        Status = GetOneKeyFromSerial (TerminalDevice->SerialIo, &Input);

        if (EFI_ERROR (Status)) {
          if (Status == EFI_DEVICE_ERROR) {
            REPORT_STATUS_CODE_WITH_DEVICE_PATH (
              EFI_ERROR_CODE | EFI_ERROR_MINOR,
              (EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_EC_INPUT_ERROR),
              TerminalDevice->DevicePath
              );
          }
          break;
        }

        RawFiFoInsertOneKey (TerminalDevice, Input);
      }
    }

(1) This code has a bug; it checks the output-only parameter called
"Control" without verifying the Status variable. Worse, "Control" is
never set or initialized before that point, so the code can easily act
upon an indeterminate value.

(2) The EFI_SERIAL_INPUT_BUFFER_EMPTY check looks like an optimization
only. The loop that depends on it copies characters from the serial
terminal into an internal queue, as long as the internal queue has room,
*and* the terminal device can provide characters.

If the EFI_SERIAL_INPUT_BUFFER_EMPTY bit is always clear, then the
GetOneKeyFromSerial() function can still exit the loop early. Namely,
GetOneKeyFromSerial() calls SerialIo->Read(), and as far as I
understand, this series doesn't change the semantics of that
(non-extended) serial library function, in any of the library instances.
So, if 0 bytes could be read, GetOneKeyFromSerial() returns
EFI_NOT_READY, and the outer loop is exited.

(3) Therefore, always returning success and setting Control to zero is a
safe choice for a "null" implementation of GetControl(). This is what
"EmbeddedPkg/Library/SerialPortExtLibNull/SerialPortExtLibNull.c" does.

Returning "unsupported", and setting Control to zero is similarly safe.
However, in general, a function should not modify output parameters
(unless explicitly specified so) if it returns "unsupported".

Returning "unsupported" and *not* setting Control to zero is unsafe at
the moment (although it would be self-consistent for the GetControl()
function itself). The problem is that Control would be indeterminate at
the time of the check, meaning the EFI_SERIAL_INPUT_BUFFER_EMPTY bit
could be set. That would prevent GetOneKeyFromSerial() from being called
at all.

That is why I implemented the
interfaces for FdtPL011SerialPortLib in V2 patch series. And another
EarlyFdtPL011SerialPortLib does not need implement the interfaces or
just return RETURN_UNSUPPORTED as it does not link to SerialDxe, you can
also the implementation of SerialPortRead() and SerialPortPoll() in
EarlyFdtPL011SerialPortLib.c that do nothing.

I've been missing the above GetControl() context all this time.

At this point my opinion is as follows:

- Your patch "[edk2] [PATCH V3 10/12] OvmfPkg XenConsoleSerialPortLib:
Implement Get(Set)Control/SetAttributes" is correct, and my R-b stands.

- Your patch "[edk2] [PATCH V3 11/12] ArmVirtPkg: Use SerialDxe in
MdeModulePkg instead of EmbeddedPkg" (i.e., this patch) is *also*
correct:

Reviewed-by: Laszlo Ersek <ler...@redhat.com>

Firstly, thanks for the Reviewed-by.
According to your comments to the "[edk2] [PATCH *V2* 11/12] ArmVirtPkg:
Use SerialDxe in MdeModulePkg instead of EmbeddedPkg", I sent out this
patch V3, although it still does not match your original expectation.
In fact, personally, I still prefer "[edk2] [PATCH *V2* 11/12]
ArmVirtPkg: Use SerialDxe in MdeModulePkg instead of EmbeddedPkg" that
can leverage PL011UartGetControl() and etc in PL011UartLib, or even can
be like the change style for OvmfPkg.
Anyway, want to confirm your final preference.

Using PL011UartLib makes sense, I guess, but I think it would be prudent
to separate that change out to a different, followup patch. (It doesn't
even have to be in this series.)

Backing GetControl() with PL011UartLib is a feature addition /
behavioral change. If you submit that separately, I guess Ard too could
chime in on the review of that. (I don't know anything about the PL011
UART.)

That is fine. I will soon submit V4 patch series to include the patch that you suggested for TerminalConIn since up to now all the patches in V3 patch series have got one or more Reviewed-by.

Thanks,
Star




- *However*, the bug in "TerminalConIn.c" must be fixed. Can you please
include the following change as a separate patch in your series,
somewhere near the beginning?

diff --git
a/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConIn.c
b/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConIn.c
index c216ed9..349bec2 100644
--- a/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConIn.c
+++ b/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConIn.c
@@ -562,10 +562,12 @@ TerminalConInTimerHandler (
     }
     //
     // Check whether serial buffer is empty.
+  // Skip the key transfer loop only if the SerialIo protocol instance
+  // successfully reports EFI_SERIAL_INPUT_BUFFER_EMPTY.
     //
     Status = SerialIo->GetControl (SerialIo, &Control);

-  if ((Control & EFI_SERIAL_INPUT_BUFFER_EMPTY) == 0) {
+  if (EFI_ERROR (Status) || (Control &
EFI_SERIAL_INPUT_BUFFER_EMPTY) == 0) {
       //
       // Fetch all the keys in the serial buffer,
       // and insert the byte stream into RawFIFO.


The commit message could be something like:

MdeModulePkg: TerminalDxe: avoid checking uninitialized variable

The SerialIo->GetControl() function is not required to set the Control
output parameter on error. Make sure we apply the
EFI_SERIAL_INPUT_BUFFER_EMPTY optimization in
TerminalConInTimerHandler() only if the SerialIo->GetControl()
function call set that bit in the Control variable.

Yes, that is good. I can include it in the V4 patch series with your
Suggested-by and Signed-off-by.

I think a Suggested-by should suffice. :)

Thanks!
Laszlo


_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to