Ein '''Complementary Metal Oxide Semiconductor''' (= '''CMOS''') ist eigentlich ein elektronischer Baustein, aber im Bereich der Betriebssystemprogrammierung ist damit meistens der Batterie-gepufferte SRAM eines [[x86]]- bzw. [[x86-64]]-Computers gemeint. In diesem speichert das [[BIOS]] Informationen beispielsweise über die angeschlossene Hardware. Außerdem wird darin die momentane Uhrzeit und das Datum gespeichert und von einer [[RTC | Echtzeituhr]] aktualisiert.
== Aufbau ==
Im CMOS werden folgende jeweils 1 Byte große Felder gespeichert. Die mit ''BCD'' markierten Einträge sind standardmässig im [[BCD | BCD-Format]] kodiert. Die Kodierung kann aber auch im [[CMOS#0x0B - Statusregister B | Statusregister B]] (Bit 2) geändert werden. Dabei ist allerdings zu beachten, dass die momentanen Werte im Register an die neue Kodierung angepasst werden müssen und dies nicht von selbst geschieht.
=== 0x0F - Shutdown-Statusbyte ===
80286-Prozessoren konnten nicht vom [[Protected Mode]] in den Realmode zurückgeschaltet werden. Zu diesem Zweck war ein Prozessor-Reset nötig. Das Shutdown-Statusbyte dient dazu dem BIOS anzuzeigen, ob der PC neu gebootet oder der Prozessor nur im Realmode neu gestartet werden soll.
{| {{prettytable}}
!Wert
!Beschreibung
|-
| 0x00 || Normale Ausführung des POST
|-
| 0x01 || Chip Satz Initialisierung für Real Mode
|-
| 0x02 || Power-On Reset durchführen
|-
| 0x03 || Power-On Reset durchführen
|-
| 0x04 || int 0x19-reboot
|-
| 0x05 || EOI an PIC ausgeben, Tastatur resetten, Sprung zur Addresse [0x0040:0x0067]
|-
| 0x06 || Sprung zur Addresse [0x0040:0x0067] ohne EOI
|-
| 0x07 || zurück zu Int 0x15, Funktion 0x87 (Block im Extenden Memory verschieben)
|-
| 0x08 || zurück zum POST Speicher Test
|-
| 0x09 || zurück zu Int 0x15, Funktion 0x87 (Block im Extenden Memory verschieben)
|-
| 0x0A || JMP zu [0x0040:0x0067]
|-
| 0x0B || IRET zu [0x0040:0x0067]
|-
| 0x0C || RET zu [0x0040:0x0067]
|}
=== 0x10 - Typ der [[FDC | Diskettenlaufwerke]] ===
In diesem Byte wird der Typ der [[FDC | Diskettenlaufwerke]] gespeichert, wobei in den Bits 4-7 der Typ des ersten Laufwerks gespeichert ist und in den Bits 0-3 der Typ des zweiten Laufwerks.
Die Typen sind wie folgt kodiert:
0000b = Laufwerk nicht vorhanden
0001b = 5 1/4'' - 360 kB
0010b = 5 1/4'' - 1.2 MB
0011b = 3 1/2'' - 720 kB
0100b = 3 1/2'' - 1.44 MB (sollte eigentlich heutzutage der Standard sein)
0101b - 1111b sind unbenutzt
=== 0x12 - Typ der Festplattenlaufwerke ===
In diesem Byte wird der Typ der Festplattenlaufwerke gespeichert, wobei in den Bits 4-7 der Typ des ersten Laufwerks gespeichert ist und in den Bits 0-3 der Typ des zweiten Laufwerks.
Die Typen sind wie folgt kodiert:
0000b = Laufwerk nicht vorhanden
0001b - 1110b = Typen 1-14
1111b = Typ laut Erweiterungsbyte der Festplatte
=== 0x14 - Gerätebyte ===
Hier werden Informationen über die allgemeine Hardwarekonfiguration des PCs gespeichert.
{| {{prettytable}}
! Bits || 7-6 || 5-4 || 3 || 2 || 1 || 0
|-
| || Anzahl Floppys || Display-Typ || Display vorhanden? || Keyboard vorhanden? || Mathematischer Koprozessor vorhanden? || Floppy
|}
Anzahl Floppys
Auf diesen Wert nur verlassen wenn Floppy=1
00b 1 Floppy-Laufwerk
01b 2 Floppy-Laufwerke
Display-Typ
00b BIOS-Display-Adapter
01b CGA (40 Spalten)
10b CGA (80 Spalten)
11b Monochrom
=== 0x2E & 0x2F - CMOS-Prüfsumme ===
Die CMOS-Prüfsumme ist eine 16 Bit grosse, byteweise Summe der Werte der Bytes von 0x10 bis 0x2D.
== Programmierung ==
Die Programmierung des CMOS ist denkbar einfach: Die sieben niederwertigen Bits des I/O Ports 0x70 dienen als Offset (siehe Tabelle). Das höchste Bit sollte nicht verändert werden, es dient als [[Non_Maskable_Interrupt | NMI]]-Maskierungsregister. Durch Lesen bzw. Schreiben des I/O Ports 0x71 kann dann der Wert an diesem Offset gelesen bzw. geschrieben werden.
=== Assembler Beispielcode===
;Ein Makro um ein Byte aus dem CMOS auszulesen
;Der einzige Parameter ist das Offset des Bytes welches gelesen werden soll
;Rückgabe ist das gelesene Byte in AL
%macro read_byte 1
in al, 0x70 ;Bit 7 des Ports sichern
and al, 10000000b
or al, %1 ;Offset (Parameter 1) dazumixen
out 0x70, al ;Offset setzen
in al, 0x71 ;Byte lesen
%endmacro
=== C/C++ Beispielcode ===
#define CMOS_PORT_ADDRESS 0x70
#define CMOS_PORT_DATA 0x71
/**
* Liest ein Byte aus den CMOS
* @param offset Offset im CMOS
* @return Gelesener Wert
*/
uint8_t cmos_read(uint8_t offset) {
uint8_t tmp = inb(CMOS_PORT_ADDRESS);
outb(CMOS_PORT_ADDRESS, (tmp & 0x80) | (offset & 0x7F));
return inb(CMOS_PORT_DATA);
}
/**
* Schreibt ein Byte in das CMOS
* @param offset Offset im CMOS
* @param val Zu schreibender Wert
*/
void cmos_write(uint8_t offset,uint8_t val) {
uint8_t tmp = inb(CMOS_PORT_ADDRESS);
outb(CMOS_PORT_ADDRESS, (tmp & 0x80) | (offset & 0x7F));
outb(CMOS_PORT_DATA,val);
}
== Weblinks ==
* [http://www.nondot.org/sabre/os/files/MiscHW/RealtimeClockFAQ.txt Real Time Clock / CMOS Setup Reference] (''englisch'')
* [http://www.bioscentral.com/misc/cmosmap.htm CMOS-Aufbau] (''englisch'')
* [http://bochs.sourceforge.net/doc/docbook/development/cmos-map.html Bochs's CMOS map] (''englisch'')
* [http://www.bios-info.de/4p92x846/iscmos.htm BIOS Kompendium] (''deutsch'')
[[Category:Hardware]]
[[en:CMOS]]