37
1 Betriebssystembau 2. Übung Olaf Spinczyk und Michael Engel Arbeitsgruppe Eingebettete Systemsoftware Lehrstuhl für Informatik 12 TU Dortmund [email protected] http://ess.cs.uni-dortmund.de/~os/

Betriebssystembau: 2. Übung · 2019-11-29 · Klasse keyboard_interrupt erbt von Klasse interrupt ... Beim PC ist das der Programmable Interrupt Controller 8259A ... -ICW = Initialization

  • Upload
    others

  • View
    0

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Betriebssystembau: 2. Übung · 2019-11-29 · Klasse keyboard_interrupt erbt von Klasse interrupt ... Beim PC ist das der Programmable Interrupt Controller 8259A ... -ICW = Initialization

11

Betriebssystembau

2. Übung

Olaf Spinczyk und Michael EngelArbeitsgruppe Eingebettete Systemsoftware

Lehrstuhl für Informatik 12TU Dortmund [email protected]://ess.cs.uni-dortmund.de/~os/

Page 2: Betriebssystembau: 2. Übung · 2019-11-29 · Klasse keyboard_interrupt erbt von Klasse interrupt ... Beim PC ist das der Programmable Interrupt Controller 8259A ... -ICW = Initialization

Betriebssystembau: 2. Übung 22

Überblick● C++ Crashkurs (Teil 2)

● Aufgabe 1: Tastatur-Programmierung

● Aufgabe 2: Unterbrechungsbehandlung

Page 3: Betriebssystembau: 2. Übung · 2019-11-29 · Klasse keyboard_interrupt erbt von Klasse interrupt ... Beim PC ist das der Programmable Interrupt Controller 8259A ... -ICW = Initialization

Betriebssystembau: 2. Übung 33

C++-Konzepte (Crashkurs Teil 2)● Übersetzungs- und Bindevorgang

● Präprozessor

● Vererbung und Mehrfachvererbung

● Virtuelle Funktionen

Page 4: Betriebssystembau: 2. Übung · 2019-11-29 · Klasse keyboard_interrupt erbt von Klasse interrupt ... Beim PC ist das der Programmable Interrupt Controller 8259A ... -ICW = Initialization

Betriebssystembau: 2. Übung 44

C++ - Übersetzungsprozess

Page 5: Betriebssystembau: 2. Übung · 2019-11-29 · Klasse keyboard_interrupt erbt von Klasse interrupt ... Beim PC ist das der Programmable Interrupt Controller 8259A ... -ICW = Initialization

Betriebssystembau: 2. Übung 55

Sourcecode - Präprozessor● Zwei Dateiendungen:● .cc — C++ Source Code● .h — „Header Files“ mit Definitionen von Datentypen,

Konstanten, Präprozessor-Makros etc.● Die Endungen sind Konvention, aber nicht zwingend●oft z.B. auch .cpp, .hpp o.ä.

● Header-Files werden mit Hilfe des Präprozessors textuell in .cc-Files integriert●#include – Anweisung:

- #include <iostream> für System-Headerfiles- #include "device.h" für eigene Headerfiles

Page 6: Betriebssystembau: 2. Übung · 2019-11-29 · Klasse keyboard_interrupt erbt von Klasse interrupt ... Beim PC ist das der Programmable Interrupt Controller 8259A ... -ICW = Initialization

Betriebssystembau: 2. Übung 66

Sourcecode - Präprozessor● Weitere Präprozessorfunktionen:

● Makrodefinition, z.B. für Konstanten:

- #define pi 3.1415926

- #define VGA_BASE 0xb8000

- ohne Semikolon am Ende!● Bedingte Compilierung:

- #ifdef DEBUG .... #endif

- #ifndef VGA_BASE#define VGA_BASE 0xb8000#endif

● Der Präprozessor expandiert Makros im Source Code, fügt Header-Files ein und erzeugt eine neue Textdatei, die der Compiler vorgesetzt bekommt

Page 7: Betriebssystembau: 2. Übung · 2019-11-29 · Klasse keyboard_interrupt erbt von Klasse interrupt ... Beim PC ist das der Programmable Interrupt Controller 8259A ... -ICW = Initialization

Betriebssystembau: 2. Übung 77

Sourcecode - Präprozessor● Wichtige Anwendung für #define und #ifndef:●Verhindern von mehrfacher Inklusion von Header-

Dateien- Header-Dateien dürfen wiederum Header-Dateien

inkludieren -> Ringschluss...

#ifndef __cgastr_include__#define __cgastr_include__

#include "object/o_stream.h"#include "machine/cgascr.h"

class CGA_Stream /* Hier muesst ihr selbst Code vervollstaendigen */ {/* Hier muesst ihr selbst Code vervollstaendigen */ };#endif

Page 8: Betriebssystembau: 2. Übung · 2019-11-29 · Klasse keyboard_interrupt erbt von Klasse interrupt ... Beim PC ist das der Programmable Interrupt Controller 8259A ... -ICW = Initialization

Betriebssystembau: 2. Übung 88

Sourcecode - Compiler● Erzeugt aus vom Präprozessor vorverarbeitetem Source

Code eine Objektdatei (.o)● Diese ist i.a. nicht direkt ausführbar, da noch Referenzen auf

Funktionen oder Variablen in anderen Objektdateien enthalten sein können

● Der Compiler überprüft den Source Code auf Syntaxfehler und erzeugt ggf.●Fehlermeldungen (errors)●Warnungen (warnings)

● Eine Objektdatei wird nur bei fehlerfreier Übersetzung erzeugt●Warnungen führen nicht zum Abbruch des

Übersetzungsvorgangs! Sie sollten aber beachtet werden...

Page 9: Betriebssystembau: 2. Übung · 2019-11-29 · Klasse keyboard_interrupt erbt von Klasse interrupt ... Beim PC ist das der Programmable Interrupt Controller 8259A ... -ICW = Initialization

Betriebssystembau: 2. Übung 99

Sourcecode - Linker● Der Linker faßt eine Menge an Objektdateien (.o) sowie

bei Bedarf Libraries (.a, .so) zu einem ausführbaren Programm zusammen:●Auflösung von Referenzen●Sortierung der einzelnen Teile der Objektdateien im

Speicherabbild der ausführbaren Datei● „Normalerweise“ gibt es zwei Link-Modi:●dynamisch – Libraries werden erst zur Zeit der

Ausführung des Programms zum Objektcode geladen und Referenzen darin aufgelöst

●statisch – Libraries werden zur Link-Zeit in ein komplett ausführbares Programm integriert

● Vor-/Nachteile beider Ansätze? Welcher davon ist für unsere Systementwicklung geeignet?

Page 10: Betriebssystembau: 2. Übung · 2019-11-29 · Klasse keyboard_interrupt erbt von Klasse interrupt ... Beim PC ist das der Programmable Interrupt Controller 8259A ... -ICW = Initialization

Betriebssystembau: 2. Übung 1010

Einfache Vererbung● Klasse keyboard_interrupt erbt von Klasse interrupt● Vererbungsoperator „:“ (entspricht extends in Java)

interrupt.h: keyboard_interrupt.h:

class interrupt { #include "interrupt.h" ... class keyboard_interrupt :} public interrupt {

public:keyboard_interrupt();~keyboard_interrupt();

}

Page 11: Betriebssystembau: 2. Übung · 2019-11-29 · Klasse keyboard_interrupt erbt von Klasse interrupt ... Beim PC ist das der Programmable Interrupt Controller 8259A ... -ICW = Initialization

Betriebssystembau: 2. Übung 1111

Mehrfachvererbung● Klasse keyboard_interrupt erbt von Klassen interrupt und

keys:

keyboard_interrupt.h:

#include "interrupt.h"

class keyboard_interrupt : public interrupt, public keys {public:

keyboard_interrupt();~keyboard_interrupt();

}

Page 12: Betriebssystembau: 2. Übung · 2019-11-29 · Klasse keyboard_interrupt erbt von Klasse interrupt ... Beim PC ist das der Programmable Interrupt Controller 8259A ... -ICW = Initialization

Betriebssystembau: 2. Übung 1212

Virtuelle Funktionen● Virtuelle Funktionen sind Funktionen einer Basisklasse.● Eine abgeleitete Klasse kann sie überschreiben und

übernimmt damit die Ausführung der Funktion für ihre Klassenmitglieder. ● das funktioniert auch mit nicht virtuellen Klassen...

● Das Besondere an virtuellen Funktionen ist, dass das Objekt selbst weiss, zu welcher abgeleiteten Klasse es gehört und seine zugehörige Klassenfunktion ruft.

● Nicht jede Funktion ist standardmäßig virtuell, es muss explizit das Schlüsselwort „virtual“ verwendet werden! (im Gegensatz zu Java)

Page 13: Betriebssystembau: 2. Übung · 2019-11-29 · Klasse keyboard_interrupt erbt von Klasse interrupt ... Beim PC ist das der Programmable Interrupt Controller 8259A ... -ICW = Initialization

Betriebssystembau: 2. Übung 1313

Virtuelle Funktionen #include <iostream>

class base{public:

virtual void display(){

cout<<”\nBase”;}

};class derived : public base{ public: void display() { cout<<”\nDerived”; }};

void main(){ base *ptr = new derived(); ptr->display();}

● Ausgabe:

„Derived“

● ohne das virtual vor void display():

„Base“

Page 14: Betriebssystembau: 2. Übung · 2019-11-29 · Klasse keyboard_interrupt erbt von Klasse interrupt ... Beim PC ist das der Programmable Interrupt Controller 8259A ... -ICW = Initialization

Betriebssystembau: 2. Übung 1414

Virtuelle Destruktoren● Es gibt eine Faustregel, die besagt, dass jede Klasse mit

virtuellen Funktionen auch einen virtuellen Destruktor haben soll.

● Da ein nicht virtueller Destruktor nicht gewährleistet, dass abgeleitete Klassen ordnungsgemäß abgebaut werden, kann ein nicht virtueller Destruktor sogar so interpretiert werden, dass der Autor ein Ableiten seiner Klasse nicht vorgesehen hat und wohl auch nicht empfiehlt.

Page 15: Betriebssystembau: 2. Übung · 2019-11-29 · Klasse keyboard_interrupt erbt von Klasse interrupt ... Beim PC ist das der Programmable Interrupt Controller 8259A ... -ICW = Initialization

Betriebssystembau: 2. Übung 1515

Überblick● C++ Crashkurs (Teil 2)

● Aufgabe 1: Tastatur-Programmierung

● Aufgabe 2: Unterbrechungsbehandlung

Page 16: Betriebssystembau: 2. Übung · 2019-11-29 · Klasse keyboard_interrupt erbt von Klasse interrupt ... Beim PC ist das der Programmable Interrupt Controller 8259A ... -ICW = Initialization

Betriebssystembau: 2. Übung 1616

PC-Tastatur● klassisch:

● moderner PC: USB-Tastatur● USB Legacy Support: Ansteuerung funktioniert immer noch

zusätzlich über den Tastaturcontroller (Rückwärtskompatibilität)

Page 17: Betriebssystembau: 2. Übung · 2019-11-29 · Klasse keyboard_interrupt erbt von Klasse interrupt ... Beim PC ist das der Programmable Interrupt Controller 8259A ... -ICW = Initialization

Betriebssystembau: 2. Übung 1717

Tastenkodierungen

T a s t e S c a n- C o d e

A 3 0

a 3 0

S 3 1

D 3 2

C u r s o r h o c h 7 2

C u r s o r r u n t e r 8 0

Darstellung im Programm(und im CGA-Speicher!):Zeichencodes (ASCII)

Darstellung in der Hardware:Tastencodes

● Jede Taste hat eindeutigen Tastencode (Scan-Code)● Scan-Code ist 7-Bit Zahl (max. 128 Tasten)

● Tastaturcontroller sendet zusätzliche Informationen● Make-Code beim Drücken / Halten einer Taste● Break-Code beim Loslassen

Page 18: Betriebssystembau: 2. Übung · 2019-11-29 · Klasse keyboard_interrupt erbt von Klasse interrupt ... Beim PC ist das der Programmable Interrupt Controller 8259A ... -ICW = Initialization

Betriebssystembau: 2. Übung 1818

Make- und Break-Codes● Üblicherweise gilt

● Make-Code (Taste gedrückt) = Scan-Code

● Break-Code (Taste losgelassen) = Scan-Code + 128 (Bit 7)

● Einige Tasten senden jedoch mehrere Codes● z.B. Funktionstasten (F1-F12)

● aus historischen Gründen (XT-Tastatur)

● bis zu drei Make/Break-Codes pro Taste

● Eingebaute Wiederholungsfunktion● Hardware sendet zusätzliche Make-Codes,

wenn eine Taste länger gehalten wird

Dekodierung ist mühsam bei OOStuBS in der Vorgabe enthalten: bool key_decoded()

Page 19: Betriebssystembau: 2. Übung · 2019-11-29 · Klasse keyboard_interrupt erbt von Klasse interrupt ... Beim PC ist das der Programmable Interrupt Controller 8259A ... -ICW = Initialization

Betriebssystembau: 2. Übung 1919

Datenaustausch mit der Tastatur● Tastaturcontroller wird über zwei E/A-Ports angesprochen

● Ein-/Ausgaberegister (data_port) 0x60

● Steuerregister (ctrl_port) 0x64

data_port

ctrl_port

Keyboard_Controller set_led: LED ein-/ausset_speed: Wiederholungsrate

cpu_reset: Warmstart ...

Make-CodeBreak-Code

Status der Tastatur

SchreibenLesen

Page 20: Betriebssystembau: 2. Übung · 2019-11-29 · Klasse keyboard_interrupt erbt von Klasse interrupt ... Beim PC ist das der Programmable Interrupt Controller 8259A ... -ICW = Initialization

Betriebssystembau: 2. Übung 2020

Status der Tastatur● Statusregister stellt folgende Informationen bereit:

Page 21: Betriebssystembau: 2. Übung · 2019-11-29 · Klasse keyboard_interrupt erbt von Klasse interrupt ... Beim PC ist das der Programmable Interrupt Controller 8259A ... -ICW = Initialization

Betriebssystembau: 2. Übung 2121

Status der Tastatur - Verwendung

● Aktive Tastaturabfrage (nicht durch Unterbrechungen):● Warten, bis outb in ctrl_port gesetzt ist

● Make-/Break-Code vom data_port lesen (löscht ctrl_port.outb)

● Tastatur programmieren (set_led, set_speed)● Befehlsbyte in data_port schreiben

● Tastatur antwortet mit ack (0xfa), ggfs. auf Antwort warten (s.o.)

● Datenbyte in data_port schreiben (LED-Codes, Repeat-Rate)

● Tastatur antwortet mit ack, ggfs. auf Antwort warten

Page 22: Betriebssystembau: 2. Übung · 2019-11-29 · Klasse keyboard_interrupt erbt von Klasse interrupt ... Beim PC ist das der Programmable Interrupt Controller 8259A ... -ICW = Initialization

Betriebssystembau: 2. Übung 2222

Tastatur programmieren● set_led 0xed, <led_mask> in data_port● set_speed 0xf3, <config_byte> in data_port

Parameter für set_led Befehl: (led_mask)

Parameter für set_speed Befehl: (config_byte)

Page 23: Betriebssystembau: 2. Übung · 2019-11-29 · Klasse keyboard_interrupt erbt von Klasse interrupt ... Beim PC ist das der Programmable Interrupt Controller 8259A ... -ICW = Initialization

Betriebssystembau: 2. Übung 2323

Überblick● C++ Crashkurs (Teil 2)

● Aufgabe 1: Tastatur-Programmierung

● Aufgabe 2: Unterbrechungsbehandlung

Page 24: Betriebssystembau: 2. Übung · 2019-11-29 · Klasse keyboard_interrupt erbt von Klasse interrupt ... Beim PC ist das der Programmable Interrupt Controller 8259A ... -ICW = Initialization

Betriebssystembau: 2. Übung 2424

Hardware-IRQs bei x86 CPUs● Bis einschließlich i486 hatten x86 CPUs nur einen

Interrupt-Eingang (INT) plus einen NMI Eingang● INT kann mit dem IE-Bit im Statuswort maskiert werden

- cli-Befehl (clear interrupt enable) – Interruptverarbeitung sperren

- sti-Befehl (set interrupt enable) – Interruptverarbeitung freigeben

● NMI kann auf der CPU nicht maskiert werden (sagt ja schon der Name)- beim PC aber trotzdem durch externe Hardware...

● Externer Controller muss Nummer auf den Bus legen● Beim PC ist das der Programmable Interrupt Controller 8259A● Datenaustausch zwischen CPU und PIC 8259A erfolgt nach

einem festgelegtem Protokoll

Page 25: Betriebssystembau: 2. Übung · 2019-11-29 · Klasse keyboard_interrupt erbt von Klasse interrupt ... Beim PC ist das der Programmable Interrupt Controller 8259A ... -ICW = Initialization

Betriebssystembau: 2. Übung 2525

Ablauf eines Hardware IRQ (mit PIC)PIC 8259A IDT Handler <n>CPU (i386)

<n> (8 Bit, Datenbus)

INTA-Pin

Applikation

INT-Pin

<interruption>

INTA-Pin

EOI-Befehl (konfigurationsabhängig)

IRET Befehl

<continue>

So

ftware

Ha

rdw

ar e

Page 26: Betriebssystembau: 2. Übung · 2019-11-29 · Klasse keyboard_interrupt erbt von Klasse interrupt ... Beim PC ist das der Programmable Interrupt Controller 8259A ... -ICW = Initialization

Betriebssystembau: 2. Übung 2626

Kaskadierung im PC (15 Interrupts)

Page 27: Betriebssystembau: 2. Übung · 2019-11-29 · Klasse keyboard_interrupt erbt von Klasse interrupt ... Beim PC ist das der Programmable Interrupt Controller 8259A ... -ICW = Initialization

Betriebssystembau: 2. Übung 2727

i386 Interrupt-Deskriptortabelle (IDT)

IDTR

● maximal 256 Einträge- Basisadresse und Größe in IDTR

● 8 Byte pro Eintrag (Gate)- Task-Gate (Hardwaretasks)

- Trap-Gate (Ausnahmehandler)

- Interrupt-Gate (Ausnahmehandler + cli)

Page 28: Betriebssystembau: 2. Übung · 2019-11-29 · Klasse keyboard_interrupt erbt von Klasse interrupt ... Beim PC ist das der Programmable Interrupt Controller 8259A ... -ICW = Initialization

Betriebssystembau: 2. Übung 2828

i386 IDT: Aufbau

Traps Hardware/Software IRQs

0 31 255

IDT

Number Description 0 Divide-by-zero 1 Debug exception 2 Non-Maskable Interrupt (NMI) 3 Breakpoint (INT 3) 4 Overflow 5 Bound exception 6 Invalid Opcode 7 FPU not available 8 Double Fault 9 Coprocessor Segment Overrun 10 Invalid TSS 11 Segment not present 12 Stack exception 13 General Protection 14 Page fault 15 Reserved 16 Floating-point error 17 Alignment Check 18 Machine Check 19-31 Reserved By Intel

● Einträge 0-31 für Traps (fest)● Trap = Ausnahme, die

synchronzum Kontrollfluss auftritt- Division durch 0

- Seitenfehler

- Unterbrechungspunkt

- ...

● Einträge 32-255 für IRQs (variabel)- Software (INT <nummer>)

- Hardware (INT-Pin der CPU auf HIGH, Nummer auf Datenbus)

Page 29: Betriebssystembau: 2. Übung · 2019-11-29 · Klasse keyboard_interrupt erbt von Klasse interrupt ... Beim PC ist das der Programmable Interrupt Controller 8259A ... -ICW = Initialization

Betriebssystembau: 2. Übung 2929

Zustandssicherung● Wenn eine Unterbrechung eintritt, sichert die CPU

automatisch einen Teil des Zustands auf dem Stapel● condition codes (eflags)● aktives Codesegment (cs)● Rücksprungadresse (eip)

● Der automatisch gesichterte Zustand wird bei der Ausführung von iret zurückgesetzt● verwendet der Handler weitere Register,

so muss er diese selber sichern!

eflags

cs

eipesp

esp - 8

esp - 4

esp - 12

Page 30: Betriebssystembau: 2. Übung · 2019-11-29 · Klasse keyboard_interrupt erbt von Klasse interrupt ... Beim PC ist das der Programmable Interrupt Controller 8259A ... -ICW = Initialization

Betriebssystembau: 2. Übung 3030

PIC 8259A – Interner Aufbau

höchste

niedrigste

Page 31: Betriebssystembau: 2. Übung · 2019-11-29 · Klasse keyboard_interrupt erbt von Klasse interrupt ... Beim PC ist das der Programmable Interrupt Controller 8259A ... -ICW = Initialization

Betriebssystembau: 2. Übung 3131

Zugriff auf die PICs über IO-Ports

Port 0x20

Port 0x21

Master

Port 0xa0

Port 0xa1

Slave

ICW1 (Initialisierung beginnen)OCW2 (EOI, ...)OCW3 (IRR lesen, ISR lesen, ...)

ICW2-4 (Initialisierungsdaten)OCW1 (= IMR)

IRRISROffset

IMR

● Jeder PIC hat zwei Ports, die gelesen/geschrieben werden können● Schreibdaten: ICW1-4, OCW1-3

- ICW = Initialization Control Word – Initialisierung des PICs

- OCW = Operation Control Word – Kommandos im Betrieb

● Lesedaten abhängig von Kommando

SchreibenLesen

<wie Master><wie Master>

Page 32: Betriebssystembau: 2. Übung · 2019-11-29 · Klasse keyboard_interrupt erbt von Klasse interrupt ... Beim PC ist das der Programmable Interrupt Controller 8259A ... -ICW = Initialization

Betriebssystembau: 2. Übung 3232

Initialisierung der PICs – Teil 1

OO-Stubs Einstellung:

00010001

Master

00010001

Slave

OO-Stubs Einstellung:

00100000

Master

00101000

Slave

Page 33: Betriebssystembau: 2. Übung · 2019-11-29 · Klasse keyboard_interrupt erbt von Klasse interrupt ... Beim PC ist das der Programmable Interrupt Controller 8259A ... -ICW = Initialization

Betriebssystembau: 2. Übung 3333

Mapping der HW-IRQs (OO-Stubs)

IRQ 0 System Timer IRQ 1 Tastatur (Keyboard) IRQ 2 PIC Kaskadierung IRQ 3 COM 2 IRQ 4 COM 1 IRQ 5 IRQ 6 Floppy IRQ 7 LPT 1 IRQ 8 CMOS Echtzeituhr IRQ 9 (HW-Mapping von IRQ 2) IRQ10 IRQ11 IRQ12 PS/2 IRQ13 numerischer Coprozessor IRQ14 1. IDE Port IRQ15 2. IDE Port

Traps <unbenutzt>

0 255

IDT HW

4732

Standard ATIRQ-Belegung

Page 34: Betriebssystembau: 2. Übung · 2019-11-29 · Klasse keyboard_interrupt erbt von Klasse interrupt ... Beim PC ist das der Programmable Interrupt Controller 8259A ... -ICW = Initialization

Betriebssystembau: 2. Übung 3434

Initialisierung der PICs – Teil 2

OO-Stubs Einstellung:

00000100

Master

00000010

Slave

OO-Stubs Einstellung:

00000011

Master

00000011

Slave

Page 35: Betriebssystembau: 2. Übung · 2019-11-29 · Klasse keyboard_interrupt erbt von Klasse interrupt ... Beim PC ist das der Programmable Interrupt Controller 8259A ... -ICW = Initialization

Betriebssystembau: 2. Übung 3535

Programmierung der PICs

● Interruptmaske (IMR)- schreiben und lesen über

Port 0x21 / 0xa1

Page 36: Betriebssystembau: 2. Übung · 2019-11-29 · Klasse keyboard_interrupt erbt von Klasse interrupt ... Beim PC ist das der Programmable Interrupt Controller 8259A ... -ICW = Initialization

Betriebssystembau: 2. Übung 3636

Interrupthandler in OO-Stubs● Behandlung startet in der Funktion guardian()

● bekommt die IRQ-Nummer als Parameter:

void guardian( unsigned int slot ) { ... // IRQ-Handler (Gate) aktivieren}

● Interrupts sind während der Abarbeitung gesperrt- können mit sti manuell wieder zugelassen werden

- werden automatisch wieder zugelassen, wenn guardian() terminiert

● Die eigentlichen (spezifischen) IRQ-Handler● sind Instanzen der Klasse Gate● werden an- und abgemeldet über die Klasse Plugbox

Page 37: Betriebssystembau: 2. Übung · 2019-11-29 · Klasse keyboard_interrupt erbt von Klasse interrupt ... Beim PC ist das der Programmable Interrupt Controller 8259A ... -ICW = Initialization

Betriebssystembau: 2. Übung 3737

Interrupthandler in OO-Stubs