Browse Source

[PXE] Add PMM support to romprefix.S (untested)

ROM initialisation vector now attempts to allocate a 2MB block using
PMM.  If successful, it copies the ROM image to this block, then
shrinks the ROM image to allow for more option ROMs.  If unsuccessful,
it leaves the ROM as-is.

ROM BEV now attempts to return to the BIOS, resorting to INT 18 only
if the BIOS stack has been corrupted.
tags/v0.9.4
Michael Brown 16 years ago
parent
commit
12f203c606
3 changed files with 243 additions and 73 deletions
  1. 58
    30
      src/arch/i386/prefix/libprefix.S
  2. 183
    43
      src/arch/i386/prefix/romprefix.S
  3. 2
    0
      src/arch/i386/scripts/i386.lds

+ 58
- 30
src/arch/i386/prefix/libprefix.S View File

17
  *
17
  *
18
  */
18
  */
19
 
19
 
20
+	.arch i386
21
+	.section ".prefix.lib", "awx", @progbits
22
+	.section ".data16", "aw", @progbits
23
+
20
 /**
24
 /**
21
  * High memory temporary load address
25
  * High memory temporary load address
22
  *
26
  *
27
  * We use the start of an even megabyte so that we don't have to worry
31
  * We use the start of an even megabyte so that we don't have to worry
28
  * about the current state of the A20 line.
32
  * about the current state of the A20 line.
29
  *
33
  *
30
- * We use 4MB rather than 2MB because there is at least one commercial
31
- * PXE ROM ("Broadcom UNDI, PXE-2.1 (build 082) v2.0.4") which stores
32
- * data required by the UNDI ROM loader (yes, the ROM loader; that's
33
- * the component which should be impossible to damage short of
34
- * screwing with the MMU) around the 2MB mark.  Sadly, this is not a
35
- * joke.
36
- *
34
+ * We use 4MB rather than 2MB because some PXE stack / PMM BIOS
35
+ * combinations are known to place data required by other UNDI ROMs
36
+ * loader around the 2MB mark.
37
  */
37
  */
38
-#define HIGHMEM_LOADPOINT ( 4 << 20 )
38
+	.globl	HIGHMEM_LOADPOINT
39
+	.equ	HIGHMEM_LOADPOINT, ( 4 << 20 )
39
 
40
 
40
 /* Image compression enabled */
41
 /* Image compression enabled */
41
 #define COMPRESS 1
42
 #define COMPRESS 1
42
 
43
 
43
 #define CR0_PE 1
44
 #define CR0_PE 1
44
 
45
 
45
-	.arch i386
46
-	.section ".prefix.lib", "awx", @progbits
47
-	.section ".data16", "aw", @progbits
48
-
49
 /****************************************************************************
46
 /****************************************************************************
50
  * pm_call (real-mode near call)
47
  * pm_call (real-mode near call)
51
  *
48
  *
223
  * Returns:
220
  * Returns:
224
  *   %ds:esi : next source address (will be a multiple of 16)
221
  *   %ds:esi : next source address (will be a multiple of 16)
225
  * Corrupts:
222
  * Corrupts:
226
- *   %edi, %ecx, %edx
223
+ *   %ecx, %edx
227
  ****************************************************************************
224
  ****************************************************************************
228
  */
225
  */
229
 	.section ".prefix.lib"
226
 	.section ".prefix.lib"
230
 	.code16
227
 	.code16
231
 install_block:
228
 install_block:
229
+	/* Preserve registers */
230
+	pushl	%edi
231
+	
232
 #if COMPRESS
232
 #if COMPRESS
233
 	/* Decompress source to destination */
233
 	/* Decompress source to destination */
234
 	call	decompress16
234
 	call	decompress16
249
 	addl	$0xf, %esi
249
 	addl	$0xf, %esi
250
 	andl	$~0xf, %esi
250
 	andl	$~0xf, %esi
251
 
251
 
252
+	/* Restore registers and return */
253
+	popl	%edi
252
 	ret
254
 	ret
253
 	.size install_block, . - install_block
255
 	.size install_block, . - install_block
254
 	
256
 	
270
  */
272
  */
271
 	.section ".prefix.lib"
273
 	.section ".prefix.lib"
272
 	.code16
274
 	.code16
275
+	.globl	alloc_basemem
273
 alloc_basemem:
276
 alloc_basemem:
274
 	/* FBMS => %ax as segment address */
277
 	/* FBMS => %ax as segment address */
275
 	movw	$0x40, %ax
278
 	movw	$0x40, %ax
308
  * Returns:
311
  * Returns:
309
  *   %esi : next source physical address (will be a multiple of 16)
312
  *   %esi : next source physical address (will be a multiple of 16)
310
  * Corrupts:
313
  * Corrupts:
311
- *   %edi, %ecx, %edx
314
+ *   %ecx, %edx
312
  ****************************************************************************
315
  ****************************************************************************
313
  */
316
  */
314
 	.section ".prefix.lib"
317
 	.section ".prefix.lib"
315
 	.code16
318
 	.code16
316
 install_basemem:
319
 install_basemem:
317
 	/* Preserve registers */
320
 	/* Preserve registers */
321
+	pushl	%edi
318
 	pushw	%ds
322
 	pushw	%ds
319
 
323
 
320
 	/* Preserve original %esi */
324
 	/* Preserve original %esi */
335
 
339
 
336
 	/* Restore registers */
340
 	/* Restore registers */
337
 	popw	%ds
341
 	popw	%ds
342
+	popl	%edi
338
 	ret
343
 	ret
339
 	.size install_basemem, . - install_basemem
344
 	.size install_basemem, . - install_basemem
340
 
345
 
351
  * Returns:
356
  * Returns:
352
  *   %esi : next source physical address (will be a multiple of 16)
357
  *   %esi : next source physical address (will be a multiple of 16)
353
  * Corrupts:
358
  * Corrupts:
354
- *   %edi, %ecx, %edx
359
+ *   %ecx, %edx
355
  ****************************************************************************
360
  ****************************************************************************
356
  */
361
  */
357
 
362
 
376
 	
381
 	
377
 /****************************************************************************
382
 /****************************************************************************
378
  * install (real-mode near call)
383
  * install (real-mode near call)
379
- * install_prealloc (real-mode near call)
380
  *
384
  *
381
  * Install all text and data segments.
385
  * Install all text and data segments.
382
  *
386
  *
383
  * Parameters:
387
  * Parameters:
384
- *   %ax : .text16 segment address (install_prealloc only)
385
- *   %bx : .data16 segment address (install_prealloc only)
388
+ *   none
386
  * Returns:
389
  * Returns:
387
- *   %ax : .text16 segment address
388
- *   %bx : .data16 segment address
389
- *   %edi : .text physical address (if applicable)
390
+ *   %ax  : .text16 segment address
391
+ *   %bx  : .data16 segment address
390
  * Corrupts:
392
  * Corrupts:
391
  *   none
393
  *   none
392
  ****************************************************************************
394
  ****************************************************************************
395
 	.code16
397
 	.code16
396
 	.globl install
398
 	.globl install
397
 install:
399
 install:
400
+	/* Preserve registers */
401
+	pushl	%esi
402
+	pushl	%edi
398
 	/* Allocate space for .text16 and .data16 */
403
 	/* Allocate space for .text16 and .data16 */
399
 	call	alloc_basemem
404
 	call	alloc_basemem
405
+	/* Image source = %cs:0000 */
406
+	xorl	%esi, %esi
407
+	/* Image destination = HIGHMEM_LOADPOINT */
408
+	movl	$HIGHMEM_LOADPOINT, %edi
409
+	/* Install text and data segments */
410
+	call	install_prealloc
411
+	/* Restore registers and return */
412
+	popl	%edi
413
+	popl	%esi
414
+	ret
400
 	.size install, . - install
415
 	.size install, . - install
416
+
417
+/****************************************************************************
418
+ * install_prealloc (real-mode near call)
419
+ *
420
+ * Install all text and data segments.
421
+ *
422
+ * Parameters:
423
+ *   %ax  : .text16 segment address
424
+ *   %bx  : .data16 segment address
425
+ *   %esi : Image source physical address (or zero for %cs:0000)
426
+ *   %edi : Decompression temporary area physical address
427
+ * Corrupts:
428
+ *   none
429
+ ****************************************************************************
430
+ */
431
+	.section ".prefix.lib"
432
+	.code16
401
 	.globl install_prealloc
433
 	.globl install_prealloc
402
 install_prealloc:
434
 install_prealloc:
403
 	/* Save registers */
435
 	/* Save registers */
436
+	pushal
404
 	pushw	%ds
437
 	pushw	%ds
405
 	pushw	%es
438
 	pushw	%es
406
-	pushl	%esi
407
-	pushl	%ecx
408
-	pushl	%edx
409
 
439
 
410
 	/* Sanity: clear the direction flag asap */
440
 	/* Sanity: clear the direction flag asap */
411
 	cld
441
 	cld
412
 
442
 
413
 	/* Calculate physical address of payload (i.e. first source) */
443
 	/* Calculate physical address of payload (i.e. first source) */
414
-	xorl	%esi, %esi
444
+	testl	%esi, %esi
445
+	jnz	1f
415
 	movw	%cs, %si
446
 	movw	%cs, %si
416
 	shll	$4, %esi
447
 	shll	$4, %esi
417
-	addl	$_payload_offset, %esi
448
+1:	addl	$_payload_offset, %esi
418
 
449
 
419
 	/* Install .text16 */
450
 	/* Install .text16 */
420
 	movw	%ax, %es
451
 	movw	%ax, %es
440
 	 * prior to reading the E820 memory map and relocating
471
 	 * prior to reading the E820 memory map and relocating
441
 	 * properly.
472
 	 * properly.
442
 	 */
473
 	 */
443
-	movl	$HIGHMEM_LOADPOINT, %edi
444
 	movl	$_textdata_progbits_size, %ecx
474
 	movl	$_textdata_progbits_size, %ecx
445
 	movl	$_textdata_size, %edx
475
 	movl	$_textdata_size, %edx
446
 	pushl	%edi
476
 	pushl	%edi
473
 
503
 
474
 #endif
504
 #endif
475
 	/* Restore registers */
505
 	/* Restore registers */
476
-	popl	%edx
477
-	popl	%ecx
478
-	popl	%esi
479
 	popw	%es
506
 	popw	%es
480
 	popw	%ds
507
 	popw	%ds
508
+	popal
481
 	ret
509
 	ret
482
 	.size install_prealloc, . - install_prealloc
510
 	.size install_prealloc, . - install_prealloc
483
 
511
 

+ 183
- 43
src/arch/i386/prefix/romprefix.S View File

6
  * table so using a noticeable amount of stack space is a no-no.
6
  * table so using a noticeable amount of stack space is a no-no.
7
  */
7
  */
8
 
8
 
9
+#define PNP_SIGNATURE ( '$' + ( 'P' << 8 ) + ( 'n' << 16 ) + ( 'P' << 24 ) )
10
+#define PMM_SIGNATURE ( '$' + ( 'P' << 8 ) + ( 'M' << 16 ) + ( 'M' << 24 ) )
11
+#define STACK_MAGIC ( 'L' + ( 'R' << 8 ) + ( 'E' << 16 ) + ( 'T' << 24 ) )
12
+
9
 	.text
13
 	.text
10
 	.code16
14
 	.code16
11
 	.arch i386
15
 	.arch i386
15
 romheader:
19
 romheader:
16
 	.word	0xAA55			/* BIOS extension signature */
20
 	.word	0xAA55			/* BIOS extension signature */
17
 romheader_size:	.byte _load_size_sect	/* Size in 512-byte blocks */
21
 romheader_size:	.byte _load_size_sect	/* Size in 512-byte blocks */
18
-	jmp	init_vector		/* Initialisation vector */
22
+	jmp	init			/* Initialisation vector */
23
+checksum:
24
+	.byte	0
19
 	.org	0x16
25
 	.org	0x16
20
 	.word	undiheader
26
 	.word	undiheader
21
 	.org	0x18
27
 	.org	0x18
72
 	.byte	0x54			/* Device indicator */
78
 	.byte	0x54			/* Device indicator */
73
 	.word	0x0000			/* Boot connection vector */
79
 	.word	0x0000			/* Boot connection vector */
74
 	.word	0x0000			/* Disconnect vector */
80
 	.word	0x0000			/* Disconnect vector */
75
-	.word	exec_vector		/* Boot execution vector */
81
+	.word	bev_entry		/* Boot execution vector */
76
 	.word	0x0000			/* Reserved */
82
 	.word	0x0000			/* Reserved */
77
 	.word	0x0000			/* Static resource information vector*/
83
 	.word	0x0000			/* Static resource information vector*/
78
 	.equ pnpheader_len, . - pnpheader
84
 	.equ pnpheader_len, . - pnpheader
98
 	.equ undiheader_len, . - undiheader
104
 	.equ undiheader_len, . - undiheader
99
 	.size undiheader, . - undiheader
105
 	.size undiheader, . - undiheader
100
 
106
 
101
-/* Initialisation vector
107
+/* Initialisation (called once during POST)
102
  *
108
  *
103
  * Determine whether or not this is a PnP system via a signature
109
  * Determine whether or not this is a PnP system via a signature
104
  * check.  If it is PnP, return to the PnP BIOS indicating that we are
110
  * check.  If it is PnP, return to the PnP BIOS indicating that we are
105
  * a boot-capable device; the BIOS will call our boot execution vector
111
  * a boot-capable device; the BIOS will call our boot execution vector
106
  * if it wants to boot us.  If it is not PnP, hook INT 19.
112
  * if it wants to boot us.  If it is not PnP, hook INT 19.
107
  */
113
  */
108
-init_vector:
109
-	pushw	%si
110
-	cmpw	$'$'+'P'*256, %es:0(%di)
111
-	jne	notpnp
112
-	cmpw	$'n'+'P'*256, %es:2(%di)
113
-	jne	notpnp
114
-ispnp:
115
-	movw	$ispnp_message, %si
116
-	jmp	99f
117
-notpnp:
114
+init:
115
+	/* Preserve registers, clear direction flag, set %ds=%cs */
116
+	pushaw
118
 	pushw	%ds
117
 	pushw	%ds
119
-	pushw	$0
120
-	popw	%ds
118
+	pushw	%es
119
+	cld
121
 	pushw	%cs
120
 	pushw	%cs
122
-	pushw	$exec_vector
123
-	popl	( 0x19 * 4 )
124
 	popw	%ds
121
 	popw	%ds
125
-	movw	$notpnp_message, %si
122
+	/* Print message as early as possible */
123
+	movw	$init_message, %si
124
+	call	print_message
125
+	/* Check for PnP BIOS */
126
+	cmpl	$PNP_SIGNATURE, %es:0(%di)
127
+	je	ispnp
128
+notpnp:	/* Not PnP: hook INT19 */
129
+	xorw	%ax, %ax
130
+	movw	%ax, %es
131
+	pushw	%cs
132
+	pushw	$int19_entry
133
+	popl	%es:( 0x19 * 4 )
134
+	jmp	99f
135
+ispnp:	/* Is PnP: print PnP message */
136
+	movw	$init_message_pnp, %si
137
+	call	print_message
138
+	/* Check for PMM */
139
+	movw	$( 0xe000 - 1 ), %di
140
+pmm_scan:
141
+	incw	%di
142
+	jz	99f
143
+	movw	%di, %es
144
+	cmpl	$PMM_SIGNATURE, %es:0
145
+	jne	pmm_scan
146
+	xorw	%bx, %bx
147
+	xorw	%si, %si
148
+	movzbw	%es:5, %cx
149
+1:	es lodsb
150
+	addb	%al, %bl
151
+	loop	1b
152
+	jnz	pmm_scan
153
+	/* PMM found: print PMM message */
154
+	movw	$init_message_pmm, %si
155
+	call	print_message
156
+	/* Try to allocate 2MB block via PMM */
157
+	pushw	$0x0006		/* Aligned, extended memory */
158
+	pushl	$0xffffffff	/* No handle */
159
+	pushl	$( 0x00200000 / 16 ) /* 2MB in paragraphs */
160
+	pushw	$0x0000		/* pmmAllocate */
161
+	lcall	%es:*(7)
162
+	addw	$12, %sp
163
+	testw	%dx, %dx	/* %ax==0 even on success, since align=2MB */
164
+	jnz	gotpmm
165
+	movw	$init_message_pmm_failed, %si
166
+	call	print_message
167
+	jmp	99f
168
+gotpmm:	/* PMM allocation succeeded: copy ROM to PMM block */
169
+	pushal			/* PMM presence implies 1kB stack */
170
+	movw	%ax, %es	/* %ax=0 already - see above */
171
+	pushw	%dx
172
+	pushw	%ax
173
+	popl	%edi
174
+	movl	%edi, image_source
175
+	xorl	%esi, %esi
176
+	movzbl	romheader_size, %ecx
177
+	shll	$9, %ecx
178
+	addr32 rep movsb	/* PMM presence implies flat real mode */
179
+	movl	%edi, decompress_to
180
+	/* Shrink ROM and update checksum */
181
+	xorw	%bx, %bx
182
+	xorw	%si, %si
183
+	movb	$_prefix_size_sect, romheader_size
184
+	shlw	$9, %cx
185
+1:	lodsb
186
+	addb	%al, %bl
187
+	loop	1b
188
+	subb	%bl, checksum
189
+	popal
126
 99:
190
 99:
191
+	/* Print CRLF to terminate messages */
192
+	movw	$init_message_crlf, %si
127
 	call	print_message
193
 	call	print_message
194
+	/* Restore registers */
195
+	popw	%es
196
+	popw	%ds
197
+	popaw
198
+	/* Indicate boot capability to PnP BIOS, if present */
128
 	movw	$0x20, %ax
199
 	movw	$0x20, %ax
129
-	popw	%si
130
 	lret
200
 	lret
131
-	.size init_vector, . - init_vector
132
-
133
-ispnp_message:
134
-	.asciz	"gPXE detected PnP BIOS\r\n"
135
-	.size ispnp_message, . - ispnp_message
136
-notpnp_message:
137
-	.asciz	"gPXE detected non-PnP BIOS\r\n"
138
-	.size notpnp_message, . - notpnp_message
139
-
140
-/* Boot execution vector
141
- *pciheader_size
142
- * Called by the PnP BIOS when it wants to boot us, or via the hooked
143
- * INT 19 if we detected a non-PnP BIOS.
144
- */	
145
-exec_vector:
146
-	/* Obtain a reasonably-sized stack */
201
+	.size init, . - init
202
+
203
+init_message:
204
+	.asciz	"gPXE (http://etherboot.org)"
205
+	.size	init_message, . - init_message
206
+init_message_pnp:
207
+	.asciz	" - PnP BIOS detected"
208
+	.size init_message_pnp, . - init_message_pnp
209
+init_message_pmm:
210
+	.asciz	", using PMM"
211
+	.size init_message_pmm, . - init_message_pmm
212
+init_message_pmm_failed:
213
+	.asciz	" (failed)"
214
+	.size init_message_pmm_failed, . - init_message_pmm_failed
215
+init_message_crlf:
216
+	.asciz	"\r\n"
217
+	.size	init_message_crlf, . - init_message_crlf
218
+
219
+/* ROM image location
220
+ *
221
+ * May be either within option ROM space, or within PMM-allocated block.
222
+ */
223
+image_source:
224
+	.long	0
225
+	.size	image_source, . - image_source
226
+/* Temporary decompression area
227
+ *
228
+ * May be either at HIGHMEM_LOADPOINT, or within PMM-allocated block.
229
+ */
230
+decompress_to:
231
+	.long	HIGHMEM_LOADPOINT
232
+	.size	decompress_to, . - decompress_to
233
+
234
+/* Boot Execution Vector entry point
235
+ *
236
+ * Called by the PnP BIOS when it wants to boot us.
237
+ */
238
+bev_entry:
239
+	pushw	%cs
240
+	call	exec
241
+	lret
242
+	.size	bev_entry, . - bev_entry
243
+
244
+/* INT19 entry point
245
+ *
246
+ * Called via the hooked INT 19 if we detected a non-PnP BIOS.
247
+ */
248
+int19_entry:
249
+	pushw	%cs
250
+	call	exec
251
+	/* No real way to return from INT19 */
252
+	int	$0x18
253
+	.size	int19_entry, . - int19_entry
254
+
255
+/* Execute as a boot device
256
+ *
257
+ */
258
+exec:	/* Set %ds = %cs */
259
+	pushw	%cs
260
+	popw	%ds
261
+
262
+	/* Print message as soon as possible */
263
+	movw	$exec_message, %si
264
+	call	print_message
265
+
266
+	/* Store magic word on BIOS stack and remember BIOS %ss:sp */
267
+	pushl	$STACK_MAGIC
268
+	movw	%ss, %dx
269
+	movw	%sp, %bp
270
+
271
+	/* Obtain a reasonably-sized temporary stack */
147
 	xorw	%ax, %ax
272
 	xorw	%ax, %ax
148
 	movw	%ax, %ss
273
 	movw	%ax, %ss
149
 	movw	$0x7c00, %sp
274
 	movw	$0x7c00, %sp
150
-	
151
-	movw	$exec_message, %si
152
-	call	print_message
153
 
275
 
154
-	call	install
276
+	/* Install gPXE */
277
+	movl	image_source, %esi
278
+	movl	decompress_to, %edi
279
+	call	alloc_basemem
280
+	call	install_prealloc
155
 
281
 
156
 	/* Set up real-mode stack */
282
 	/* Set up real-mode stack */
157
 	movw	%bx, %ss
283
 	movw	%bx, %ss
162
 	pushw	$1f
288
 	pushw	$1f
163
 	lret
289
 	lret
164
 	.section ".text16", "awx", @progbits
290
 	.section ".text16", "awx", @progbits
165
-1:
291
+1:	/* Call main() */
166
 	pushl	$main
292
 	pushl	$main
167
 	pushw	%cs
293
 	pushw	%cs
168
 	call	prot_call
294
 	call	prot_call
169
-	popl	%eax /* discard */
295
+	/* No need to clean up stack; we are about to reload %ss:sp */
296
+	
297
+	/* Restore BIOS stack */
298
+	movw	%dx, %ss
299
+	movw	%bp, %sp
170
 
300
 
171
-	/* Boot next device */
301
+	/* Check magic word on BIOS stack */
302
+	popl	%eax
303
+	cmpl	$STACK_MAGIC, %eax
304
+	jne	1f
305
+	/* BIOS stack OK: return to caller */
306
+	lret
307
+1:	/* BIOS stack corrupt: use INT 18 */
172
 	int	$0x18
308
 	int	$0x18
173
 	.previous
309
 	.previous
174
 
310
 
182
  */
318
  */
183
 undiloader:
319
 undiloader:
184
 	/* Save registers */
320
 	/* Save registers */
321
+	pushl	%esi
185
 	pushl	%edi
322
 	pushl	%edi
186
 	pushw	%es
323
 	pushw	%es
187
 	pushw	%bx
324
 	pushw	%bx
193
 	pushw	%di
330
 	pushw	%di
194
 	movw	%es:12(%di), %bx
331
 	movw	%es:12(%di), %bx
195
 	movw	%es:14(%di), %ax
332
 	movw	%es:14(%di), %ax
333
+	movl	%cs:image_source, %esi
334
+	movl	%cs:decompress_to, %edi
196
 	call	install_prealloc
335
 	call	install_prealloc
197
 	popw	%di
336
 	popw	%di
198
 	/* Call UNDI loader C code */
337
 	/* Call UNDI loader C code */
208
 	popw	%bx
347
 	popw	%bx
209
 	popw	%es
348
 	popw	%es
210
 	popl	%edi
349
 	popl	%edi
350
+	popl	%esi
211
 	lret
351
 	lret
212
 	.size undiloader, . - undiloader
352
 	.size undiloader, . - undiloader
213
 				
353
 				
218
 	pushw	%bx
358
 	pushw	%bx
219
 	pushw	%bp
359
 	pushw	%bp
220
 	movw    $0x0007, %bx
360
 	movw    $0x0007, %bx
221
-1:	cs lodsb
361
+1:	lodsb
222
 	testb	%al, %al
362
 	testb	%al, %al
223
 	je	2f
363
 	je	2f
224
 	movb    $0x0e, %ah              /* write char, tty mode */
364
 	movb    $0x0e, %ah              /* write char, tty mode */

+ 2
- 0
src/arch/i386/scripts/i386.lds View File

257
     /*
257
     /*
258
      * Values calculated to save code from doing it
258
      * Values calculated to save code from doing it
259
      */
259
      */
260
+    _prefix_size_pgh	= ( ( _prefix_size + 15 ) / 16 );
261
+    _prefix_size_sect	= ( ( _prefix_size + 511 ) / 512 );
260
     _text16_size_pgh	= ( ( _text16_size + 15 ) / 16 );
262
     _text16_size_pgh	= ( ( _text16_size + 15 ) / 16 );
261
     _data16_size_pgh	= ( ( _data16_size + 15 ) / 16 );
263
     _data16_size_pgh	= ( ( _data16_size + 15 ) / 16 );
262
 
264
 

Loading…
Cancel
Save