63
63
#define RTC_REG_C 12
64
64
#define RTC_REG_D 13
65
65
66
- /* PC cmos mappings */
67
- #define REG_IBM_CENTURY_BYTE 0x32
68
- #define REG_IBM_PS2_CENTURY_BYTE 0x37
66
+ #define REG_A_UIP 0x80
69
67
70
- RTCState rtc_state ;
68
+ #define REG_B_SET 0x80
69
+ #define REG_B_PIE 0x40
70
+ #define REG_B_AIE 0x20
71
+ #define REG_B_UIE 0x10
72
+
73
+ struct RTCState {
74
+ uint8_t cmos_data [128 ];
75
+ uint8_t cmos_index ;
76
+ int current_time ; /* in seconds */
77
+ int irq ;
78
+ uint8_t buf_data [10 ]; /* buffered data */
79
+ /* periodic timer */
80
+ QEMUTimer * periodic_timer ;
81
+ int64_t next_periodic_time ;
82
+ /* second update */
83
+ int64_t next_second_time ;
84
+ QEMUTimer * second_timer ;
85
+ QEMUTimer * second_timer2 ;
86
+ };
87
+
88
+ static void rtc_set_time (RTCState * s );
89
+ static void rtc_set_date_buf (RTCState * s , const struct tm * tm );
90
+ static void rtc_copy_date (RTCState * s );
91
+
92
+ static void rtc_timer_update (RTCState * s , int64_t current_time )
93
+ {
94
+ int period_code , period ;
95
+ int64_t cur_clock , next_irq_clock ;
96
+
97
+ period_code = s -> cmos_data [RTC_REG_A ] & 0x0f ;
98
+ if (period_code != 0 &&
99
+ (s -> cmos_data [RTC_REG_B ] & REG_B_PIE )) {
100
+ if (period_code <= 2 )
101
+ period_code += 7 ;
102
+ /* period in 32 Khz cycles */
103
+ period = 1 << (period_code - 1 );
104
+ /* compute 32 khz clock */
105
+ cur_clock = muldiv64 (current_time , 32768 , ticks_per_sec );
106
+ next_irq_clock = (cur_clock & ~(period - 1 )) + period ;
107
+ s -> next_periodic_time = muldiv64 (next_irq_clock , ticks_per_sec , 32768 ) + 1 ;
108
+ qemu_mod_timer (s -> periodic_timer , s -> next_periodic_time );
109
+ } else {
110
+ qemu_del_timer (s -> periodic_timer );
111
+ }
112
+ }
113
+
114
+ static void rtc_periodic_timer (void * opaque )
115
+ {
116
+ RTCState * s = opaque ;
117
+
118
+ rtc_timer_update (s , s -> next_periodic_time );
119
+ s -> cmos_data [RTC_REG_C ] |= 0xc0 ;
120
+ pic_set_irq (s -> irq , 1 );
121
+ }
71
122
72
123
static void cmos_ioport_write (void * opaque , uint32_t addr , uint32_t data )
73
124
{
@@ -80,7 +131,7 @@ static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data)
80
131
printf ("cmos: write index=0x%02x val=0x%02x\n" ,
81
132
s -> cmos_index , data );
82
133
#endif
83
- switch (addr ) {
134
+ switch (s -> cmos_index ) {
84
135
case RTC_SECONDS_ALARM :
85
136
case RTC_MINUTES_ALARM :
86
137
case RTC_HOURS_ALARM :
@@ -95,10 +146,30 @@ static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data)
95
146
case RTC_MONTH :
96
147
case RTC_YEAR :
97
148
s -> cmos_data [s -> cmos_index ] = data ;
149
+ /* if in set mode, do not update the time */
150
+ if (!(s -> cmos_data [RTC_REG_B ] & REG_B_SET )) {
151
+ rtc_set_time (s );
152
+ }
98
153
break ;
99
154
case RTC_REG_A :
155
+ /* UIP bit is read only */
156
+ s -> cmos_data [RTC_REG_A ] = (data & ~REG_A_UIP ) |
157
+ (s -> cmos_data [RTC_REG_A ] & REG_A_UIP );
158
+ rtc_timer_update (s , qemu_get_clock (vm_clock ));
159
+ break ;
100
160
case RTC_REG_B :
101
- s -> cmos_data [s -> cmos_index ] = data ;
161
+ if (data & REG_B_SET ) {
162
+ /* set mode: reset UIP mode */
163
+ s -> cmos_data [RTC_REG_A ] &= ~REG_A_UIP ;
164
+ data &= ~REG_B_UIE ;
165
+ } else {
166
+ /* if disabling set mode, update the time */
167
+ if (s -> cmos_data [RTC_REG_B ] & REG_B_SET ) {
168
+ rtc_set_time (s );
169
+ }
170
+ }
171
+ s -> cmos_data [RTC_REG_B ] = data ;
172
+ rtc_timer_update (s , qemu_get_clock (vm_clock ));
102
173
break ;
103
174
case RTC_REG_C :
104
175
case RTC_REG_D :
@@ -111,27 +182,104 @@ static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data)
111
182
}
112
183
}
113
184
114
- static inline int to_bcd (int a )
185
+ static inline int to_bcd (RTCState * s , int a )
115
186
{
116
- return ((a / 10 ) << 4 ) | (a % 10 );
187
+ if (s -> cmos_data [RTC_REG_B ] & 0x04 ) {
188
+ return a ;
189
+ } else {
190
+ return ((a / 10 ) << 4 ) | (a % 10 );
191
+ }
117
192
}
118
193
119
- static void cmos_update_time (RTCState * s )
194
+ static inline int from_bcd (RTCState * s , int a )
120
195
{
121
- struct tm * tm ;
196
+ if (s -> cmos_data [RTC_REG_B ] & 0x04 ) {
197
+ return a ;
198
+ } else {
199
+ return ((a >> 4 ) * 10 ) + (a & 0x0f );
200
+ }
201
+ }
202
+
203
+ static void rtc_set_time (RTCState * s )
204
+ {
205
+ struct tm tm1 , * tm = & tm1 ;
206
+
207
+ tm -> tm_sec = from_bcd (s , s -> cmos_data [RTC_SECONDS ]);
208
+ tm -> tm_min = from_bcd (s , s -> cmos_data [RTC_MINUTES ]);
209
+ tm -> tm_hour = from_bcd (s , s -> cmos_data [RTC_HOURS ]);
210
+ tm -> tm_wday = from_bcd (s , s -> cmos_data [RTC_DAY_OF_WEEK ]);
211
+ tm -> tm_mday = from_bcd (s , s -> cmos_data [RTC_DAY_OF_MONTH ]);
212
+ tm -> tm_mon = from_bcd (s , s -> cmos_data [RTC_MONTH ]) - 1 ;
213
+ tm -> tm_year = from_bcd (s , s -> cmos_data [RTC_YEAR ]) + 100 ;
214
+
215
+ /* update internal state */
216
+ s -> buf_data [RTC_SECONDS ] = s -> cmos_data [RTC_SECONDS ];
217
+ s -> buf_data [RTC_MINUTES ] = s -> cmos_data [RTC_MINUTES ];
218
+ s -> buf_data [RTC_HOURS ] = s -> cmos_data [RTC_HOURS ];
219
+ s -> buf_data [RTC_DAY_OF_WEEK ] = s -> cmos_data [RTC_DAY_OF_WEEK ];
220
+ s -> buf_data [RTC_DAY_OF_MONTH ] = s -> cmos_data [RTC_DAY_OF_MONTH ];
221
+ s -> buf_data [RTC_MONTH ] = s -> cmos_data [RTC_MONTH ];
222
+ s -> buf_data [RTC_YEAR ] = s -> cmos_data [RTC_YEAR ];
223
+ s -> current_time = mktime (tm );
224
+ }
225
+
226
+ static void rtc_update_second (void * opaque )
227
+ {
228
+ RTCState * s = opaque ;
229
+
230
+ /* if the oscillator is not in normal operation, we do not update */
231
+ if ((s -> cmos_data [RTC_REG_A ] & 0x70 ) != 0x20 ) {
232
+ s -> next_second_time += ticks_per_sec ;
233
+ qemu_mod_timer (s -> second_timer , s -> next_second_time );
234
+ } else {
235
+ s -> current_time ++ ;
236
+
237
+ if (!(s -> cmos_data [RTC_REG_B ] & REG_B_SET )) {
238
+ /* update in progress bit */
239
+ s -> cmos_data [RTC_REG_A ] |= REG_A_UIP ;
240
+ }
241
+ qemu_mod_timer (s -> second_timer2 ,
242
+ s -> next_second_time + (ticks_per_sec * 99 ) / 100 );
243
+ }
244
+ }
245
+
246
+ static void rtc_update_second2 (void * opaque )
247
+ {
248
+ RTCState * s = opaque ;
122
249
time_t ti ;
123
250
124
- ti = time (NULL );
125
- tm = gmtime (& ti );
126
- s -> cmos_data [RTC_SECONDS ] = to_bcd (tm -> tm_sec );
127
- s -> cmos_data [RTC_MINUTES ] = to_bcd (tm -> tm_min );
128
- s -> cmos_data [RTC_HOURS ] = to_bcd (tm -> tm_hour );
129
- s -> cmos_data [RTC_DAY_OF_WEEK ] = to_bcd (tm -> tm_wday );
130
- s -> cmos_data [RTC_DAY_OF_MONTH ] = to_bcd (tm -> tm_mday );
131
- s -> cmos_data [RTC_MONTH ] = to_bcd (tm -> tm_mon + 1 );
132
- s -> cmos_data [RTC_YEAR ] = to_bcd (tm -> tm_year % 100 );
133
- s -> cmos_data [REG_IBM_CENTURY_BYTE ] = to_bcd ((tm -> tm_year / 100 ) + 19 );
134
- s -> cmos_data [REG_IBM_PS2_CENTURY_BYTE ] = s -> cmos_data [REG_IBM_CENTURY_BYTE ];
251
+ ti = s -> current_time ;
252
+ rtc_set_date_buf (s , gmtime (& ti ));
253
+
254
+ if (!(s -> cmos_data [RTC_REG_B ] & REG_B_SET )) {
255
+ rtc_copy_date (s );
256
+ }
257
+
258
+ /* check alarm */
259
+ if (s -> cmos_data [RTC_REG_B ] & REG_B_AIE ) {
260
+ if (((s -> cmos_data [RTC_SECONDS_ALARM ] & 0xc0 ) == 0xc0 ||
261
+ s -> cmos_data [RTC_SECONDS_ALARM ] == s -> buf_data [RTC_SECONDS ]) &&
262
+ ((s -> cmos_data [RTC_MINUTES_ALARM ] & 0xc0 ) == 0xc0 ||
263
+ s -> cmos_data [RTC_MINUTES_ALARM ] == s -> buf_data [RTC_MINUTES ]) &&
264
+ ((s -> cmos_data [RTC_HOURS_ALARM ] & 0xc0 ) == 0xc0 ||
265
+ s -> cmos_data [RTC_HOURS_ALARM ] == s -> buf_data [RTC_HOURS ])) {
266
+
267
+ s -> cmos_data [RTC_REG_C ] |= 0xa0 ;
268
+ pic_set_irq (s -> irq , 1 );
269
+ }
270
+ }
271
+
272
+ /* update ended interrupt */
273
+ if (s -> cmos_data [RTC_REG_B ] & REG_B_UIE ) {
274
+ s -> cmos_data [RTC_REG_C ] |= 0x90 ;
275
+ pic_set_irq (s -> irq , 1 );
276
+ }
277
+
278
+ /* clear update in progress bit */
279
+ s -> cmos_data [RTC_REG_A ] &= ~REG_A_UIP ;
280
+
281
+ s -> next_second_time += ticks_per_sec ;
282
+ qemu_mod_timer (s -> second_timer , s -> next_second_time );
135
283
}
136
284
137
285
static uint32_t cmos_ioport_read (void * opaque , uint32_t addr )
@@ -149,16 +297,10 @@ static uint32_t cmos_ioport_read(void *opaque, uint32_t addr)
149
297
case RTC_DAY_OF_MONTH :
150
298
case RTC_MONTH :
151
299
case RTC_YEAR :
152
- case REG_IBM_CENTURY_BYTE :
153
- case REG_IBM_PS2_CENTURY_BYTE :
154
- cmos_update_time (s );
155
300
ret = s -> cmos_data [s -> cmos_index ];
156
301
break ;
157
302
case RTC_REG_A :
158
303
ret = s -> cmos_data [s -> cmos_index ];
159
- /* toggle update-in-progress bit for Linux (same hack as
160
- plex86) */
161
- s -> cmos_data [RTC_REG_A ] ^= 0x80 ;
162
304
break ;
163
305
case RTC_REG_C :
164
306
ret = s -> cmos_data [s -> cmos_index ];
@@ -177,27 +319,115 @@ static uint32_t cmos_ioport_read(void *opaque, uint32_t addr)
177
319
}
178
320
}
179
321
180
- void rtc_timer ( void )
322
+ static void rtc_set_date_buf ( RTCState * s , const struct tm * tm )
181
323
{
182
- RTCState * s = & rtc_state ;
183
- if (s -> cmos_data [RTC_REG_B ] & 0x50 ) {
184
- pic_set_irq (s -> irq , 1 );
324
+ s -> buf_data [RTC_SECONDS ] = to_bcd (s , tm -> tm_sec );
325
+ s -> buf_data [RTC_MINUTES ] = to_bcd (s , tm -> tm_min );
326
+ if (s -> cmos_data [RTC_REG_B ] & 0x02 ) {
327
+ /* 24 hour format */
328
+ s -> buf_data [RTC_HOURS ] = to_bcd (s , tm -> tm_hour );
329
+ } else {
330
+ /* 12 hour format */
331
+ s -> buf_data [RTC_HOURS ] = to_bcd (s , tm -> tm_hour % 12 );
332
+ if (tm -> tm_hour >= 12 )
333
+ s -> buf_data [RTC_HOURS ] |= 0x80 ;
185
334
}
335
+ s -> buf_data [RTC_DAY_OF_WEEK ] = to_bcd (s , tm -> tm_wday );
336
+ s -> buf_data [RTC_DAY_OF_MONTH ] = to_bcd (s , tm -> tm_mday );
337
+ s -> buf_data [RTC_MONTH ] = to_bcd (s , tm -> tm_mon + 1 );
338
+ s -> buf_data [RTC_YEAR ] = to_bcd (s , tm -> tm_year % 100 );
339
+ }
340
+
341
+ static void rtc_copy_date (RTCState * s )
342
+ {
343
+ s -> cmos_data [RTC_SECONDS ] = s -> buf_data [RTC_SECONDS ];
344
+ s -> cmos_data [RTC_MINUTES ] = s -> buf_data [RTC_MINUTES ];
345
+ s -> cmos_data [RTC_HOURS ] = s -> buf_data [RTC_HOURS ];
346
+ s -> cmos_data [RTC_DAY_OF_WEEK ] = s -> buf_data [RTC_DAY_OF_WEEK ];
347
+ s -> cmos_data [RTC_DAY_OF_MONTH ] = s -> buf_data [RTC_DAY_OF_MONTH ];
348
+ s -> cmos_data [RTC_MONTH ] = s -> buf_data [RTC_MONTH ];
349
+ s -> cmos_data [RTC_YEAR ] = s -> buf_data [RTC_YEAR ];
350
+ }
351
+
352
+ void rtc_set_memory (RTCState * s , int addr , int val )
353
+ {
354
+ if (addr >= 0 && addr <= 127 )
355
+ s -> cmos_data [addr ] = val ;
356
+ }
357
+
358
+ void rtc_set_date (RTCState * s , const struct tm * tm )
359
+ {
360
+ s -> current_time = mktime ((struct tm * )tm );
361
+ rtc_set_date_buf (s , tm );
362
+ rtc_copy_date (s );
363
+ }
364
+
365
+ static void rtc_save (QEMUFile * f , void * opaque )
366
+ {
367
+ RTCState * s = opaque ;
368
+
369
+ qemu_put_buffer (f , s -> cmos_data , 128 );
370
+ qemu_put_8s (f , & s -> cmos_index );
371
+ qemu_put_be32s (f , & s -> current_time );
372
+ qemu_put_buffer (f , s -> buf_data , 10 );
373
+
374
+ qemu_put_timer (f , s -> periodic_timer );
375
+ qemu_put_be64s (f , & s -> next_periodic_time );
376
+
377
+ qemu_put_be64s (f , & s -> next_second_time );
378
+ qemu_put_timer (f , s -> second_timer );
379
+ qemu_put_timer (f , s -> second_timer2 );
186
380
}
187
381
188
- void rtc_init ( int base , int irq )
382
+ static int rtc_load ( QEMUFile * f , void * opaque , int version_id )
189
383
{
190
- RTCState * s = & rtc_state ;
384
+ RTCState * s = opaque ;
385
+
386
+ if (version_id != 1 )
387
+ return - EINVAL ;
191
388
192
- cmos_update_time (s );
389
+ qemu_get_buffer (f , s -> cmos_data , 128 );
390
+ qemu_get_8s (f , & s -> cmos_index );
391
+ qemu_get_be32s (f , & s -> current_time );
392
+ qemu_get_buffer (f , s -> buf_data , 10 );
393
+
394
+ qemu_get_timer (f , s -> periodic_timer );
395
+ qemu_get_be64s (f , & s -> next_periodic_time );
396
+
397
+ qemu_get_be64s (f , & s -> next_second_time );
398
+ qemu_get_timer (f , s -> second_timer );
399
+ qemu_get_timer (f , s -> second_timer2 );
400
+ return 0 ;
401
+ }
402
+
403
+ RTCState * rtc_init (int base , int irq )
404
+ {
405
+ RTCState * s ;
406
+
407
+ s = qemu_mallocz (sizeof (RTCState ));
408
+ if (!s )
409
+ return NULL ;
193
410
194
411
s -> irq = irq ;
195
412
s -> cmos_data [RTC_REG_A ] = 0x26 ;
196
413
s -> cmos_data [RTC_REG_B ] = 0x02 ;
197
414
s -> cmos_data [RTC_REG_C ] = 0x00 ;
198
415
s -> cmos_data [RTC_REG_D ] = 0x80 ;
199
416
417
+ s -> periodic_timer = qemu_new_timer (vm_clock ,
418
+ rtc_periodic_timer , s );
419
+ s -> second_timer = qemu_new_timer (vm_clock ,
420
+ rtc_update_second , s );
421
+ s -> second_timer2 = qemu_new_timer (vm_clock ,
422
+ rtc_update_second2 , s );
423
+
424
+ s -> next_second_time = qemu_get_clock (vm_clock ) + (ticks_per_sec * 99 ) / 100 ;
425
+ qemu_mod_timer (s -> second_timer2 , s -> next_second_time );
426
+
200
427
register_ioport_write (base , 2 , 1 , cmos_ioport_write , s );
201
428
register_ioport_read (base , 2 , 1 , cmos_ioport_read , s );
429
+
430
+ register_savevm ("mc146818rtc" , base , 1 , rtc_save , rtc_load , s );
431
+ return s ;
202
432
}
203
433
0 commit comments