summaryrefslogtreecommitdiffstats
path: root/private/ntos/boot
diff options
context:
space:
mode:
Diffstat (limited to 'private/ntos/boot')
-rw-r--r--private/ntos/boot/bldr/alphaldr.rsp17
-rw-r--r--private/ntos/boot/bldr/diagload.h204
-rw-r--r--private/ntos/boot/bldr/i386/initx86.c311
-rw-r--r--private/ntos/boot/bldr/i386/osloader.def59
-rw-r--r--private/ntos/boot/bldr/i386/parsboot.c1338
-rw-r--r--private/ntos/boot/bldr/i386/sources4
-rw-r--r--private/ntos/boot/bldr/ilinkldr.rsp19
-rw-r--r--private/ntos/boot/bldr/makefile6
-rw-r--r--private/ntos/boot/bldr/makefile.inc38
-rw-r--r--private/ntos/boot/bldr/mipsldr.rsp18
-rw-r--r--private/ntos/boot/bldr/msg.usa408
-rw-r--r--private/ntos/boot/bldr/osloader.c1300
-rw-r--r--private/ntos/boot/bldr/osloader.rc15
-rw-r--r--private/ntos/boot/bldr/ppcldr.rsp18
-rw-r--r--private/ntos/boot/bldr/regboot.c1588
-rw-r--r--private/ntos/boot/bldr/sources51
-rw-r--r--private/ntos/boot/bootcode/etfs/i386/etfsboot.asm584
-rw-r--r--private/ntos/boot/bootcode/etfs/i386/usa/bootetfs.h133
-rw-r--r--private/ntos/boot/bootcode/etfs/i386/usa/etfsboot.inc27
-rw-r--r--private/ntos/boot/bootcode/fat/i386/fatboot.asm426
-rw-r--r--private/ntos/boot/bootcode/fat/i386/usa/bootfat.h37
-rw-r--r--private/ntos/boot/bootcode/fat/i386/usa/fatboot.inc28
-rw-r--r--private/ntos/boot/bootcode/hpfs/i386/buf.inc222
-rw-r--r--private/ntos/boot/bootcode/hpfs/i386/chain.inc7
-rw-r--r--private/ntos/boot/bootcode/hpfs/i386/const.inc201
-rw-r--r--private/ntos/boot/bootcode/hpfs/i386/dir.inc286
-rw-r--r--private/ntos/boot/bootcode/hpfs/i386/dirent.inc80
-rw-r--r--private/ntos/boot/bootcode/hpfs/i386/filemode.inc105
-rw-r--r--private/ntos/boot/bootcode/hpfs/i386/fnode.inc214
-rw-r--r--private/ntos/boot/bootcode/hpfs/i386/fsstat.inc66
-rw-r--r--private/ntos/boot/bootcode/hpfs/i386/macro.inc781
-rw-r--r--private/ntos/boot/bootcode/hpfs/i386/makefile6
-rw-r--r--private/ntos/boot/bootcode/hpfs/i386/misc.inc64
-rw-r--r--private/ntos/boot/bootcode/hpfs/i386/pinboot.asm727
-rw-r--r--private/ntos/boot/bootcode/hpfs/i386/sources38
-rw-r--r--private/ntos/boot/bootcode/hpfs/i386/superb.inc242
-rw-r--r--private/ntos/boot/bootcode/hpfs/i386/tables.inc201
-rw-r--r--private/ntos/boot/bootcode/hpfs/i386/usa/boothpfs.h517
-rw-r--r--private/ntos/boot/bootcode/hpfs/i386/usa/pinboot.inc30
-rw-r--r--private/ntos/boot/bootcode/hpfs/i386/volume.inc102
-rw-r--r--private/ntos/boot/bootcode/mbr/i386/usa/bootmbr.h37
-rw-r--r--private/ntos/boot/bootcode/mbr/i386/usa/x86mboot.msg5
-rw-r--r--private/ntos/boot/bootcode/mbr/i386/x86mboot.asm133
-rw-r--r--private/ntos/boot/bootcode/ntfs/i386/ntfs.inc214
-rw-r--r--private/ntos/boot/bootcode/ntfs/i386/ntfsboot.asm2740
-rw-r--r--private/ntos/boot/bootcode/ntfs/i386/usa/bootntfs.h517
-rw-r--r--private/ntos/boot/bootcode/ntfs/i386/usa/ntfsboot.inc36
-rw-r--r--private/ntos/boot/bootfont/jpn/bootfont.binbin0 -> 124764 bytes
-rw-r--r--private/ntos/boot/bootfont/jpn/fntjapan.h3776
-rw-r--r--private/ntos/boot/bootfont/jpn/genfont.c110
-rw-r--r--private/ntos/boot/bootfont/jpn/makefile6
-rw-r--r--private/ntos/boot/bootfont/jpn/sources29
-rw-r--r--private/ntos/boot/bootfont/readme.txt6
-rw-r--r--private/ntos/boot/dbcs.txt48
-rw-r--r--private/ntos/boot/detect/chk/16bitbld.cmd5
-rw-r--r--private/ntos/boot/detect/chk/makefile6
-rw-r--r--private/ntos/boot/detect/chk/makefile.inc119
-rw-r--r--private/ntos/boot/detect/chk/sources67
-rw-r--r--private/ntos/boot/detect/dirs25
-rw-r--r--private/ntos/boot/detect/fre/16bitbld.cmd5
-rw-r--r--private/ntos/boot/detect/fre/makefile6
-rw-r--r--private/ntos/boot/detect/fre/makefile.inc121
-rw-r--r--private/ntos/boot/detect/fre/sources67
-rw-r--r--private/ntos/boot/detect/i386/backend.asm28
-rw-r--r--private/ntos/boot/detect/i386/bios.h175
-rw-r--r--private/ntos/boot/detect/i386/comlpt.h123
-rw-r--r--private/ntos/boot/detect/i386/comlptc.c983
-rw-r--r--private/ntos/boot/detect/i386/cpu.asm902
-rw-r--r--private/ntos/boot/detect/i386/cpu.inc72
-rw-r--r--private/ntos/boot/detect/i386/disk.h87
-rw-r--r--private/ntos/boot/detect/i386/diska.asm332
-rw-r--r--private/ntos/boot/detect/i386/diskc.c540
-rw-r--r--private/ntos/boot/detect/i386/display.c632
-rw-r--r--private/ntos/boot/detect/i386/eisa.h215
-rw-r--r--private/ntos/boot/detect/i386/hwapm.c79
-rw-r--r--private/ntos/boot/detect/i386/hwdetect.c1393
-rw-r--r--private/ntos/boot/detect/i386/hwdetect.h542
-rw-r--r--private/ntos/boot/detect/i386/hweisa.inc61
-rw-r--r--private/ntos/boot/detect/i386/hweisaa.asm279
-rw-r--r--private/ntos/boot/detect/i386/hweisac.c308
-rw-r--r--private/ntos/boot/detect/i386/hwheap.c229
-rw-r--r--private/ntos/boot/detect/i386/hwmacha.asm1346
-rw-r--r--private/ntos/boot/detect/i386/hwmcaa.asm265
-rw-r--r--private/ntos/boot/detect/i386/hwmcac.c86
-rw-r--r--private/ntos/boot/detect/i386/hwmisca.asm363
-rw-r--r--private/ntos/boot/detect/i386/hwpbiosc.c195
-rw-r--r--private/ntos/boot/detect/i386/hwpci.inc44
-rw-r--r--private/ntos/boot/detect/i386/hwpcia.asm279
-rw-r--r--private/ntos/boot/detect/i386/hwvbios.h74
-rw-r--r--private/ntos/boot/detect/i386/hwvbiosc.c968
-rw-r--r--private/ntos/boot/detect/i386/keybda.asm480
-rw-r--r--private/ntos/boot/detect/i386/keybdc.c356
-rw-r--r--private/ntos/boot/detect/i386/main.asm207
-rw-r--r--private/ntos/boot/detect/i386/main.inc53
-rw-r--r--private/ntos/boot/detect/i386/mouse.inc392
-rw-r--r--private/ntos/boot/detect/i386/mousea.asm1610
-rw-r--r--private/ntos/boot/detect/i386/mousec.c758
-rw-r--r--private/ntos/boot/detect/i386/ntmisc.h61
-rw-r--r--private/ntos/boot/detect/i386/pnpbios.h87
-rw-r--r--private/ntos/boot/detect/i386/string.h111
-rw-r--r--private/ntos/boot/detect/i386/types.h128
-rw-r--r--private/ntos/boot/detect/i386/video.inc370
-rw-r--r--private/ntos/boot/detect/i386/videoa.asm2175
-rw-r--r--private/ntos/boot/detect/i386/videoc.c300
-rw-r--r--private/ntos/boot/dirs29
-rw-r--r--private/ntos/boot/inc/bldr.h747
-rw-r--r--private/ntos/boot/inc/bldrx86.h234
-rw-r--r--private/ntos/boot/inc/cdfsboot.h175
-rw-r--r--private/ntos/boot/inc/fatboot.h293
-rw-r--r--private/ntos/boot/inc/hpfsboot.h895
-rw-r--r--private/ntos/boot/inc/ntfsboot.h204
-rw-r--r--private/ntos/boot/inc/scsiboot.h500
-rw-r--r--private/ntos/boot/lib/alpha/alphamem.c189
-rw-r--r--private/ntos/boot/lib/alpha/ntsetup.c855
-rw-r--r--private/ntos/boot/lib/alpha/palldr.c399
-rw-r--r--private/ntos/boot/lib/alpha/sources4
-rw-r--r--private/ntos/boot/lib/alpha/stubs.c244
-rw-r--r--private/ntos/boot/lib/arcdisk.c240
-rw-r--r--private/ntos/boot/lib/blbind.c836
-rw-r--r--private/ntos/boot/lib/blconfig.c939
-rw-r--r--private/ntos/boot/lib/blio.c845
-rw-r--r--private/ntos/boot/lib/blload.c736
-rw-r--r--private/ntos/boot/lib/bllog.c287
-rw-r--r--private/ntos/boot/lib/blmemory.c1256
-rw-r--r--private/ntos/boot/lib/blmisc.c131
-rw-r--r--private/ntos/boot/lib/blres.c363
-rw-r--r--private/ntos/boot/lib/bootlib.h136
-rw-r--r--private/ntos/boot/lib/cdfsboot.c1695
-rw-r--r--private/ntos/boot/lib/etfsboot.c1734
-rw-r--r--private/ntos/boot/lib/etfsboot.h210
-rw-r--r--private/ntos/boot/lib/fatboot.c5639
-rw-r--r--private/ntos/boot/lib/hpfsboot.c1515
-rw-r--r--private/ntos/boot/lib/i386/abios.h175
-rw-r--r--private/ntos/boot/lib/i386/abiosc.c1307
-rw-r--r--private/ntos/boot/lib/i386/arcemul.c1789
-rw-r--r--private/ntos/boot/lib/i386/biosdrv.c2177
-rw-r--r--private/ntos/boot/lib/i386/bootfont.h106
-rw-r--r--private/ntos/boot/lib/i386/bootx86.h414
-rw-r--r--private/ntos/boot/lib/i386/decode.inc515
-rw-r--r--private/ntos/boot/lib/i386/disp_gr.c1146
-rw-r--r--private/ntos/boot/lib/i386/disp_tm.c441
-rw-r--r--private/ntos/boot/lib/i386/display.c659
-rw-r--r--private/ntos/boot/lib/i386/displayp.h154
-rw-r--r--private/ntos/boot/lib/i386/driverld.c92
-rw-r--r--private/ntos/boot/lib/i386/entry.c482
-rw-r--r--private/ntos/boot/lib/i386/flop.h38
-rw-r--r--private/ntos/boot/lib/i386/flopcach.c316
-rw-r--r--private/ntos/boot/lib/i386/ixbusdat.c535
-rw-r--r--private/ntos/boot/lib/i386/ixcmos.asm172
-rw-r--r--private/ntos/boot/lib/i386/ixfwhal.h147
-rw-r--r--private/ntos/boot/lib/i386/ixhwsup.c2007
-rw-r--r--private/ntos/boot/lib/i386/ixpcibus.c1381
-rw-r--r--private/ntos/boot/lib/i386/ixphwsup.c119
-rw-r--r--private/ntos/boot/lib/i386/lnkconst.asm18
-rw-r--r--private/ntos/boot/lib/i386/machine.c390
-rw-r--r--private/ntos/boot/lib/i386/mca.h240
-rw-r--r--private/ntos/boot/lib/i386/mdequ.inc224
-rw-r--r--private/ntos/boot/lib/i386/memory.c1704
-rw-r--r--private/ntos/boot/lib/i386/ntsetup.c379
-rw-r--r--private/ntos/boot/lib/i386/osloader.def58
-rw-r--r--private/ntos/boot/lib/i386/rdcomp.asm317
-rw-r--r--private/ntos/boot/lib/i386/sources24
-rw-r--r--private/ntos/boot/lib/i386/stubs.c190
-rw-r--r--private/ntos/boot/lib/i386/xxioacc.asm362
-rw-r--r--private/ntos/boot/lib/makefile6
-rw-r--r--private/ntos/boot/lib/mips/coffldr.c247
-rw-r--r--private/ntos/boot/lib/mips/fwio.c345
-rw-r--r--private/ntos/boot/lib/mips/ntsetup.c652
-rw-r--r--private/ntos/boot/lib/mips/query.s70
-rw-r--r--private/ntos/boot/lib/mips/sources5
-rw-r--r--private/ntos/boot/lib/mips/stubs.c245
-rw-r--r--private/ntos/boot/lib/mips/xxchkstk.s54
-rw-r--r--private/ntos/boot/lib/mips/xxconout.c400
-rw-r--r--private/ntos/boot/lib/nlsboot.c709
-rw-r--r--private/ntos/boot/lib/ntfsboot.c3416
-rw-r--r--private/ntos/boot/lib/peldr.c499
-rw-r--r--private/ntos/boot/lib/ppc/ntsetup.c1615
-rw-r--r--private/ntos/boot/lib/ppc/query.s103
-rw-r--r--private/ntos/boot/lib/ppc/sources5
-rw-r--r--private/ntos/boot/lib/ppc/stubs.c244
-rw-r--r--private/ntos/boot/lib/ppc/xxchkstk.s51
-rw-r--r--private/ntos/boot/lib/scsiboot.c5588
-rw-r--r--private/ntos/boot/lib/scsidisk.c3225
-rw-r--r--private/ntos/boot/lib/sources56
-rw-r--r--private/ntos/boot/makefil0106
-rw-r--r--private/ntos/boot/setup/alpha/sources5
-rw-r--r--private/ntos/boot/setup/alphaldr.rsp17
-rw-r--r--private/ntos/boot/setup/arcdisp.c1762
-rw-r--r--private/ntos/boot/setup/arcdtect.c553
-rw-r--r--private/ntos/boot/setup/config.c126
-rw-r--r--private/ntos/boot/setup/i386/cpu386.asm82
-rw-r--r--private/ntos/boot/setup/i386/detmach.asm386
-rw-r--r--private/ntos/boot/setup/i386/detsup.c184
-rw-r--r--private/ntos/boot/setup/i386/initx86.c126
-rw-r--r--private/ntos/boot/setup/i386/setupldr.def58
-rw-r--r--private/ntos/boot/setup/i386/sources9
-rw-r--r--private/ntos/boot/setup/i386/x86dtect.c363
-rw-r--r--private/ntos/boot/setup/ilinkldr.rsp19
-rw-r--r--private/ntos/boot/setup/makefile6
-rw-r--r--private/ntos/boot/setup/makefile.inc63
-rw-r--r--private/ntos/boot/setup/mips/sources5
-rw-r--r--private/ntos/boot/setup/mipsldr.rsp17
-rw-r--r--private/ntos/boot/setup/msgs.usa474
-rw-r--r--private/ntos/boot/setup/oemdisk.c1953
-rw-r--r--private/ntos/boot/setup/parseini.c1973
-rw-r--r--private/ntos/boot/setup/ppc/sources5
-rw-r--r--private/ntos/boot/setup/ppcldr.rsp17
-rw-r--r--private/ntos/boot/setup/setup.c2526
-rw-r--r--private/ntos/boot/setup/setupldr.h550
-rw-r--r--private/ntos/boot/setup/setupldr.rc16
-rw-r--r--private/ntos/boot/setup/sources47
-rw-r--r--private/ntos/boot/startup/16bitbld.cmd9
-rw-r--r--private/ntos/boot/startup/i386/a20.asm359
-rw-r--r--private/ntos/boot/startup/i386/abios.inc112
-rw-r--r--private/ntos/boot/startup/i386/abiosa.asm556
-rw-r--r--private/ntos/boot/startup/i386/backend.asm28
-rw-r--r--private/ntos/boot/startup/i386/constant.h91
-rw-r--r--private/ntos/boot/startup/i386/display.c632
-rw-r--r--private/ntos/boot/startup/i386/eisa.h102
-rw-r--r--private/ntos/boot/startup/i386/eisa.inc61
-rw-r--r--private/ntos/boot/startup/i386/eisaa.asm216
-rw-r--r--private/ntos/boot/startup/i386/eisac.c538
-rw-r--r--private/ntos/boot/startup/i386/exp.asm1610
-rw-r--r--private/ntos/boot/startup/i386/global.h190
-rw-r--r--private/ntos/boot/startup/i386/macro.inc239
-rw-r--r--private/ntos/boot/startup/i386/main.c642
-rw-r--r--private/ntos/boot/startup/i386/memmap.h83
-rw-r--r--private/ntos/boot/startup/i386/memmap.inc24
-rw-r--r--private/ntos/boot/startup/i386/ntmisc.h60
-rw-r--r--private/ntos/boot/startup/i386/su.asm1458
-rw-r--r--private/ntos/boot/startup/i386/su.h14
-rw-r--r--private/ntos/boot/startup/i386/su.inc466
-rw-r--r--private/ntos/boot/startup/i386/sudata.asm522
-rw-r--r--private/ntos/boot/startup/i386/trap.asm388
-rw-r--r--private/ntos/boot/startup/i386/trapdump.c425
-rw-r--r--private/ntos/boot/startup/i386/types.h383
-rw-r--r--private/ntos/boot/startup/i386/usa/strings.h44
-rw-r--r--private/ntos/boot/startup/makefile6
-rw-r--r--private/ntos/boot/startup/makefile.inc125
-rw-r--r--private/ntos/boot/startup/sources54
-rw-r--r--private/ntos/boot/veneer/makefile6
-rw-r--r--private/ntos/boot/veneer/makefile.inc64
-rw-r--r--private/ntos/boot/veneer/ppc/pxcache.s139
-rw-r--r--private/ntos/boot/veneer/ppc/pxutil.s62
-rw-r--r--private/ntos/boot/veneer/ppc/sources36
-rw-r--r--private/ntos/boot/veneer/ppc/vrmp.s171
-rw-r--r--private/ntos/boot/veneer/ppc/vrstart.s116
-rw-r--r--private/ntos/boot/veneer/proto.h222
-rw-r--r--private/ntos/boot/veneer/sources49
-rw-r--r--private/ntos/boot/veneer/veneer.h287
-rw-r--r--private/ntos/boot/veneer/verno.c34
-rw-r--r--private/ntos/boot/veneer/vrbat.h112
-rw-r--r--private/ntos/boot/veneer/vrconfig.c567
-rw-r--r--private/ntos/boot/veneer/vrcons.c55
-rw-r--r--private/ntos/boot/veneer/vrcpiwrp.c525
-rw-r--r--private/ntos/boot/veneer/vrdisp.c169
-rw-r--r--private/ntos/boot/veneer/vrdumptr.c212
-rw-r--r--private/ntos/boot/veneer/vrenv.c254
-rw-r--r--private/ntos/boot/veneer/vrheader.h325
-rw-r--r--private/ntos/boot/veneer/vrio.c1425
-rw-r--r--private/ntos/boot/veneer/vrlib.c614
-rw-r--r--private/ntos/boot/veneer/vrload.c1035
-rw-r--r--private/ntos/boot/veneer/vrmain.c1314
-rw-r--r--private/ntos/boot/veneer/vrmalloc.c355
-rw-r--r--private/ntos/boot/veneer/vrmemory.c481
-rw-r--r--private/ntos/boot/veneer/vrmisc.c221
-rw-r--r--private/ntos/boot/veneer/vrpehdr.c138
-rw-r--r--private/ntos/boot/veneer/vrrstart.c274
-rw-r--r--private/ntos/boot/veneer/vrsup.c369
-rw-r--r--private/ntos/boot/veneer/vrtree.c2012
-rw-r--r--private/ntos/boot/veneer/vrtree.h153
271 files changed, 125908 insertions, 0 deletions
diff --git a/private/ntos/boot/bldr/alphaldr.rsp b/private/ntos/boot/bldr/alphaldr.rsp
new file mode 100644
index 000000000..5ede2f3cc
--- /dev/null
+++ b/private/ntos/boot/bldr/alphaldr.rsp
@@ -0,0 +1,17 @@
+-machine:alpha
+-rom
+-force:multiple
+-debug:notmapped
+-debugtype:coff
+-fixed
+-map:obj\alpha\osloader.map
+-align:0x200
+-base:0x80600000
+-entry:BlOsLoader
+obj\alpha\bldr.lib
+obj\alpha\osloader.res
+..\obj\alpha\boot.lib
+..\..\obj\alpha\ke.lib
+..\..\rtl\obj\alpha\bldrrtl.lib
+..\..\..\..\public\sdk\lib\alpha\libcntpr.lib
+..\..\config\obj\alpha\bconfig.lib
diff --git a/private/ntos/boot/bldr/diagload.h b/private/ntos/boot/bldr/diagload.h
new file mode 100644
index 000000000..ee596e88d
--- /dev/null
+++ b/private/ntos/boot/bldr/diagload.h
@@ -0,0 +1,204 @@
+//
+// Diagnostic loader messages.
+//
+//
+// Defines for Class, Detail and Action are used to lookup
+// text from DiagLoadClass, DiagLoadDetail and DiagLoadAction
+// respectively. One must change LOAD_CL_END, DIAG_BL_END
+// and LOAD_ACT_END to reflect any change in the content of
+// the tables. They are used for bounds checking to avoid
+// access violations.
+
+//
+// Class Definitions
+//
+
+#define LOAD_SW_INT_ERR_CLASS 0x00000000L
+#define LOAD_SW_MISRQD_FILE_CLASS 0x00000001L
+#define LOAD_SW_BAD_FILE_CLASS 0x00000002L
+#define LOAD_SW_MIS_FILE_CLASS 0x00000003L
+#define LOAD_HW_MEM_CLASS 0x00000004L
+#define LOAD_HW_DISK_CLASS 0x00000005L
+#define LOAD_HW_GEN_ERR_CLASS 0x00000006L
+#define LOAD_HW_FW_CFG_CLASS 0x00000007L
+#define LOAD_CL_END 0x00000008L
+
+
+//
+// Class Declarations
+//
+
+static PCHAR DiagLoadClass[] = {
+
+"Windows NT could not start because of an error in the software.\r\nPlease report this problem as :\r\n\0",
+"Windows NT could not start because the following file was not found\r\nand is required :\r\n\0",
+"Windows NT could not start because of a bad copy of the following file :\r\n\0",
+"Windows NT could not start because the following file is missing or corrupt:\r\n\0",
+"Windows NT could not start because of a hardware memory configuration\r\nproblem.\r\n\0",
+"Windows NT could not start because of a computer disk hardware\r\nconfiguration problem.\r\n\0",
+"Windows NT could not start because of a general computer hardware\r\nconfiguration problem.\r\n\0",
+"Windows NT could not start because of the following ARC firmware\r\nboot configuration problem :\r\n\0"
+
+};
+
+//
+// Detail Definitions
+//
+
+#define DIAG_BL_MEMORY_INIT 0L
+#define DIAG_BL_CONFIG_INIT 1L
+#define DIAG_BL_IO_INIT 2L
+#define DIAG_BL_FW_GET_BOOT_DEVICE 3L
+#define DIAG_BL_OPEN_BOOT_DEVICE 4L
+#define DIAG_BL_FW_GET_SYSTEM_DEVICE 5L
+#define DIAG_BL_FW_OPEN_SYSTEM_DEVICE 6L
+#define DIAG_BL_GET_SYSTEM_PATH 7L
+#define DIAG_BL_LOAD_SYSTEM_IMAGE 8L
+#define DIAG_BL_FIND_HAL_IMAGE 9L
+#define DIAG_BL_LOAD_HAL_IMAGE 10L
+#define DIAG_BL_LOAD_SYSTEM_IMAGE_DATA 11L
+#define DIAG_BL_LOAD_HAL_IMAGE_DATA 12L
+#define DIAG_BL_LOAD_SYSTEM_DLLS 13L
+#define DIAG_BL_LOAD_HAL_DLLS 14L
+#define DIAG_BL_READ_SYSTEM_REGISTRY 15L
+#define DIAG_BL_LOAD_SYSTEM_REGISTRY 16L
+#define DIAG_BL_FIND_SYSTEM_DRIVERS 17L
+#define DIAG_BL_READ_SYSTEM_DRIVERS 18L
+#define DIAG_BL_LOAD_DEVICE_DRIVER 19L
+#define DIAG_BL_LOAD_SYSTEM_HIVE 20L
+#define DIAG_BL_SYSTEM_PART_DEV_NAME 21L
+#define DIAG_BL_BOOT_PART_DEV_NAME 22L
+#define DIAG_BL_ARC_BOOT_DEV_NAME 23L
+#define DIAG_BL_ARC_HAL_NAME 24L
+#define DIAG_BL_SETUP_FOR_NT 25L
+#define DIAG_BL_KERNEL_INIT_XFER 26L
+#define DIAG_BL_END 27L
+
+//
+// Detail Declarations
+//
+
+static PCHAR DiagLoadDetail[] = {
+
+// DIAG_BL_MEMORY_INIT 0L
+"Check hardware memory configuration and amount of RAM.\r\n\0",
+
+// DIAG_BL_CONFIG_INIT 1L
+"Too many configuration entries.\r\n\0",
+
+// DIAG_BL_IO_INIT 2L
+"Could not access disk partition tables \r\n\0",
+
+// DIAG_BL_FW_GET_BOOT_DEVICE 3L
+"The 'osloadpartition' parameter setting is invalid.\r\n\0",
+
+// DIAG_BL_OPEN_BOOT_DEVICE 4L
+"Could not read from the selected boot disk. Check boot path\r\nand disk hardware.\r\n\0",
+
+// DIAG_BL_FW_GET_SYSTEM_DEVICE 5L
+"The 'systempartition' parameter setting is invalid.\r\n\0",
+
+// DIAG_BL_FW_OPEN_SYSTEM_DEVICE 6L
+"Could not read from the selected system boot disk.\r\nCheck 'systempartition' path.\r\n\0",
+
+// DIAG_BL_GET_SYSTEM_PATH 7L
+"The 'osloadfilename' parameter does not point to a valid file.\r\n\0",
+
+// DIAG_BL_LOAD_SYSTEM_IMAGE 8L
+"<winnt root>\\system32\\ntoskrnl.exe.\r\n\0",
+
+// DIAG_BL_FIND_HAL_IMAGE 9L
+"The 'osloader' parameter does not point to a valid file.\r\n\0",
+
+// DIAG_BL_LOAD_HAL_IMAGE 10L
+#if defined(i386)
+"<winnt root>\\system32\\hal.dll.\r\n\0",
+#endif
+
+#if defined(MIPS)
+"'osloader'\\hal.dll\r\n\0",
+#endif
+
+// DIAG_BL_LOAD_SYSTEM_IMAGE_DATA 11L
+"Loader error 1.\r\n\0",
+
+// DIAG_BL_LOAD_HAL_IMAGE_DATA 12L
+"Loader error 2.\r\n\0",
+
+// DIAG_BL_LOAD_SYSTEM_DLLS 13L
+"load needed DLLs for kernel.\r\n\0",
+
+// DIAG_BL_LOAD_HAL_DLLS 14L
+"load needed DLLs for HAL.\r\n\0",
+
+// DIAG_BL_READ_SYSTEM_REGISTRY 15L
+"<winnt root>\\system32\\config\\system. \r\n\0",
+
+// DIAG_BL_LOAD_SYSTEM_REGISTRY 16L
+"<winnt root>\\system32\\config\\system. \r\n\0",
+
+// DIAG_BL_FIND_SYSTEM_DRIVERS 17L
+"find system drivers.\r\n\0",
+
+// DIAG_BL_READ_SYSTEM_DRIVERS 18L
+"read system drivers.\r\n\0",
+
+// DIAG_BL_LOAD_DEVICE_DRIVER 19L
+"did not load system boot device driver.\r\n\0",
+
+// DIAG_BL_LOAD_SYSTEM_HIVE 20L
+"load system hardware configuration file.\r\n\0",
+
+// DIAG_BL_SYSTEM_PART_DEV_NAME 21L
+"find system partition name device name.\r\n\0",
+
+// DIAG_BL_BOOT_PART_DEV_NAME 22L
+"find boot partition name.\r\n\0",
+
+// DIAG_BL_ARC_BOOT_DEV_NAME 23L
+"did not properly generate ARC name for HAL and system paths.\r\n\0",
+
+// DIAG_BL_ARC_HAL_NAME 24L
+"did not properly generate ARC name for HAL and system paths.\r\n\0",
+
+// DIAG_BL_SETUP_FOR_NT 25L
+"Loader error 3.\r\n\0",
+
+// DIAG_BL_KERNEL_INIT_XFER 25L
+"<winnt root>\\system32\\ntoskrnl.exe\r\n\0"
+
+};
+
+
+//
+// Action Definitions
+//
+
+#define LOAD_SW_INT_ERR_ACT 0x00000000L
+#define LOAD_SW_FILE_REST_ACT 0x00000001L
+#define LOAD_SW_FILE_REINST_ACT 0x00000002L
+#define LOAD_HW_MEM_ACT 0x00000003L
+#define LOAD_HW_DISK_ACT 0x00000004L
+#define LOAD_HW_GEN_ACT 0x00000005L
+#define LOAD_HW_FW_CFG_ACT 0x00000006L
+#define LOAD_ACT_END 0x00000007L
+
+
+//
+// Action Declarations
+//
+
+static PCHAR DiagLoadAction[] = {
+
+"Please contact your support person to report this problem.\r\n\0",
+"You can attempt to repair this file by starting Windows NT\r\n"
+"Setup using the original Setup floppy disk or CD-ROM.\r\n"
+"Select 'r' at the first screen to start repair.\r\n\0",
+"Please re-install a copy of the above file.\r\n\0",
+"Please check the Windows NT(TM) documentation about hardware\r\nmemory requirements and your hardware reference manuals for\r\nadditional information.\r\n\0",
+"Please check the Windows NT(TM) documentation about hardware\r\ndisk configuration and your hardware reference manuals for\r\nadditional information.\r\n\0",
+"Please check the Windows NT(TM) documentation about hardware\r\nconfiguration and your hardware reference manuals for additional\r\ninformation.\r\n\0",
+"Please check the Windows NT(TM) documentation about ARC configuration\r\noptions and your hardware reference manuals for additional\r\ninformation.\r\n\0"
+};
+
+
diff --git a/private/ntos/boot/bldr/i386/initx86.c b/private/ntos/boot/bldr/i386/initx86.c
new file mode 100644
index 000000000..699f53945
--- /dev/null
+++ b/private/ntos/boot/bldr/i386/initx86.c
@@ -0,0 +1,311 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ initx86.c
+
+Abstract:
+
+ Does any x86-specific initialization, then starts the common ARC osloader
+
+Author:
+
+ John Vert (jvert) 4-Nov-1993
+
+Revision History:
+
+--*/
+#include "bldrx86.h"
+#include "msg.h"
+
+UCHAR BootPartitionName[80];
+UCHAR KernelBootDevice[80];
+UCHAR OsLoadFilename[100];
+UCHAR OsLoaderFilename[100];
+UCHAR SystemPartition[100];
+UCHAR OsLoadPartition[100];
+UCHAR OsLoadOptions[100];
+UCHAR ConsoleInputName[50];
+UCHAR MyBuffer[SECTOR_SIZE+32];
+UCHAR ConsoleOutputName[50];
+UCHAR X86SystemPartition[sizeof("x86systempartition=") + sizeof(BootPartitionName)];
+
+
+VOID
+BlStartup(
+ IN PCHAR PartitionName
+ )
+
+/*++
+
+Routine Description:
+
+ Does x86-specific initialization, particularly presenting the boot.ini
+ menu and running NTDETECT, then calls to the common osloader.
+
+Arguments:
+
+ PartitionName - Supplies the ARC name of the partition (or floppy) that
+ setupldr was loaded from.
+
+Return Value:
+
+ Does not return
+
+--*/
+
+{
+ PUCHAR Argv[10];
+ ARC_STATUS Status;
+ ULONG BootFileId;
+ PCHAR BootFile;
+ ULONG Read;
+ PCHAR p;
+ ULONG i;
+ ULONG DriveId;
+ ULONG FileSize;
+ ULONG Count;
+ LARGE_INTEGER SeekPosition;
+ PCHAR LoadOptions = NULL;
+ BOOLEAN UseTimeOut=TRUE;
+ BOOLEAN AlreadyInitialized = FALSE;
+ extern BOOLEAN FwDescriptorsValid;
+
+ //
+ // Open the boot partition so we can load boot drivers off it.
+ //
+ Status = ArcOpen(PartitionName, ArcOpenReadOnly, &DriveId);
+ if (Status != ESUCCESS) {
+ BlPrint("Couldn't open drive %s\n",PartitionName);
+ BlPrint(BlFindMessage(BL_DRIVE_ERROR),PartitionName);
+ goto BootFailed;
+ }
+
+ //
+ // Initialize dbcs font and display support.
+ //
+ TextGrInitialize(DriveId);
+
+ do {
+
+ Status = BlOpen( DriveId,
+ "\\boot.ini",
+ ArcOpenReadOnly,
+ &BootFileId );
+
+ BootFile = MyBuffer;
+
+ RtlZeroMemory(MyBuffer, SECTOR_SIZE+32);
+
+ if (Status != ESUCCESS) {
+ BootFile[0]='\0';
+ } else {
+ //
+ // Determine the length of the boot.ini file by reading to the end of
+ // file.
+ //
+
+ FileSize = 0;
+ do {
+ Status = BlRead(BootFileId, BootFile, SECTOR_SIZE, &Count);
+ if (Status != ESUCCESS) {
+ BlClose(BootFileId);
+ BlPrint(BlFindMessage(BL_READ_ERROR),Status);
+ BootFile[0] = '\0';
+ FileSize = 0;
+ Count = 0;
+ goto BootFailed;
+ }
+
+ FileSize += Count;
+ } while (Count != 0);
+
+ if (FileSize >= SECTOR_SIZE) {
+
+ //
+ // We need to allocate a bigger buffer, since the boot.ini file
+ // is bigger than one sector.
+ //
+
+ BootFile=FwAllocateHeap(FileSize);
+ }
+
+ if (BootFile == NULL) {
+ BlPrint(BlFindMessage(BL_READ_ERROR),ENOMEM);
+ BootFile = MyBuffer;
+ BootFile[0] = '\0';
+ goto BootFailed;
+ } else {
+
+ SeekPosition.QuadPart = 0;
+ Status = BlSeek(BootFileId,
+ &SeekPosition,
+ SeekAbsolute);
+ if (Status != ESUCCESS) {
+ BlPrint(BlFindMessage(BL_READ_ERROR),Status);
+ BootFile = MyBuffer;
+ BootFile[0] = '\0';
+ goto BootFailed;
+ } else {
+ Status = BlRead( BootFileId,
+ BootFile,
+ FileSize,
+ &Read );
+
+ SeekPosition.QuadPart = 0;
+ Status = BlSeek(BootFileId,
+ &SeekPosition,
+ SeekAbsolute);
+ if (Status != ESUCCESS) {
+ BlPrint(BlFindMessage(BL_READ_ERROR),Status);
+ BootFile = MyBuffer;
+ BootFile[0] = '\0';
+ goto BootFailed;
+ } else {
+ BootFile[Read]='\0';
+ }
+ }
+ }
+
+ //
+ // Find Ctrl-Z, if it exists
+ //
+
+ p=BootFile;
+ while ((*p!='\0') && (*p!=26)) {
+ ++p;
+ }
+ if (*p != '\0') {
+ *p='\0';
+ }
+ BlClose(BootFileId);
+ }
+
+ if (!AlreadyInitialized) {
+ AbiosInitDataStructures();
+ }
+
+ MdShutoffFloppy();
+
+ TextClearDisplay();
+
+ p=BlSelectKernel(DriveId,BootFile, &LoadOptions, UseTimeOut);
+
+ if (!AlreadyInitialized) {
+
+ BlPrint(BlFindMessage(BL_NTDETECT_MSG));
+ if (!BlDetectHardware(DriveId, LoadOptions)) {
+ BlPrint(BlFindMessage(BL_NTDETECT_FAILURE));
+ return;
+ }
+
+ TextClearDisplay();
+
+ //
+ // Initialize SCSI boot driver, if necessary.
+ //
+ if(!_strnicmp(p,"scsi(",5)) {
+ AEInitializeIo(DriveId);
+ }
+ ArcClose(DriveId);
+ //
+ // Indicate that fw memory descriptors cannot be changed from
+ // now on.
+ //
+ FwDescriptorsValid = FALSE;
+ } else {
+ TextClearDisplay();
+ }
+
+ //
+ // Set AlreadyInitialized Flag to TRUE to indicate that ntdetect
+ // and abios init routines have been run.
+ //
+
+ AlreadyInitialized = TRUE;
+
+ //
+ // Only time out the boot menu the first time through the boot.
+ // For all subsequent reboots, the menu will stay up.
+ //
+ UseTimeOut=FALSE;
+
+ i=0;
+ while (*p !='\\') {
+ KernelBootDevice[i] = *p;
+ i++;
+ p++;
+ }
+ KernelBootDevice[i] = '\0';
+
+ strcpy(OsLoadFilename,"osloadfilename=");
+ strcat(OsLoadFilename,p);
+
+ //
+ // We are fooling the OS Loader here. It only uses the osloader= variable
+ // to determine where to load HAL.DLL from. Since x86 systems have no
+ // "system partition" we want to load HAL.DLL from \nt\system\HAL.DLL.
+ // So we pass that it as the osloader path.
+ //
+
+ strcpy(OsLoaderFilename,"osloader=");
+ strcat(OsLoaderFilename,p);
+ strcat(OsLoaderFilename,"\\System32\\NTLDR");
+
+ strcpy(SystemPartition,"systempartition=");
+ strcat(SystemPartition,KernelBootDevice);
+
+ strcpy(OsLoadPartition,"osloadpartition=");
+ strcat(OsLoadPartition,KernelBootDevice);
+
+ strcpy(OsLoadOptions,"osloadoptions=");
+ if (LoadOptions) {
+ strcat(OsLoadOptions,LoadOptions);
+ }
+
+
+ strcpy(ConsoleInputName,"consolein=multi(0)key(0)keyboard(0)");
+
+ strcpy(ConsoleOutputName,"consoleout=multi(0)video(0)monitor(0)");
+
+ strcpy(X86SystemPartition,"x86systempartition=");
+ strcat(X86SystemPartition,PartitionName);
+
+ Argv[0]="load";
+
+ Argv[1]=OsLoaderFilename;
+ Argv[2]=SystemPartition;
+ Argv[3]=OsLoadFilename;
+ Argv[4]=OsLoadPartition;
+ Argv[5]=OsLoadOptions;
+ Argv[6]=ConsoleInputName;
+ Argv[7]=ConsoleOutputName;
+ Argv[8]=X86SystemPartition;
+
+ Status = BlOsLoader(9,Argv,NULL);
+
+ BootFailed:
+
+ if (Status != ESUCCESS) {
+ //
+ // Boot failed, wait for reboot
+ //
+ while (TRUE) {
+ GET_KEY();
+ }
+ } else {
+ //
+ // Need to reopen the drive
+ //
+ Status = ArcOpen(BootPartitionName, ArcOpenReadOnly, &DriveId);
+ if (Status != ESUCCESS) {
+ BlPrint(BlFindMessage(BL_DRIVE_ERROR),BootPartitionName);
+ goto BootFailed;
+ }
+
+ }
+ } while (TRUE);
+
+}
diff --git a/private/ntos/boot/bldr/i386/osloader.def b/private/ntos/boot/bldr/i386/osloader.def
new file mode 100644
index 000000000..ab81b648e
--- /dev/null
+++ b/private/ntos/boot/bldr/i386/osloader.def
@@ -0,0 +1,59 @@
+NAME osloader
+
+EXPORTS
+ BlLoadImage
+ BlpBindImportName
+ BlAllocateAlignedDescriptor
+ BlOpen
+ BlClose
+ BlRead
+ BlWrite
+ BlGetFileInformation
+ BlSetFileInformation
+
+ RtlAssert
+ ScsiDebugPrint
+ ScsiPortInitialize
+ ScsiPortFreeDeviceBase
+ ScsiPortGetDeviceBase
+ ScsiPortGetLogicalUnit
+ ScsiPortGetPhysicalAddress
+ ScsiPortGetSrb
+ ScsiPortGetUncachedExtension
+ ScsiPortGetVirtualAddress
+ ScsiPortFlushDma
+ ScsiPortIoMapTransfer
+ ScsiPortNotification
+ ScsiPortLogError
+ ScsiPortCompleteRequest
+ ScsiPortMoveMemory
+ ScsiPortReadPortUchar
+ ScsiPortReadPortUshort
+ ScsiPortReadPortUlong
+ ScsiPortReadRegisterUchar
+ ScsiPortReadRegisterUshort
+ ScsiPortReadRegisterUlong
+ ScsiPortReadRegisterBufferUchar
+ ScsiPortReadRegisterBufferUshort
+ ScsiPortReadRegisterBufferUlong
+ ScsiPortReadPortBufferUchar
+ ScsiPortReadPortBufferUshort
+ ScsiPortReadPortBufferUlong
+ ScsiPortStallExecution
+ ScsiPortValidateRange
+ ScsiPortWritePortUchar
+ ScsiPortWritePortUshort
+ ScsiPortWritePortUlong
+ ScsiPortWriteRegisterUchar
+ ScsiPortWriteRegisterUshort
+ ScsiPortWriteRegisterUlong
+ ScsiPortWriteRegisterBufferUchar
+ ScsiPortWriteRegisterBufferUshort
+ ScsiPortWriteRegisterBufferUlong
+ ScsiPortWritePortBufferUchar
+ ScsiPortWritePortBufferUshort
+ ScsiPortWritePortBufferUlong
+ ScsiPortConvertUlongToPhysicalAddress
+ ScsiPortConvertPhysicalAddressToUlong
+ ScsiPortGetBusData
+ ScsiPortSetBusDataByOffset
diff --git a/private/ntos/boot/bldr/i386/parsboot.c b/private/ntos/boot/bldr/i386/parsboot.c
new file mode 100644
index 000000000..5d8e78a8c
--- /dev/null
+++ b/private/ntos/boot/bldr/i386/parsboot.c
@@ -0,0 +1,1338 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ parsboot.c
+
+Abstract:
+
+ Parses the boot.ini file, displays a menu, and provides a kernel
+ path and name to be passed to osloader.
+
+Author:
+
+ John Vert (jvert) 22-Jul-1991
+
+Revision History:
+
+--*/
+#include "bldrx86.h"
+#include "msg.h"
+#include "ntdddisk.h"
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#define ENTER_KEY 0x0d
+
+#define MAX_SELECTIONS 10
+#define MAX_TITLE_LENGTH 71
+
+#define WIN95_DOS 1
+#define DOS_WIN95 2
+
+typedef struct _MENU_OPTION {
+ PCHAR Title;
+ PCHAR Path;
+ BOOLEAN EnableDebug;
+ ULONG MaxMemory;
+ PCHAR LoadOptions;
+ int ForcedScsiOrdinal;
+ int Win95;
+} MENU_OPTION, *PMENU_OPTION;
+
+int ForcedScsiOrdinal = -1;
+
+
+//
+// Private function prototypes
+//
+VOID
+BlpRebootDOS(
+ IN PCHAR BootSectorImage OPTIONAL
+ );
+
+PCHAR
+BlpNextLine(
+ IN PCHAR String
+ );
+
+VOID
+BlpTranslateDosToArc(
+ IN PCHAR DosName,
+ OUT PCHAR ArcName
+ );
+
+VOID
+BlpTruncateMemory(
+ IN ULONG MaxMemory
+ );
+
+ULONG
+BlpPresentMenu(
+ IN PMENU_OPTION MenuOptions,
+ IN ULONG NumberSelections,
+ IN ULONG Default,
+ IN LONG Timeout
+ );
+
+PCHAR *
+BlpFileToLines(
+ IN PCHAR File,
+ OUT PULONG LineCount
+ );
+
+PCHAR *
+BlpFindSection(
+ IN PCHAR SectionName,
+ IN PCHAR *BootFile,
+ IN ULONG BootFileLines,
+ OUT PULONG NumberLines
+ );
+
+VOID
+BlpRenameWin95Files(
+ IN ULONG DriveId,
+ IN ULONG Type
+ );
+
+
+
+
+PCHAR
+BlSelectKernel(
+ IN ULONG DriveId,
+ IN PCHAR BootFile,
+ OUT PCHAR *LoadOptions,
+ IN BOOLEAN UseTimeOut
+ )
+/*++
+
+Routine Description:
+
+ Parses the boot.txt file and determines the fully-qualified name of
+ the kernel to be booted.
+
+Arguments:
+
+ BootFile - Pointer to the beginning of the loaded boot.txt file
+
+ Debugger - Returns the enable/disable state of the kernel debugger
+
+ UseTimeOut - Supplies whether the boot menu should time out or not.
+
+Return Value:
+
+ Pointer to the name of a kernel to boot.
+
+--*/
+
+{
+ PCHAR *MbLines;
+ PCHAR *OsLines;
+ PCHAR *FileLines;
+#if DBG
+ PCHAR *DebugLines;
+ ULONG DebugLineCount;
+#endif
+ ULONG FileLineCount;
+ ULONG OsLineCount;
+ ULONG MbLineCount;
+ PCHAR pCurrent;
+ PCHAR Option;
+ MENU_OPTION MenuOption[MAX_SELECTIONS+1];
+ ULONG NumberSystems=0;
+ ULONG i;
+ LONG Timeout;
+ ULONG Selection;
+ ULONG DefaultSelection=0;
+ static CHAR Kernel[128];
+ CHAR DosName[3];
+ PCHAR DefaultPath="C:\\winnt\\";
+ PCHAR DefaultTitle="NT (default)";
+ PCHAR p;
+
+ *LoadOptions = NULL;
+
+ if (*BootFile == '\0') {
+ //
+ // No boot.ini file, so we boot the default.
+ //
+ BlPrint(BlFindMessage(BL_INVALID_BOOT_INI),DefaultPath);
+ MenuOption[0].Path = DefaultPath;
+ MenuOption[0].Title = DefaultTitle;
+ MenuOption[0].MaxMemory = 0;
+ MenuOption[0].LoadOptions = NULL;
+ MenuOption[0].Win95 = 0;
+ NumberSystems = 1;
+ DefaultSelection = 0;
+ MbLineCount = 0;
+ OsLineCount = 0;
+ MenuOption[0].EnableDebug = FALSE;
+#if DBG
+ DebugLineCount = 0;
+#endif
+ } else {
+ FileLines = BlpFileToLines(BootFile, &FileLineCount);
+ MbLines = BlpFindSection("[boot loader]",
+ FileLines,
+ FileLineCount,
+ &MbLineCount);
+ if (MbLines==NULL) {
+ MbLines = BlpFindSection("[flexboot]",
+ FileLines,
+ FileLineCount,
+ &MbLineCount);
+ if (MbLines==NULL) {
+ MbLines = BlpFindSection("[multiboot]",
+ FileLines,
+ FileLineCount,
+ &MbLineCount);
+ }
+ }
+
+ OsLines = BlpFindSection("[operating systems]",
+ FileLines,
+ FileLineCount,
+ &OsLineCount);
+
+ if (OsLineCount == 0) {
+ BlPrint(BlFindMessage(BL_INVALID_BOOT_INI),DefaultPath);
+ MenuOption[0].Path = DefaultPath;
+ MenuOption[0].Title = DefaultTitle;
+ MenuOption[0].MaxMemory = 0;
+ MenuOption[0].LoadOptions = NULL;
+ MenuOption[0].Win95 = 0;
+ NumberSystems = 1;
+ DefaultSelection = 0;
+ }
+
+#if DBG
+ DebugLines = BlpFindSection("[debug]",
+ FileLines,
+ FileLineCount,
+ &DebugLineCount);
+#endif
+ }
+
+
+ //
+ // Parse the [operating systems] section
+ //
+
+ for (i=0; i<OsLineCount; i++) {
+
+ if (NumberSystems == MAX_SELECTIONS) {
+ break;
+ }
+
+ pCurrent = OsLines[i];
+
+ //
+ // Throw away any leading whitespace
+ //
+
+ pCurrent += strspn(pCurrent, " \t");
+ if (*pCurrent == '\0') {
+ //
+ // This is a blank line, so we just throw it away.
+ //
+ continue;
+ }
+
+ MenuOption[NumberSystems].Path = pCurrent;
+
+ //
+ // The first space or '=' character indicates the end of the
+ // path specifier, so we need to replace it with a '\0'
+ //
+ while ((*pCurrent != ' ')&&
+ (*pCurrent != '=')&&
+ (*pCurrent != '\0')) {
+ ++pCurrent;
+ }
+ *pCurrent = '\0';
+
+ //
+ // The next character that is not space, equals, or double-quote
+ // is the start of the title.
+ //
+
+ ++pCurrent;
+ while ((*pCurrent == ' ') ||
+ (*pCurrent == '=') ||
+ (*pCurrent == '"')) {
+ ++pCurrent;
+ }
+
+ if (pCurrent=='\0') {
+ //
+ // No title was found, so just use the path as the title.
+ //
+ MenuOption[NumberSystems].Title = MenuOption[NumberSystems].Path;
+ } else {
+ MenuOption[NumberSystems].Title = pCurrent;
+ }
+
+ //
+ // The next character that is either a double-quote or a \0
+ // indicates the end of the title.
+ //
+ while ((*pCurrent != '\0')&&
+ (*pCurrent != '"')) {
+ ++pCurrent;
+ }
+
+ //
+ // Look for a scsi(x) ordinal to use for opens on scsi ARC paths.
+ // This spec must immediately follow the title and is not part
+ // of the load options.
+ //
+ MenuOption[NumberSystems].ForcedScsiOrdinal = -1;
+ if(p=strstr(pCurrent,"/SCSIORDINAL:")) {
+ *pCurrent = 0;
+ pCurrent = p + sizeof("/SCSIORDINAL:") - 1;
+ MenuOption[NumberSystems].ForcedScsiOrdinal = atoi(pCurrent);
+ // pCurrent is adjusted adequately for the code that follows.
+ }
+
+ //
+ // If there is a DEBUG parameter after the description, then
+ // we need to pass the DEBUG option to the osloader.
+ //
+ MenuOption[NumberSystems].MaxMemory=0;
+ MenuOption[NumberSystems].EnableDebug = FALSE;
+ MenuOption[NumberSystems].LoadOptions = NULL;
+ MenuOption[NumberSystems].Win95 = 0;
+ if (strchr(pCurrent,'/') != NULL) {
+ *pCurrent = '\0';
+ pCurrent = strchr(pCurrent+1,'/');
+ MenuOption[NumberSystems].LoadOptions = pCurrent;
+ _strupr(pCurrent);
+ if (pCurrent != NULL) {
+ if (Option = strstr(pCurrent,"/MAXMEM")) {
+ MenuOption[NumberSystems].MaxMemory = atoi(Option+8);
+ }
+
+ if (strstr(pCurrent, "/WIN95DOS")) {
+ MenuOption[NumberSystems].Win95 = WIN95_DOS;
+ } else if (strstr(pCurrent, "/WIN95")) {
+ MenuOption[NumberSystems].Win95 = DOS_WIN95;
+ }
+
+ //
+ // As long as /nodebug is specified, this is NO debug system
+ // If /NODEBUG is not specified, and either one of the
+ // DEBUGPORT or BAUDRATE is specified, this is debug system.
+ //
+
+ if (strstr(pCurrent, "/NODEBUG") == NULL) {
+ if (strstr(pCurrent, "/DEBUG") ||
+ strstr(pCurrent, "/BAUDRATE")) {
+ if (_stricmp(MenuOption[NumberSystems].Path, "C:\\")==0) {
+ MenuOption[NumberSystems].EnableDebug = FALSE;
+ } else {
+ MenuOption[NumberSystems].EnableDebug = TRUE;
+ }
+ }
+ }
+ }
+ } else {
+ *pCurrent = '\0';
+ }
+ ++NumberSystems;
+ }
+
+ //
+ // Set default timeout value
+ //
+ if (UseTimeOut) {
+ Timeout = 0;
+ } else {
+ Timeout = -1;
+ }
+
+ //
+ // Parse the [boot loader] section
+ //
+ for (i=0; i<MbLineCount; i++) {
+
+ pCurrent = MbLines[i];
+
+ //
+ // Throw away any leading whitespace
+ //
+ pCurrent += strspn(pCurrent, " \t");
+ if (*pCurrent == '\0') {
+ //
+ // This is a blank line, so we just throw it away.
+ //
+ continue;
+ }
+
+ //
+ // Check for "timeout" line
+ //
+ if (_strnicmp(pCurrent,"timeout",7) == 0) {
+
+ pCurrent = strchr(pCurrent,'=');
+ if (pCurrent != NULL) {
+ if (UseTimeOut) {
+ Timeout = atoi(++pCurrent);
+ }
+ }
+ }
+
+ //
+ // Check for "default" line
+ //
+ else if (_strnicmp(pCurrent,"default",7) == 0) {
+
+ pCurrent = strchr(pCurrent,'=');
+ if (pCurrent != NULL) {
+ DefaultPath = ++pCurrent;
+ DefaultPath += strspn(DefaultPath," \t");
+ }
+
+ }
+
+ }
+
+#if DBG
+ //
+ // Parse the [debug] section
+ //
+ for (i=0; i<DebugLineCount; i++) {
+ extern ULONG ScsiDebug;
+
+ pCurrent = DebugLines[i];
+
+ //
+ // Throw away leading whitespace
+ //
+ pCurrent += strspn(pCurrent, " \t");
+ if (*pCurrent == '\0') {
+ //
+ // throw away blank lines
+ //
+ continue;
+ }
+
+ if (_strnicmp(pCurrent,"scsidebug",9) == 0) {
+ pCurrent = strchr(pCurrent,'=');
+ if (pCurrent != NULL) {
+ ScsiDebug = atoi(++pCurrent);
+ }
+ }
+ }
+
+#endif
+
+ //
+ // Now look for a Title entry from the [operating systems] section
+ // that matches the default entry from the [multiboot] section. This
+ // will give us a title. If no entry matches, we will add an entry
+ // at the end of the list and provide a default Title.
+ //
+ i=0;
+ while (_stricmp(MenuOption[i].Path,DefaultPath) != 0) {
+ ++i;
+ if (i==NumberSystems) {
+ //
+ // Create a default entry in the Title and Path arrays
+ //
+
+ MenuOption[NumberSystems].Path = DefaultPath;
+ MenuOption[NumberSystems].Title = DefaultTitle;
+ MenuOption[NumberSystems].EnableDebug = FALSE;
+ MenuOption[NumberSystems].MaxMemory = 0;
+ MenuOption[NumberSystems].LoadOptions = NULL;
+ MenuOption[NumberSystems].Win95 = 0;
+ ++NumberSystems;
+ }
+ }
+ DefaultSelection = i;
+
+ //
+ // Display the menu of choices
+ //
+
+ TextClearDisplay();
+ TextSetCursorPosition(0,0);
+
+ Selection = BlpPresentMenu( MenuOption,
+ NumberSystems,
+ DefaultSelection,
+ Timeout);
+
+ if (MenuOption[Selection].Win95) {
+ BlpRenameWin95Files( DriveId, MenuOption[Selection].Win95 );
+ }
+
+ if (_strnicmp(MenuOption[Selection].Path,"C:\\",3) == 0) {
+
+ //
+ // This syntax means that we are booting a root-based os
+ // from an alternate boot sector image.
+ // If no file name is specified, BlpRebootDos will default to
+ // \bootsect.dos.
+ //
+ BlpRebootDOS(MenuOption[Selection].Path[3] ? &MenuOption[Selection].Path[2] : NULL);
+
+ //
+ // If this returns, it means that the file does not exist as a bootsector.
+ // This allows c:\winnt35 to work as a boot path specifier as opposed to
+ // a boot sector image filename specifier.
+ //
+ }
+
+ if (MenuOption[Selection].Path[1]==':') {
+ //
+ // We need to translate the DOS name into an ARC name
+ //
+ DosName[0] = MenuOption[Selection].Path[0];
+ DosName[1] = MenuOption[Selection].Path[1];
+ DosName[2] = '\0';
+
+ BlpTranslateDosToArc(DosName,Kernel);
+ strcat(Kernel,MenuOption[Selection].Path+2);
+ } else {
+ strcpy(Kernel,MenuOption[Selection].Path);
+ }
+ pCurrent = MenuOption[Selection].LoadOptions;
+
+ if (pCurrent != NULL) {
+
+ //
+ // Remove '/' from LoadOptions string.
+ //
+
+ *LoadOptions = pCurrent + 1;
+ while (*pCurrent != '\0') {
+ if (*pCurrent == '/') {
+ *pCurrent = ' ';
+ }
+ ++pCurrent;
+ }
+ } else {
+ *LoadOptions = NULL;
+ }
+
+ //
+ // Make sure there is no trailing slash
+ //
+
+ if (Kernel[strlen(Kernel)-1] == '\\') {
+ Kernel[strlen(Kernel)-1] = '\0';
+ }
+
+ //
+ // If MaxMemory is not zero, adjust the memory descriptors to eliminate
+ // memory above the boundary line
+ //
+ BlpTruncateMemory(MenuOption[Selection].MaxMemory);
+ ForcedScsiOrdinal = MenuOption[Selection].ForcedScsiOrdinal;
+
+ return(Kernel);
+}
+
+
+PCHAR *
+BlpFileToLines(
+ IN PCHAR File,
+ OUT PULONG LineCount
+ )
+
+/*++
+
+Routine Description:
+
+ This routine converts the loaded BOOT.INI file into an array of
+ pointers to NULL-terminated ASCII strings.
+
+Arguments:
+
+ File - supplies a pointer to the in-memory image of the BOOT.INI file.
+ This will be converted in place by turning CR/LF pairs into
+ null terminators.
+
+ LineCount - Returns the number of lines in the BOOT.INI file.
+
+Return Value:
+
+ A pointer to an array of pointers to ASCIIZ strings. The array will
+ have LineCount elements.
+
+ NULL if the function did not succeed for some reason.
+
+--*/
+
+{
+ ULONG Line;
+ PCHAR *LineArray;
+ PCHAR p;
+ PCHAR Space;
+
+ p = File;
+
+ //
+ // First count the number of lines in the file so we know how large
+ // an array to allocate.
+ //
+ *LineCount=1;
+ while (*p != '\0') {
+ p=strchr(p, '\n');
+ if (p==NULL) {
+ break;
+ }
+ ++p;
+
+ //
+ // See if there's any text following the CR/LF.
+ //
+ if (*p=='\0') {
+ break;
+ }
+
+ *LineCount += 1;
+ }
+
+ LineArray = BlAllocateHeap(*LineCount * sizeof(PCHAR));
+
+ //
+ // Now step through the file again, replacing CR/LF with \0\0 and
+ // filling in the array of pointers.
+ //
+ p=File;
+ for (Line=0; Line < *LineCount; Line++) {
+ LineArray[Line] = p;
+ p=strchr(p, '\r');
+ if (p != NULL) {
+ *p = '\0';
+ ++p;
+ if (*p=='\n') {
+ *p = '\0';
+ ++p;
+ }
+ } else {
+ p=strchr(LineArray[Line], '\n');
+ if (p != NULL) {
+ *p = '\0';
+ ++p;
+ }
+ }
+
+ //
+ // remove trailing white space
+ //
+ Space = LineArray[Line] + strlen(LineArray[Line])-1;
+ while ((*Space == ' ') || (*Space == '\t')) {
+ *Space = '\0';
+ --Space;
+ }
+ }
+
+ return(LineArray);
+}
+
+
+PCHAR *
+BlpFindSection(
+ IN PCHAR SectionName,
+ IN PCHAR *BootFile,
+ IN ULONG BootFileLines,
+ OUT PULONG NumberLines
+ )
+
+/*++
+
+Routine Description:
+
+ Finds a section ([multiboot], [operating systems], etc) in the boot.ini
+ file and returns a pointer to its first line. The search will be
+ case-insensitive.
+
+Arguments:
+
+ SectionName - Supplies the name of the section. No brackets.
+
+ BootFile - Supplies the array of pointers to lines of the ini file.
+
+ BootFileLines - Supplies the number of lines in the ini file.
+
+ NumberLines - Returns the number of lines in the section.
+
+Return Value:
+
+ Pointer to an array of ASCIIZ strings, one entry per line.
+
+ NULL, if the section was not found.
+
+--*/
+
+{
+ ULONG cnt;
+ ULONG StartLine;
+
+ for (cnt=0; cnt<BootFileLines; cnt++) {
+
+ //
+ // Check to see if this is the line we are looking for
+ //
+ if (_stricmp(BootFile[cnt],SectionName) == 0) {
+
+ //
+ // found it
+ //
+ break;
+ }
+ }
+ if (cnt==BootFileLines) {
+ //
+ // We ran out of lines, never found the right section.
+ //
+ *NumberLines = 0;
+ return(NULL);
+ }
+
+ StartLine = cnt+1;
+
+ //
+ // Find end of section
+ //
+ for (cnt=StartLine; cnt<BootFileLines; cnt++) {
+ if (BootFile[cnt][0] == '[') {
+ break;
+ }
+ }
+
+ *NumberLines = cnt-StartLine;
+
+ return(&BootFile[StartLine]);
+}
+
+PCHAR
+BlpNextLine(
+ IN PCHAR String
+ )
+
+/*++
+
+Routine Description:
+
+ Finds the beginning of the next text line
+
+Arguments:
+
+ String - Supplies a pointer to a null-terminated string
+
+Return Value:
+
+ Pointer to the character following the first CR/LF found in String
+
+ - or -
+
+ NULL - No CR/LF found before the end of the string.
+
+--*/
+
+{
+ PCHAR p;
+
+ p=strchr(String, '\n');
+ if (p==NULL) {
+ return(p);
+ }
+
+ ++p;
+
+ //
+ // If there is no text following the CR/LF, there is no next line
+ //
+ if (*p=='\0') {
+ return(NULL);
+ } else {
+ return(p);
+ }
+}
+
+VOID
+BlpRebootDOS(
+ IN PCHAR BootSectorImage OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ Loads up the bootstrap sectors and executes them (thereby rebooting
+ into DOS or OS/2)
+
+Arguments:
+
+ BootSectorImage - If specified, supplies name of file on the C: drive
+ that contains the boot sector image. In this case, this routine
+ will return if that file cannot be opened (for example, if it's
+ a directory). If not specified, then default to \bootsect.dos,
+ and this routine will never return.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG SectorId;
+ ARC_STATUS Status;
+ ULONG Read;
+ ULONG DriveId;
+ ULONG BootType;
+ LARGE_INTEGER SeekPosition;
+ extern UCHAR BootPartitionName[];
+
+ //
+ // HACKHACK John Vert (jvert)
+ // Some SCSI drives get really confused and return zeroes when
+ // you use the BIOS to query their size after the AHA driver has
+ // initialized. This can completely tube OS/2 or DOS. So here
+ // we try and open both BIOS-accessible hard drives. Our open
+ // code is smart enough to retry if it gets back zeros, so hopefully
+ // this will give the SCSI drives a chance to get their act together.
+ //
+ Status = ArcOpen("multi(0)disk(0)rdisk(0)partition(0)",
+ ArcOpenReadOnly,
+ &DriveId);
+ if (Status == ESUCCESS) {
+ ArcClose(DriveId);
+ }
+
+ Status = ArcOpen("multi(0)disk(0)rdisk(1)partition(0)",
+ ArcOpenReadOnly,
+ &DriveId);
+ if (Status == ESUCCESS) {
+ ArcClose(DriveId);
+ }
+
+ //
+ // Load the boot sector at address 0x7C00 (expected by Reboot callback)
+ //
+ Status = ArcOpen(BootPartitionName,
+ ArcOpenReadOnly,
+ &DriveId);
+ if (Status != ESUCCESS) {
+ BlPrint(BlFindMessage(BL_REBOOT_IO_ERROR),BootPartitionName);
+ while (1) {
+ GET_KEY();
+ }
+ }
+ Status = BlOpen( DriveId,
+ BootSectorImage ? BootSectorImage : "\\bootsect.dos",
+ ArcOpenReadOnly,
+ &SectorId );
+
+ if (Status != ESUCCESS) {
+ if(BootSectorImage) {
+ //
+ // The boot sector image might actually be a directory.
+ // Return to the caller to attempt standard boot.
+ //
+ BlClose(DriveId);
+ return;
+ }
+ BlPrint(BlFindMessage(BL_REBOOT_IO_ERROR),BootPartitionName);
+ while (1) {
+ }
+ }
+
+ Status = BlRead( SectorId,
+ (PVOID)0x7c00,
+ SECTOR_SIZE,
+ &Read );
+
+ if (Status != ESUCCESS) {
+ BlPrint(BlFindMessage(BL_REBOOT_IO_ERROR),BootPartitionName);
+ while (1) {
+ }
+ }
+
+ //
+ // The FAT boot code is only one sector long so we just want
+ // to load it up and jump to it.
+ //
+ // For HPFS and NTFS, we can't do this because the first sector
+ // loads the rest of the boot sectors -- but we want to use
+ // the boot code in the boot sector image file we loaded.
+ //
+ // For HPFS, we load the first 20 sectors (boot code + super and
+ // space blocks) into d00:200. Fortunately this works for both
+ // NT and OS/2.
+ //
+ // For NTFS, we load the first 16 sectors and jump to d00:256.
+ // If the OEM field of the boot sector starts with NTFS, we
+ // assume it's NTFS boot code.
+ //
+
+ //
+ // Try to read 8K from the boot code image.
+ // If this succeeds, we have either HPFS or NTFS.
+ //
+ SeekPosition.QuadPart = 0;
+ BlSeek(SectorId,&SeekPosition,SeekAbsolute);
+ BlRead(SectorId,(PVOID)0xd000,SECTOR_SIZE*16,&Read);
+
+ if(Read == SECTOR_SIZE*16) {
+
+ if(memcmp((PVOID)0x7c03,"NTFS",4)) {
+
+ //
+ // HPFS -- we need to load the super block.
+ //
+ BootType = 1; // HPFS
+
+ SeekPosition.QuadPart = 16*SECTOR_SIZE;
+ ArcSeek(DriveId,&SeekPosition,SeekAbsolute);
+ ArcRead(DriveId,(PVOID)0xf000,SECTOR_SIZE*4,&Read);
+
+ } else {
+
+ //
+ // NTFS -- we've loaded everything we need to load.
+ //
+ BootType = 2; // NTFS
+ }
+ } else {
+
+ BootType = 0; // FAT
+ }
+
+ //
+ // DX must be the drive to boot from
+ //
+
+ _asm {
+ mov dx, 0x80
+ }
+ REBOOT(BootType);
+
+}
+
+
+ULONG
+BlpPresentMenu(
+ IN PMENU_OPTION MenuOption,
+ IN ULONG NumberSelections,
+ IN ULONG Default,
+ IN LONG Timeout
+ )
+
+/*++
+
+Routine Description:
+
+ Displays the menu of boot options and allows the user to select one
+ by using the arrow keys.
+
+Arguments:
+
+ MenuOption - Supplies array of menu options
+
+ NumberSelections - Supplies the number of entries in the MenuOption array.
+
+ Default - Supplies the index of the default operating system choice.
+
+ Timeout - Supplies the timeout (in seconds) before the highlighted
+ operating system choice is booted. If this value is -1,
+ the menu will never timeout.
+
+Return Value:
+
+ ULONG - The index of the operating system choice selected.
+
+--*/
+
+{
+ ULONG i;
+ ULONG Selection;
+ ULONG StartTime;
+ ULONG LastTime;
+ ULONG BiasTime=0;
+ ULONG CurrentTime;
+ LONG SecondsLeft;
+ ULONG EndTime;
+ ULONG Key;
+ ULONG MaxLength;
+ ULONG CurrentLength;
+ PCHAR SelectOs;
+ PCHAR MoveHighlight;
+ PCHAR TimeoutCountdown;
+ PCHAR EnabledKd;
+ PCHAR p;
+ BOOLEAN Moved;
+
+ //
+ // Get the strings we'll need to display.
+ //
+ SelectOs = BlFindMessage(BL_SELECT_OS);
+ MoveHighlight = BlFindMessage(BL_MOVE_HIGHLIGHT);
+ TimeoutCountdown = BlFindMessage(BL_TIMEOUT_COUNTDOWN);
+ EnabledKd = BlFindMessage(BL_ENABLED_KD_TITLE);
+ if ((SelectOs == NULL) ||
+ (MoveHighlight == NULL) ||
+ (EnabledKd == NULL) ||
+ (TimeoutCountdown==NULL)) {
+
+ return(Default);
+ }
+
+ p=strchr(TimeoutCountdown,'\r');
+ if (p!=NULL) {
+ *p='\0';
+ }
+ p=strchr(EnabledKd,'\r');
+ if (p!=NULL) {
+ *p='\0';
+ }
+
+ if (NumberSelections<=1) {
+
+ //
+ // No menu if there's only one choice.
+ //
+
+ return(0);
+ }
+ if (Timeout==0) {
+
+ //
+ // If the timeout is zero, immediately boot the default
+ //
+
+ return(Default);
+ }
+
+ //
+ // Find the longest string in the selections, so we know how long to
+ // make the highlight bar.
+ //
+
+ MaxLength=0;
+ for (i=0; i<NumberSelections; i++) {
+ CurrentLength = strlen(MenuOption[i].Title);
+ if (MenuOption[i].EnableDebug == TRUE) {
+ CurrentLength += strlen(EnabledKd);
+ }
+ if (CurrentLength > MAX_TITLE_LENGTH) {
+ //
+ // This title is too long to fit on one line, so we have to
+ // truncate it.
+ //
+ if (MenuOption[i].EnableDebug == TRUE) {
+ MenuOption[i].Title[MAX_TITLE_LENGTH - strlen(EnabledKd)] = '\0';
+ } else {
+ MenuOption[i].Title[MAX_TITLE_LENGTH] = '\0';
+ }
+ CurrentLength = MAX_TITLE_LENGTH;
+ }
+ if (CurrentLength > MaxLength) {
+ MaxLength = CurrentLength;
+ }
+ }
+
+ Selection = Default;
+ StartTime = GET_COUNTER();
+ EndTime = StartTime + (Timeout * 182) / 10;
+ BlPrint("OS Loader V4.00\n");
+ TextSetCurrentAttribute(0x07);
+ Moved = TRUE;
+ do {
+ TextSetCursorPosition(0,2);
+ BlPrint(SelectOs);
+
+ if(Moved) {
+ for (i=0; i<NumberSelections; i++) {
+ TextSetCursorPosition(0,5+i);
+ if (i==Selection) {
+ TextFillAttribute(0x70,MaxLength+8);
+ TextSetCurrentAttribute(0x70);
+ }
+ BlPrint( " %s", MenuOption[i].Title);
+
+ if (MenuOption[i].EnableDebug == TRUE) {
+ BlPrint(EnabledKd);
+ }
+ TextSetCurrentAttribute(0x07);
+ }
+ Moved = FALSE;
+ } else {
+ TextSetCursorPosition(0,5+NumberSelections-1);
+ }
+ BlPrint(MoveHighlight);
+ if (Timeout != -1) {
+ LastTime = CurrentTime;
+ CurrentTime = GET_COUNTER();
+
+ //
+ // deal with wraparound at midnight
+ // We can't do it the easy way because there are not exactly
+ // 18.2 * 60 * 60 * 24 tics/day. (just approximately)
+ //
+ if (CurrentTime < StartTime) {
+ if (BiasTime == 0) {
+ BiasTime = LastTime + 1;
+ }
+ CurrentTime += BiasTime;
+ }
+ BlPrint(TimeoutCountdown);
+
+ SecondsLeft = ((LONG)(EndTime - CurrentTime) * 10) / 182;
+
+ if (SecondsLeft < 0) {
+
+ //
+ // Note that if the user hits the PAUSE key, the counter stops
+ // and, as a result, SecondsLeft can become < 0.
+ //
+
+ SecondsLeft = 0;
+ }
+
+ BlPrint(" %d \n",SecondsLeft);
+ } else {
+ BlPrint(" \n");
+ }
+
+ //
+ // Poll for a key stroke. Any key disables the countdown
+ // timer.
+ //
+
+ Key = GET_KEY();
+ if (Key != 0) {
+ Timeout = -1;
+ }
+
+ if ( (Key==UP_ARROW) ||
+ (Key==DOWN_ARROW) ||
+ (Key==HOME_KEY) ||
+ (Key==END_KEY)
+ ) {
+ Moved = TRUE;
+ TextSetCursorPosition(0,5+Selection);
+ TextFillAttribute(0x07,MaxLength+8);
+ if (Key==DOWN_ARROW) {
+ Selection = (Selection+1) % NumberSelections;
+ } else if (Key==UP_ARROW) {
+ Selection = (Selection == 0) ? (NumberSelections-1)
+ : (Selection - 1);
+ } else if (Key==HOME_KEY) {
+ Selection = 0;
+ } else if (Key==END_KEY) {
+ Selection = NumberSelections-1;
+ }
+ }
+
+ } while ( ((Key&(ULONG)0xff) != ENTER_KEY) &&
+ ((CurrentTime < EndTime) || (Timeout == -1)) );
+
+ return(Selection);
+}
+
+
+
+VOID
+BlpTruncateMemory(
+ IN ULONG MaxMemory
+ )
+
+/*++
+
+Routine Description:
+
+ Eliminates all the memory descriptors above a given boundary
+
+Arguments:
+
+ MaxMemory - Supplies the maximum memory boundary in megabytes
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ extern MEMORY_DESCRIPTOR MDArray[];
+ extern ULONG NumberDescriptors;
+ ULONG Current = 0;
+ ULONG MaxPage = MaxMemory * 256; // Convert Mb to pages
+
+ if (MaxMemory == 0) {
+ return;
+ }
+
+ while (Current < NumberDescriptors) {
+ if (MDArray[Current].BasePage >= MaxPage) {
+ //
+ // This memory descriptor lies entirely above the boundary,
+ // eliminate it.
+ //
+ RtlMoveMemory(MDArray+Current,
+ MDArray+Current+1,
+ sizeof(MEMORY_DESCRIPTOR)*
+ (NumberDescriptors-Current-1));
+ --NumberDescriptors;
+ } else if (MDArray[Current].BasePage + MDArray[Current].PageCount > MaxPage) {
+ //
+ // This memory descriptor crosses the boundary, truncate it.
+ //
+ MDArray[Current].PageCount = MaxPage - MDArray[Current].BasePage;
+ ++Current;
+ } else {
+ //
+ // This one's ok, keep it.
+ //
+ ++Current;
+ }
+ }
+
+
+}
+
+ARC_STATUS
+BlpRenameWin95SystemFile(
+ IN ULONG DriveId,
+ IN ULONG Type,
+ IN PCHAR FileName,
+ IN PCHAR Ext,
+ IN PCHAR NewName
+ )
+
+/*++
+
+Routine Description:
+
+ Renames a file from one name to another.
+
+Arguments:
+
+ DriveId - Open drive identifier
+ Type - WIN95_DOS or DOS_WIN95
+ FileName - Base file name
+ Ext - Base extension
+ NewName - Non-NULL value causes an override of a generated name
+
+Return Value:
+
+ Arc status of the failed opperation or E_SUCCESS.
+
+--*/
+
+{
+ ARC_STATUS Status;
+ ULONG FileId;
+ ULONG FileIdCur;
+ CHAR Fname[16];
+ CHAR FnameCur[16];
+ CHAR FnameNew[16];
+
+
+ if (Type == WIN95_DOS) {
+ sprintf( Fname, "%s.dos", FileName );
+ } else {
+ if (NewName) {
+ strcpy( Fname, NewName );
+ } else {
+ sprintf( Fname, "%s.w40", FileName );
+ }
+ }
+
+ Status = BlOpen(
+ DriveId,
+ Fname,
+ ArcOpenReadOnly,
+ &FileId
+ );
+ if (Status != ESUCCESS) {
+ return Status;
+ }
+
+ sprintf( FnameCur, "%s.%s", FileName, Ext );
+
+ Status = BlOpen(
+ DriveId,
+ FnameCur,
+ ArcOpenReadOnly,
+ &FileIdCur
+ );
+ if (Status != ESUCCESS) {
+ BlClose( FileId );
+ return Status;
+ }
+
+ if (Type == WIN95_DOS) {
+ if (NewName) {
+ strcpy( FnameNew, NewName );
+ } else {
+ sprintf( FnameNew, "%s.w40", FileName );
+ }
+ } else {
+ sprintf( FnameNew, "%s.dos", FileName );
+ }
+
+ Status = BlRename(
+ FileIdCur,
+ FnameNew
+ );
+
+ BlClose( FileIdCur );
+
+ if (Status != ESUCCESS) {
+ BlClose( FileId );
+ return Status;
+ }
+
+ Status = BlRename(
+ FileId,
+ FnameCur
+ );
+
+ BlClose( FileId );
+
+ return Status;
+}
+
+
+VOID
+BlpRenameWin95Files(
+ IN ULONG DriveId,
+ IN ULONG Type
+ )
+
+/*++
+
+Routine Description:
+
+ Renames all Windows 95 system files from either their
+ Win95 DOS names to their Win95 name or the reverse.
+
+Arguments:
+
+ DriveId - Open drive identifier
+ Type - 1=dos to win95, 2=win95 to dos
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ BlpRenameWin95SystemFile( DriveId, Type, "command", "com", NULL );
+ BlpRenameWin95SystemFile( DriveId, Type, "msdos", "sys", NULL );
+ BlpRenameWin95SystemFile( DriveId, Type, "io", "sys", "winboot.sys" );
+ BlpRenameWin95SystemFile( DriveId, Type, "autoexec", "bat", NULL );
+ BlpRenameWin95SystemFile( DriveId, Type, "config", "sys", NULL );
+}
diff --git a/private/ntos/boot/bldr/i386/sources b/private/ntos/boot/bldr/i386/sources
new file mode 100644
index 000000000..319c52010
--- /dev/null
+++ b/private/ntos/boot/bldr/i386/sources
@@ -0,0 +1,4 @@
+I386_SOURCES=i386\initx86.c \
+ i386\parsboot.c
+
+NTTARGETFILES=obj\i386\NTLDR
diff --git a/private/ntos/boot/bldr/ilinkldr.rsp b/private/ntos/boot/bldr/ilinkldr.rsp
new file mode 100644
index 000000000..a29784ee9
--- /dev/null
+++ b/private/ntos/boot/bldr/ilinkldr.rsp
@@ -0,0 +1,19 @@
+-machine:i386
+-rom
+-force:multiple
+-debug:none
+-debugtype:coff
+-fixed
+-map:obj\i386\osloader.map
+-align:4096
+-base:0x300000
+-entry:NtProcessStartup@4
+obj\i386\bldr.lib
+obj\i386\osloader.res
+obj\i386\osloader.exp
+..\obj\i386\boot.lib
+..\..\obj\i386\ke.lib
+..\..\rtl\obj\i386\bldrrtl.lib
+..\..\config\obj\i386\bconfig.lib
+..\..\..\..\public\sdk\lib\i386\libcntpr.lib
+..\..\..\..\public\sdk\lib\i386\int64.lib
diff --git a/private/ntos/boot/bldr/makefile b/private/ntos/boot/bldr/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/boot/bldr/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/boot/bldr/makefile.inc b/private/ntos/boot/bldr/makefile.inc
new file mode 100644
index 000000000..45f10317f
--- /dev/null
+++ b/private/ntos/boot/bldr/makefile.inc
@@ -0,0 +1,38 @@
+!IFNDEF LANGUAGE
+LANGUAGE=usa
+!ENDIF
+
+msg.rc msg.h msg00001.bin: msg.$(LANGUAGE)
+ mc -v msg.$(LANGUAGE)
+
+
+!IF $(386)
+
+OSLOADER=obj\i386\bldr.lib ..\obj\i386\boot.lib obj\i386\osloader.exp
+
+obj\i386\osloader.res: msg.$(LANGUAGE)
+
+obj\i386\osloader.lib obj\i386\osloader.exp: i386\osloader.def
+ lib -machine:i386 -out:obj\i386\osloader.lib -def:i386\osloader.def ..\obj\i386\boot.lib obj\i386\bldr.lib
+
+obj\i386\osloader.exe: $(OSLOADER) ..\..\config\obj\i386\bconfig.lib makefile.inc ilinkldr.rsp
+ -link -out:obj\i386\osloader.exe $(LINK_LIB_IGNORE_FLAG) @ilinkldr.rsp
+
+obj\i386\NTLDR: $(OSLOADER) obj\i386\osloader.exe ..\startup\obj\i386\startup.com makefile.inc
+ -copy /b ..\startup\obj\i386\startup.com+obj\i386\osloader.exe obj\i386\NTLDR.
+
+!IFDEF _NT386TREE
+ binplace $@
+!ENDIF
+
+!ELSE
+
+OSLOADER=obj\$(TARGET_DIRECTORY)\bldr.lib ..\obj\$(TARGET_DIRECTORY)\boot.lib
+
+obj\$(TARGET_DIRECTORY)\osloader.res: msg.$(LANGUAGE)
+
+obj\$(TARGET_DIRECTORY)\osloader.exe: $(OSLOADER) ..\..\config\obj\$(TARGET_DIRECTORY)\bconfig.lib makefile.inc
+ -link -out:obj\$(TARGET_DIRECTORY)\osloader.exe -nodefaultlib $(LINK_LIB_IGNORE_FLAG) @$(TARGET_DIRECTORY)ldr.rsp
+ -@binplace obj\$(TARGET_DIRECTORY)\osloader.exe
+
+!ENDIF
diff --git a/private/ntos/boot/bldr/mipsldr.rsp b/private/ntos/boot/bldr/mipsldr.rsp
new file mode 100644
index 000000000..c75861a89
--- /dev/null
+++ b/private/ntos/boot/bldr/mipsldr.rsp
@@ -0,0 +1,18 @@
+-machine:mips
+-rom
+-force:multiple
+-debug:notmapped
+-debugtype:coff
+-fixed
+-map:obj\mips\osloader.map
+-align:0x200
+-base:0x80600000
+-entry:BlOsLoader
+obj\mips\bldr.lib
+obj\mips\osloader.res
+..\obj\mips\boot.lib
+..\..\obj\mips\ke.lib
+..\..\rtl\obj\mips\bldrrtl.lib
+..\..\..\..\public\sdk\lib\mips\libcntpr.lib
+..\..\config\obj\mips\bconfig.lib
+ \ No newline at end of file
diff --git a/private/ntos/boot/bldr/msg.usa b/private/ntos/boot/bldr/msg.usa
new file mode 100644
index 000000000..9f2921368
--- /dev/null
+++ b/private/ntos/boot/bldr/msg.usa
@@ -0,0 +1,408 @@
+;/*++
+;
+;Copyright (c) 1991 Microsoft Corporation
+;
+;Module Name:
+;
+; msg.h
+;
+;Abstract:
+;
+; This file contains the message definitions for osloader
+;
+;Author:
+;
+; John Vert (jvert) 12-Nov-1993
+;
+;Revision History:
+;
+;Notes:
+;
+; This file is generated from msg.mc
+;
+;--*/
+;
+;#ifndef _BLDR_MSG_
+;#define _BLDR_MSG_
+;
+;
+
+MessageID=9000 SymbolicName=BL_MSG_FIRST
+Language=English
+.
+
+MessageID=9001 SymbolicName=LOAD_SW_INT_ERR_CLASS
+Language=English
+Windows NT could not start because of an error in the software.
+Please report this problem as :
+.
+
+MessageID=9002 SymbolicName=LOAD_SW_MISRQD_FILE_CLASS
+Language=English
+Windows NT could not start because the following file was not found
+and is required :
+.
+
+MessageID=9003 SymbolicName=LOAD_SW_BAD_FILE_CLASS
+Language=English
+Windows NT could not start because of a bad copy of the following file :
+.
+
+MessageID=9004 SymbolicName=LOAD_SW_MIS_FILE_CLASS
+Language=English
+Windows NT could not start because the following file is missing or corrupt:
+.
+
+MessageID=9005 SymbolicName=LOAD_HW_MEM_CLASS
+Language=English
+Windows NT could not start because of a hardware memory configuration
+problem.
+.
+
+MessageID=9006 SymbolicName=LOAD_HW_DISK_CLASS
+Language=English
+Windows NT could not start because of a computer disk hardware
+configuration problem.
+.
+
+MessageID=9007 SymbolicName=LOAD_HW_GEN_ERR_CLASS
+Language=English
+Windows NT could not start because of a general computer hardware
+configuration problem.
+.
+
+MessageID=9008 SymbolicName=LOAD_HW_FW_CFG_CLASS
+Language=English
+Windows NT could not start because of the following ARC firmware
+boot configuration problem :
+.
+
+MessageID=9009 SymbolicName=DIAG_BL_MEMORY_INIT
+Language=English
+Check hardware memory configuration and amount of RAM.
+.
+
+MessageID=9010 SymbolicName=DIAG_BL_CONFIG_INIT
+Language=English
+Too many configuration entries.
+.
+
+MessageID=9011 SymbolicName=DIAG_BL_IO_INIT
+Language=English
+Could not access disk partition tables
+.
+
+MessageID=9012 SymbolicName=DIAG_BL_FW_GET_BOOT_DEVICE
+Language=English
+The 'osloadpartition' parameter setting is invalid.
+.
+
+MessageID=9013 SymbolicName=DIAG_BL_OPEN_BOOT_DEVICE
+Language=English
+Could not read from the selected boot disk. Check boot path
+and disk hardware.
+.
+
+MessageID=9014 SymbolicName=DIAG_BL_FW_GET_SYSTEM_DEVICE
+Language=English
+The 'systempartition' parameter setting is invalid.
+.
+
+MessageID=9015 SymbolicName=DIAG_BL_FW_OPEN_SYSTEM_DEVICE
+Language=English
+Could not read from the selected system boot disk.
+Check 'systempartition' path.
+.
+
+MessageID=9016 SymbolicName=DIAG_BL_GET_SYSTEM_PATH
+Language=English
+The 'osloadfilename' parameter does not point to a valid file.
+.
+
+MessageID=9017 SymbolicName=DIAG_BL_LOAD_SYSTEM_IMAGE
+Language=English
+<winnt root>\system32\ntoskrnl.exe.
+.
+
+MessageID=9018 SymbolicName=DIAG_BL_FIND_HAL_IMAGE
+Language=English
+The 'osloader' parameter does not point to a valid file.
+.
+
+MessageID=9019 SymbolicName=DIAG_BL_LOAD_HAL_IMAGE_X86
+Language=English
+<winnt root>\system32\hal.dll.
+.
+
+MessageID=9020 SymbolicName=DIAG_BL_LOAD_HAL_IMAGE_ARC
+Language=English
+'osloader'\hal.dll
+.
+;#ifdef _X86_
+;#define DIAG_BL_LOAD_HAL_IMAGE DIAG_BL_LOAD_HAL_IMAGE_X86
+;#else
+;#define DIAG_BL_LOAD_HAL_IMAGE DIAG_BL_LOAD_HAL_IMAGE_ARC
+;#endif
+
+MessageID=9021 SymbolicName=DIAG_BL_LOAD_SYSTEM_IMAGE_DATA
+Language=English
+Loader error 1.
+.
+
+MessageID=9022 SymbolicName=DIAG_BL_LOAD_HAL_IMAGE_DATA
+Language=English
+Loader error 2.
+.
+
+MessageID=9023 SymbolicName=DIAG_BL_LOAD_SYSTEM_DLLS
+Language=English
+load needed DLLs for kernel.
+.
+
+MessageID=9024 SymbolicName=DIAG_BL_LOAD_HAL_DLLS
+Language=English
+load needed DLLs for HAL.
+.
+
+MessageID=9026 SymbolicName=DIAG_BL_FIND_SYSTEM_DRIVERS
+Language=English
+find system drivers.
+.
+
+MessageID=9027 SymbolicName=DIAG_BL_READ_SYSTEM_DRIVERS
+Language=English
+read system drivers.
+.
+
+MessageID=9028 SymbolicName=DIAG_BL_LOAD_DEVICE_DRIVER
+Language=English
+did not load system boot device driver.
+.
+
+MessageID=9029 SymbolicName=DIAG_BL_LOAD_SYSTEM_HIVE
+Language=English
+load system hardware configuration file.
+.
+
+MessageID=9030 SymbolicName=DIAG_BL_SYSTEM_PART_DEV_NAME
+Language=English
+find system partition name device name.
+.
+
+MessageID=9031 SymbolicName=DIAG_BL_BOOT_PART_DEV_NAME
+Language=English
+find boot partition name.
+.
+
+MessageID=9032 SymbolicName=DIAG_BL_ARC_BOOT_DEV_NAME
+Language=English
+did not properly generate ARC name for HAL and system paths.
+.
+
+MessageID=9034 SymbolicName=DIAG_BL_SETUP_FOR_NT
+Language=English
+Loader error 3.
+.
+
+MessageID=9035 SymbolicName=DIAG_BL_KERNEL_INIT_XFER
+Language=English
+<winnt root>\system32\ntoskrnl.exe
+.
+
+MessageID=9036 SymbolicName=LOAD_SW_INT_ERR_ACT
+Language=English
+Please contact your support person to report this problem.
+.
+
+MessageID=9037 SymbolicName=LOAD_SW_FILE_REST_ACT
+Language=English
+You can attempt to repair this file by starting Windows NT
+Setup using the original Setup floppy disk or CD-ROM.
+Select 'r' at the first screen to start repair.
+.
+
+MessageID=9038 SymbolicName=LOAD_SW_FILE_REINST_ACT
+Language=English
+Please re-install a copy of the above file.
+.
+
+MessageID=9039 SymbolicName=LOAD_HW_MEM_ACT
+Language=English
+Please check the Windows NT(TM) documentation about hardware
+memory requirements and your hardware reference manuals for
+additional information.
+.
+
+MessageID=9040 SymbolicName=LOAD_HW_DISK_ACT
+Language=English
+Please check the Windows NT(TM) documentation about hardware
+disk configuration and your hardware reference manuals for
+additional information.
+.
+
+MessageID=9041 SymbolicName=LOAD_HW_GEN_ACT
+Language=English
+Please check the Windows NT(TM) documentation about hardware
+configuration and your hardware reference manuals for additional
+information.
+.
+
+MessageID=9042 SymbolicName=LOAD_HW_FW_CFG_ACT
+Language=English
+Please check the Windows NT(TM) documentation about ARC configuration
+options and your hardware reference manuals for additional
+information.
+.
+
+MessageID=9043 SymbolicName=BL_LKG_MENU_HEADER
+Language=English
+ Hardware Profile/Configuration Recovery Menu
+
+This menu allows you to select a hardware profile
+to be used when Windows NT is started.
+
+If your system is not starting correctly, then you may switch to a previous
+system configuration, which may overcome startup problems.
+IMPORTANT: System configuration changes made since the last successful
+startup will be discarded.
+.
+
+MessageID=9044 SymbolicName=BL_LKG_MENU_TRAILER
+Language=English
+Use the up and down arrow keys to move the highlight
+to the selection you want. Then press ENTER.
+.
+
+MessageID=9045 SymbolicName=BL_LKG_MENU_TRAILER_NO_PROFILES
+Language=English
+No hardware profiles are currently defined. Hardware profiles
+can be created from the System applet of the control panel.
+.
+
+MessageID=9046 SymbolicName=BL_SWITCH_LKG_TRAILER
+Language=English
+To switch to the Last Known Good configuration, press 'L'.
+To Exit this menu and restart your computer, press F3.
+.
+
+MessageID=9047 SymbolicName=BL_SWITCH_DEFAULT_TRAILER
+Language=English
+To switch to the default configuration, press 'D'.
+To Exit this menu and restart your computer, press F3.
+.
+
+;//
+;// The following two messages are used to provide the mnemonic keypress
+;// that toggles between the Last Known Good control set and the default
+;// control set. (see BL_SWITCH_LKG_TRAILER and BL_SWITCH_DEFAULT_TRAILER)
+;//
+MessageID=9048 SymbolicName=BL_LKG_SELECT_MNEMONIC
+Language=English
+L
+.
+
+MessageID=9049 SymbolicName=BL_DEFAULT_SELECT_MNEMONIC
+Language=English
+D
+.
+
+MessageID=9050 SymbolicName=BL_LKG_TIMEOUT
+Language=English
+Seconds until highlighted choice will be started automatically: %d
+.
+
+MessageID=9051 SymbolicName=BL_LKG_MENU_PROMPT
+Language=English
+
+Press spacebar NOW to invoke Hardware Profile/Last Known Good menu
+.
+
+MessageID=9052 SymbolicName=BL_BOOT_DEFAULT_PROMPT
+Language=English
+Boot default hardware configuration
+.
+
+;
+; //
+; // Following messages are for the x86-specific
+; // boot menu.
+; //
+;
+MessageID=10001 SymbolicName=BL_ENABLED_KD_TITLE
+Language=English
+ [debugger enabled]
+.
+
+MessageID=10002 SymbolicName=BL_DEFAULT_TITLE
+Language=English
+Windows NT (default)
+.
+
+MessageID=10003 SymbolicName=BL_MISSING_BOOT_INI
+Language=English
+NTLDR: BOOT.INI file not found.
+.
+
+MessageID=10004 SymbolicName=BL_MISSING_OS_SECTION
+Language=English
+NTLDR: no [operating systems] section in boot.txt.
+.
+
+MessageID=10005 SymbolicName=BL_BOOTING_DEFAULT
+Language=English
+Booting default kernel from %s.
+.
+
+MessageID=10006 SymbolicName=BL_SELECT_OS
+Language=English
+Please select the operating system to start:
+.
+
+MessageID=10007 SymbolicName=BL_MOVE_HIGHLIGHT
+Language=English
+
+
+Use  and  to move the highlight to your choice.
+Press Enter to choose.
+
+.
+
+MessageID=10008 SymbolicName=BL_TIMEOUT_COUNTDOWN
+Language=English
+Seconds until highlighted choice will be started automatically:
+.
+
+MessageID=10009 SymbolicName=BL_INVALID_BOOT_INI
+Language=English
+Invalid BOOT.INI file
+Booting from %s
+.
+
+MessageID=10010 SymbolicName=BL_REBOOT_IO_ERROR
+Language=English
+I/O Error accessing boot sector file %s\\BOOTSECT.DOS
+.
+
+MessageID=10011 SymbolicName=BL_DRIVE_ERROR
+Language=English
+NTLDR: Couldn't open drive %s
+.
+
+MessageID=10012 SymbolicName=BL_READ_ERROR
+Language=English
+NTLDR: Fatal Error %d reading BOOT.INI
+.
+
+MessageID=10013 SymbolicName=BL_NTDETECT_MSG
+Language=English
+
+NTDETECT V4.0 Checking Hardware ...
+
+.
+
+MessageID=10014 SymbolicName=BL_NTDETECT_FAILURE
+Language=English
+NTDETECT failed
+.
+
+;#endif // _BLDR_MSG_
diff --git a/private/ntos/boot/bldr/osloader.c b/private/ntos/boot/bldr/osloader.c
new file mode 100644
index 000000000..5ecb5ecc3
--- /dev/null
+++ b/private/ntos/boot/bldr/osloader.c
@@ -0,0 +1,1300 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ osloader.c
+
+Abstract:
+
+ This module contains the code that implements the NT operating system
+ loader.
+
+Author:
+
+ David N. Cutler (davec) 10-May-1991
+
+Revision History:
+
+--*/
+
+#include "bldr.h"
+#include "ctype.h"
+#include "stdio.h"
+#include "string.h"
+#include "msg.h"
+
+
+BOOLEAN BlRebootSystem = FALSE;
+
+//
+// Define transfer entry of loaded image.
+//
+
+typedef
+VOID
+(*PTRANSFER_ROUTINE) (
+ PLOADER_PARAMETER_BLOCK LoaderBlock
+ );
+
+
+BOOLEAN
+BlGetDriveSignature(
+ IN PCHAR Name,
+ OUT PULONG Signature
+ );
+
+PVOID
+BlLoadDataFile(
+ IN ULONG DeviceId,
+ IN PCHAR LoadDevice,
+ IN PCHAR SystemPath,
+ IN PUNICODE_STRING Filename,
+ IN MEMORY_TYPE MemoryType,
+ OUT PULONG FileSize
+ );
+
+//
+// Define local static data.
+//
+
+
+PCHAR ArcStatusCodeMessages[] = {
+ "operation was success",
+ "E2BIG",
+ "EACCES",
+ "EAGAIN",
+ "EBADF",
+ "EBUSY",
+ "EFAULT",
+ "EINVAL",
+ "EIO",
+ "EISDIR",
+ "EMFILE",
+ "EMLINK",
+ "ENAMETOOLONG",
+ "ENODEV",
+ "ENOENT",
+ "ENOEXEC",
+ "ENOMEM",
+ "ENOSPC",
+ "ENOTDIR",
+ "ENOTTY",
+ "ENXIO",
+ "EROFS",
+};
+
+//
+// Diagnostic load messages
+//
+
+VOID
+BlFatalError(
+ IN ULONG ClassMessage,
+ IN ULONG DetailMessage,
+ IN ULONG ActionMessage
+ );
+
+VOID
+BlBadFileMessage(
+ IN PCHAR BadFileName
+ );
+
+//
+// Define external static data.
+//
+
+ULONG BlConsoleOutDeviceId = 0;
+ULONG BlConsoleInDeviceId = 0;
+ULONG BlDcacheFillSize = 32;
+
+#if DBG
+BOOLEAN BlOutputDots=FALSE;
+#else
+BOOLEAN BlOutputDots=TRUE;
+#endif
+
+
+CHAR KernelFileName[8+1+3+1]="ntoskrnl.exe";
+CHAR HalFileName[8+1+3+1]="hal.dll";
+
+ARC_STATUS
+BlOsLoader (
+ IN ULONG Argc,
+ IN PCHAR Argv[],
+ IN PCHAR Envp[]
+ )
+
+/*++
+
+Routine Description:
+
+ This is the main routine that controls the loading of the NT operating
+ system on an ARC compliant system. It opens the system partition,
+ the boot partition, the console input device, and the console output
+ device. The NT operating system and all its DLLs are loaded and bound
+ together. Control is then transfered to the loaded system.
+
+Arguments:
+
+ Argc - Supplies the number of arguments that were provided on the
+ command that invoked this program.
+
+ Argv - Supplies a pointer to a vector of pointers to null terminated
+ argument strings.
+
+ Envp - Supplies a pointer to a vector of pointers to null terminated
+ environment variables.
+
+Return Value:
+
+ EBADF is returned if the specified OS image cannot be loaded.
+
+--*/
+
+{
+
+ CHAR BootDirectoryPath[256];
+ ULONG CacheLineSize;
+ PCHAR ConsoleOutDevice;
+ PCHAR ConsoleInDevice;
+ ULONG Count;
+ PCONFIGURATION_COMPONENT_DATA DataCache;
+ CHAR DeviceName[256];
+ CHAR DevicePrefix[256];
+ PCHAR DirectoryEnd;
+ CHAR DllName[256];
+ CHAR DriverDirectoryPath[256];
+ PCHAR FileName;
+ ULONG FileSize;
+ PLDR_DATA_TABLE_ENTRY HalDataTableEntry;
+ CHAR HalDirectoryPath[256];
+ CHAR KernelDirectoryPath[256];
+ PVOID HalBase;
+ PVOID SystemBase;
+ ULONG Index;
+ ULONG Limit;
+ ULONG LinesPerBlock;
+ PCHAR LoadDevice;
+ ULONG LoadDeviceId;
+ PCHAR LoadFileName;
+ PCHAR LoadOptions;
+ ULONG i;
+ CHAR OutputBuffer[256];
+ ARC_STATUS Status;
+ PLDR_DATA_TABLE_ENTRY SystemDataTableEntry;
+ PCHAR SystemDevice;
+ ULONG SystemDeviceId;
+ PTRANSFER_ROUTINE SystemEntry;
+ PIMAGE_NT_HEADERS NtHeaders;
+ PWSTR BootFileSystem;
+ PCHAR LastKnownGood;
+ BOOLEAN BreakInKey;
+ CHAR BadFileName[128];
+ PBOOTFS_INFO FsInfo;
+
+ //
+ // Get the name of the console output device and open the device for
+ // write access.
+ //
+
+ ConsoleOutDevice = BlGetArgumentValue(Argc, Argv, "consoleout");
+ if (ConsoleOutDevice == NULL) {
+ return ENODEV;
+ }
+
+ Status = ArcOpen(ConsoleOutDevice, ArcOpenWriteOnly, &BlConsoleOutDeviceId);
+ if (Status != ESUCCESS) {
+ return Status;
+ }
+
+ //
+ // Get the name of the console input device and open the device for
+ // read access.
+ //
+
+ ConsoleInDevice = BlGetArgumentValue(Argc, Argv, "consolein");
+ if (ConsoleInDevice == NULL) {
+ return ENODEV;
+ }
+
+ Status = ArcOpen(ConsoleInDevice, ArcOpenReadOnly, &BlConsoleInDeviceId);
+ if (Status != ESUCCESS) {
+ return Status;
+ }
+
+ //
+ // Announce OS Loader.
+ //
+
+ strcpy(&OutputBuffer[0], "OS Loader V4.00\r\n");
+ ArcWrite(BlConsoleOutDeviceId,
+ &OutputBuffer[0],
+ strlen(&OutputBuffer[0]),
+ &Count);
+
+ //
+ // Initialize the memory descriptor list, the OS loader heap, and the
+ // OS loader parameter block.
+ //
+
+ Status = BlMemoryInitialize();
+ if (Status != ESUCCESS) {
+ BlFatalError(LOAD_HW_MEM_CLASS,
+ DIAG_BL_MEMORY_INIT,
+ LOAD_HW_MEM_ACT);
+ goto LoadFailed;
+ }
+
+
+ //
+ // Compute the data cache fill size. This value is used to align
+ // I/O buffers in case the host system does not support coherent
+ // caches.
+ //
+ // If a combined secondary cache is present, then use the fill size
+ // for that cache. Otherwise, if a secondary data cache is present,
+ // then use the fill size for that cache. Otherwise, if a primary
+ // data cache is present, then use the fill size for that cache.
+ // Otherwise, use the default fill size.
+ //
+
+ DataCache = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
+ CacheClass,
+ SecondaryCache,
+ NULL);
+
+ if (DataCache == NULL) {
+ DataCache = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
+ CacheClass,
+ SecondaryDcache,
+ NULL);
+
+ if (DataCache == NULL) {
+ DataCache = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
+ CacheClass,
+ PrimaryDcache,
+ NULL);
+ }
+ }
+
+ if (DataCache != NULL) {
+ LinesPerBlock = DataCache->ComponentEntry.Key >> 24;
+ CacheLineSize = 1 << ((DataCache->ComponentEntry.Key >> 16) & 0xff);
+ BlDcacheFillSize = LinesPerBlock * CacheLineSize;
+ }
+
+ //
+ // Initialize the OS loader I/O system.
+ //
+
+ Status = BlIoInitialize();
+ if (Status != ESUCCESS) {
+ BlFatalError(LOAD_HW_DISK_CLASS,
+ DIAG_BL_IO_INIT,
+ LOAD_HW_DISK_ACT);
+ goto LoadFailed;
+ }
+
+ //
+ // Initialize the resource section
+ //
+ Status = BlInitResources(Argv[0]);
+ if (Status != ESUCCESS) {
+ BlFatalError(LOAD_HW_DISK_CLASS,
+ DIAG_BL_IO_INIT,
+ LOAD_HW_DISK_ACT);
+ }
+
+ //
+ // Initialize the NT configuration tree.
+ //
+
+ BlLoaderBlock->ConfigurationRoot = NULL;
+
+
+ Status = BlConfigurationInitialize(NULL, NULL);
+ if (Status != ESUCCESS) {
+ BlFatalError(LOAD_HW_FW_CFG_CLASS,
+ DIAG_BL_CONFIG_INIT,
+ LOAD_HW_FW_CFG_ACT);
+ goto LoadFailed;
+ }
+
+ //
+ // Copy the osloadoptions argument into the LoaderBlock
+ //
+
+ LoadOptions = BlGetArgumentValue(Argc, Argv, "osloadoptions");
+ if (LoadOptions != NULL) {
+ FileSize = strlen(LoadOptions)+1;
+ FileName = (PCHAR)BlAllocateHeap(FileSize);
+ strcpy(FileName, LoadOptions);
+ BlLoaderBlock->LoadOptions = FileName;
+
+ //
+ // check for magic switch that says we should output
+ // the filenames of the files instead of just dots.
+ //
+ if ((strstr(FileName,"SOS")!=NULL) ||
+ (strstr(FileName,"sos")!=NULL)) {
+ BlOutputDots=FALSE;
+ }
+
+ FileName=strstr(BlLoaderBlock->LoadOptions,"HAL=");
+ if (FileName) {
+ for (i=0; i<sizeof(HalFileName); i++) {
+ if (FileName[4+i]==' ') {
+ HalFileName[i]='\0';
+ break;
+ }
+
+ HalFileName[i]=FileName[4+i];
+ }
+ }
+ HalFileName[sizeof(HalFileName)-1]='\0';
+
+ FileName=strstr(BlLoaderBlock->LoadOptions,"KERNEL=");
+ if (FileName) {
+ for (i=0; i<sizeof(KernelFileName); i++) {
+ if (FileName[7+i]==' ') {
+ KernelFileName[i]='\0';
+ break;
+ }
+
+ KernelFileName[i]=FileName[7+i];
+ }
+ }
+ KernelFileName[sizeof(KernelFileName)-1]='\0';
+
+ } else {
+ BlLoaderBlock->LoadOptions = NULL;
+ }
+
+ //
+ // Get the name of the load device and open the device for read access.
+ //
+
+ LoadDevice = BlGetArgumentValue(Argc, Argv, "osloadpartition");
+ if (LoadDevice == NULL) {
+ Status = ENODEV;
+ BlFatalError(LOAD_HW_FW_CFG_CLASS,
+ DIAG_BL_FW_GET_BOOT_DEVICE,
+ LOAD_HW_FW_CFG_ACT);
+ goto LoadFailed;
+ }
+
+ Status = ArcOpen(LoadDevice, ArcOpenReadOnly, &LoadDeviceId);
+ if (Status != ESUCCESS) {
+ BlFatalError(LOAD_HW_DISK_CLASS,
+ DIAG_BL_OPEN_BOOT_DEVICE,
+ LOAD_HW_DISK_ACT);
+ goto LoadFailed;
+ }
+
+ //
+ // Get the name of the system device and open the device for read access.
+ //
+
+ SystemDevice = BlGetArgumentValue(Argc, Argv, "systempartition");
+ if (SystemDevice == NULL) {
+ Status = ENODEV;
+ BlFatalError(LOAD_HW_FW_CFG_CLASS,
+ DIAG_BL_FW_GET_SYSTEM_DEVICE,
+ LOAD_HW_FW_CFG_ACT);
+ goto LoadFailed;
+ }
+
+ Status = ArcOpen(SystemDevice, ArcOpenReadOnly, &SystemDeviceId);
+ if (Status != ESUCCESS) {
+ BlFatalError(LOAD_HW_FW_CFG_CLASS,
+ DIAG_BL_FW_OPEN_SYSTEM_DEVICE,
+ LOAD_HW_FW_CFG_ACT);
+ goto LoadFailed;
+ }
+
+ //
+ // Initialize the debugging system.
+ //
+
+ BlLogInitialize(SystemDeviceId);
+
+ //
+ // Display the Configuration prompt for breakin key at this
+ // point. No key presses are checked for at this point, but
+ // this gives the user a little more reaction time.
+ //
+ BlStartConfigPrompt();
+
+#if defined(_PPC_)
+
+ Status = BlPpcInitialize();
+ if (Status != ESUCCESS) {
+ goto LoadFailed;
+ }
+
+#endif // defined(_PPC_)
+
+ //
+ // Get the path name of the system root directory.
+ //
+
+ LoadFileName = BlGetArgumentValue(Argc, Argv, "osloadfilename");
+ if (LoadFileName == NULL) {
+ Status = ENOENT;
+ BlFatalError(LOAD_HW_FW_CFG_CLASS,
+ DIAG_BL_FW_GET_BOOT_DEVICE,
+ LOAD_HW_FW_CFG_ACT);
+ goto LoadFailed;
+ }
+
+ //
+ // LoadFileName is of the form <SystemRoot> ( "\winnt" )
+ //
+
+ //
+ // Generate the directory name of the SYSTEM32 directory.
+ //
+ strcpy(BootDirectoryPath, LoadFileName);
+ strcat(BootDirectoryPath, "\\System32\\");
+
+ //
+ // Generate the full pathname of ntoskrnl.exe
+ // "\winnt\system32\ntoskrnl.exe"
+ //
+ strcpy(KernelDirectoryPath, BootDirectoryPath);
+ strcat(KernelDirectoryPath, KernelFileName);
+
+ //
+ // Load the system image into memory.
+ //
+
+ BlOutputLoadMessage(LoadDevice, KernelDirectoryPath);
+ Status = BlLoadImage(LoadDeviceId,
+ LoaderSystemCode,
+ KernelDirectoryPath,
+ TARGET_IMAGE,
+ &SystemBase);
+
+ if (Status != ESUCCESS) {
+ BlFatalError(LOAD_SW_MIS_FILE_CLASS,
+ DIAG_BL_LOAD_SYSTEM_IMAGE,
+ LOAD_SW_FILE_REINST_ACT);
+ goto LoadFailed;
+ }
+
+ //
+ // Whatever filesystem was used to load the system image is the
+ // one that needs to be loaded along with the boot drivers.
+ //
+ FsInfo = BlGetFsInfo(LoadDeviceId);
+ if (FsInfo != NULL) {
+ BootFileSystem = FsInfo->DriverName;
+ } else {
+ BlFatalError(LOAD_SW_MIS_FILE_CLASS,
+ DIAG_BL_LOAD_SYSTEM_IMAGE,
+ LOAD_SW_FILE_REINST_ACT);
+ goto LoadFailed;
+ }
+
+ //
+ // Get the path name of the OS loader file and isolate the directory
+ // path so it can be used to load the HAL DLL.
+ //
+
+ FileName = BlGetArgumentValue(Argc, Argv, "osloader");
+
+ if (FileName == NULL) {
+ Status = ENOENT;
+ BlFatalError(LOAD_HW_FW_CFG_CLASS,
+ DIAG_BL_FIND_HAL_IMAGE,
+ LOAD_HW_FW_CFG_ACT);
+ goto LoadFailed;
+ }
+
+ DirectoryEnd = strrchr(FileName, '\\');
+ FileName = strchr(FileName, '\\');
+ HalDirectoryPath[0] = 0;
+ if (DirectoryEnd != NULL) {
+ Limit = (ULONG)DirectoryEnd - (ULONG)FileName + 1;
+ for (Index = 0; Index < Limit; Index += 1) {
+ HalDirectoryPath[Index] = *FileName++;
+ }
+
+ HalDirectoryPath[Index] = 0;
+ }
+
+ //
+ // Generate the full path name for the HAL DLL image and load it into
+ // memory.
+ //
+
+ strcpy(&DllName[0], &HalDirectoryPath[0]);
+ strcat(&DllName[0], HalFileName);
+ BlOutputLoadMessage(SystemDevice, &DllName[0]);
+
+ Status = BlLoadImage(SystemDeviceId,
+ LoaderHalCode,
+ &DllName[0],
+ TARGET_IMAGE,
+ &HalBase);
+
+ if (Status != ESUCCESS) {
+ BlFatalError(LOAD_SW_MIS_FILE_CLASS,
+ DIAG_BL_LOAD_HAL_IMAGE,
+ LOAD_SW_FILE_REINST_ACT);
+ goto LoadFailed;
+ }
+
+ //
+ // Generate a loader data entry for the system image.
+ //
+
+ Status = BlAllocateDataTableEntry("ntoskrnl.exe",
+ KernelDirectoryPath,
+ SystemBase,
+ &SystemDataTableEntry);
+
+ if (Status != ESUCCESS) {
+ BlFatalError(LOAD_SW_INT_ERR_CLASS,
+ DIAG_BL_LOAD_SYSTEM_IMAGE,
+ LOAD_SW_INT_ERR_ACT);
+ goto LoadFailed;
+ }
+
+ //
+ // Generate a loader data entry for the HAL DLL.
+ //
+
+ Status = BlAllocateDataTableEntry("hal.dll",
+ &DllName[0],
+ HalBase,
+ &HalDataTableEntry);
+
+ if (Status != ESUCCESS) {
+ BlFatalError(LOAD_SW_INT_ERR_CLASS,
+ DIAG_BL_LOAD_HAL_IMAGE,
+ LOAD_SW_INT_ERR_ACT);
+ goto LoadFailed;
+ }
+
+#if defined(_ALPHA_)
+
+ Status = BlLoadPal(SystemDeviceId,
+ LoaderSystemCode,
+ &HalDirectoryPath[0],
+ TARGET_IMAGE,
+ &BlLoaderBlock->u.Alpha.PalBaseAddress,
+ SystemDevice);
+
+ if (Status != ESUCCESS) {
+ BlFatalError(LOAD_SW_MIS_FILE_CLASS,
+ DIAG_BL_LOAD_SYSTEM_DLLS,
+ LOAD_SW_FILE_REINST_ACT);
+ goto LoadFailed;
+ }
+
+#endif // _ALPHA_
+
+ //
+ // Scan the import table for the system image and load all referenced
+ // DLLs.
+ //
+
+ Status = BlScanImportDescriptorTable(LoadDeviceId,
+ LoadDevice,
+ &BootDirectoryPath[0],
+ SystemDataTableEntry);
+
+ if (Status != ESUCCESS) {
+ BlFatalError(LOAD_SW_INT_ERR_CLASS,
+ DIAG_BL_LOAD_SYSTEM_DLLS,
+ LOAD_SW_INT_ERR_ACT);
+ goto LoadFailed;
+ }
+
+ //
+ // Scan the import table for the HAL DLL and load all referenced DLLs.
+ //
+
+ Status = BlScanImportDescriptorTable(SystemDeviceId,
+ SystemDevice,
+ &HalDirectoryPath[0],
+ HalDataTableEntry);
+
+
+ if (Status != ESUCCESS) {
+ BlFatalError(LOAD_SW_INT_ERR_CLASS,
+ DIAG_BL_LOAD_HAL_DLLS,
+ LOAD_SW_INT_ERR_ACT);
+ goto LoadFailed;
+ }
+
+ //
+ // Relocate the system entry point and set system specific information.
+ //
+
+ NtHeaders = RtlImageNtHeader(SystemBase);
+ SystemEntry = (PTRANSFER_ROUTINE)((ULONG)SystemBase +
+ NtHeaders->OptionalHeader.AddressOfEntryPoint);
+
+#ifdef MIPS
+
+ BlLoaderBlock->u.Mips.GpBase = (ULONG)SystemBase +
+ NtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_GLOBALPTR].VirtualAddress;
+
+#endif
+
+#if defined(_ALPHA_)
+
+ BlLoaderBlock->u.Alpha.GpBase = (ULONG)SystemBase +
+ NtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_GLOBALPTR].VirtualAddress;
+
+#endif
+
+ //
+ // Form the directory path for all device drivers.
+ //
+
+ strcpy(&DriverDirectoryPath[0], &BootDirectoryPath[0]);
+ strcat(&DriverDirectoryPath[0], "\\Drivers\\");
+
+ //
+ // Allocate structure for NLS data. This will be loaded and filled
+ // in by BlLoadAndScanSystemHive.
+ //
+
+ BlLoaderBlock->NlsData = BlAllocateHeap(sizeof(NLS_DATA_BLOCK));
+ if (BlLoaderBlock->NlsData == NULL) {
+ Status = ENOMEM;
+ BlFatalError(LOAD_HW_MEM_CLASS,
+ DIAG_BL_LOAD_SYSTEM_HIVE,
+ LOAD_HW_MEM_ACT);
+ goto LoadFailed;
+ }
+ //
+ // Load the registry SYSTEM hive.
+ //
+ // DIAG_BL_LOAD_SYSTEM_REGISTRY_HIVE
+ // "Cannot load system hardware configuration file.\r\n"
+
+
+ Status = BlLoadAndScanSystemHive(LoadDeviceId,
+ LoadDevice,
+ LoadFileName,
+ BootFileSystem,
+ BadFileName);
+
+ if (Status != ESUCCESS) {
+ if (BlRebootSystem) {
+ Status = ESUCCESS;
+ } else {
+ BlBadFileMessage(BadFileName);
+ }
+ goto LoadFailed;
+ }
+
+ //
+ // Generate the ARC boot device name and NT path name.
+ //
+
+ Status = BlGenerateDeviceNames(LoadDevice, &DeviceName[0], &DevicePrefix[0]);
+ if (Status != ESUCCESS) {
+ BlFatalError(LOAD_HW_FW_CFG_CLASS,
+ DIAG_BL_ARC_BOOT_DEV_NAME,
+ LOAD_HW_FW_CFG_ACT);
+ goto LoadFailed;
+ }
+
+ FileSize = strlen(&DeviceName[0]) + 1;
+ FileName = (PCHAR)BlAllocateHeap(FileSize);
+ strcpy(FileName, &DeviceName[0]);
+ BlLoaderBlock->ArcBootDeviceName = FileName;
+
+ FileSize = strlen(LoadFileName) + 2;
+ FileName = (PCHAR)BlAllocateHeap( FileSize);
+ strcpy(FileName, LoadFileName);
+ strcat(FileName, "\\");
+ BlLoaderBlock->NtBootPathName = FileName;
+
+ //
+ // Generate the ARC HAL device name and NT path name.
+ //
+
+#ifdef i386
+
+ //
+ // On X86, the systempartition variable lies, and instead points to the location
+ // of the hal. We pass in another variable, 'X86SystemPartition', that tell us
+ // the real system partition.
+ //
+
+ strcpy(&DeviceName[0], BlGetArgumentValue(Argc, Argv, "x86systempartition"));
+
+#else
+
+ Status = BlGenerateDeviceNames(SystemDevice, &DeviceName[0], &DevicePrefix[0]);
+ if (Status != ESUCCESS) {
+ BlFatalError(LOAD_HW_FW_CFG_CLASS,
+ DIAG_BL_ARC_BOOT_DEV_NAME,
+ LOAD_HW_FW_CFG_ACT);
+ goto LoadFailed;
+ }
+
+#endif //i386
+
+ FileSize = strlen(&DeviceName[0]) + 1;
+ FileName = (PCHAR)BlAllocateHeap(FileSize);
+ strcpy(FileName, &DeviceName[0]);
+ BlLoaderBlock->ArcHalDeviceName = FileName;
+
+#ifdef i386
+
+ //
+ // On X86, this structure is unfortunately named. What we really need here is the
+ // osloader path. What we actually have is a path to the HAL. Since this path is
+ // always at the root of the partition, hardcode it here.
+ //
+
+ FileName = (PCHAR)BlAllocateHeap(2);
+ FileName[0] = '\\';
+ FileName[1] = '\0';
+
+#else
+
+ FileSize = strlen(&HalDirectoryPath[0]) + 1;
+ FileName = (PCHAR)BlAllocateHeap(FileSize);
+ strcpy(FileName, &HalDirectoryPath[0]);
+
+#endif //i386
+
+ BlLoaderBlock->NtHalPathName = FileName;
+
+ //
+ // Get the NTFT drive signatures to allow the kernel to create the
+ // correct ARC name <=> NT name mappings.
+ //
+ BlGetArcDiskInformation();
+
+ //
+ // Execute the architecture specific setup code.
+ //
+
+ Status = BlSetupForNt(BlLoaderBlock);
+ if (Status != ESUCCESS) {
+ BlFatalError(LOAD_SW_INT_ERR_CLASS,
+ DIAG_BL_SETUP_FOR_NT,
+ LOAD_SW_INT_ERR_ACT);
+
+ goto LoadFailed;
+ }
+
+ //
+ // Turn off the debugging system.
+ //
+
+ BlLogTerminate();
+
+ //
+ // Transfer control to loaded image.
+ //
+
+ (SystemEntry)(BlLoaderBlock);
+
+ Status = EBADF;
+ BlFatalError(LOAD_SW_BAD_FILE_CLASS,
+ DIAG_BL_KERNEL_INIT_XFER,
+ LOAD_SW_FILE_REINST_ACT);
+
+ //
+ // The load failed.
+ //
+
+LoadFailed:
+ return Status;
+
+}
+
+VOID
+BlOutputLoadMessage (
+ IN PCHAR DeviceName,
+ IN PCHAR FileName
+ )
+
+/*++
+
+Routine Description:
+
+ This routine outputs a loading message to the console output device.
+
+Arguments:
+
+ DeviceName - Supplies a pointer to a zero terminated device name.
+
+ FileName - Supplies a pointer to a zero terminated file name.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ULONG Count;
+ CHAR OutputBuffer[256];
+
+ //
+ // Construct and output loading file message.
+ //
+
+ if (!BlOutputDots) {
+ strcpy(&OutputBuffer[0], " ");
+ strcat(&OutputBuffer[0], DeviceName);
+ strcat(&OutputBuffer[0], FileName);
+ strcat(&OutputBuffer[0], "\r\n");
+
+ } else {
+ strcpy(&OutputBuffer[0],".");
+ }
+
+ BlLog((LOG_LOGFILE,OutputBuffer));
+
+ ArcWrite(BlConsoleOutDeviceId,
+ &OutputBuffer[0],
+ strlen(&OutputBuffer[0]),
+ &Count);
+
+ return;
+}
+
+
+ARC_STATUS
+BlLoadAndScanSystemHive(
+ IN ULONG DeviceId,
+ IN PCHAR DeviceName,
+ IN PCHAR DirectoryPath,
+ IN PWSTR BootFileSystem,
+ OUT PCHAR BadFileName
+ )
+
+/*++
+
+Routine Description:
+
+ This function loads the system hive into memory, verifies its
+ consistency, scans it for the list of boot drivers, and loads
+ the resulting list of drivers.
+
+ If the system hive cannot be loaded or is not a valid hive, it
+ is rejected and the system.alt hive is used. If this is invalid,
+ the boot must fail.
+
+Arguments:
+
+ DeviceId - Supplies the file id of the device the system tree is on.
+
+ DeviceName - Supplies the name of the device the system tree is on.
+
+ DirectoryPath - Supplies a pointer to the zero-terminated directory path
+ of the root of the NT system32 directory.
+
+ HiveName - Supplies the name of the SYSTEM hive
+
+ BadFileName - Returns the file required for booting that was corrupt
+ or missing. This will not be filled in if ESUCCESS is returned.
+
+Return Value:
+
+ ESUCCESS - System hive valid and all necessary boot drivers successfully
+ loaded.
+
+ !ESUCCESS - System hive corrupt or critical boot drivers not present.
+
+--*/
+
+{
+ ARC_STATUS Status;
+ PCHAR FailReason;
+ CHAR Directory[256];
+ CHAR FontDirectory[256];
+ UNICODE_STRING AnsiCodepage;
+ UNICODE_STRING OemCodepage;
+ UNICODE_STRING OemHalFont;
+ UNICODE_STRING LanguageTable;
+ BOOLEAN RestartSetup;
+
+ strcpy(Directory,DirectoryPath);
+ strcat(Directory,"\\system32\\config\\");
+ Status = BlLoadAndInitSystemHive(DeviceId,
+ DeviceName,
+ Directory,
+ "system",
+ FALSE,
+ &RestartSetup);
+
+ if(Status != ESUCCESS) {
+ //
+ // bogus hive, try system.alt
+ //
+ Status = BlLoadAndInitSystemHive(DeviceId,
+ DeviceName,
+ Directory,
+ "system.alt",
+ TRUE,
+ &RestartSetup);
+ if(Status != ESUCCESS) {
+ strcpy(BadFileName,DirectoryPath);
+ strcat(BadFileName,"\\SYSTEM32\\CONFIG\\SYSTEM");
+ goto HiveScanFailed;
+ }
+ }
+
+ if(RestartSetup) {
+ //
+ // Need to restart setup
+ //
+ Status = BlLoadAndInitSystemHive(DeviceId,
+ DeviceName,
+ Directory,
+ "system.sav",
+ TRUE,
+ &RestartSetup);
+ if(Status != ESUCCESS) {
+ strcpy(BadFileName,DirectoryPath);
+ strcat(BadFileName,"\\SYSTEM32\\CONFIG\\SYSTEM.SAV");
+ goto HiveScanFailed;
+ }
+ }
+
+ //
+ // Hive is there, it's valid, go compute the driver list and NLS
+ // filenames. Note that if this fails, there is no point in switching
+ // to system.alt, since it will always be the same as system.
+ //
+ FailReason = BlScanRegistry(BootFileSystem,
+ &BlLoaderBlock->BootDriverListHead,
+ &AnsiCodepage,
+ &OemCodepage,
+ &LanguageTable,
+ &OemHalFont);
+ if (FailReason != NULL) {
+ Status = EBADF;
+ strcpy(BadFileName,Directory);
+ strcat(BadFileName,"SYSTEM");
+ goto HiveScanFailed;
+ }
+
+ strcpy(Directory,DirectoryPath);
+ strcat(Directory,"\\system32\\");
+ //
+ // Load NLS data tables
+ //
+
+ Status = BlLoadNLSData(DeviceId,
+ DeviceName,
+ Directory,
+ &AnsiCodepage,
+ &OemCodepage,
+ &LanguageTable,
+ BadFileName);
+ if (Status != ESUCCESS) {
+ goto HiveScanFailed;
+ }
+
+ //
+ // Load the OEM font file to be used by the HAL for possible frame
+ // buffer displays.
+ //
+
+#ifdef i386
+ if ( !OemHalFont.Buffer ) {
+ goto oktoskipfont;
+ }
+#endif
+
+ //
+ // On newer systems fonts are in the FONTS directory.
+ // On older systems fonts are in the SYSTEM directory.
+ //
+ strcpy(FontDirectory, DirectoryPath);
+ strcat(FontDirectory, "\\FONTS\\");
+
+ Status = BlLoadOemHalFont(DeviceId,
+ DeviceName,
+ FontDirectory,
+ &OemHalFont,
+ BadFileName);
+
+ if(Status != ESUCCESS) {
+ strcpy(FontDirectory, DirectoryPath);
+ strcat(FontDirectory, "\\SYSTEM\\");
+
+ Status = BlLoadOemHalFont(DeviceId,
+ DeviceName,
+ FontDirectory,
+ &OemHalFont,
+ BadFileName);
+ }
+
+ if (Status != ESUCCESS) {
+#ifndef i386
+ goto HiveScanFailed;
+#endif
+
+ }
+#ifdef i386
+oktoskipfont:
+#endif
+ //
+ // Load boot drivers
+ //
+ strcpy(Directory,DirectoryPath);
+ strcat(Directory,"\\");
+ Status = BlLoadBootDrivers(DeviceId,
+ DeviceName,
+ Directory,
+ &BlLoaderBlock->BootDriverListHead,
+ BadFileName);
+
+ if (Status == ESUCCESS) {
+ return(Status);
+ }
+
+HiveScanFailed:
+ return(Status);
+}
+
+
+BOOLEAN
+BlGetDriveSignature(
+ IN PCHAR Name,
+ OUT PULONG Signature
+ )
+
+/*++
+
+Routine Description:
+
+ This routine gets the NTFT disk signature for a specified partition or
+ path.
+
+Arguments:
+
+ Name - Supplies the arcname of the partition or drive.
+
+ Signature - Returns the NTFT disk signature for the drive.
+
+Return Value:
+
+ TRUE - success, Signature will be filled in.
+
+ FALSE - failed, Signature will not be filled in.
+
+--*/
+
+{
+ UCHAR SectorBuffer[512+256];
+ CHAR DiskName[256];
+ ULONG DiskId;
+ PCHAR p;
+ ARC_STATUS Status;
+ ULONG Count;
+ LARGE_INTEGER SeekValue;
+
+ //
+ // Generate the arcname ("...partition(0)") for the raw disk device
+ // where the boot partition is, so we can read the MBR.
+ //
+ strcpy(DiskName, Name);
+ p=DiskName;
+ while (*p != '\0') {
+ if (_strnicmp(p, "partition(",10) == 0) {
+ break;
+ }
+ ++p;
+ }
+ if (*p != '\0') {
+ strcpy(p,"partition(0)");
+ }
+
+ Status = ArcOpen(DiskName,ArcOpenReadOnly, &DiskId);
+ if (Status!=ESUCCESS) {
+ return(FALSE);
+ }
+
+ //
+ // Read the first sector of the physical drive
+ //
+ SeekValue.QuadPart = 0;
+ Status = ArcSeek(DiskId, &SeekValue, SeekAbsolute);
+ if (Status==ESUCCESS) {
+ Status = ArcRead(DiskId,
+ ALIGN_BUFFER(SectorBuffer),
+ 512,
+ &Count);
+ }
+ ArcClose(DiskId);
+ if (Status!=ESUCCESS) {
+ return(FALSE);
+ }
+
+ //
+ // copy NTFT signature.
+ //
+ *Signature = ((PULONG)SectorBuffer)[PARTITION_TABLE_OFFSET/2-1];
+ return(TRUE);
+}
+
+
+VOID
+BlBadFileMessage(
+ IN PCHAR BadFileName
+ )
+
+/*++
+
+Routine Description:
+
+ This function displays the error message for a missing or incorrect
+ critical file.
+
+Arguments:
+
+ BadFileName - Supplies the name of the file that is missing or
+ corrupt.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG Count;
+ PCHAR Text;
+
+ ArcWrite(BlConsoleOutDeviceId,
+ "\r\n",
+ strlen("\r\n"),
+ &Count);
+
+ Text = BlFindMessage(LOAD_SW_MIS_FILE_CLASS);
+ if (Text != NULL) {
+ ArcWrite(BlConsoleOutDeviceId,
+ Text,
+ strlen(Text),
+ &Count);
+ }
+
+ ArcWrite(BlConsoleOutDeviceId,
+ BadFileName,
+ strlen(BadFileName),
+ &Count);
+
+ ArcWrite(BlConsoleOutDeviceId,
+ "\r\n\r\n",
+ strlen("\r\n\r\n"),
+ &Count);
+
+ Text = BlFindMessage(LOAD_SW_FILE_REST_ACT);
+ if (Text != NULL) {
+ ArcWrite(BlConsoleOutDeviceId,
+ Text,
+ strlen(Text),
+ &Count);
+ }
+
+}
+
+
+VOID
+BlClearToEndOfScreen(
+ VOID
+ );
+
+VOID
+BlFatalError(
+ IN ULONG ClassMessage,
+ IN ULONG DetailMessage,
+ IN ULONG ActionMessage
+ )
+
+/*++
+
+Routine Description:
+
+ This function looks up messages to display at a error condition.
+ It attempts to locate the string in the resource section of the
+ osloader. If that fails, it prints a numerical error code.
+
+ The only time it should print a numerical error code is if the
+ resource section could not be located. This will only happen
+ on ARC machines where boot fails before the osloader.exe file
+ can be opened.
+
+Arguments:
+
+ ClassMessage - General message that describes the class of
+ problem.
+
+ DetailMessage - Detailed description of what caused problem
+
+ ActionMessage - Message that describes a course of action
+ for user to take.
+
+Return Value:
+
+ none
+
+--*/
+
+
+{
+ PCHAR Text;
+ CHAR Buffer[40];
+ ULONG Count;
+
+ ArcWrite(BlConsoleOutDeviceId,
+ "\r\n",
+ strlen("\r\n"),
+ &Count);
+
+
+ //
+ // Remove any remains from the last known good message
+ //
+ BlClearToEndOfScreen();
+
+ Text = BlFindMessage(ClassMessage);
+ if (Text == NULL) {
+ sprintf(Buffer,"%08lx\r\n",ClassMessage);
+ Text = Buffer;
+ }
+ ArcWrite(BlConsoleOutDeviceId,
+ Text,
+ strlen(Text),
+ &Count);
+
+ Text = BlFindMessage(DetailMessage);
+ if (Text == NULL) {
+ sprintf(Buffer,"%08lx\r\n",DetailMessage);
+ Text = Buffer;
+ }
+ ArcWrite(BlConsoleOutDeviceId,
+ Text,
+ strlen(Text),
+ &Count);
+
+ Text = BlFindMessage(ActionMessage);
+ if (Text == NULL) {
+ sprintf(Buffer,"%08lx\r\n",ActionMessage);
+ Text = Buffer;
+ }
+ ArcWrite(BlConsoleOutDeviceId,
+ Text,
+ strlen(Text),
+ &Count);
+
+}
diff --git a/private/ntos/boot/bldr/osloader.rc b/private/ntos/boot/bldr/osloader.rc
new file mode 100644
index 000000000..5ba26c53f
--- /dev/null
+++ b/private/ntos/boot/bldr/osloader.rc
@@ -0,0 +1,15 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Boot Loader"
+#define VER_INTERNALNAME_STR "osloader.exe"
+
+#include "common.ver"
+
+//
+// message text
+//
+#include "msg.rc"
diff --git a/private/ntos/boot/bldr/ppcldr.rsp b/private/ntos/boot/bldr/ppcldr.rsp
new file mode 100644
index 000000000..247cd4405
--- /dev/null
+++ b/private/ntos/boot/bldr/ppcldr.rsp
@@ -0,0 +1,18 @@
+-machine:ppc
+-rom
+-force:multiple
+-debug:notmapped
+-debugtype:coff
+-map:obj\ppc\osloader.map
+-align:0x200
+-base:0x80600000
+-entry:BlOsLoader
+obj\ppc\bldr.lib
+obj\ppc\osloader.res
+..\obj\ppc\boot.lib
+..\..\obj\ppc\ke.lib
+..\..\rtl\obj\ppc\bldrrtl.lib
+..\..\..\..\public\sdk\lib\ppc\libcntpr.lib
+..\..\config\obj\ppc\bconfig.lib
+..\..\..\..\public\sdk\lib\ppc\int64.lib
+
diff --git a/private/ntos/boot/bldr/regboot.c b/private/ntos/boot/bldr/regboot.c
new file mode 100644
index 000000000..f802ef6ba
--- /dev/null
+++ b/private/ntos/boot/bldr/regboot.c
@@ -0,0 +1,1588 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ regboot.c
+
+Abstract:
+
+ Provides a minimal registry implementation designed to be used by the
+ osloader at boot time. This includes loading the system hive
+ ( <SystemRoot>\config\SYSTEM ) into memory, and computing the driver
+ load list from it.
+
+Author:
+
+ John Vert (jvert) 10-Mar-1992
+
+Revision History:
+
+--*/
+#include "bldr.h"
+#include "msg.h"
+#include "cmp.h"
+#include "stdio.h"
+#include "string.h"
+
+CMHIVE BootHive;
+ULONG CmLogLevel=100;
+ULONG CmLogSelect=0;
+
+ULONG ScreenWidth=80;
+ULONG ScreenHeight=25;
+
+ULONG LkgStartTime;
+
+
+//
+// defines for doing console I/O
+//
+#define ASCII_CR 0x0d
+#define ASCII_LF 0x0a
+#define ESC 0x1B
+#define SGR_INVERSE 7
+#define SGR_INTENSE 1
+#define SGR_NORMAL 0
+
+
+//
+// Private function prototypes
+//
+
+BOOLEAN
+BlInitializeHive(
+ IN PVOID HiveImage,
+ IN PCMHIVE Hive,
+ IN BOOLEAN IsAlternate
+ );
+
+BOOLEAN
+BlpCheckRestartSetup(
+ VOID
+ );
+
+PVOID
+BlpHiveAllocate(
+ IN ULONG Length,
+ IN BOOLEAN UseForIo
+ );
+
+//
+// prototypes for console I/O routines
+//
+
+VOID
+BlpClearScreen(
+ VOID
+ );
+
+VOID
+BlClearToEndOfScreen(
+ VOID
+ );
+
+VOID
+BlpClearToEndOfLine(
+ VOID
+ );
+
+VOID
+BlpPositionCursor(
+ IN ULONG Column,
+ IN ULONG Row
+ );
+
+VOID
+BlpSetInverseMode(
+ IN BOOLEAN InverseOn
+ );
+
+
+VOID
+BlStartConfigPrompt(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine displays the LKG prompt, records the current time,
+ and returns. The prompt is displayed before the kernel and HAL
+ are loaded, and then removed afterwards.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG Count;
+ PCHAR LkgPrompt;
+
+ LkgPrompt = BlFindMessage(BL_LKG_MENU_PROMPT);
+ if (LkgPrompt==NULL) {
+ return;
+ }
+ //
+ // display LKG prompt
+ //
+ BlpPositionCursor(1,3);
+ ArcWrite(BlConsoleOutDeviceId,
+ LkgPrompt,
+ strlen(LkgPrompt),
+ &Count);
+ BlpPositionCursor(1,2);
+ LkgStartTime = ArcGetRelativeTime();
+}
+
+
+BOOLEAN
+BlEndConfigPrompt(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine waits until the LKG timeout has expired or the
+ user presses a key and then removes the LKG prompt.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE - Space bar pressed.
+
+ FALSE - Space bar was not pressed.
+
+--*/
+{
+ ULONG EndTime;
+ ULONG Count;
+ UCHAR Key;
+ ULONG Status;
+
+ EndTime = LkgStartTime + 3;
+ if (EndTime <= ArcGetRelativeTime()) {
+ EndTime = ArcGetRelativeTime()+1;
+ }
+
+ do {
+ if ((Status = ArcGetReadStatus(ARC_CONSOLE_INPUT)) == ESUCCESS) {
+ //
+ // There is a key pending, so see if it's the spacebar.
+ //
+ ArcRead(ARC_CONSOLE_INPUT,
+ &Key,
+ sizeof(Key),
+ &Count);
+ if (Key == ' ') {
+ return(TRUE);
+ }
+ }
+ } while (ArcGetRelativeTime() < EndTime);
+
+ //
+ // make LKG prompt go away, so as not to startle the user.
+ //
+ BlClearToEndOfScreen();
+
+ return(FALSE);
+}
+
+
+VOID
+BlpSwitchControlSet(
+ OUT PCM_HARDWARE_PROFILE_LIST *ProfileList,
+ IN BOOLEAN UseLastKnownGood,
+ OUT PHCELL_INDEX ControlSet
+ )
+
+/*++
+
+Routine Description:
+
+ Switches the current control set to the specified control
+ set and rebuilds the hardware profile list.
+
+Arguments:
+
+ ProfileList - Returns the new hardware profile list
+
+ UseLastKnownGood - Supplies whether the LKG control set is to be used.
+
+ ControlSet - Returns the HCELL_INDEX of the new control set.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UNICODE_STRING ControlName;
+ HCELL_INDEX NewControlSet;
+ BOOLEAN AutoSelect; // ignored
+ ULONG ProfileTimeout; // ignored
+
+ //
+ // Find the new control set.
+ //
+ if (UseLastKnownGood) {
+ RtlInitUnicodeString(&ControlName, L"LastKnownGood");
+ } else {
+ RtlInitUnicodeString(&ControlName, L"Default");
+ }
+ NewControlSet = CmpFindControlSet(&BootHive.Hive,
+ BootHive.Hive.BaseBlock->RootCell,
+ &ControlName,
+ &AutoSelect);
+ if (NewControlSet == HCELL_NIL) {
+ return;
+ }
+
+ CmpFindProfileOption(&BootHive.Hive,
+ NewControlSet,
+ ProfileList,
+ NULL);
+ *ControlSet = NewControlSet;
+}
+
+
+ULONG
+BlpCountLines(
+ IN PCHAR Lines
+ )
+
+/*++
+
+Routine Description:
+
+ Counts the number of lines in the given string.
+
+Arguments:
+
+ Lines - Supplies a pointer to the start of the string
+
+Return Value:
+
+ The number of lines in the string.
+
+--*/
+
+{
+ PCHAR p;
+ ULONG NumLines = 0;
+
+ p=Lines;
+ while (*p != 0) {
+ if ((*p == '\r') && (*(p+1) == '\n')) {
+ ++NumLines;
+ ++p; // move forward to \n
+ }
+ ++p;
+ }
+ return(NumLines);
+}
+
+
+BOOLEAN
+BlConfigMenuPrompt(
+ IN ULONG Timeout,
+ IN OUT PBOOLEAN UseLastKnownGood,
+ IN OUT PHCELL_INDEX ControlSet,
+ OUT PCM_HARDWARE_PROFILE_LIST *ProfileList,
+ OUT PCM_HARDWARE_PROFILE *HardwareProfile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine provides the user-interface for the configuration menu.
+ The prompt is given if the user hits the break-in key, or if the
+ LastKnownGood environment variable is TRUE and AutoSelect is FALSE, or
+ if the timeout value on the hardware profile configuration is non-zero
+
+Arguments:
+
+ Timeout - Supplies the timeout value for the menu. -1 or 0 implies the menu
+ will never timeout.
+
+ UseLastKnownGood - Returns the LastKnownGood setting that should be
+ used for the boot.
+
+ ControlSet - Returns the control set (either Default or LKG)
+
+ ProfileList - Supplies the default list of profiles.
+ Returns the current list of profiles.
+ (may change due to switching to/from the LKG controlset)
+
+ HardwareProfile - Returns the hardware profile that should be used.
+
+Return Value:
+
+ TRUE - Boot should proceed.
+
+ FALSE - The user has chosen to return to the firmware menu/flexboot menu.
+
+--*/
+
+{
+ ULONG HeaderLines;
+ ULONG TrailerLines;
+ ULONG i;
+ ULONG Count;
+ UCHAR Key;
+ PCHAR MenuHeader;
+ PCHAR MenuTrailer1;
+ PCHAR MenuTrailer2;
+ PCHAR p;
+ ULONG OptionLength;
+ CHAR MenuOption[80];
+ PCM_HARDWARE_PROFILE Profile;
+ ULONG ProfileCount;
+ UCHAR LkgMnemonic;
+ UCHAR DefaultMnemonic;
+ PCHAR Temp;
+ ULONG DisplayLines;
+ ULONG TopProfileLine=0;
+ ULONG CurrentSelection = 0;
+ ULONG CurrentProfile;
+ ULONG EndTime;
+ ULONG CurrentTime;
+ PCHAR TimeoutPrompt;
+
+ if ((Timeout != (ULONG)-1) && (Timeout != 0)) {
+ CurrentTime = ArcGetRelativeTime();
+ EndTime = CurrentTime + Timeout;
+ TimeoutPrompt = BlFindMessage(BL_LKG_TIMEOUT);
+ p=strchr(TimeoutPrompt, '\n');
+ if (p) {
+ *p = '\0';
+ }
+ p=strchr(TimeoutPrompt, '\r');
+ if (p) {
+ *p = '\0';
+ }
+ } else {
+ TimeoutPrompt = NULL;
+ }
+ MenuHeader = BlFindMessage(BL_LKG_MENU_HEADER);
+ Temp = BlFindMessage(BL_LKG_SELECT_MNEMONIC);
+ if (Temp == NULL) {
+ return(TRUE);
+ }
+ LkgMnemonic = toupper(Temp[0]);
+ Temp = BlFindMessage(BL_DEFAULT_SELECT_MNEMONIC);
+ if (Temp == NULL) {
+ return(TRUE);
+ }
+ DefaultMnemonic = toupper(Temp[0]);
+
+Restart:
+ if (*ProfileList == NULL) {
+ ProfileCount = 0;
+ } else {
+ ProfileCount = (*ProfileList)->CurrentProfileCount;
+ }
+ if (ProfileCount == 0) {
+ MenuTrailer1 = BlFindMessage(BL_LKG_MENU_TRAILER_NO_PROFILES);
+ } else {
+ MenuTrailer1 = BlFindMessage(BL_LKG_MENU_TRAILER);
+ }
+ if (*UseLastKnownGood) {
+ MenuTrailer2 = BlFindMessage(BL_SWITCH_DEFAULT_TRAILER);
+ } else {
+ MenuTrailer2 = BlFindMessage(BL_SWITCH_LKG_TRAILER);
+ }
+ if ((MenuHeader==NULL) || (MenuTrailer1==NULL) || (MenuTrailer2==NULL)) {
+ return(TRUE);
+ }
+ //
+ // strip trailing /r/n from MenuTrailer2 to prevent it from scrolling
+ // the screen when we output it.
+ //
+#if 0
+ p=MenuTrailer2 + strlen(MenuTrailer2) - 1;
+ while ((*p == '\r') || (*p == '\n')) {
+ *p = '\0';
+ --p;
+ }
+#endif
+ BlpClearScreen();
+ BlpSetInverseMode(FALSE);
+
+ //
+ // Count the number of lines in the header.
+ //
+ HeaderLines=BlpCountLines(MenuHeader);
+
+ //
+ // Display the menu header.
+ //
+
+ ArcWrite(BlConsoleOutDeviceId,
+ MenuHeader,
+ strlen(MenuHeader),
+ &Count);
+
+ //
+ // Count the number of lines in the trailer.
+ //
+ TrailerLines=BlpCountLines(MenuTrailer1) + BlpCountLines(MenuTrailer2);
+
+ //
+ // Display the trailing prompt.
+ //
+ if (TimeoutPrompt) {
+ TrailerLines += 1;
+ }
+
+ BlpPositionCursor(1, ScreenHeight-TrailerLines);
+ ArcWrite(BlConsoleOutDeviceId,
+ MenuTrailer1,
+ strlen(MenuTrailer1),
+ &Count);
+ ArcWrite(BlConsoleOutDeviceId,
+ MenuTrailer2,
+ strlen(MenuTrailer2),
+ &Count);
+
+ //
+ // Compute number of selections that can be displayed
+ //
+ DisplayLines = ScreenHeight-HeaderLines-TrailerLines-3;
+ if (ProfileCount < DisplayLines) {
+ DisplayLines = ProfileCount;
+ }
+
+ //
+ // Start menu selection loop.
+ //
+
+ do {
+ if (ProfileCount > 0) {
+ //
+ // Display options with current selection highlighted
+ //
+ for (i=0; i < DisplayLines; i++) {
+ CurrentProfile = i+TopProfileLine;
+ Profile = &(*ProfileList)->Profile[CurrentProfile];
+ RtlUnicodeToMultiByteN(MenuOption,
+ sizeof(MenuOption),
+ &OptionLength,
+ Profile->FriendlyName,
+ Profile->NameLength);
+ BlpPositionCursor(5, HeaderLines+i+2);
+ BlpSetInverseMode((BOOLEAN)(CurrentProfile == CurrentSelection));
+ ArcWrite(BlConsoleOutDeviceId,
+ MenuOption,
+ OptionLength,
+ &Count);
+ BlpSetInverseMode(FALSE);
+ BlpClearToEndOfLine();
+ }
+ } else {
+ //
+ // No profile options available, just display the default
+ // highlighted to indicate that ENTER will start the system.
+ //
+ Temp = BlFindMessage(BL_BOOT_DEFAULT_PROMPT);
+ if (Temp != NULL) {
+ BlpPositionCursor(5, HeaderLines+3);
+ BlpSetInverseMode(TRUE);
+ ArcWrite(BlConsoleOutDeviceId,
+ Temp,
+ strlen(Temp),
+ &Count);
+ BlpSetInverseMode(FALSE);
+ }
+ }
+ if (TimeoutPrompt) {
+ CurrentTime = ArcGetRelativeTime();
+ sprintf(MenuOption, TimeoutPrompt, EndTime-CurrentTime);
+ BlpPositionCursor(1, ScreenHeight);
+ ArcWrite(BlConsoleOutDeviceId,
+ MenuOption,
+ strlen(MenuOption),
+ &Count);
+ BlpClearToEndOfLine();
+ }
+
+ //
+ // Loop waiting for keypress or time change.
+ //
+ do {
+ if (ArcGetReadStatus(ARC_CONSOLE_INPUT) == ESUCCESS) {
+ TimeoutPrompt = NULL; // turn off timeout prompt
+ BlpPositionCursor(1,ScreenHeight);
+ BlpClearToEndOfLine();
+ ArcRead(ARC_CONSOLE_INPUT,
+ &Key,
+ sizeof(Key),
+ &Count);
+ break;
+ }
+
+ if (TimeoutPrompt) {
+ if (ArcGetRelativeTime() != CurrentTime) {
+ //
+ // Time has changed, update the countdown and check for timeout
+ //
+ CurrentTime = ArcGetRelativeTime();
+ sprintf(MenuOption, TimeoutPrompt, EndTime-CurrentTime);
+ BlpPositionCursor(1, ScreenHeight);
+ ArcWrite(BlConsoleOutDeviceId,
+ MenuOption,
+ strlen(MenuOption),
+ &Count);
+ BlpClearToEndOfLine();
+ if (EndTime == CurrentTime) {
+ goto ProcessSelection;
+ }
+ }
+ }
+
+ } while ( TRUE );
+
+ switch (Key) {
+ case ESC:
+
+ //
+ // See if the next character is '[' in which case we
+ // have a special control sequence.
+ //
+
+ ArcRead(ARC_CONSOLE_INPUT,
+ &Key,
+ sizeof(Key),
+ &Count);
+
+ if (Key!='[') {
+ break;
+ }
+
+ //
+ // deliberate fall-through
+ //
+
+ case ASCI_CSI_IN:
+
+ ArcRead(ARC_CONSOLE_INPUT,
+ &Key,
+ sizeof(Key),
+ &Count);
+
+ switch (Key) {
+ case 'A':
+ //
+ // Cursor up
+ //
+ if (ProfileCount > 0) {
+ if (CurrentSelection==0) {
+ CurrentSelection = ProfileCount - 1;
+ if (TopProfileLine + DisplayLines <= CurrentSelection) {
+ TopProfileLine = CurrentSelection - DisplayLines + 1;
+ }
+ } else {
+ if (--CurrentSelection < TopProfileLine) {
+ //
+ // Scroll up
+ //
+ TopProfileLine = CurrentSelection;
+ }
+ }
+ }
+ break;
+
+ case 'B':
+
+ //
+ // Cursor down
+ //
+
+ if (ProfileCount > 0) {
+ CurrentSelection = (CurrentSelection+1) % ProfileCount;
+ if (CurrentSelection == 0) {
+ TopProfileLine = 0;
+ } else if (TopProfileLine + DisplayLines <= CurrentSelection) {
+ TopProfileLine = CurrentSelection - DisplayLines + 1;
+ }
+ }
+ break;
+
+ case 'O':
+ //
+ // Function key
+ //
+ ArcRead(ARC_CONSOLE_INPUT,
+ &Key,
+ sizeof(Key),
+ &Count);
+ switch (Key) {
+ case 'w':
+ //
+ // F3
+ //
+ *ControlSet = HCELL_NIL;
+ return(FALSE);
+ default:
+ break;
+ }
+
+ default:
+ break;
+
+ }
+
+ continue;
+
+ default:
+ if ((toupper(Key) == LkgMnemonic) && (*UseLastKnownGood == FALSE)) {
+ *UseLastKnownGood = TRUE;
+ BlpSwitchControlSet(ProfileList,
+ TRUE,
+ ControlSet);
+ goto Restart;
+ //
+ // regenerate profile list here
+ //
+ } else if ((toupper(Key) == DefaultMnemonic) && (*UseLastKnownGood)) {
+ *UseLastKnownGood = FALSE;
+ BlpSwitchControlSet(ProfileList,
+ FALSE,
+ ControlSet);
+ goto Restart;
+ }
+ break;
+
+ }
+
+ } while ( (Key != ASCII_CR) && (Key != ASCII_LF) );
+
+ProcessSelection:
+ if (ProfileCount > 0) {
+ CmpSetCurrentProfile(&BootHive.Hive,
+ *ControlSet,
+ &(*ProfileList)->Profile[CurrentSelection]);
+ }
+
+ return(TRUE);
+}
+
+
+ARC_STATUS
+BlLoadBootDrivers(
+ IN ULONG DefaultDeviceId,
+ IN PCHAR DefaultLoadDevice,
+ IN PCHAR SystemPath,
+ IN PLIST_ENTRY BootDriverListHead,
+ OUT PCHAR BadFileName
+ )
+
+/*++
+
+Routine Description:
+
+ Walks the boot driver list and loads all the drivers
+
+Arguments:
+
+ DefaultDeviceId - Supplies the device ID of the boot partition
+
+ DefaultLoadDevice - Supplies the ARC name of the boot partition
+
+ SystemPath - Supplies the path to the system root
+
+ BootDriverListHead - Supplies the head of the boot driver list
+
+ BadFileName - Returns the filename of the critical driver that
+ did not load. Not valid if ESUCCESS is returned.
+
+Return Value:
+
+ ESUCCESS is returned if all the boot drivers were successfully loaded.
+ Otherwise, an unsuccessful status is returned.
+--*/
+
+{
+ ULONG DeviceId;
+ PCHAR LoadDevice;
+ PBOOT_DRIVER_NODE DriverNode;
+ PBOOT_DRIVER_LIST_ENTRY DriverEntry;
+ PLIST_ENTRY NextEntry;
+ CHAR DriverName[64];
+ PCHAR NameStart;
+ CHAR DriverDevice[128];
+ CHAR DriverPath[128];
+ ARC_STATUS Status;
+ UNICODE_STRING DeviceName;
+ UNICODE_STRING FileName;
+ PWSTR p;
+
+ NextEntry = BootDriverListHead->Flink;
+ while (NextEntry != BootDriverListHead) {
+ DriverNode = CONTAINING_RECORD(NextEntry,
+ BOOT_DRIVER_NODE,
+ ListEntry.Link);
+
+ Status = ESUCCESS;
+
+ DriverEntry = &DriverNode->ListEntry;
+
+ if (DriverEntry->FilePath.Buffer[0] != L'\\') {
+
+ //
+ // This is a relative pathname, so generate the full pathname
+ // relative to the boot partition.
+ //
+
+ sprintf(DriverPath, "%s%wZ",SystemPath,&DriverEntry->FilePath);
+ DeviceId = DefaultDeviceId;
+ LoadDevice = DefaultLoadDevice;
+
+ } else {
+
+ //
+ // This is an absolute pathname, of the form
+ // "\ArcDeviceName\dir\subdir\filename"
+ //
+ // We need to open the specified ARC device and pass that
+ // to BlLoadDeviceDriver.
+ //
+
+ p = DeviceName.Buffer = DriverEntry->FilePath.Buffer+1;
+ DeviceName.Length = 0;
+ DeviceName.MaximumLength = DriverEntry->FilePath.MaximumLength-sizeof(WCHAR);
+
+ while ((*p != L'\\') &&
+ (DeviceName.Length < DeviceName.MaximumLength)) {
+
+ ++p;
+ DeviceName.Length += sizeof(WCHAR);
+
+ }
+
+ DeviceName.MaximumLength = DeviceName.Length;
+ sprintf(DriverDevice, "%wZ", &DeviceName);
+
+ Status = ArcOpen(DriverDevice,ArcOpenReadOnly,&DeviceId);
+
+ FileName.Buffer = p+1;
+ FileName.Length = DriverEntry->FilePath.Length - DeviceName.Length - 2*sizeof(WCHAR);
+ FileName.MaximumLength = FileName.Length;
+ //
+ // Device successfully opened, parse out the path and filename.
+ //
+ sprintf(DriverPath, "%wZ", &FileName);
+ LoadDevice = DriverDevice;
+ }
+
+ NameStart = strrchr(DriverPath, '\\');
+ if (NameStart != NULL) {
+ strcpy(DriverName, NameStart+1);
+ *(NameStart+1) = '\0';
+
+ if (Status == ESUCCESS) {
+ Status = BlLoadDeviceDriver(DeviceId,
+ LoadDevice,
+ DriverPath,
+ DriverName,
+ LDRP_ENTRY_PROCESSED,
+ &DriverEntry->LdrEntry);
+ }
+
+ NextEntry = DriverEntry->Link.Flink;
+
+ if (Status != ESUCCESS) {
+
+ //
+ // Attempt to load driver failed, remove it from the list.
+ //
+ RemoveEntryList(&DriverEntry->Link);
+
+ //
+ // Check the Error Control of the failed driver. If it
+ // was critical, fail the boot. If the driver
+ // wasn't critical, keep going.
+ //
+ if (DriverNode->ErrorControl == CriticalError) {
+ strcpy(BadFileName,DriverPath);
+ strcat(BadFileName,DriverName);
+ return(Status);
+ }
+
+ }
+
+ } else {
+
+ NextEntry = DriverEntry->Link.Flink;
+
+ }
+
+ }
+
+ return(ESUCCESS);
+
+}
+
+
+ARC_STATUS
+BlLoadAndInitSystemHive(
+ IN ULONG DeviceId,
+ IN PCHAR DeviceName,
+ IN PCHAR DirectoryPath,
+ IN PCHAR HiveName,
+ IN BOOLEAN IsAlternate,
+ OUT PBOOLEAN RestartSetup
+ )
+
+/*++
+
+Routine Description:
+
+ Loads the registry SYSTEM hive, verifies it is a valid hive file,
+ and inits the relevant registry structures. (particularly the HHIVE)
+
+Arguments:
+
+ DeviceId - Supplies the file id of the device the system tree is on.
+
+ DeviceName - Supplies the name of the device the system tree is on.
+
+ DirectoryPath - Supplies a pointer to the zero-terminated directory path
+ of the root of the NT tree.
+
+ HiveName - Supplies the name of the system hive (ie, "SYSTEM",
+ "SYSTEM.ALT", or "SYSTEM.SAV").
+
+ IsAlternate - Supplies whether or not the hive to be loaded is the
+ alternate hive.
+
+ RestartSetup - if the hive to be loaded is not the alternate, then
+ this routine will check for a value of RestartSetup in the Setup
+ key. If present and non-0, then this variable receives TRUE.
+ Otherwise it receives FALSE.
+
+Return Value:
+
+ ESUCCESS is returned if the system hive was successfully loaded.
+ Otherwise, an unsuccessful status is returned.
+
+--*/
+
+{
+ ARC_STATUS Status;
+
+ *RestartSetup = FALSE;
+
+ BlpClearToEndOfLine();
+ Status = BlLoadSystemHive(DeviceId,
+ DeviceName,
+ DirectoryPath,
+ HiveName);
+ if (Status!=ESUCCESS) {
+ return(Status);
+ }
+
+ if (!BlInitializeHive(BlLoaderBlock->RegistryBase,
+ &BootHive,
+ IsAlternate)) {
+ return(EINVAL);
+ }
+
+ //
+ // See whether we need to switch to the backup setup hive.
+ //
+ *RestartSetup = BlpCheckRestartSetup();
+
+ return(ESUCCESS);
+}
+
+HCELL_INDEX
+BlpDetermineControlSet(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Determines the appropriate control set and static hardware profile.
+ This routine ends the configuration prompt. If the user has hit a
+ key, the configuration menu is displayed. If the user has not hit
+ a key, but the default controlset specifies a non-zero timeout for
+ the configuration menu, the configuration menu is displayed.
+
+ If the configuration menu is displayed, further modifications to the
+ control set and hardware profile can be made by the user. If not,
+ the default hardware profile is selected.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ HCELL_INDEX of control set to boot from.
+ HCELL_NIL on error.
+
+--*/
+
+{
+ BOOLEAN UseLastKnownGood;
+ BOOLEAN ConfigMenu = FALSE;
+ PCHAR LastKnownGood;
+ HCELL_INDEX ControlSet;
+ HCELL_INDEX ProfileControl;
+ UNICODE_STRING DefaultControlName;
+ UNICODE_STRING LkgControlName;
+ PUNICODE_STRING ControlName;
+ BOOLEAN AutoSelect;
+ ULONG ProfileTimeout = (ULONG)0;
+ PCM_HARDWARE_PROFILE_LIST ProfileList;
+ PCM_HARDWARE_PROFILE SelectedProfile;
+
+ RtlInitUnicodeString(&DefaultControlName, L"Default");
+ RtlInitUnicodeString(&LkgControlName, L"LastKnownGood");
+ //
+ // The initial decision of whether to use LKG is based on the
+ // LastKnownGood environment variable
+ //
+ LastKnownGood = ArcGetEnvironmentVariable("LastKnownGood");
+ if (LastKnownGood == NULL) {
+ UseLastKnownGood = FALSE;
+ } else {
+ UseLastKnownGood = (_stricmp(LastKnownGood, "TRUE") == 0);
+ }
+
+ //
+ // Get the appropriate control set
+ // and check the hardware profile timeout value.
+ //
+ if (UseLastKnownGood) {
+ ControlName = &LkgControlName;
+ } else {
+ ControlName = &DefaultControlName;
+ }
+ ControlSet = CmpFindControlSet(&BootHive.Hive,
+ BootHive.Hive.BaseBlock->RootCell,
+ ControlName,
+ &AutoSelect);
+ if (ControlSet == HCELL_NIL) {
+ return(HCELL_NIL);
+ }
+
+ //
+ // Check the hardware profile configuration options to
+ // determine the timeout value for the config menu.
+ //
+ ProfileList = NULL;
+ ProfileControl = CmpFindProfileOption(&BootHive.Hive,
+ ControlSet,
+ &ProfileList,
+ &ProfileTimeout);
+
+ //
+ // Now check to see whether the config menu should be displayed.
+ // Display the menu if:
+ // - user has pressed a key OR
+ // - we are booting from LKG and AutoSelect is FALSE. OR
+ // - ProfileTimeout != 0
+ //
+ if (BlEndConfigPrompt() ||
+ (UseLastKnownGood && !AutoSelect) ||
+ ((ProfileTimeout != 0) &&
+ (ProfileList != NULL) &&
+ (ProfileList->CurrentProfileCount > 1))) {
+ //
+ // Display the configuration menu.
+ //
+ BlRebootSystem = !BlConfigMenuPrompt(ProfileTimeout,
+ &UseLastKnownGood,
+ &ControlSet,
+ &ProfileList,
+ &SelectedProfile);
+ BlpClearScreen();
+ } else {
+
+ if ((ProfileControl != HCELL_NIL) &&
+ (ProfileList != NULL)) {
+ //
+ // The system is configured to boot the default
+ // profile directly. Since the returned profile
+ // list is sorted by priority, the first entry in
+ // the list is our default.
+ //
+ CmpSetCurrentProfile(&BootHive.Hive,
+ ControlSet,
+ &ProfileList->Profile[0]);
+ }
+ }
+
+ return(ControlSet);
+}
+
+
+BOOLEAN
+BlpCheckRestartSetup(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Examine the system hive loaded and described by BootHive, to see
+ whether it contains a Setup key, and if so, whether that key has
+ a "RestartSetup" value that is non-0.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Boolean value indicating whether the above condition is satisfied.
+
+--*/
+
+{
+ HCELL_INDEX KeyCell;
+ HCELL_INDEX ValueCell;
+ UNICODE_STRING UnicodeString;
+ PCM_KEY_VALUE Value;
+ PULONG Data;
+ ULONG DataSize;
+
+ //
+ // Address the Setup key
+ //
+ RtlInitUnicodeString(&UnicodeString,L"Setup");
+ KeyCell = CmpFindSubKeyByName(
+ &BootHive.Hive,
+ (PCM_KEY_NODE)HvGetCell(&BootHive.Hive,BootHive.Hive.BaseBlock->RootCell),
+ &UnicodeString
+ );
+
+ if(KeyCell == HCELL_NIL) {
+ return(FALSE);
+ }
+
+ //
+ // Find RestartSetup value in Setup key
+ //
+ RtlInitUnicodeString(&UnicodeString,L"RestartSetup");
+ ValueCell = CmpFindValueByName(
+ &BootHive.Hive,
+ (PCM_KEY_NODE)HvGetCell(&BootHive.Hive,KeyCell),
+ &UnicodeString
+ );
+
+ if(ValueCell == HCELL_NIL) {
+ return(FALSE);
+ }
+
+ //
+ // Validate value and check.
+ //
+ Value = (PCM_KEY_VALUE)HvGetCell(&BootHive.Hive,ValueCell);
+ if(Value->Type != REG_DWORD) {
+ return(FALSE);
+ }
+
+ Data = (PULONG)(CmpIsHKeyValueSmall(DataSize,Value->DataLength)
+ ? (struct _CELL_DATA *)&Value->Data
+ : HvGetCell(&BootHive.Hive,Value->Data));
+
+ if(DataSize != sizeof(ULONG)) {
+ return(FALSE);
+ }
+
+ return((BOOLEAN)(*Data != 0));
+}
+
+
+PCHAR
+BlScanRegistry(
+ IN PWSTR BootFileSystemPath,
+ OUT PLIST_ENTRY BootDriverListHead,
+ OUT PUNICODE_STRING AnsiCodepage,
+ OUT PUNICODE_STRING OemCodepage,
+ OUT PUNICODE_STRING LanguageTable,
+ OUT PUNICODE_STRING OemHalFont
+ )
+
+/*++
+
+Routine Description:
+
+ Scans the SYSTEM hive, determines the control set and static hardware
+ profile (with appropriate input from the user) and finally
+ computes the list of boot drivers to be loaded.
+
+Arguments:
+
+ BootFileSystemPath - Supplies the name of the image the filesystem
+ for the boot volume was read from. The last entry in
+ BootDriverListHead will refer to this file, and to the registry
+ key entry that controls it.
+
+ BootDriverListHead - Receives a pointer to the first element of the
+ list of boot drivers. Each element in this singly linked list will
+ provide the loader with two paths. The first is the path of the
+ file that contains the driver to load, the second is the path of
+ the registry key that controls that driver. Both will be passed
+ to the system via the loader heap.
+
+ AnsiCodepage - Receives the name of the ANSI codepage data file
+
+ OemCodepage - Receives the name of the OEM codepage data file
+
+ Language - Receives the name of the language case table data file
+
+ OemHalfont - receives the name of the OEM font to be used by the HAL.
+
+Return Value:
+
+ NULL if all is well.
+ NON-NULL if the hive is corrupt or inconsistent. Return value is a
+ pointer to a string that describes what is wrong.
+
+--*/
+
+{
+ HCELL_INDEX ControlSet;
+ UNICODE_STRING ControlName;
+ BOOLEAN AutoSelect;
+ BOOLEAN KeepGoing;
+
+ ControlSet = BlpDetermineControlSet();
+
+ if (ControlSet == HCELL_NIL) {
+ return("CmpFindControlSet");
+ }
+
+#if 0
+ need to move this to BlpDetermineControlSet()
+
+ if (UseLastKnownGood && !AutoSelect) {
+ KeepGoing = BlLastKnownGoodPrompt(&UseLastKnownGood);
+ if (!UseLastKnownGood) {
+ RtlInitUnicodeString(&ControlName, L"Default");
+ ControlSet = CmpFindControlSet(&BootHive.Hive,
+ BootHive.Hive.BaseBlock->RootCell,
+ &ControlName,
+ &AutoSelect);
+ if (ControlSet == HCELL_NIL) {
+ return("CmpFindControlSet");
+ }
+ }
+ }
+#endif
+
+ if (!CmpFindNLSData(&BootHive.Hive,
+ ControlSet,
+ AnsiCodepage,
+ OemCodepage,
+ LanguageTable,
+ OemHalFont)) {
+ return("CmpFindNLSData");
+ }
+
+ InitializeListHead(BootDriverListHead);
+ if (!CmpFindDrivers(&BootHive.Hive,
+ ControlSet,
+ BootLoad,
+ BootFileSystemPath,
+ BootDriverListHead)) {
+ return("CmpFindDriver");
+ }
+
+ if (!CmpSortDriverList(&BootHive.Hive,
+ ControlSet,
+ BootDriverListHead)) {
+ return("Missing or invalid Control\\ServiceGroupOrder\\List registry value");
+ }
+
+ if (!CmpResolveDriverDependencies(BootDriverListHead)) {
+ return("CmpResolveDriverDependencies");
+ }
+
+ return( NULL );
+}
+
+
+
+BOOLEAN
+BlInitializeHive(
+ IN PVOID HiveImage,
+ IN PCMHIVE Hive,
+ IN BOOLEAN IsAlternate
+ )
+
+/*++
+
+Routine Description:
+
+ Initializes the hive data structure based on the in-memory hive image.
+
+Arguments:
+
+ HiveImage - Supplies a pointer to the in-memory hive image.
+
+ Hive - Supplies the CMHIVE structure to be filled in.
+
+ IsAlternate - Supplies whether or not the hive is the alternate hive,
+ which indicates that the primary hive is corrupt and should be
+ rewritten by the system.
+
+Return Value:
+
+ TRUE - Hive successfully initialized.
+
+ FALSE - Hive is corrupt.
+
+--*/
+{
+ NTSTATUS status;
+ ULONG HiveCheckCode;
+
+ status = HvInitializeHive(
+ &Hive->Hive,
+ HINIT_MEMORY_INPLACE,
+ FALSE,
+ IsAlternate ? HFILE_TYPE_ALTERNATE : HFILE_TYPE_PRIMARY,
+ HiveImage,
+ (PALLOCATE_ROUTINE)BlpHiveAllocate, // allocate
+ NULL, // free
+ NULL, // setsize
+ NULL, // write
+ NULL, // read
+ NULL, // flush
+ 1, // cluster
+ NULL
+ );
+
+ if (!NT_SUCCESS(status)) {
+ return FALSE;
+ }
+
+ HiveCheckCode = CmCheckRegistry(Hive,TRUE);
+ if (HiveCheckCode != 0) {
+ return(FALSE);
+ } else {
+ return TRUE;
+ }
+
+}
+
+
+PVOID
+BlpHiveAllocate(
+ IN ULONG Length,
+ IN BOOLEAN UseForIo
+ )
+
+/*++
+
+Routine Description:
+
+ Wrapper for hive allocation calls. It just calls BlAllocateHeap.
+
+Arguments:
+
+ Length - Supplies the size of block required in bytes.
+
+ UseForIo - Supplies whether or not the memory is to be used for I/O
+ (this is currently ignored)
+
+Return Value:
+
+ address of the block of memory
+ or
+ NULL if no memory available
+
+--*/
+
+{
+ return(BlAllocateHeap(Length));
+
+}
+
+
+VOID
+BlpClearScreen(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Clears the screen.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ CHAR Buffer[16];
+ ULONG Count;
+
+ sprintf(Buffer, ASCI_CSI_OUT "2J");
+
+ ArcWrite(BlConsoleOutDeviceId,
+ Buffer,
+ strlen(Buffer),
+ &Count);
+
+}
+
+
+VOID
+BlClearToEndOfScreen(
+ VOID
+ )
+{
+ CHAR Buffer[16];
+ ULONG Count;
+
+ sprintf(Buffer, ASCI_CSI_OUT "J");
+ ArcWrite(BlConsoleOutDeviceId,
+ Buffer,
+ strlen(Buffer),
+ &Count);
+}
+
+
+VOID
+BlpClearToEndOfLine(
+ VOID
+ )
+{
+ CHAR Buffer[16];
+ ULONG Count;
+
+ sprintf(Buffer, ASCI_CSI_OUT "K");
+ ArcWrite(BlConsoleOutDeviceId,
+ Buffer,
+ strlen(Buffer),
+ &Count);
+}
+
+
+VOID
+BlpPositionCursor(
+ IN ULONG Column,
+ IN ULONG Row
+ )
+
+/*++
+
+Routine Description:
+
+ Sets the position of the cursor on the screen.
+
+Arguments:
+
+ Column - supplies new Column for the cursor position.
+
+ Row - supplies new Row for the cursor position.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ CHAR Buffer[16];
+ ULONG Count;
+
+ sprintf(Buffer, ASCI_CSI_OUT "%d;%dH", Row, Column);
+
+ ArcWrite(BlConsoleOutDeviceId,
+ Buffer,
+ strlen(Buffer),
+ &Count);
+
+
+}
+
+
+VOID
+BlpSetInverseMode(
+ IN BOOLEAN InverseOn
+ )
+
+/*++
+
+Routine Description:
+
+ Sets inverse console output mode on or off.
+
+Arguments:
+
+ InverseOn - supplies whether inverse mode should be turned on (TRUE)
+ or off (FALSE)
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ CHAR Buffer[16];
+ ULONG Count;
+
+ sprintf(Buffer, ASCI_CSI_OUT ";%dm", InverseOn ? SGR_INVERSE : SGR_INTENSE);
+
+ ArcWrite(BlConsoleOutDeviceId,
+ Buffer,
+ strlen(Buffer),
+ &Count);
+
+
+}
+
+NTSTATUS
+HvLoadHive(
+ PHHIVE Hive,
+ PVOID *Image
+ )
+{
+ UNREFERENCED_PARAMETER(Hive);
+ UNREFERENCED_PARAMETER(Image);
+ return(STATUS_SUCCESS);
+}
+
+BOOLEAN
+HvMarkCellDirty(
+ PHHIVE Hive,
+ HCELL_INDEX Cell
+ )
+{
+ UNREFERENCED_PARAMETER(Hive);
+ UNREFERENCED_PARAMETER(Cell);
+ return(TRUE);
+}
+
+BOOLEAN
+HvMarkDirty(
+ PHHIVE Hive,
+ HCELL_INDEX Start,
+ ULONG Length
+ )
+{
+ UNREFERENCED_PARAMETER(Hive);
+ UNREFERENCED_PARAMETER(Start);
+ UNREFERENCED_PARAMETER(Length);
+ return(TRUE);
+}
+
+BOOLEAN
+HvMarkClean(
+ PHHIVE Hive,
+ HCELL_INDEX Start,
+ ULONG Length
+ )
+{
+ UNREFERENCED_PARAMETER(Hive);
+ UNREFERENCED_PARAMETER(Start);
+ UNREFERENCED_PARAMETER(Length);
+ return(TRUE);
+}
+
+BOOLEAN
+HvpDoWriteHive(
+ PHHIVE Hive,
+ ULONG FileType
+ )
+{
+ UNREFERENCED_PARAMETER(Hive);
+ UNREFERENCED_PARAMETER(FileType);
+ return(TRUE);
+}
+
+BOOLEAN
+HvpGrowLog1(
+ PHHIVE Hive,
+ ULONG Count
+ )
+{
+ UNREFERENCED_PARAMETER(Hive);
+ UNREFERENCED_PARAMETER(Count);
+ return(TRUE);
+}
+
+BOOLEAN
+HvpGrowLog2(
+ PHHIVE Hive,
+ ULONG Size
+ )
+{
+ UNREFERENCED_PARAMETER(Hive);
+ UNREFERENCED_PARAMETER(Size);
+ return(TRUE);
+}
+
+BOOLEAN
+CmpValidateHiveSecurityDescriptors(
+ IN PHHIVE Hive
+ )
+{
+ UNREFERENCED_PARAMETER(Hive);
+ return(TRUE);
+}
+
+
+BOOLEAN
+CmpTestRegistryLock()
+{
+ return TRUE;
+}
+
+BOOLEAN
+CmpTestRegistryLockExclusive()
+{
+ return TRUE;
+}
+
+
+BOOLEAN
+HvIsBinDirty(
+IN PHHIVE Hive,
+IN HCELL_INDEX Cell
+)
+{
+ return(FALSE);
+}
+PHBIN
+HvpAddBin(
+ IN PHHIVE Hive,
+ IN ULONG NewSize,
+ IN HSTORAGE_TYPE Type
+ )
+{
+ return(NULL);
+}
diff --git a/private/ntos/boot/bldr/sources b/private/ntos/boot/bldr/sources
new file mode 100644
index 000000000..fe2865e0c
--- /dev/null
+++ b/private/ntos/boot/bldr/sources
@@ -0,0 +1,51 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=bldr
+
+TARGETNAME=bldr
+TARGETPATH=obj
+TARGETTYPE=LIBRARY
+
+SYNCHRONIZE_DRAIN=1
+
+INCLUDES=\nt\public\sdk\inc;..\inc;..\..\inc;..\..\config
+
+C_DEFINES=$(C_DEFINES) -D_NTSYSTEM_
+
+SOURCES=osloader.c \
+ regboot.c \
+ osloader.rc
+
+NTTARGETFILE0=msg.h msg.rc
+
+!IF $(ALPHA) || $(MIPS) || $(PPC)
+
+NTTARGETFILES=obj\*\osloader.exe
+
+!ENDIF
+
+UMLIBS=..\..\config\obj\*\bconfig.lib ..\obj\*\boot.lib
+UMRES=obj\*\setupldr.res
diff --git a/private/ntos/boot/bootcode/etfs/i386/etfsboot.asm b/private/ntos/boot/bootcode/etfs/i386/etfsboot.asm
new file mode 100644
index 000000000..15d2d4a85
--- /dev/null
+++ b/private/ntos/boot/bootcode/etfs/i386/etfsboot.asm
@@ -0,0 +1,584 @@
+;++
+;
+;Copyright (c) 1995 Compaq Computer Corporation
+;
+;Module Name:
+;
+; etfsboot.asm
+;
+;Abstract:
+;
+; The ROM in the IBM PC starts the boot process by performing a hardware
+; initialization and a verification of all external devices. If an El
+; Torito CD-ROM with no-emulation support is detected, it will then load
+; the "image" pointed to in the Boot Catalog. This "image" is placed at
+; the physical address specified in the Boot Catalog (which should be 07C00h).
+;
+; The code in this "image" is responsible for locating NTLDR, loading the
+; first sector of NTLDR into memory at 2000:0000, and branching to it.
+;
+; There are only two errors possible during execution of this code.
+; 1 - NTLDR does not exist
+; 2 - BIOS read error
+;
+; In both cases, a short message is printed, and the user is prompted to
+; reboot the system.
+;
+;
+;Author:
+;
+; Steve Collins (stevec) 25-Oct-1995
+;
+;Environment:
+;
+; Image has been loaded at 7C0:0000 by BIOS.
+; Real mode
+; ISO 9660 El Torito no-emulation CD-ROM Boot support
+; DL = El Torito drive number we booted from
+;
+;Revision History:
+;
+;--
+ page ,132
+ title boot - NTLDR ETFS loader
+ name etfsboot
+
+
+BootSeg segment at 07c0h
+BootSeg ends
+
+DirSeg segment at 1000h
+DirSeg ends
+
+NtLdrSeg segment at 2000h
+NtLdrSeg ends
+
+BootCode segment ;would like to use BootSeg here, but LINK flips its lid
+ ASSUME CS:BootCode,DS:NOTHING,ES:NOTHING,SS:NOTHING
+
+ public ETFSBOOT
+ETFSBOOT proc far
+
+ xor ax,ax ; Setup the stack to a known good spot
+ mov ss,ax ; Stack is set to 0000:7c00, which is just below this code
+ mov sp,7c00h
+
+ mov ax,BootSeg ; Set DS to our code/data segment (07C0h)
+ mov ds,ax
+assume DS:BootCode
+
+;
+; Save the Drive Number for later use
+ mov DriveNum,dl
+
+;
+; The system is now prepared for us to begin reading. First, we need to
+; read in the Primary Volume Descriptor so we can locate the root directory
+;
+.286
+ push 01h ; Word 0 (low word) of Transfer size = 1 block (2048 bytes)
+ push 0h ; Word 1 (high word) of Transfer size = 0
+ push DirSeg ; Segment of Transfer buffer = DirSeg
+ push 010h ; Word 0 (low word) of Starting absolute block number = 10h
+ push 0h ; Word 1 of Starting absolute block number = 0
+.8086
+ call ExtRead
+ add sp,10 ; Clean 5 arguments off the stack
+
+;
+; Determine the root directory location LBN -> ExtentLoc1:ExtentLoc0
+; determine the root directory data length in bytes -> ExtentLen1:ExtentLen0
+;
+ mov ax,DirSeg ; ES is set to segment used for storing PVD and directories
+ mov es,ax
+ASSUME ES:DirSeg
+ mov ax,es:[09eh] ; 32-bit LBN of extent at offset 158 in Primary Volume Descriptor
+ mov ExtentLoc0,ax ; store low word
+ mov ax,es:[0a0h]
+ mov ExtentLoc1,ax ; store high word
+ mov ax,es:[0a6h] ; 32-bit Root directory data length in bytes at offset 166 in Primary Volume Descriptor
+ mov ExtentLen0,ax ; store low word
+ mov ax,es:[0a8h]
+ mov ExtentLen1,ax ; store high word
+
+;
+; Now read in the root directory
+;
+.286
+ push DirSeg ; Segment used for transfer = DirSeg
+.8086
+ call ReadExtent
+ add sp,2 ; Clean 1 argument off the stack
+
+;
+; Scan for the presence of the I386 directory
+; ES points to directory segment
+;
+ mov EntryToFind, offset I386DIRNAME
+ mov EntryLen,4
+ mov IsDir,1
+ call ScanForEntry
+
+;
+; We found the I386 directory entry, so now get its extent location (offset -31 from filename ID)
+; ES:[BX] still points to the directory record for the I386 directory
+;
+ call GetExtentInfo
+
+;
+; Now read in the I386 directory
+;
+.286
+ push DirSeg ; Segment used for transfer = DirSeg
+.8086
+ call ReadExtent
+ add sp,2 ; Clean 1 argument off the stack
+
+;
+; Scan for the presence of SETUPLDR.BIN
+; ES points to directory segment
+;
+ mov ax,DirSeg
+ mov es,ax
+ mov EntryToFind, offset LOADERNAME
+ mov EntryLen,12
+ mov IsDir,0
+ call ScanForEntry
+
+;
+; We found the loader entry, so now get its extent location (offset -31 from filename ID)
+; ES:[BX] still points to the directory record for the LOADER
+;
+ call GetExtentInfo
+
+;
+; Now, go read the file
+;
+.286
+ push NtLdrSeg ; Segment used for transfer = NtLdrSeg
+.8086
+ call ReadExtent
+ add sp,2 ; Clean 1 argument off the stack
+
+;
+; NTLDR requires:
+; DL = INT 13 drive number we booted from
+;
+ mov dl, DriveNum ; DL = CD drive number - this isn't really necessary since DirveNum is already in dl
+ xor ax,ax
+.386
+ push NtLdrSeg
+ push ax
+ retf ; "return" to NTLDR.
+
+ETFSBOOT endp
+
+
+;
+; ScanForEntry - Scan for an entry in a directory
+;
+; Entry:
+; ES:0 points to the beginning of the directory to search
+; Directory length in bytes is in ExtentLen1 and Extend_Len_0
+;
+; Exit:
+; ES:BX points to record containing entry if match is found
+; Otherwise, we jump to error routine
+;
+ScanForEntry proc near
+ mov cx,ExtentLen0 ; CX = length of root directory in bytes (low word only)
+ cld ; Work up for string compares
+ xor bx,bx
+ xor dx,dx
+ScanLoop:
+ mov si, EntryToFind
+ mov dl,byte ptr es:[bx] ; directory record length -> DL
+ cmp dl,0
+ jz Skip00 ; if the "record length" assume it is "system use" and skip it
+ mov ax,bx
+ add ax,021h ; file identifier is at offset 21h in directory record
+ mov di,ax ; ES:DI now points to file identifier
+ push cx
+ xor cx,cx
+ mov cl,EntryLen ; compare bytes
+ repe cmpsb
+ pop cx
+ jz ScanEnd ; do we have a match?
+
+CheckCountUnderFlow:
+ ; If CX is about to underflow or be 0 we need to reset CX, ES and BX if ExtentLen1 is non-0
+ cmp dx,cx
+ jae ResetCount0
+
+ sub cx,dx ; update CX to contain number of bytes left in directory
+ cmp ScanIncCount, 1
+ je ScanAdd1ToCount
+
+AdjustScanPtr: ; Adjust ES:BX to point to next record
+ add dx,bx
+ mov bx,dx
+ and bx,0fh
+ push cx
+ mov cl,4
+ shr dx,cl
+ pop cx
+ mov ax,es
+ add ax,dx
+ mov es,ax
+ jmp ScanLoop
+
+Skip00:
+ mov dx,1 ; Skip past this byte
+ jmp CheckCountUnderFlow
+
+ScanAdd1ToCount:
+ inc cx
+ mov ScanIncCount,0
+ jmp AdjustScanPtr
+
+S0:
+ mov ScanIncCount,1 ; We'll need to increment Count next time we get a chance
+ jmp SetNewCount
+
+ResetCount0:
+ cmp ExtentLen1,0 ; Do we still have at least 64K bytes left to scan?
+ je BootErr$bnf ; We overran the end of the directory - corrupt/invalid directory
+ sub ExtentLen1,1
+
+ add bx,dx ; Adjust ES:BX to point to next record - we cross seg boundary here
+ push bx
+ push cx
+ mov cl,4
+ shr bx,cl
+ pop cx
+ mov ax,es
+ add ax,bx
+ mov es,ax
+ pop bx
+ and bx,0fh
+
+ sub dx,cx ; Get overflow amount
+ je S0 ; If we ended right on the boundary we need to make special adjustments
+ dec dx
+SetNewCount:
+ mov ax,0ffffh
+ sub ax,dx ; and subtract it from 10000h
+ mov cx,ax ; - this is the new count
+ jmp ScanLoop
+
+ScanEnd:
+ cmp IsDir,1
+ je CheckDir
+
+ test byte ptr es:[bx][25],2 ; Is this a file?
+ jnz CheckCountUnderFlow ; No - go to next record
+ jmp CheckLen
+
+CheckDir:
+ test byte ptr es:[bx][25],2 ; Is this a directory?
+ jz CheckCountUnderFlow ; No - go to next record
+
+CheckLen:
+ mov al,EntryLen
+ cmp byte ptr es:[bx][32],al ; Is the identifier length correct?
+ jnz CheckCountUnderFlow ; No - go to next record
+
+ ret
+ScanForEntry endp
+
+;
+; BootErr - print error message and hang the system.
+;
+BootErr proc
+BootErr$bnf:
+ MOV SI,OFFSET MSG_NO_NTLDR
+ jmp short BootErr2
+BootErr$mof:
+ MOV SI,OFFSET MSG_MEM_OVERFLOW
+ jmp short BootErr2
+BootErr2:
+ call BootErrPrint
+ MOV SI,OFFSET MSG_REBOOT_ERROR
+ call BootErrPrint
+ sti
+ jmp $ ;Wait forever
+
+BootErrPrint:
+ LODSB ; Get next character
+ or al,al
+ jz BEdone
+
+ MOV AH,14 ; Write teletype
+ MOV BX,7 ; Attribute
+ INT 10H ; Print it
+ jmp BootErrPrint
+BEdone:
+
+ ret
+BootErr endp
+
+;
+; ExtRead - Do an INT 13h extended read
+; NOTE: I force the offset of the Transfer buffer address to be 0
+; I force the high 2 words of the Starting absolute block number to be 0
+; - This allows for a max 4 GB medium - a safe assumption for now
+;
+; Entry:
+; Arg1 - word 0 (low word) of Number of 2048-byte blocks to transfer
+; Arg2 - word 1 (high word) of Number of 2048-byte blocks to transfer
+; Arg3 - segment of Transfer buffer address
+; Arg4 - word 0 (low word) of Starting absolute block number
+; Arg5 - word 1 of Starting absolute block number
+;
+; Exit
+; The following are modified:
+; Count0
+; Count1
+; Dest
+; Source0
+; Source1
+; PartialRead
+; NumBlocks
+; Disk Address Packet [DiskAddPack]
+;
+ExtRead proc near
+ push bp ; set up stack frame so we can get args
+ mov bp,sp
+
+ push bx ; Save registers used during this routine
+ push si
+ push dx
+ push ax
+
+ mov bx,offset DiskAddPack ; Use BX as base to index into Disk Address Packet
+
+ ; Set up constant fields
+ mov [bx][0],byte ptr 010h ; Offset 0: Packet size = 16 bytes
+ mov [bx][1],byte ptr 0h ; Offset 1: Reserved (must be 0)
+ mov [bx][3],byte ptr 0h ; Offset 3: Reserved (must be 0)
+ mov [bx][4],word ptr 0h ; Offset 4: Offset of Transfer buffer address (force 0)
+ mov [bx][12],word ptr 0h ; Offset 12: Word 2 of Starting absolute block number (force 0)
+ mov [bx][14],word ptr 0h ; Offset 14: Word 3 (high word) of Starting absolute block number (force 0)
+
+;
+; Initialize loop variables
+;
+ mov ax,[bp][12] ; set COUNT to number of blocks to transfer
+ mov Count0,ax
+ mov ax,[bp][10]
+ mov Count1,ax
+
+ mov ax,[bp][8] ; set DEST to destination segment
+ mov Dest,ax
+
+ mov ax,[bp][6] ; set SOURCE to source lbn
+ mov Source0,ax
+ mov ax,[bp][4]
+ mov Source1,ax
+
+ExtReadLoop:
+;
+; First check if COUNT <= 32
+;
+ cmp Count1,word ptr 0h ; Is upper word 0?
+ jne SetupPartialRead ; No - we're trying to read at least 64K blocks (128 MB)
+ cmp Count0,word ptr 20h ; Is lower word greater than 32?
+ jg SetupPartialRead ; Yes - only read in 32-block increments
+
+ mov PartialRead,0 ; Clear flag to indicate we are doing a full read
+
+ mov ax,Count0 ; NUMBLOCKS = COUNT
+ mov NumBlocks,al ; Since Count0 < 32 we're OK just using low byte
+
+ jmp DoExtRead ; Do read
+
+SetupPartialRead:
+;
+; Since COUNT > 32,
+; Set flag indicating we are only doing a partial read
+;
+ mov PartialRead,1
+
+ mov NumBlocks,20h ; NUMBYTES = 32
+
+DoExtRead:
+;
+; Perform Extended Read
+;
+ mov al,NumBlocks ; Offset 2: Number of 2048-byte blocks to transfer
+ mov [bx][2],al
+ mov ax,Dest ; Offset 6: Segment of Transfer buffer address
+ mov [bx][6],ax
+ mov ax,Source0 ; Offset 8: Word 0 (low word) of Starting absolute block number
+ mov [bx][8],ax
+ mov ax,Source1 ; Offset 10: Word 1 of Starting absolute block number
+ mov [bx][10],ax
+
+ mov si,offset DiskAddPack ; Disk Address Packet in DS:SI
+ mov ah,042h ; Function = Extended Read
+ mov dl,DriveNum ; CD-ROM drive number
+ int 13h
+
+;
+; Determine if we are done reading
+;
+ cmp PartialRead,1 ; Did we just do a partial read?
+ jne ExtReadDone ; No - we're done
+
+ReadjustValues:
+;
+; We're not done reading yet, so
+; COUNT = COUNT - 32
+;
+ sub Count0,020h ; Subtract low-order words
+ sbb Count1,0h ; Subtract high-order words
+
+;
+; Just read 32 blocks and have more to read
+; Increment DEST to next 64K segment (this equates to adding 1000h to the segment)
+;
+ add Dest,1000h
+ jc BootErr$mof ; Error if we overflowed
+
+;
+; SOURCE = SOURCE + 32 blocks
+;
+ add Source0,word ptr 020h ; Add low order words
+ adc Source1,word ptr 0h ; Add high order words
+ ; NOTE - I don't account for overflow - probably OK now since we already account for 4 GB medium
+
+;
+; jump back to top of loop to do another read
+;
+ jmp ExtReadLoop
+
+ExtReadDone:
+
+ pop ax ; Restore registers used during this routine
+ pop dx
+ pop si
+ pop bx
+
+ mov sp,bp ; restore BP and SP
+ pop bp
+
+ ret
+ExtRead endp
+
+;
+; ReadExtent - Read in an extent
+;
+; Arg1 - segment to transfer extent to
+;
+; Entry:
+; ExtentLen0 = word 0 (low word) of extent length in bytes
+; ExtentLen1 = word 1 (high word) of extent length in bytes
+; ExtentLoc0 = word 0 (low word) of starting absolute block number of extent
+; ExtentLoc1 = word 1 of starting absolute block number of extent
+;
+; Exit:
+; ExtRead exit mods
+;
+ReadExtent proc near
+ push bp ; set up stack frame so we can get args
+ mov bp,sp
+
+ push cx ; Save registers used during this routine
+ push bx
+ push ax
+
+ mov cl,11 ; Convert length in bytes to 2048-byte blocks
+ mov bx,ExtentLen1 ; Directory length = BX:AX
+ mov ax,ExtentLen0
+
+.386
+ shrd ax,bx,cl ; Shift AX, filling with BX
+.8086
+ shr bx,cl ; BX:AX = number of blocks (rounded down)
+ test ExtentLen0,07ffh ; If any of the low-order 11 bits are set we need to round up
+ jz ReadExtentNoRoundUp
+ add ax,1 ; We need to round up by incrementing AX, and
+ adc bx,0 ; adding the carry to BX
+ReadExtentNoRoundUp:
+
+ push ax ; Word 0 (low word) of Transfer size = AX
+ push bx ; Word 1 (high word) of Transfer size = BX
+.286
+ push [bp][4] ; Segment used to transfer extent
+.8086
+ push ExtentLoc0 ; Word 0 (low word) of Starting absolute block number
+ push ExtentLoc1 ; Word 1 of Starting absolute block number
+ call ExtRead
+ add sp,10 ; Clean 5 arguments off the stack
+
+ pop ax ; Restore registers used during this routine
+ pop bx
+ pop cx
+
+ mov sp,bp ; restore BP and SP
+ pop bp
+
+ ret
+ReadExtent endp
+
+;
+; GetExtentInfo - Get extent location
+;
+; Entry:
+; ES:BX points to record
+; Exit:
+; Location -> ExtentLoc1 and ExtentLoc0
+; Length -> ExtentLen1 and ExtentLen0
+;
+GetExtentInfo proc near
+ push ax ; Save registers used during this routine
+
+ mov ax,es:[bx][2] ; 32-bit LBN of extent
+ mov ExtentLoc0,ax ; store low word
+ mov ax,es:[bx][4]
+ mov ExtentLoc1,ax ; store high word
+ mov ax,es:[bx][10] ; 32-bit file length in bytes
+ mov ExtentLen0,ax ; store low word
+ mov ax,es:[bx][12]
+ mov ExtentLen1,ax ; store high word
+
+ pop ax ; Restore registers used during this routine
+
+ ret
+GetExtentInfo endp
+
+
+include etfsboot.inc ; message text
+
+DiskAddPack db 16 dup (?) ; Disk Address Packet
+PartialRead db 0 ; Boolean indicating whether or not we are doing a partial read
+LOADERNAME db "SETUPLDR.BIN"
+I386DIRNAME db "I386"
+DriveNum db (?) ; Drive number used for INT 13h extended reads
+ExtentLoc0 dw (?) ; Loader LBN - low word
+ExtentLoc1 dw (?) ; Loader LBN - high word
+ExtentLen0 dw (?) ; Loader Length - low word
+ExtentLen1 dw (?) ; Loader Length - high word
+Count0 dw (?) ; Read Count - low word
+Count1 dw (?) ; Read Count - high word
+Dest dw (?) ; Read Destination segment
+Source0 dw (?) ; Read Source - word 0 (low word)
+Source1 dw (?) ; Read Source - word 1
+NumBlocks db (?) ; Number of blocks to Read
+EntryToFind dw (?) ; Offset of string trying to match in ScanForEntry
+EntryLen db (?) ; Length in bytes of entry to match in ScanForEntry
+IsDir db (?) ; Boolean indicating whether or not entry to match in ScanForEntry is a directory
+ScanIncCount db 0 ; Boolean indicating if we need to add 1 to Count after adjustment in ScanForEntry
+
+ .errnz ($-ETFSBOOT) GT 2046 ; FATAL PROBLEM: boot sector is too large
+
+ org 2046
+ db 55h,0aah
+
+BootSectorEnd label dword
+
+BootCode ends
+
+
+ END ETFSBOOT
+
diff --git a/private/ntos/boot/bootcode/etfs/i386/usa/bootetfs.h b/private/ntos/boot/bootcode/etfs/i386/usa/bootetfs.h
new file mode 100644
index 000000000..65d3066a9
--- /dev/null
+++ b/private/ntos/boot/bootcode/etfs/i386/usa/bootetfs.h
@@ -0,0 +1,133 @@
+#define ETFSBOOTCODE_SIZE 2048
+
+
+unsigned char EtfsBootCode[] = {
+51,192,142,208,188,0,124,184,192,7,142,216,136,22,29,3,
+106,1,106,0,104,0,16,106,16,106,0,232,103,1,131,196,
+10,184,0,16,142,192,38,161,158,0,163,30,3,38,161,160,
+0,163,32,3,38,161,166,0,163,34,3,38,161,168,0,163,
+36,3,104,0,16,232,4,2,131,196,2,199,6,49,3,25,
+3,198,6,51,3,4,144,198,6,52,3,1,144,232,61,0,
+232,37,2,104,0,16,232,227,1,131,196,2,184,0,16,142,
+192,199,6,49,3,13,3,198,6,51,3,12,144,198,6,52,
+3,0,144,232,23,0,232,255,1,104,0,32,232,189,1,131,
+196,2,138,22,29,3,51,192,104,0,32,80,203,139,14,34,
+3,252,51,219,51,210,139,54,49,3,38,138,23,128,250,0,
+15,132,59,0,139,195,5,33,0,139,248,81,51,201,138,14,
+51,3,243,166,89,15,132,109,0,59,209,15,131,55,0,43,
+202,128,62,53,3,1,15,132,26,0,3,211,139,218,131,227,
+15,81,177,4,211,234,89,140,192,3,194,142,192,235,183,186,
+1,0,235,213,65,198,6,53,3,0,144,235,221,198,6,53,
+3,1,144,235,39,144,131,62,36,3,0,15,132,79,0,131,
+46,36,3,1,3,218,83,81,177,4,211,235,89,140,192,3,
+195,142,192,91,131,227,15,43,209,116,210,74,184,255,255,43,
+194,139,200,233,112,255,128,62,52,3,1,15,132,10,0,38,
+246,71,25,2,117,131,235,10,144,38,246,71,25,2,15,132,
+119,255,160,51,3,38,56,71,32,15,133,108,255,195,190,167,
+2,235,5,190,195,2,235,0,232,9,0,190,225,2,232,3,
+0,251,235,254,172,10,192,15,132,9,0,180,14,187,7,0,
+205,16,235,240,195,85,139,236,83,86,82,80,187,252,2,198,
+7,16,198,71,1,0,198,71,3,0,199,71,4,0,0,199,
+71,12,0,0,199,71,14,0,0,139,70,12,163,38,3,139,
+70,10,163,40,3,139,70,8,163,42,3,139,70,6,163,44,
+3,139,70,4,163,46,3,129,62,40,3,0,0,15,133,25,
+0,129,62,38,3,32,0,15,143,15,0,198,6,12,3,0,
+144,161,38,3,162,48,3,235,13,144,198,6,12,3,1,144,
+198,6,48,3,32,144,160,48,3,136,71,2,161,42,3,137,
+71,6,161,44,3,137,71,8,161,46,3,137,71,10,190,252,
+2,180,66,138,22,29,3,205,19,128,62,12,3,1,15,133,
+34,0,131,46,38,3,32,131,30,40,3,0,129,6,42,3,
+0,16,15,130,45,255,129,6,44,3,32,0,129,22,46,3,
+0,0,235,131,88,90,94,91,139,229,93,195,85,139,236,81,
+83,80,177,11,139,30,36,3,161,34,3,15,173,216,211,235,
+247,6,34,3,255,7,116,6,5,1,0,131,211,0,80,83,
+255,118,4,255,54,30,3,255,54,32,3,232,7,255,131,196,
+10,88,91,89,139,229,93,195,80,38,139,71,2,163,30,3,
+38,139,71,4,163,32,3,38,139,71,10,163,34,3,38,139,
+71,12,163,36,3,88,195,66,79,79,84,58,32,67,111,117,
+108,100,110,39,116,32,102,105,110,100,32,78,84,76,68,82,
+13,10,0,66,79,79,84,58,32,77,101,109,111,114,121,32,
+111,118,101,114,102,108,111,119,32,101,114,114,111,114,13,10,
+0,80,108,101,97,115,101,32,105,110,115,101,114,116,32,97,
+110,111,116,104,101,114,32,100,105,115,107,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,83,69,84,
+85,80,76,68,82,46,66,73,78,73,51,56,54,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,85,170
+};
diff --git a/private/ntos/boot/bootcode/etfs/i386/usa/etfsboot.inc b/private/ntos/boot/bootcode/etfs/i386/usa/etfsboot.inc
new file mode 100644
index 000000000..2273eb55d
--- /dev/null
+++ b/private/ntos/boot/bootcode/etfs/i386/usa/etfsboot.inc
@@ -0,0 +1,27 @@
+;++
+;
+;Copyright (c) 1995 Compaq Computer Corporation
+;
+;Module Name:
+;
+; etfsboot.inc
+;
+;Abstract:
+;
+; This contains the message text that the boot sector prints out on
+; error conditions
+;
+;Author:
+;
+; Steve Collins (stevec) 25-Oct-1995
+;
+;Revision History:
+;
+;--
+
+MSG_NO_NTLDR db "BOOT: Couldn't find NTLDR"
+ db 0dh, 0ah, 0
+MSG_MEM_OVERFLOW db "BOOT: Memory overflow error"
+ db 0dh, 0ah, 0
+MSG_REBOOT_ERROR db "Please insert another disk"
+ db 0
diff --git a/private/ntos/boot/bootcode/fat/i386/fatboot.asm b/private/ntos/boot/bootcode/fat/i386/fatboot.asm
new file mode 100644
index 000000000..b349538bd
--- /dev/null
+++ b/private/ntos/boot/bootcode/fat/i386/fatboot.asm
@@ -0,0 +1,426 @@
+;++
+;
+;Copyright (c) 1991 Microsoft Corporation
+;
+;Module Name:
+;
+; fatboot.asm
+;
+;Abstract:
+;
+; The ROM in the IBM PC starts the boot process by performing a hardware
+; initialization and a verification of all external devices. If all goes
+; well, it will then load from the boot drive the sector from track 0, head 0,
+; sector 1. This sector is placed at physical address 07C00h.
+;
+; The code in this sector is responsible for locating NTLDR, loading the
+; first sector of NTLDR into memory at 2000:0000, and branching to it. The
+; first sector of NTLDR is special code which knows enough about FAT and
+; BIOS to load the rest of NTLDR into memory.
+;
+; There are only two errors possible during execution of this code.
+; 1 - NTLDR does not exist
+; 2 - BIOS read error
+;
+; In both cases, a short message is printed, and the user is prompted to
+; reboot the system.
+;
+; At the beginning of the boot sector, there is a table which describes the
+; structure of the media. This is equivalent to the BPB with some
+; additional information describing the physical layout of the driver (heads,
+; tracks, sectors)
+;
+;
+;Author:
+;
+; John Vert (jvert) 31-Aug-1991
+;
+;Environment:
+;
+; Sector has been loaded at 7C0:0000 by BIOS.
+; Real mode
+; FAT file system
+;
+;Revision History:
+;
+;--
+ page ,132
+ title boot - NTLDR FAT loader
+ name fatboot
+
+DIR_ENT struc
+ Filename db 11 dup(?)
+ Attribute db ?
+ Reserved db 10 dup(?)
+ Time dw 2 dup(?)
+ StartCluster dw ?
+ FileSize dd ?
+DIR_ENT ends
+
+;
+; This is the structure used to pass all shared data between the boot sector
+; and NTLDR.
+;
+
+SHARED struc
+ ReadClusters dd ? ; function pointer
+ ReadSectors dd ? ; function pointer
+ SectorBase dd ? ; starting sector
+SHARED ends
+
+
+
+DoubleWord struc
+lsw dw ?
+msw dw ?
+DoubleWord ends
+
+SectorSize equ 512 ; sector size
+
+BootSeg segment at 07c0h
+BootSeg ends
+
+DirSeg segment at 1000h
+DirSeg ends
+
+NtLdrSeg segment at 2000h
+NtLdrSeg ends
+
+BootCode segment ;would like to use BootSeg here, but LINK flips its lid
+ ASSUME CS:BootCode,DS:NOTHING,ES:NOTHING,SS:NOTHING
+
+ public FATBOOT
+FATBOOT proc far
+
+ jmp Start
+
+;
+; THE FOLLOWING DATA CONFIGURES THE BOOT PROGRAM
+; FOR ANY TYPE OF DRIVE OR HARDFILE
+;
+; Note that this data is just a place-holder here. The actual values will
+; be filled in by FORMAT or SYS. When installing the boot sector, only the
+; code following the BPB (from Start to the end) should be copied into the
+; first sector.
+;
+
+Version db "MSDOS5.0"
+BPB label byte
+BytesPerSector dw SectorSize ; Size of a physical sector
+SectorsPerCluster db 8 ; Sectors per allocation unit
+ReservedSectors dw 1 ; Number of reserved sectors
+Fats db 2 ; Number of fats
+DirectoryEntries dw 512 ; Number of directory entries
+Sectors dw 4*17*305-1 ; No. of sectors - no. of hidden sectors
+Media db 0F8H ; Media byte
+FatSectors dw 8 ; Number of fat sectors
+SectorsPerTrack dw 17 ; Sectors per track
+Heads dw 4 ; Number of surfaces
+HiddenSectors dd 1 ; Number of hidden sectors
+SectorsLong dd 0 ; Number of sectors iff Sectors = 0
+
+;
+; The following byte is NOT part of the BPB but is set by SYS and format
+; We should NOT change its position.
+;
+
+; keep order of DriveNumber and CurrentHead!
+DriveNumber db 80h ; Physical drive number (0 or 80h)
+CurrentHead db ? ; Unitialized
+
+Signature db 41 ; Signature Byte for bootsector
+BootID dd ? ; Boot ID field.
+Boot_Vol_Label db 11 dup (?)
+Boot_System_ID db 'FAT ' ;"FAT " or "OTHER_FS"
+
+
+Start:
+ xor ax,ax ; Setup the stack to a known good spot
+ mov ss,ax
+ mov sp,7c00h
+
+.386
+ push BootSeg
+.8086
+ pop ds
+assume DS:BootCode
+
+; The system is now prepared for us to begin reading. First, determine
+; logical sector numbers of the start of the directory and the start of the
+; data area.
+;
+ MOV AL,Fats ;Determine sector root directory starts on
+ MUL FatSectors
+;##### what if result > 65535 ?????
+ ADD AX,ReservedSectors
+;##### what if result > 65535 ?????
+ PUSH AX ; AX = Fats*FatSectors + ReservedSectors + HiddenSectors
+ XCHG CX,AX ; (CX) = start of DIR
+;
+; Take into account size of directory (only know number of directory entries)
+;
+ MOV AX,size DIR_ENT ; bytes per directory entry
+ MUL DirectoryEntries ; convert to bytes in directory
+ MOV BX,BytesPerSector ; add in sector size
+ ADD AX,BX
+ DEC AX ; decrement so that we round up
+ DIV BX ; convert to sector number
+ ADD CX,AX
+ MOV ClusterBase,CX ; save it for later
+;
+; Load in the root directory.
+;
+.386
+ push DirSeg ; es:bx -> directory segment
+.8086
+ pop es
+ASSUME ES:DirSeg
+ xor bx,bx
+ pop Arguments.SectorBase.lsw
+ mov Arguments.SectorBase.msw,bx
+
+;
+; DoRead does a RETF, but LINK pukes if we do a FAR call in a /tiny program.
+;
+; (al) = # of sectors to read
+;
+ push cs
+ call DoRead
+ jc BootErr$he
+
+; Now we scan for the presence of NTLDR
+
+ xor bx,bx
+ mov cx,DirectoryEntries
+L10:
+ mov di,bx
+ push cx
+ mov cx,11
+ mov si, offset LOADERNAME
+ repe cmpsb
+ pop cx
+ jz L10end
+
+ add bx,size DIR_ENT
+ loop L10
+L10end:
+
+ jcxz BootErr$bnf
+
+ mov dx,es:[bx].StartCluster ; (dx) = starting cluster number
+ push dx
+ mov ax,1 ; (al) = sectors to read
+;
+; Now, go read the file
+;
+
+.386
+ push NtLdrSeg
+.8086
+ pop es
+ ASSUME ES:NtLdrSeg
+ xor bx,bx ; (es:bx) -> start of NTLDR
+
+
+;
+; LINK barfs if we do a FAR call in a TINY program, so we have to fake it
+; out by pushing CS.
+;
+
+ push cs
+ call ClusterRead
+ jc BootErr$he
+
+;
+; NTLDR requires:
+; BX = Starting Cluster Number of NTLDR
+; DL = INT 13 drive number we booted from
+; DS:SI -> the boot media's BPB
+; DS:DI -> argument structure
+; 1000:0000 - entire FAT is loaded
+;
+
+ pop BX ; (bx) = Starting Cluster Number
+ lea si,BPB ; ds:si -> BPB
+ lea di,Arguments ; ds:di -> Arguments
+
+ push ds
+ pop [di].ReadClusters.msw
+ mov [di].ReadClusters.lsw, offset ClusterRead
+ push ds
+ pop [di].ReadSectors.msw
+ mov [di].ReadSectors.lsw, offset DoRead
+ MOV dl,DriveNumber ; dl = boot drive
+
+;
+; FAR JMP to 2000:0003. This is hand-coded, because I can't figure out
+; how to make MASM do this for me. By entering NTLDR here, we skip the
+; initial jump and execute the FAT-specific code to load the rest of
+; NTLDR.
+;
+ db 0EAh ; JMP FAR PTR
+ dw 3 ; 2000:3
+ dw 02000h
+FATBOOT endp
+
+; BootErr - print error message and hang the system.
+;
+BootErr proc
+BootErr$bnf:
+ MOV SI,OFFSET MSG_NO_NTLDR
+ jmp short BootErr2
+BootErr$he:
+ MOV SI,OFFSET MSG_READ_ERROR
+BootErr2:
+ call BootErrPrint
+ MOV SI,OFFSET MSG_REBOOT_ERROR
+ call BootErrPrint
+ sti
+ jmp $ ;Wait forever
+
+BootErrPrint:
+ LODSB ; Get next character
+ or al,al
+ jz BEdone
+
+ MOV AH,14 ; Write teletype
+ MOV BX,7 ; Attribute
+ INT 10H ; Print it
+ jmp BootErrPrint
+BEdone:
+
+ ret
+BootErr endp
+
+; ClusterRead - read AL sectors into ES:BX starting from
+; cluster DX
+;
+ClusterRead proc
+ push ax ; (TOS) = # of sectors to read
+ dec dx
+ dec dx ; adjust for reserved clusters 0 and 1
+ mov al,SectorsPerCluster
+ xor ah,ah
+ mul dx ; DX:AX = starting sector number
+ add ax,ClusterBase ; adjust for FATs, root dir, boot sec.
+ adc dx,0
+ mov Arguments.SectorBase.lsw,ax
+ mov Arguments.SectorBase.msw,dx
+ pop ax ; (al) = # of sectors to read
+
+;
+; Now we've converted the cluster number to a SectorBase, so just fall
+; through into DoRead
+;
+
+ClusterRead endp
+
+
+;
+; DoRead - read AL sectors into ES:BX starting from sector
+; SectorBase.
+;
+DoRead proc
+
+ mov SectorCount,AL
+DRloop:
+ MOV AX,Arguments.SectorBase.lsw ; Starting sector
+ MOV DX,Arguments.SectorBase.msw ; Starting sector
+;
+; DoDiv - convert logical sector number in AX to physical Head/Track/Sector
+; in CurrentHead/CurrentTrack/CurrentSector.
+;
+ ADD AX,HiddenSectors.lsw ;adjust for partition's base sector
+ ADC DX,HiddenSectors.msw
+ DIV SectorsPerTrack
+ INC DL ; sector numbers are 1-based
+ MOV CurrentSector,DL
+ XOR DX,DX
+ DIV Heads
+ MOV CurrentHead,DL
+ MOV CurrentTrack,AX
+;
+;DoDiv endp
+;
+
+
+; CurrentHead is the head for this next disk request
+; CurrentTrack is the track for this next request
+; CurrentSector is the beginning sector number for this request
+
+; Compute the number of sectors that we may be able to read in a single ROM
+; request.
+
+ MOV AX,SectorsPerTrack
+ SUB AL,CurrentSector
+ INC AX
+ cmp al,SectorCount
+ jbe DoCall
+ mov al,SectorCount
+ xor ah,ah
+
+; AX is the number of sectors that we may read.
+
+;
+; DoCall - call ROM BIOS to read AL sectors into ES:BX.
+;
+DoCall:
+ PUSH AX
+ MOV AH,2
+ MOV cx,CurrentTrack
+.386
+ SHL ch,6
+.8086
+ OR ch,CurrentSector
+ XCHG CH,CL
+ MOV DX,WORD PTR DriveNumber
+ INT 13H
+;
+;DoCall endp
+;
+
+.386
+ jnc DcNoErr
+ add sp,2
+ stc
+ retf
+.8086
+
+DcNoErr:
+ POP AX
+ SUB SectorCount,AL ; Are we finished?
+ jbe DRdone
+ ADD Arguments.SectorBase.lsw,AX ; increment logical sector position
+ ADC Arguments.SectorBase.msw,0
+ MUL BytesPerSector ; determine next offset for read
+ ADD BX,AX ; (BX)=(BX)+(SI)*(Bytes per sector)
+
+ jmp DRloop
+DRdone:
+ mov SectorCount,al
+ clc
+ retf
+DoRead endp
+
+ include fatboot.inc ;suck in the message text
+
+LOADERNAME DB "NTLDR "
+
+ .errnz ($-FATBOOT) GT 510,<FATAL PROBLEM: boot sector is too large>
+
+ org 510
+ db 55h,0aah
+
+BootSectorEnd label dword
+
+BootCode ends
+
+;Unitialized variables go here--beyond the end of the boot sector in free memory
+CurrentTrack equ word ptr BootSectorEnd + 4 ; current track
+CurrentSector equ byte ptr BootSectorEnd + 6 ; current sector
+SectorCount equ byte ptr BootSectorEnd + 7 ; number of sectors to read
+ClusterBase equ word ptr BootSectorEnd + 8 ; first sector of cluster # 2
+Retries equ byte ptr BootSectorEnd + 10
+Arguments equ byte ptr BootSectorEnd + 11 ; structure passed to NTLDR
+
+ END FATBOOT
diff --git a/private/ntos/boot/bootcode/fat/i386/usa/bootfat.h b/private/ntos/boot/bootcode/fat/i386/usa/bootfat.h
new file mode 100644
index 000000000..9ccbd1a4a
--- /dev/null
+++ b/private/ntos/boot/bootcode/fat/i386/usa/bootfat.h
@@ -0,0 +1,37 @@
+#define FATBOOTCODE_SIZE 512
+
+
+unsigned char FatBootCode[] = {
+235,60,144,77,83,68,79,83,53,46,48,0,2,8,1,0,
+2,0,2,3,81,248,8,0,17,0,4,0,1,0,0,0,
+0,0,0,0,128,0,41,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,70,65,84,32,32,32,32,32,51,192,
+142,208,188,0,124,104,192,7,31,160,16,0,247,38,22,0,
+3,6,14,0,80,145,184,32,0,247,38,17,0,139,30,11,
+0,3,195,72,247,243,3,200,137,14,8,2,104,0,16,7,
+51,219,143,6,19,2,137,30,21,2,14,232,144,0,114,87,
+51,219,139,14,17,0,139,251,81,185,11,0,190,220,1,243,
+166,89,116,5,131,195,32,226,237,227,55,38,139,87,26,82,
+184,1,0,104,0,32,7,51,219,14,232,72,0,114,40,91,
+141,54,11,0,141,62,11,2,30,143,69,2,199,5,245,0,
+30,143,69,6,199,69,4,14,1,138,22,36,0,234,3,0,
+0,32,190,134,1,235,3,190,162,1,232,9,0,190,193,1,
+232,3,0,251,235,254,172,10,192,116,9,180,14,187,7,0,
+205,16,235,242,195,80,74,74,160,13,0,50,228,247,226,3,
+6,8,2,131,210,0,163,19,2,137,22,21,2,88,162,7,
+2,161,19,2,139,22,21,2,3,6,28,0,19,22,30,0,
+247,54,24,0,254,194,136,22,6,2,51,210,247,54,26,0,
+136,22,37,0,163,4,2,161,24,0,42,6,6,2,64,58,
+6,7,2,118,5,160,7,2,50,228,80,180,2,139,14,4,
+2,192,229,6,10,46,6,2,134,233,139,22,36,0,205,19,
+15,131,5,0,131,196,2,249,203,88,40,6,7,2,118,17,
+1,6,19,2,131,22,21,2,0,247,38,11,0,3,216,235,
+144,162,7,2,248,203,66,79,79,84,58,32,67,111,117,108,
+100,110,39,116,32,102,105,110,100,32,78,84,76,68,82,13,
+10,0,66,79,79,84,58,32,73,47,79,32,101,114,114,111,
+114,32,114,101,97,100,105,110,103,32,100,105,115,107,13,10,
+0,80,108,101,97,115,101,32,105,110,115,101,114,116,32,97,
+110,111,116,104,101,114,32,100,105,115,107,0,78,84,76,68,
+82,32,32,32,32,32,32,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,85,170
+};
diff --git a/private/ntos/boot/bootcode/fat/i386/usa/fatboot.inc b/private/ntos/boot/bootcode/fat/i386/usa/fatboot.inc
new file mode 100644
index 000000000..5ef7d5185
--- /dev/null
+++ b/private/ntos/boot/bootcode/fat/i386/usa/fatboot.inc
@@ -0,0 +1,28 @@
+;++
+;
+;Copyright (c) 1991 Microsoft Corporation
+;
+;Module Name:
+;
+; fatboot.inc
+;
+;Abstract:
+;
+; This contains the message text that the boot sector prints out on
+; error conditions
+;
+;Author:
+;
+; John Vert (jvert) 31-Aug-1991
+;
+;Revision History:
+;
+;--
+
+MSG_NO_NTLDR db "BOOT: Couldn't find NTLDR"
+ db 0dh, 0ah, 0
+MSG_READ_ERROR db "BOOT: I/O error reading disk"
+ db 0dh, 0ah, 0
+MSG_REBOOT_ERROR db "Please insert another disk"
+ db 0
+ \ No newline at end of file
diff --git a/private/ntos/boot/bootcode/hpfs/i386/buf.inc b/private/ntos/boot/bootcode/hpfs/i386/buf.inc
new file mode 100644
index 000000000..fe2eb8377
--- /dev/null
+++ b/private/ntos/boot/bootcode/hpfs/i386/buf.inc
@@ -0,0 +1,222 @@
+;static char *SCCSID = "@(#)buf.h 12.1 88/11/21";
+;** BUF.H - Buffer definitions
+;
+; HPFS Utilities
+; Peter A. Williams
+; Copyright 1988 Microsoft Corporation
+;
+; Modification history:
+; P.A. Williams 08/01/89 Added typedef BUFNODE and PBUFNODE.
+;
+
+;* Buffer Nodes
+;
+; When the comments talk about "buffer address" they're always
+; talking about the buffer header address. If we're talking
+; about the address of the data field of the buffer, we say
+; "buffer data".
+;
+; These buffer headers are also used as I/O request blocks for
+; the data in the buffer. The B_IOP field contains the
+; function. Sometimes we need an I/O request block which
+; isn't assocated with a buffer - for example, when we read
+; directly into an application's memory area. For this, we keep
+; a pool of I/O request blocks which are actually BUFNODE
+; structures, but they aren't associated with a buffer and the
+; B_ADDR field is used to hold the I/O target address.
+; These BUFNODEs have BF_IORQ in the flags field to distinguish
+; them from regular buffer headers.
+;
+; Note that we use the B_SUM field for debugging purposes. This is an
+; array of SPB words, each of which holds the CAS (high and low
+; 16 bits xored togehter) of one of the sectors. We can then check
+; this value to make sure that we're setting the dirty bits
+; correctly.
+;
+; NOTE - see the discussion on holding and locking at the end of
+; this file
+;
+
+BUFNODE struc
+
+ B_LRU db (size DCHDR) dup (?) ; LRU chain, if not BF_IORQ
+ B_LRUH dd ? ; address of LRU chain head if not locked/held
+ ; if lcoked/held, we're on that chain but
+ ; this guy points to it's regular chain
+ B_SEC dd ? ; VSector #
+ B_ADDR dd ? ; address of data
+ B_DCHN db (size DCHDR) dup (?) ; doubly linked list of dirty buffers
+ B_dirt db ? ; 1 bit per dirty sector
+ ; used to optimize the write. Non dirty
+ ; marked sectors may still be rewritten
+ B_iop db ? ; disk driver I/O operation
+ B_type db ? ; type of info
+ B_FLAG db ? ; flags
+ B_HCNT dw ? ; hold count
+ B_LCNT db ? ; lock count (really a flag, only 0 or 1
+ B_BADSEC db ? ; 1 bit per defective sector
+ B_next dd ? ; advisory address of next buffer content
+ ; always a buffer header addr, never 0
+ B_DADR dd ? ; address of routine to call when I/O is done
+
+ ; The following two fields are redefined
+ ; if BF_IORQ is set.
+ B_HASH db (size DCHDR) dup (?) ; sector hash chain
+ B_HTA dd ? ; address of entry in hash table
+
+ B_WAIT dd ? ; head of wait chain
+ifdef DEBUG
+ B_SUM dw 4 dup (?) ; holds checksum of buffer contents
+else
+ B_XTRA db 8 dup (?)
+endif
+
+; 64 byte boundary
+
+ B_LDTIME dd ? ; time (in ms/512) when buffer was last dirtied
+ B_FDTIME dd ? ; time (in ms/512) when buffer got first dirtied
+ B_LWWAIT dd ? ; head of lazy write wait chain
+ B_XTRA2 db 64-16 dup (?)
+BUFNODE ends
+
+;typedef struct BUFNODE BUFNODE;
+;typedef struct BUFNODE *PBUFNODE;
+
+BUFHDRSHIFT equ 7
+
+ifdef MASM
+ .errnz (size BUFNODE) - (1 SHL BUFHDRSHIFT)
+endif
+
+; Following are alternative offsets if BF_IORQ is set
+
+B_XFER equ (DWORD PTR B_HTA) ; holds transfer sec cnt
+B_NADR equ (DWORD PTR B_HASH) ; addr of client's NOTEREC
+B_NMSK equ (DWORD PTR B_HASH+4) ; notification mask
+ifdef MASM
+ .errnz (size DCHDR)-8 ; enough room for double map
+endif
+
+; B_FLAG bits
+
+BFL_LWLOCK equ 00000001h ; buffer is being lazy written in a block
+
+
+; B_type values
+
+BF_FREE equ 0 ; buffer is free (not in LRU list)
+BF_LRU equ 1 ; buffer in LRU list
+
+
+; Priority values for LRU placement
+
+BP_KEEP equ 0 ; Buffer contains future-usable data
+BP_NOOPINION equ 1 ; Buffer contains marginally useful data
+BP_TOSS equ 2 ; Buffer is unlikely to be used
+
+; NOTEREC - Notification Record
+;
+; Some callers may post several disk requests in parallel and
+; want to keep track of when they're *all* complete. I/O
+; request blocks (buffer headers w/o buffers) have fields to
+; allow this. The caller stores the address of his NOTEREC,
+; and when each request completes it clears it's associated bit.
+; When all of the bits clear the block chain in the NOTEREC
+; is woken.
+;
+; Note that there can be only one thread blocked on a NOTEREC
+; because the first guy to wakeup will return the NOTEREC to the
+; heap or whatever. This occurs naturally; unlike I/O to the
+; buffer cache, NOTERECs are used for direct I/O. If someone
+; else wants to do I/O to the same location and if record and file
+; locking allows that, then they'll get their own NOTEREC or
+; cache I/O request and have a horse race. NOTERECs are only used
+; to do file data I/O, all "filesystem" structures are manipulated
+; via the cache.
+;
+; The fields are DWORD, but only the low byte of the MSK and FLD
+; records are used for normal completion. The 3rd byte of NTR_FLD
+; (..FF....h) is used for error posting - these bits are
+; set if an irrecoverable error occured in the I/O.
+;
+
+NOTEREC struc
+ NTR_FLD dd ? ; the mask bit field
+ NTR_BLC dd ? ; head of the block chain
+ NTR_MSK dd ? ; next bit to set in NTR_FLD
+NOTEREC ends
+
+
+;* Holding and Locking
+;
+; LOCK means that the buffer contents are inconsistant/incorrect. No body
+; is allowed to look at the contents of the buffer. This is done
+; when we're reading in from the disk; we'll mark the buffer
+; with the VSector # (so that any other folks that want that sector
+; won't issue their own reads in parallel) but we mark it LOCKED
+; so that nobody looks at it's contents which aren't correct yet.
+;
+; LOCKed is pretty rare because most folks which are mucking
+; with a buffer have it back in a consistant state before they
+; allow a context switch.
+;
+; An important exception to this is directory manipulation -
+; directory splitting, etc. In this case, a flag has been set
+; on the directory itself (in SBDIR) so that no one will try to
+; look at the directory contents. The cache block which has the
+; inconsistant DIRBLK might also have sectors belonging to someone
+; else and those sectors can be accessed by other folks because
+; the buffer isn't locked. (We don't lock the directory and not
+; the block for this reason, it's a fallout. We lock the directory
+; because it's too mucky for people to "back out" if they're
+; searching down into a directory and find out that they've
+; reached an area which is being rebuilt. The rebuilding might
+; propigate up and change the unlocked higher DIRBLKs that this
+; other guy has already accessed... So we lock the whole directory,
+; and thus needn't bother locking the cache blocks themselves.
+;
+; HOLD means that the contents are valid, but the cache block must continue
+; to hold that data. Folks use this when they need to access
+; two different sectors at the same time. They HOLD one when
+; they read the other so that there's no chance that by the
+; time the 2nd read finishes the first one has been evicted.
+; This is much cheaper than remembering the first one's VSector
+; # and calling RDBUF N times as you transfer N words of info
+; between the two sectors.
+;
+; By definition only one guy can lock a buffer (the lock count should
+; go to a flag; it's already a flag on directorys) but the hold
+; value is a count, since multiple people can hold. (Like the
+; electrician's safety plate which allows multiple electricians
+; to lock a breaker OPEN so that it can't be closed until ALL are
+; done). (SBDIRs have a hold count for the same reason - folks
+; may yield while in a directory and don't want it to change out
+; from under them)
+;
+; We also use hold when we set dirty bits. The concern is that
+; if we're going to write something to a buffer, yield the CPU,
+; then write something else, we don't want to have to make two
+; calls to SetDirt, one after each write. This costs time, and
+; also it would be a waste if the lazywriter were to write this
+; guy anyhow, since he's going to get dirty again ASAP and
+; writing him out doesn't free the cache block anyway, since it's
+; held.
+;
+; So my current algorithm is that I won't lazywrite anybody who
+; is held, and therefore won't mark them clean. This means,
+; in effect, that there is no ordering constraint on dirtying
+; a buffer or marking it dirty so long as it is held the entire
+; time. I think that the code now always marks it dirty before
+; a yield, even if held, because the debug code is a bit hard
+; assed about it, but this could be relaxed under the current
+; lazywrite rules I've just described.
+;
+; Both in the case of directorys and cache blocks, the theory is that
+; since these buffers are MRU, it's extremely rare that we'd actually try
+; to reclaim their buffer slots, and in general it's rare that there's
+; a conflict in their use. So in actual execution, these locks are
+; very rarely encountered. They're cheap - INC to set and DEC to clear,
+; so almost always all we're doing is INCing and DECing a location
+; and it's just two wasted instructions. Once in a while, though,
+; it's a big bacon save, as they say.
+;
diff --git a/private/ntos/boot/bootcode/hpfs/i386/chain.inc b/private/ntos/boot/bootcode/hpfs/i386/chain.inc
new file mode 100644
index 000000000..b1528c2a1
--- /dev/null
+++ b/private/ntos/boot/bootcode/hpfs/i386/chain.inc
@@ -0,0 +1,7 @@
+;static char *SCCSID = "@(#)chain.h 12.1 88/11/21";
+;* Doubly Chained Definitions
+
+DCHDR struc
+ FWD dd ? ; forward pointer
+ BAK dd ? ; backward pointer
+DCHDR ends
diff --git a/private/ntos/boot/bootcode/hpfs/i386/const.inc b/private/ntos/boot/bootcode/hpfs/i386/const.inc
new file mode 100644
index 000000000..5304fabfe
--- /dev/null
+++ b/private/ntos/boot/bootcode/hpfs/i386/const.inc
@@ -0,0 +1,201 @@
+;static char *SCCSID = "@(#)const.h 12.3 89/09/19";
+; #define DEBUG 1
+
+
+;* Constants for File System
+
+MAXPATH equ 256 ; maximum path length
+GROWDELT equ 8
+MVPFXSIZE equ 2 ; Size of the multivolume pathname prefix
+
+; Sector sizes
+
+SECSIZE equ 512 ; 512 bytes per sector
+SECSHIFT equ 9 ; 2^9 = SECSIZE
+SECMSK equ 01ffh ; sector size mask
+
+ifdef MASM
+ .errnz SECSIZE-512 ; C code uses 512 as a magic number - grep them out
+endif
+
+; Cache Sizes
+
+SPB equ 4 ; sectors per buffer
+SPB4 equ 1
+
+ifdef SPB4
+SPBMASK equ 3 ; mask for SPB
+SPBSHIFT equ 2
+SPBBITS equ 0fh ; SPB number of one bits, low order
+endif
+
+ifdef SPB8
+SPBMASK equ 7 ; mask for SPB
+SPBSHIFT equ 3
+SPBBITS equ 0ffh ; SPB number of one bits, low order
+endif
+
+ifdef OLD_CACHE
+BUFCNT equ 8
+endif
+
+BMASK equ SPB*SECSIZE-1 ; mask offset in to cache block
+BSHIFT equ SECSHIFT+SPBSHIFT
+
+LWBUFCT equ 16 ; size of reblocking lazy write buffer
+
+; OFT Hash Table Size (8 bytes each)
+
+OFTHASHCNT equ 16 ; 16 hash chains for open files
+OFTHASHMSK equ 78h ; mask for computing hash offset
+
+
+; Number of I/O command blocks which aren't associated with buffers
+
+IOBCNT equ 8 ; 8 should be enough BUGBUG
+
+; # of OS/2 ram semaphores that we can be blocked on, simultaneously.
+
+SEMCNT equ 32
+
+
+; Cache Hash
+;
+; A sector hash is used to locate the start of a chain, the chain
+; is then scanned linearly.
+;
+; For our current size of 256 hash chains, we get:
+;
+; 1 meg of cache RAM = 256 blocks = 1 blocks per chain (average)
+; 2 meg of cache RAM = 512 blocks = 2 blocks per chain (average)
+;
+
+HASHCNT equ 256 ; 1024 bytes of hash header
+
+; Directory Lookaside record count
+
+DLCNT equ 10 ; 10 guys for now
+
+; Maximum DIRBLKs we may need to allocate for any given
+; operation. This is in effect the maximum tree depth.
+;
+; Worst case, with 256 character file names and nearly empty
+; DIRBLKs, 10 is enough levels for 60,000 files - about 40 megabytes
+; of space just for that directory. Given more practical file length
+; names this is enough for 10s of millions of files in a directory.
+;
+
+MAX_DIR_NEED equ 10
+
+
+;* Heap Definitions
+
+HHSIZ equ 4 ; size, in bytes, of heap header
+GROHEAPCNT equ 50 ; grow heap if we have to compact more
+ ; than once per 50 allocations
+
+;* Special Transition Locking Structure size
+
+TRANCNT equ 4 ; just need 4 spots
+
+
+; Zero offset
+;
+; MASM won't take 0.BAK, so we use ZERO.BAK
+;
+
+dumy struc
+ ZERO db ?
+dumy ends
+
+
+; Maximum number of volumes that we can mount
+;
+; The volume ID is kept in the high bits of the sector numbers
+; kept in our RAM structures,
+; so there is a tradeoff between max volumes and max sectors.
+;
+; 32 max volumes gives us a 65 billion byte volume limit,
+; which should last us for a while. Since sector numbers
+; are stored on the disk without their volume upper bits
+; this is strictly an implimentation detail; we can adjust
+; the number of volumes or eliminate this tradeoff in other
+; implimentations which will be 100% media compatable.
+;
+; We use the term VSector to indicate a vol/sector combination
+; and PSector to indicate just the physical absolute sector #
+;
+;
+
+VOLMAX equ 32 ; 64 max volumes.
+
+MAXSEC equ 134217728 ; 2^32/32 max sectors
+
+SECMASK equ 07FFFFFFh ; mask for sector number
+
+HSECMASK equ 07h ; high byte sector mask
+
+HVOLMASK equ 0f8h ; high byte volume mask
+SVOLMASK equ 1fh ; shifted right volume mask
+
+VOLRSHIFT equ (32-5) ; shift right to extract volume index
+VOLLSHIFT equ 5 ; shift left to extract volume index
+
+
+;* Signature Values for Disk Structures
+;
+; These signature values help with debugging and they'll
+; be used by the CHKDSK utility to help repair disks.
+;
+; WARNING - the low byte of all valid signatures must be non-zero,
+; since we destroy signatures by clearing the low byte.
+
+J equ ((('J'-'A')*40+('G'-'A'))*40+'L'-'A')
+R equ ((('R'-'A')*40+('P'-'A'))*40+'W'-'A')
+
+ifdef MASM
+ABSIGVAL equ J*40*40*40 + R ; allocation blk
+DBSIGVAL equ 40000000h + J*40*40*40 + R ; directory blks
+FNSIGVAL equ 0C0000000h + J*40*40*40 + R ; fnodes
+else
+ABSIGVAL equ (long)J*40*40*40 + (long)R ; allocation blk
+DBSIGVAL equ 40000000hL + (long)J*40*40*40 + (long)R ; directory blks
+OLDFNSIGVAL equ 80000000hL + (long)J*40*40*40 + (long)R ; fnodes
+FNSIGVAL equ 0C0000000hL + (long)J*40*40*40 + (long)R ; fnodes
+endif
+
+
+
+;* FastFile bitmaps
+;
+; 0x00000000 all checking disabled
+; 0x00000001 FF_FLUSHLAZY DoZap lazy writes are automatically flushed
+; 0x00000002 FF_ZAPSEC DoZap blasts sector numbers/sector data
+; 0x00000004 FF_LRUCHK vbs verification of LRU/dirty integrity
+; 0x00000008 FF_CHKSUM sector checksumming is omitted
+; 0x00000010 FF_PLACECHK placebuf verifies location of buffer
+; 0x00000020 FF_HEAPCHK verify heap headers
+; 0x00000040 FF_DIRMAP produce inram map of directory tree
+; 0x00000080 FF_HASHCHN check hash chains
+;
+
+FF_FLUSHLAZY equ 00000001h
+FF_ZAPSEC equ 00000002h
+FF_LRUCHK equ 00000004h
+FF_CHKSUM equ 00000008h
+FF_PLACECHK equ 00000010h
+FF_HEAPCHK equ 00000020h
+FF_DIRMAP equ 00000040h
+FF_HASHCHN equ 00000080h
+
+; Dependency dumys.
+;
+; The assembler won't to an ".errnz" comparing two external
+; addresses, since it doesn't know their address. So we
+; put the .errnz in the module which defines the address,
+; and we make that location and all folks that rely upon the
+; relationship reference that dumy.
+;
+; If you change a relationship with such a dumy definition, you
+; must find and edit all references to this dumy.
+;
diff --git a/private/ntos/boot/bootcode/hpfs/i386/dir.inc b/private/ntos/boot/bootcode/hpfs/i386/dir.inc
new file mode 100644
index 000000000..9e2d44469
--- /dev/null
+++ b/private/ntos/boot/bootcode/hpfs/i386/dir.inc
@@ -0,0 +1,286 @@
+;** DIR.H - Dirblk and Dirent definitions
+;
+; FILESYS
+; Gregory A. Jones
+; Copyright 1988 Microsoft Corporation
+;
+; Modification history:
+; P.A. Williams 06/01/89 Replaced field DIR_USECNT with fields
+; DIR_FLEX and DIR_CPAGE. Added DF_NEEDEAS
+; define.
+; P.A. Williams 07/10/89 Add define DF_NEWNAME for "new" hpfs file
+; names.
+; P.A. Williams 07/14/89 Added typedefs for DIRENT and DIRBLK.
+; P.A. Williams 07/21/89 Converted DIRSIZP form ASM defn to C defn.
+;
+
+ifdef MASM
+ include dirent.inc
+else
+attr_directory equ 10h
+endif
+
+
+; Directory Entry Fields
+;
+; Directory entries are always left as a multiple of 4
+; to speed up moves. The DIR_NAMA field is variable length,
+; the DIR_BTP field, if present, is the last dword in the record.
+; ACL information may be stored after the DIR_NAMA field but before
+; the DIR_BTP field so the DIR_BTP field must be located by going
+; backwards from the end of the record
+;
+; WARNING - Mkdir block copies some of these entries and
+; makes assumptions about which fields get copied. Check
+; mkdir if stuff is added.
+;
+
+DIRENT struc
+ DIR_ELEN dw ? ; length of this entry (including free space)
+ DIR_FLAG dw ? ; flags - low byte defined below
+ ; high byte holds the old attr_ FAT values
+ DIR_FN dd ? ; FNODE Sector
+ DIR_MTIM dd ? ; last modification time
+ DIR_SIZE dd ? ; file size
+
+ DIR_ATIM dd ? ; last access time
+ DIR_CTIM dd ? ; fnode creation time
+ DIR_EALEN dd ? ; bytes of extended attributes
+ DIR_FLEX db ? ; description of "flex" area,
+ ; following file name:
+ ; bits 0-2: # of ACEs in DE
+ ; bits 3-7: reserved
+ DIR_CPAGE db ? ; code page index on volume
+
+; the following fields have information specific to the name and directory
+; position of the file. This info is not propigated for a move/rename
+; That code uses DIR_NAML as a seperator - check MOVE if changes are
+; made to this structure
+
+ DIR_NAML db ? ; length of file name
+ DIR_NAMA db ? ; name goes here
+
+; ACL information may be stored here
+
+; long DIR_BTP; btree pointer to descendent DIRBLK record.
+ ; This is only present if DF_BTP is set.
+ ; This field is referenced from the end of
+ ; the record, not DIR_NAMA+DIR_NAML
+DIRENT ends
+
+
+ifdef MASM
+DIR_BTP equ dword ptr -4 ; referenced from the end of the record
+endif
+SIZE_DIR_BTP equ 4
+
+MAX_DIRACL equ 3 ; max of 3 ACLs in dirent
+DIRSIZL equ offset DIR_NAMA ; base size of leaf dir entry (minus name)
+DIRSIZP equ (size DIRENT+4) ; base size of dir entry with btree ptr w/o name
+
+MAX_DIRENT equ (DIRSIZP+255+MAX_DIRACL*(size (long))+10) ; max size of a DIRENT
+ ; (plus some slop)
+
+
+; Directory Block Definition
+;
+; The change count field is incremented every time we move any
+; of the entries in this block. For efficiency reasons, folks
+; remember the Sector # and offset of a directory entry, and the
+; value of the DB_CCNT field when that info was recorded.
+; If the DB_CCNT field is different then the remembered value,
+; then the entry offset is invalid and the entry should be
+; refound from the top. Note that when a directory block splits,
+; the old DIRBLK gets the old DB_CCNT field. Since
+; the new DIRBLK is previously unknown, it can have
+; any DB_CCNT value. We start with zero so that DB_CCNT
+; gives us a feel for the change rate in the directory.
+;
+
+DIRBLK struc
+ DB_SIG dd ? ; signature value
+ DB_FREP dd ? ; offset of first free byte
+ DB_CCNT dd ? ; change count (low order bit is flag)
+ ; =1 if this block is topmost
+ ; =0 otherwise
+ DB_PAR dd ? ; parent directory PSector # if not topmost
+ ; FNODE sector if topmost
+ DB_SEC dd ? ; PSector # of this directory block
+
+ DB_START db ? ; first dirent record goes here
+ DB_DUMY db 2027 dup (?) ; round out to 2048 bytes
+
+
+DIRBLK ends
+
+; BUGBUG - we should init DB_CCNT with a random value
+; to prevent a fakeout by deleting one directory
+; and then creating another (find sequences will
+; remember sector numbers and signatures...)
+
+
+; Maximum entries per directory.
+
+MAXDIRE equ (size DIRBLK- DB_START)/(size DIRENT)
+
+
+
+
+
+;* DIR_FLAG values
+;
+
+DF_SPEC equ 0001h ; special .. entry
+DF_ACL equ 0002h ; item has ACL
+DF_BTP equ 0004h ; entry has a btree down pointer
+DF_END equ 0008h ; is dumy end record
+DF_XACL equ 0040h ; item has explicit ACL
+DF_NEEDEAS equ 0080h ; item has "need" EAs
+DF_NEWNAME equ 4000h ; item name is of "new" pinball format
+
+DF_RMASK equ DF_ACL+DF_XACL ; only attributes preserved for rename
+
+ifdef MASM
+ .errnz DF_BTP - SIZE_DIR_BTP ; code uses this "coincidence"
+endif
+
+; Attributes which creation can specify
+
+DF_CMASK equ attr_read_only+attr_hidden+attr_archive
+
+; Directory Lookaside Structure
+;
+; We keep info on all directories that we've seen in SBDIR records
+; in RAM, but we keep the last N that we've seen in a special
+; DIRLOOK list in RAM.
+;
+
+DIRLOOK struc
+ DL_LNK db (size DCHDR) dup (?) ; forward and backwards link
+ DL_VSECVAL dd ? ; VOL_SECVAL value
+ DL_SUM dd ? ; checksum value
+ DL_NAM dd ? ; pointer to name string on heap
+ DL_SBD dd ? ; pointer to SBDIR structure
+DIRLOOK ends
+
+
+; Subdirectory Linkage Structure
+;
+; For every directory that we've seen on the disk we keep a
+; SBDIR record in ram, linked into a heirarchy which parallels
+; the disk heirarchy. We never discard these, so we end up
+; with a RAM copy of all the parts of the directory heirarchy
+; that the user is using.
+;
+; Each SBDIR entry is on a circular doubly linked chain of
+; siblings (directors with the same parent directory). If a
+; directory contains no subdirectories the SD_ENT field is 0.
+; If a directory has subdirectories, their SBDIR entries are
+; in turn in a SD_SIB chain and the SD_ENT field points to
+; one of those SBDIR entries.
+;
+; SBDIR contains a lock and a hold mechanism. A directory is
+; locked when it is being edited; no other threads may view it
+; until it is unlocked. A directory which is HELD is one which
+; is being accessed and can't be edited.
+;
+; The locking and holding algorithms are complicated by the fact
+; that we almost never block so we want to do our typical locking
+; and unlocking inline, without calls, and with minimum tests.
+; We do this with a held count, and bits for locked, lock pending,
+; and solo pending. (Solo means that a user wants sole access to
+; the structure. He'll continue to block until no one else is
+; using it. This is typically done to delete the structure)
+; Another bit is the OR of the lock pending and solo pending bits,
+; and is high order in the dword which encompases SD_HCNT so that
+; when folks release their SD_HCNT value they can simulatneously
+; test to see if there is a pending action.
+;
+; To Hold the SBDIR:
+; If it's not locked and doesn't have a lock pending,
+; increment hold count
+; else
+; block on it and retry.
+;
+; To Unhold the SBDIR:
+; decrement the HCNT field.
+; If SD_PND & (HCNT == 0)
+; wake up waiters.
+;
+; To lock the SBDIR:
+; If locked, block and retry.
+; If HCNT != 0
+; if (lock pending already set)
+; block and retry
+; set lock pending. Block until HCNT is zero.
+; set locked
+;
+; To unlock the SBDIR:
+; clear lock bit.
+; If the block list is non-zero, issue a wakeup.
+;
+; To Solo the SBDIR:
+; Keep blocking until no one else is blocked on it and
+; no one has it held or locked.
+;
+; General Considerations:
+; Anyone who blocks on an SBDIR because it's held must
+; be sure to set a pending bit and the SD_PND bit so
+; that the unhold operation will wake them up.
+;
+; Anyone who blocks on an SBDIR must increment the
+; SD_BCNT field to prevent a SOLO operation from yanking
+; the rug out from under them. SOLO can't depend upon
+; checking the lock list because a blanket wakeup may
+; have cleared the lock list. If the SOLO guy gets control
+; first he'll believe that he can have it.
+;
+;
+
+SBDIR struc
+ SD_FNW db (size DCHDR) dup (?) ; FNWORK (findnotify) chain
+ SD_SIB db (size DCHDR) dup (?) ; chain of siblings
+ SD_LRU db (size DCHDR) dup (?) ; LRU chain
+ SD_ENT dd ? ; pointer to a descendent, or 0
+ SD_PAR dd ? ; pointer to parent SBDIR, 0 if root
+ SD_SEC db (size SECPTR) dup (?) ; VSector and hint of top dirblk
+ SD_FNO dd ? ; FNODE # of directory
+ SD_SUM dd ? ; checksum of name string
+ SD_CNT dw ? ; # of subdirectories in this one
+ SD_OPEN dw ? ; count of # of guys that have this open
+
+; We sometimes inc/dec SD_HCNT as a dword to test the HO bit in SD_FLAG
+
+ ; the following three fields are used to
+ ; control access. They're identical in use
+ ; to the equivalent fields in OFT
+
+ SD_HCNT dw ? ; held count, has SDH_PND bit also
+ SD_DMYZERO db ? ; must be zero
+ SD_FLAG db ? ; flag byte, high order in SD_HCNT dword
+ SD_WAIT dd ? ; head of the wait chain
+ SD_FREEDCNT dd ? ; incremented each time we free a DIRBLK
+ ; for this guy. See RDE for details
+ SD_WCNT dw ? ; count of folks blocked on this
+ SD_FNDCNT dw ? ; count of active finds in this directory
+ SD_ATIME dd ? ; time of last access
+ SD_NAM dd ? ; address of name string
+ SD_ACL dd ? ; SBDIR ACL pointer, 0 if none
+ ; points to DWORD count, followed by ACEs
+ ; if low bit of address is 0, is heap space
+ ; if low bit is 1, is system memory
+
+SBDIR ends
+
+SD_ACL_LIM equ 1024 ; *SD_ACL lists bigger than this come from
+ ; system memory, smaller come from heap
+
+SDF_PND equ 80h ; lock pending bit
+SDF_RTP equ 20h ; restricted traversal permissions
+ ; =0 if anyone can traverse the dir
+SDF_REALLYBAD equ 10h ; directory is really bad
+SDF_IPR equ 08h ; SD_ACL has inherit records
+SDF_PSO equ 04h ; pending solo
+SDF_PLK equ 02h ; pending lock
+SDF_LCK equ 01h ; directory is locked against access
+ \ No newline at end of file
diff --git a/private/ntos/boot/bootcode/hpfs/i386/dirent.inc b/private/ntos/boot/bootcode/hpfs/i386/dirent.inc
new file mode 100644
index 000000000..1ba3f82df
--- /dev/null
+++ b/private/ntos/boot/bootcode/hpfs/i386/dirent.inc
@@ -0,0 +1,80 @@
+BREAK <Directory entry>
+
+; SCCSID = @(#)dirent.inc 12.5 89/07/14
+;
+; +-----------------------------+
+; | (11 BYTE) filename/ext | 0 0
+; +-----------------------------+
+; | (BYTE) attributes | 11 B
+; +-----------------------------+
+; | (8 BYTE) reserved | 12 C
+; +-----------------------------+
+; | (WORD) First cluster of EA | 20 14
+; +-----------------------------+
+; | (WORD) time of last write | 22 16
+; +-----------------------------+
+; | (WORD) date of last write | 24 18
+; +-----------------------------+
+; | (WORD) First cluster of file| 26 1A
+; +-----------------------------+
+; | (DWORD) file size | 28 1C
+; +-----------------------------+
+;
+; First byte of filename = E5 -> free directory entry
+; = 00 -> end of allocated directory
+; Time: Bits 0-4=seconds/2, bits 5-10=minute, 11-15=hour
+; Date: Bits 0-4=day, bits 5-8=month, bits 9-15=year-1980
+;
+
+dir_entry STRUC
+dir_name DB 11 DUP (?) ; file name
+dir_attr DB ? ; attribute bits
+dir_pad DB 8 DUP (?) ; reserved for expansion
+dir_EAhandle DW ? ; handle to Extended Attributes
+dir_time DW ? ; time of last write
+dir_date DW ? ; date of last write
+dir_firstfile DW ? ; first allocation unit of file
+dir_size_l DW ? ; low 16 bits of file size
+dir_size_h DW ? ; high 16 bits of file size
+dir_entry ENDS
+
+DIRENT_DELETED EQU 0E5h ; indicator of deleted file
+DIRENT_NOFEALIST EQU 0 ; Indicates no extended attributes
+
+
+;
+; Values for dir_attr
+;
+; attr_newfiles is used in the case of IFS to indicate that the type of file
+; being requested for findfirst/next is a "new" file i.e. long
+; name or a mixed-case name that the FAT FS does not support.
+;
+attr_read_only EQU 1h
+attr_hidden EQU 2h
+attr_system EQU 4h
+attr_volume_id EQU 8h
+attr_directory EQU 10h
+attr_archive EQU 20h
+attr_device EQU 40h ; This is a VERY special bit.
+ ; NO directory entry on a disk EVER
+ ; has this bit set. It is set non-zero
+ ; when a device is found by GETPATH
+
+attr_newfiles EQU 40h ; name is non-8.3. never set for FAT FS
+
+attr_all EQU attr_hidden OR attr_system OR attr_directory
+ ; OR of hard attributes for FINDENTRY
+
+attr_ignore EQU attr_read_only OR attr_archive OR attr_device
+ ; ignore these attributes during
+ ; search first/next
+
+attr_changeable EQU attr_read_only OR attr_hidden OR attr_system OR attr_archive
+ ; changeable via CHMOD
+
+attr_used EQU attr_read_only OR attr_hidden OR attr_system OR attr_volume_id OR attr_directory OR attr_archive OR attr_newfiles
+ ; We ignore the rest for $Creat due to LOTUS
+ ; passing in an attribute of 0x8000!!
+
+INV_3XBOX_SRCH_ATTRS EQU attr_newfiles ; we should not pass this bit
+ ; for FSDS from 3xbox.
diff --git a/private/ntos/boot/bootcode/hpfs/i386/filemode.inc b/private/ntos/boot/bootcode/hpfs/i386/filemode.inc
new file mode 100644
index 000000000..2e9165204
--- /dev/null
+++ b/private/ntos/boot/bootcode/hpfs/i386/filemode.inc
@@ -0,0 +1,105 @@
+; SCCSID = @(#)filemode.inc 12.6 89/04/26
+
+BREAK <Standard I/O assignments>
+
+stdin EQU 0
+stdout EQU 1
+stderr EQU 2
+stdaux EQU 3
+stdprn EQU 4
+
+BREAK <File modes - passed to open, stored in sf_mode or JFN_Flags>
+
+;
+; The OS/2 api calls DosOpen, DosSetFHandState, and DosQFHandState
+; all use a mode word parameter. Some of these values are stored
+; in the sft (system file table) in the field sf_mode. Others
+; are stored in the JFN flags (JFN_Flg_Ptr). The layout of
+; sf_mode and the word parameter for the call is the same. The
+; following EQU's are used to get to these values. The layout
+; of the word is:
+;
+; 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+; D W F C R L L L I S S S M A A A
+;
+; with:
+; AAA (2-0): The Access mode (read only, etc.)
+; SSS (6-4): Sharing mode (deny write acces to others, etc.)
+; LLL (8-10): Locality of reference (sequential, random, etc.)
+; M (3) : Monitor open
+; I (7) : Not inherited by child
+; R (11): Rumored to be used by spooler. API caller must set
+; this to zero.
+; C (12): Advise device driver not to cache data. This is
+; stored in JFN flags.
+; F (13): Fail errors
+; W (14): write through
+; D (15): Direct access open
+;
+; The DosOpen2 and $Extended_Open2 calls has an additional word for
+; openmode. The layout of this word is
+;
+; 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+; P U U U U U U U U U U U U U U U
+;
+; with:
+; P (15): Open physical disk (used by FDISK program). This bit
+; is set by procedure DevReturnHandle. API/INT21h
+; caller must set this bit to zero. This bit is stored
+; in sft.
+;
+; U : Unused anywhere. API caller must set these bits to
+; zero.
+;
+; NOTE: Please document all use of the openmode bits including those
+; that are internal to the kernel (e.g. the P bit).
+
+; wwwwxxxxyyyyzzzz
+; 5432109876543210
+open_access EQU 0000000000000111B
+open_for_read EQU 00h
+open_for_write EQU 01h
+open_for_both EQU 02h
+open_max EQU 02h
+open_for_exec EQU 03h ; open via internal exec call
+ ; (not available to API)
+
+open_monitor EQU 0000000000001000B
+
+open_sharing_mode EQU 0000000001110000B
+sharing_compat EQU 000H
+sharing_deny_both EQU 010H
+sharing_deny_write EQU 020H
+sharing_deny_read EQU 030H
+sharing_deny_none EQU 040H
+sharing_max EQU 040H ; max value for check_access_AX
+ ; (check_access_ax handles
+
+; these bits are for openmode
+open_no_inherit EQU 0000000010000000B ; Child does not inherit handle
+open_autofail EQU 0010000000000000B ; hard errors failed
+open_write_through EQU 0100000000000000B ; write through to disk
+open_direct EQU 1000000000000000B ; open of a device for direct access
+open_no_cache EQU 0001000000000000B ; don't cache data
+
+open_locality EQU 0000011100000000B ; locality of reference
+locality_unknown EQU 000H
+locality_sequential EQU 100H
+locality_random EQU 200H
+locality_semirandom EQU 300H
+
+; these bits are for openmode2 available to DosOpen2/$Extended_Open2
+;
+open2_phys_disk EQU 1000000000000000B ; open physical disk
+
+; Bits carried in SFT mode field (@PhysDisk)
+o_mode_in_sft EQU open_direct+open_monitor+open_sharing_mode+open_access+open_locality
+
+; Bits carried in JFN flags
+o_mode_in_flags EQU open_write_through+open_autofail+open_no_inherit+open_no_cache
+
+; Reserved bits
+o_mode_reserved EQU NOT (o_mode_in_sft+o_mode_in_flags)
+o_mode2_reserved equ -1 ; all bits are reserved
+
+SUBTTL
diff --git a/private/ntos/boot/bootcode/hpfs/i386/fnode.inc b/private/ntos/boot/bootcode/hpfs/i386/fnode.inc
new file mode 100644
index 000000000..af0207520
--- /dev/null
+++ b/private/ntos/boot/bootcode/hpfs/i386/fnode.inc
@@ -0,0 +1,214 @@
+;** FNODE.H - Fnode definitions
+;
+; FILESYS
+; Gregory A. Jones
+; Copyright 1988 Microsoft Corporation
+;
+; Modification history:
+; P.A. Williams 06/01/89 Added fields FN_ACLBASE and FN_NEACNT
+; to fnode.
+; P.A. Williams 08/01/89 Added typedef FNODE and PFNODE, ALBLK, PALBLK,
+; ALLEAF, PALLEAF, ALSEC, and PALSEC.
+;
+
+
+;* File Allocation Tracking
+;
+; File space is allocated as a list of extents, each extent as
+; large as we can make it. This list is kept in a B+TREE format.
+; Each B+TREE block consists of a single sector containing an
+; ALSEC record, except for the top most block. The topmost block
+; consists of just an ALBLK structure, is usually much smaller than
+; 512 bytes, and is typically included in another structure.
+;
+; The leaf block(s) in the tree contain triples which indicate
+; the logical to physical mapping for this file. Typically this
+; extent list is small enough that it is wholy contained in the
+; fnode ALBLK stucture. If more than ALCNT extents are required
+; then the tree is split into two levels. Note that when the
+; topmost B+TREE block is 'split' no actual split is necessary,
+; since the new child block is much bigger than the parent block
+; and can contain all of the old records plus the new one. Thus,
+; we can have B+TREEs where the root block contains only one
+; downpointer.
+;
+; The following rules apply:
+;
+; 1) if the file is not empty, there is at least one sector allocated
+; to logical offset 0. This simplifys some critical loops.
+;
+; 2) The last entry in the last node block contains a AN_LOF value of
+; FFFFFFFF. This allows us to extend that last leaf block
+; without having to update the node block.
+;
+; 3) For the node records, the AN_SEC points to a node or leaf
+; sector which describes extents which occur before that
+; record's AN_LOF value.
+;
+
+;* Allocation block structure
+;
+; Each allocation block consists of one of these. This may be
+; a small block imbedded in an FNODE or OFT structure, or it
+; may occupy a whole sector and be embedded in an ALSEC structure.
+;
+
+ALBLK struc
+ AB_FLAG db ? ; flags
+ AB_FLAG2 db 3 dup (?) ; unused - sometimes copied with AB_FLAG
+ AB_FCNT db ? ; free count - slots for ALLEAF or ALNODE
+ AB_OCNT db ? ; occupied count - # of ALLEAF or ALNODEs
+ AB_FREP dw ? ; offset to last item+1
+ ; ALLEAF or ALNODE records go here
+ALBLK ends
+
+ABF_NODE equ 80h ; if not a leaf node
+ABF_BIN equ 40h ; suggest using binary search to find
+ABF_FNP equ 20h ; parent is an FNODE
+ABF_NFG equ 01h ; not a flag, high order bit of AB_FREP
+
+; Allocation Node Structure
+;
+; These follow an ALBLK header for a node block
+
+ALNODE struc
+ AN_LOF dd ? ; logical offset (sectors
+ AN_SEC dd ? ; sector for guys < this
+ALNODE ends
+
+
+; Allocation Leaf Structure
+;
+; These follow an ALBLK header in a leaf block
+
+ALLEAF struc
+ AL_LOF dd ? ; logical sector offset (sectors)
+ AL_LEN dd ? ; length of extent (sectors)
+ AL_POF dd ? ; physical sector offset (sectors)
+ALLEAF ends
+
+
+;* Allocation Sector Structure
+;
+; Root ALBLK structures are contained within other structures,
+; such as the FNODE. When the B+TREE is more than one level,
+; though, the non-root nodes are each held in a sector.
+;
+; This structure defines that format
+;
+
+ALSEC struc
+ AS_SIG dd ? ; signature
+ AS_SEC dd ? ; sector # of this sector
+ AS_RENT dd ? ; parent sector # or FNODE #
+ AS_ALBLK db (size ALBLK) dup (?) ; ALBLK goes here
+ ; ALNODE or ALLEAF records start here
+ALSEC ends
+
+; # of bytes available for ALLEAF or ALNODE values. Size chosen
+; so an integral # of either structure fits
+
+ifdef MASM
+ASSIZ equ ((SECSIZE - size ALSEC)/24*24)
+ .errnz size ALLEAF-12
+ .errnz size ALNODE-8
+ .errnz (ASSIZ + AL_LOF + size AL_LOF + size ALBLK) GT 512 ; extra room for an AL_LOF value
+else
+ASSIZ equ ((SECSIZE - size ALSEC)/24*24)
+endif
+
+
+; AuxInfo Structure
+;
+; The FNODE contains two AuxInfo structures, one for ACLs and
+; one for EAs.
+;
+; These structures point to within FNODE storage and also
+; potentially point to an overflow area which is an ALBLK structure.
+; The AI_FNL stuff is stored in the FN_FREE area, the ACLs first
+; and the EAs second, any free space following. The start of the
+; EAs can be found by offseting FN_FREE with FN_ACL.AI_FNL
+;
+
+AUXINFO struc
+ AI_DAL dd ? ; non-fnode Disk Allocation length
+ AI_SEC dd ? ; sec # of first sec in extent or of ALSEC
+ AI_FNL dw ? ; length of fnode info
+ AI_DAT db ? ; non-zero if AI_SEC points to ALSEC
+AUXINFO ends
+
+;* Fnode block definition
+;
+; Every file and directory has an FNODE. The file location
+; stuff is only used for files; directories are kept in
+; a BTREE of DIRBLK records pointed to by FN_SEC[0].RSEC
+;
+
+ALCNT equ 8 ; 8 ALLEAF records in an FN_AT entry
+LEAFPERFNODE equ 8 ; 8 ALLEAF records in an FN_AT entry
+NODEPERFNODE equ 12 ; 12 ALNODE records in an FNODE.
+LEAFPERSEC equ 40 ; ALLEAF records in an allocation sector
+NODEPERSEC equ 60 ; ALNODE records in an allocation sector
+
+FNODE struc
+
+; The following file location information is copied into the OFT
+; and is used there during normal file access. The stuff in the
+; fnode record here may in fact be out of date for open files.
+; See the OFN_ in the OFT structure THESE TWO AREAS IN THE
+; RESPECTIVE RECORDS MUST HAVE IDENTICAL FORMATS.
+;
+; There are two kinds of location info: FNSCNT SPTR records
+; and then a single, double, triple, and quad indirect block pointer.
+; The "block threshold" means the first sector number which is
+; contained in that indirect block heirarchy. You use this
+; to quickly find out where to start looking.
+;
+
+ FN_SIG dd ? ; signature value
+
+; History tracking info for softer software
+
+ FN_SRH dd ? ; sequential read history
+ FN_FRH dd ? ; fast read history
+ FN_NAME db 16 dup (?) ; 1st 18 bytes of file name
+ FN_CONTFN dd ? ; fnode of directory cont. this file/dir
+
+; stuff not interesting once opened
+
+ FN_ACL db (size AUXINFO) dup (?) ; access ctl list aux info structure
+ FN_HCNT db ? ; count of valid history bits
+ FN_EA db (size AUXINFO) dup (?) ; ea aux info structure
+ FN_FLAG db ? ; FNODE flag byte
+
+ FN_AB db (size ALBLK) dup (?) ; allocation block structure
+ FN_ALREC db (ALCNT*size ALLEAF) dup (?) ; referenced from FN_AB
+ FN_VLEN dd ? ; length of valid data in file. if DIR_SIZE
+ ; is > FN_VLEN then the space inbetween
+ ; must be zapped before being shown to user
+ FN_NEACNT dd ? ; # of "need eas" in file
+
+; The following fields are unused in this release, they're for
+; future compatibility. When deleting files, if FN_EEL is non-zero
+; then FN_EEL sectors starting at FN_EEP must be released too.
+;
+
+ FN_UID db 16 dup (?) ; reserved for UID value
+ FN_ACLBASE dw ? ; FN_ACLBASE offset of 1st ACE in fnode
+ FN_SPARE db 10 dup (?); 10 more bytes emergency spares
+
+; Free pool. ACLs and EAs are stored here via the AUXINFO structure
+
+ FN_FREE db 316 dup (?) ; free space for perm and env list; perm list
+ ; comes first.
+FNODE ends
+
+
+ifdef MASM
+ .errnz AL_LOF ; verify validity of FN_DMY1 hack above
+ .errnz size AL_LOF-4
+endif
+
+; Fnode FN_FLAG bits
+
+FNF_DIR equ 01h ; is a directory fnode
diff --git a/private/ntos/boot/bootcode/hpfs/i386/fsstat.inc b/private/ntos/boot/bootcode/hpfs/i386/fsstat.inc
new file mode 100644
index 000000000..074030367
--- /dev/null
+++ b/private/ntos/boot/bootcode/hpfs/i386/fsstat.inc
@@ -0,0 +1,66 @@
+;static char *SCCSID = "@(#)fsstat.h 12.2 88/12/19";
+;** fsstat.h - file system statistics
+;
+
+CTHIST equ 10000
+
+FSSTAT struc
+ ST_OPEN dd ? ; count of OPEN calls
+ ST_CLOSE dd ? ; count of CLOSE calls
+ ST_READ dd ? ; count of READ calls
+ ST_WRITE dd ? ; count of WRITE calls
+
+ ST_DEL dd ? ; count of DELETE calls
+ ST_SEEK dd ? ; count of SEEK calls
+ ST_FINDF dd ? ; count of FINDF calls
+ ST_FINDN dd ? ; count of FINDN calls
+
+ ST_RD dd ? ; count of disk reads
+ ST_WR dd ? ; count of disk writes
+ ST_CRD dd ? ; count of cache read hits
+ ST_CWD dd ? ; count of cache write hits
+
+ ST_INVAL dd ? ; invalid LSD hints
+ ST_VALID dd ? ; valid LSD hints
+ ST_RDEH dd ? ; directory relocated
+ ST_RDEM dd ? ; directory adjusted
+
+ ST_SFB dd ? ; count of SFB calls
+ ST_VBR dd ? ; count of VBR calls
+ ST_CBR dd ? ; count of CBR calls
+ ST_AEX dd ? ; count of AddExt calls
+
+ ST_EFA dd ? ; files extended
+ ST_FLW dd ? ; FLW buffers written
+ ST_BRV dd ? ; bitmap read valid
+ ST_BRI dd ? ; bitmap read invalid
+
+ ST_BLSD dd ? ; blocked in LSD
+ ST_BRDB dd ? ; blcoked in rdb
+ ST_GFBI dd ? ; GFB interlock
+ ST_GFBW dd ? ; gfb waits
+
+ ST_LWR dd ? ; long writes
+ ST_GIB dd ? ; Getinbuf was successful
+ ST_HMIN dd ? ; heap minimum
+ ST_LWBW dd ? ; singletons output by lazy IO
+
+ ST_CLN dd ? ; clean blocks found by lazy IO
+ ST_LWW dd ? ; wakeups caused by lazy IO blocks
+ ST_QINFO dd ? ; Query info
+ ST_QIDIR dd ? ; query info on directory
+
+ ST_LWBLK dd SPB*LWBUFCT dup (?) ; Histogram of lazy write blocks
+
+; performance impact items
+
+ ST_DLRS dd ? ; directory locked forced restart
+ ST_ALSP dd ? ; count of allocation block splits
+ pad2 dd 3 dup (?)
+
+ ST_RSIZ dd 64 dup (?) ; Histogram of # sectors in read request
+ ST_WSIZ dd 64 dup (?) ; Histogram of # sectors in write request
+FSSTAT ends
+
+FS_GETSTAT equ 8004h
+FS_CLEAR equ 8005h
diff --git a/private/ntos/boot/bootcode/hpfs/i386/macro.inc b/private/ntos/boot/bootcode/hpfs/i386/macro.inc
new file mode 100644
index 000000000..153ab4fd9
--- /dev/null
+++ b/private/ntos/boot/bootcode/hpfs/i386/macro.inc
@@ -0,0 +1,781 @@
+; SCCSID = @(#)macro.inc 12.1 88/12/19
+
+;** Macros
+
+
+;* MASSUME - do an assume
+;
+; made into a macro to make screwing around during debuuing
+; easier
+;
+; Used by the file system code; not recommended for general
+; use. Will be taken out at end of project. BUGBUG
+
+
+MASSUME MACRO
+ ASSUME CS:CODE,DS:FLAT,ES:FLAT,SS:NOTHING
+ ENDM
+
+
+;* MENTER - Do an Enter
+;
+; made into a macro for better code, and to avoid problems
+; when USE16 (MASM doesn't generate the override)
+
+MENTER MACRO arg1,arg2
+ push ebp
+ mov ebp,esp
+ ifdif <arg1>,<0>
+ sub esp,arg1
+ endif
+ ENDM
+
+;* MLEAVE - do a Leave
+;
+; We need to generate the segment override in USE16, since
+; MASM won't do it
+
+MLEAVE MACRO
+ ifndef USE32
+ DB 66h
+ endif
+ leave
+ ENDM
+
+;* GetPathBuf - Allocates from the heap memory for the PathBuffer
+;
+; Enter: (eax) = size of the requested heap block (hvpb not included)
+; Exit: C clear:
+; (eax) = ptr to the heap block
+; C set: error no more heap space
+; Uses: eax, flags
+
+GetPathBuf MACRO
+ SAVE <EDI, ECX>
+ add eax, MVPFXSIZE+3+HHSIZ ; for hvpb, rounding and header
+ and al, 0fch ; round it to quad-boundary
+ifndef GHS_
+ EXTRN GHS_:near
+endif
+ call GHS_
+ RESTORE <ECX, EDI>
+ENDM
+
+;* FreePathBuf - Return PathBuffer to the Heap
+;
+;
+; Enter: (reg) = ptr to PathBuffer (that's (sizeof hvbp) after the
+; heap block address)
+; Exit: heap block released
+; Uses: reg
+
+FreePathBuf MACRO reg
+ sub reg, MVPFXSIZE ; (reg) now pts to the heap block
+ HeapChk reg
+ add dword ptr -4[reg],80000000h-4
+ENDM
+
+
+
+;* Assert - sanity checks (contolled by DEBUG switch)
+;
+; kind: one of OFT
+;
+; objs: register/word which contains address
+;
+; nopush: if non-blank, we don't preserve registers
+
+IFDEF DEBUG
+ASSERT MACRO kind, objs, nopush, arg1
+ local a
+
+a = 0
+
+
+ IFNDEF A_OFT
+ extrn A_OFT:near,A_SECPTR:near,A_DIRBLK:near,A_FNODE:near
+ extrn A_AS:near,A_HEAPNAM:near,A_DCHDR:near,A_BUF:near
+ extrn A_SBDIR:near,A_ALBLK:near
+ ENDIF
+
+ IFB <nopush>
+ pushad
+ pushfd
+ ENDIF
+
+ IFIDN <kind>,<OFT>
+ a = 1
+ mov eax,objs
+ call A_OFT ; assert OFT
+ ENDIF
+ IFIDN <kind>,<SECPTR>
+ a = 1
+ lea eax,objs
+ call A_SECPTR ; returns 'C' clear if hint field is valid
+ ENDIF
+ IFIDN <kind>,<ALBLK>
+ a = 1
+ mov eax,objs
+ call A_ALBLK
+ ENDIF
+ IFIDN <kind>,<ASREC>
+ a = 1
+ mov eax,objs
+ call A_AS
+ ENDIF
+ IFIDN <kind>,<HEAPNAM>
+ a = 1
+ mov eax,objs
+ call A_HEAPNAM
+ ENDIF
+ IFIDN <kind>,<DCHDR>
+ a = 1
+ mov edx,arg1
+ mov eax,objs
+ call A_DCHDR
+ ENDIF
+ IFIDN <kind>,<DIRBLK>
+ a = 1
+ mov eax,objs
+ call A_DIRBLK
+ ENDIF
+ IFIDN <kind>,<BUF>
+ a = 1
+ mov eax,objs
+ call A_BUF
+ ENDIF
+ IFIDN <kind>,<SBDIR>
+ a = 1
+ mov eax,objs
+ call A_SBDIR
+ ENDIF
+ IFIDN <kind>,<FNODE>
+ a = 1
+ mov eax,objs
+ call A_FNODE
+ ENDIF
+
+ IFE a
+ .error illegal option
+ ENDIF
+
+
+ IFB <nopush>
+ popfd
+ popad
+ nop ; errata
+ ENDIF
+ ENDM
+ELSE
+ ASSERT Macro a,b,c
+ ENDM
+ENDIF
+
+;** Heap sanity check macro (controlled by DEBUG flag)
+;
+; item - make sure this points to a heap allocated block
+; (return value from GHS or GHS_)
+; if blank, just the arena is checked.
+
+IFDEF DEBUG
+HeapChk Macro item
+ ifndef A_HEAP
+ extrn A_HEAP:near
+ endif
+ push edx
+ ifb <item>
+ mov edx, 0 ;; don't zap the flags
+ endif
+ ifdif <edx>, <item>
+ mov edx, item
+ endif
+ call A_HEAP
+ pop edx
+ENDM
+
+ELSE
+ HeapChk Macro item
+ ENDM
+ENDIF
+
+
+DPUBLIC MACRO arg
+ ifdef DEBUG
+ Public arg
+ endif
+ENDM
+
+
+BREAK MACRO subtitle
+ SUBTTL subtitle
+ PAGE
+ENDM
+
+;** CalcGBHShift - calculate the GBH shift factor
+
+GBHShift = 0
+
+CalcGBHShift MACRO
+ local ?tmp
+
+ if GBHShift NE 0
+ EXITM
+ endif
+
+ ?tmp = (SECSIZE*SPB) / (size BUFNODE)
+ rept 16
+ if ?tmp EQ 1
+ exitm
+ endif
+ ?tmp = ?tmp / 2
+ GBHShift = GBHShift + 1
+ endm
+
+ .errnz SECSIZE * SPB - ((size BUFNODE) SHL GBHShift)
+ENDM
+
+
+;** GBH - Get Buffer Header
+;
+; GBH takes the address of a buffer data area and returns the
+; address of it's header.
+;
+; Since the data area is linear in memory and the headers are linear,
+; we just do a simple linear mapping.
+;
+; GBH transforms the address in the register without modifying
+; any other registers.
+;
+; GBH reg
+
+GBH MACRO reg
+ CalcGBHShift
+ sub reg,Bufbase ; (reg) = offset in array of buffers
+ shr reg,GBHShift ; (reg) = offset in array of bufnotes
+
+; Get rid of low order stuff. Since reg may be an offset WITHIN
+; a buffer and not just a poitner to the header itself, we mask off the
+; low order stuff.
+
+ ifidn <reg>,<eax>
+ and al,100h - (SIZE bufnode)
+ else
+ ifidn <reg>,<ebx>
+ and bl,100h - (SIZE bufnode)
+ else
+ ifidn <reg>,<ecx>
+ and cl,100h - (SIZE bufnode)
+ else
+ %out add more code to this macro
+ .err
+ endif
+ endif
+ endif
+ add reg, OFFSET DS:Bhbase
+ ENDM
+
+;* RetHeap - Return Heap Item
+;
+; RetHeap address-of-item
+
+RetHeap MACRO reg
+ HeapChk reg
+ add dword ptr -4[reg],80000000h-4
+ ENDM
+
+
+;* GetPerm - Get Perminant Memory
+;
+; Returns a block of memory which will be perminantly
+; occupied
+
+GetPerm Macro reg,len
+ local l1,l2
+l1: mov reg,PermPtr
+ add PermPtr,len
+ cmp reg,PermLim
+ jb short l2
+ push len
+ call aapm ; allocate additional perm memory
+ jmp l1
+ align 4
+l2:
+ ENDM
+
+
+ BREAK <Double Chain Manipulation Macros>
+
+;** The following macros manipulate double-linked lists.
+;
+; All macros take as their first argument the offset to
+; the pointer pair.
+
+;** DCADDB - Add Item to Back of List
+;
+; DCADDB offset,listreg,itemreg,scrreg
+;
+; offset = offset into structure of links to edit
+; listreg = address of list head node
+; itemreg = address of item to insert
+; scrreg = scratch register to roach
+
+DCADDB MACRO o,LR,IR,SR
+ mov SR,o.BAK[LR]
+ mov o.FWD[SR],IR
+ mov o.FWD[IR],LR
+ mov o.BAK[IR],SR
+ mov o.BAK[LR],IR
+ ENDM
+
+
+;** DCADDF - Add Item to Front of List
+;
+; DCADDF offset,listreg,itemreg,scrreg
+;
+; offset = offset into structure of links to edit
+; listreg = address of list head node
+; itemreg = address of item to insert
+; scrreg = scratch register to roach
+
+DCADDF MACRO o,LR,IR,SR
+ mov SR,o.FWD[LR]
+ mov o.FWD[IR],SR
+ mov o.BAK[IR],LR
+ mov o.BAK[SR],IR
+ mov o.FWD[LR],IR
+ ENDM
+
+
+
+;** DCREM - Remove Item from Double Link Chain
+;
+; DCREM offset,adrreg,scrreg1,scrreg2
+;
+; offset = offset into structure of links to edit
+; adrreg = address of item to remove
+; scrreg? = two registers to scratch
+
+DCREM MACRO o,ir,r2,r3
+ mov r2,o.FWD[ir]
+ mov r3,o.BAK[ir]
+ mov o.BAK[r2],r3
+ mov o.FWD[r3],r2
+ ENDM
+
+
+;** DCMOVF - Move Item to the Front of the Chain
+;
+; DCMOVF offset,listreg,itemreg,scrreg,[scrreg2]
+;
+; offset = offset into structure of links to edit
+; listreg = address of list head node
+; itemreg = address of item to insert
+; scrreg = scratch register to roach
+; scrreg2 = optional additional register to roach
+;
+; BUGBUG - check users for supply of scratch registers
+
+DCMOVF MACRO o,lr,ir,sr,sr2
+ IFNB <sr2>
+ DCREM o,ir,sr,sr2
+ else
+ push lr
+ DCREM o,ir,lr,sr
+ pop lr
+ endif
+ DCADDF o,lr,ir,sr
+ ENDM
+
+
+;** DCMOVB - Move Item to the Back of the Chain
+;
+; DCMOVB offset,listreg,itemreg,scrreg
+;
+; offset = offset into structure of links to edit
+; listreg = address of list head node
+; itemreg = address of item to insert
+; scrreg = scratch register to roach
+
+DCMOVB MACRO o,lr,ir,sr
+ push lr
+ DCREM o,ir,lr,sr
+ pop lr
+ DCADDB o,lr,ir,sr
+ ENDM
+
+
+;** ADDHASH - add a buffer to hash list
+;
+; ADDHASH lsn,buf,sr1,sr2,sr3
+;
+; lsn = Vsector or Psector number of beginning of buffer
+; may be any of the arg registers
+; buf = address of buffer header
+; sr1 = scratch register
+; sr2 = 'nother scratch register
+; sr3 = last scratch register
+
+ADDHASH MACRO lsn,buf,sr1,sr2,sr3
+ local l1,l2
+
+ mov sr1,lsn
+ and sr1,(HASHCNT-1)*4 ; (sr1) = hash index
+ add sr1,offset DGROUP:HashTab
+ mov B_HTA[buf],sr1 ; save hash ptr for later use by DCADDF
+ mov sr2,[sr1]
+ifidn <sr2>,<ecx>
+ jecxz l1
+else
+ and sr2,sr2
+ jz short l1 ; nobody on list yet
+endif
+ DCADDF B_HASH,sr2,buf,sr3 ; add to hash list
+ jmp short l2
+
+ align 4
+l1: mov B_HASH.FWD[buf],buf ; empty list, make self-linked
+ mov B_HASH.BAK[buf],buf
+l2: mov [sr1],buf ; put our guy at front of chain
+ ENDM
+
+
+;** HASHFIND - find a sector in the hash
+;
+; HASHFIND lsn,buf,sr1,fnd
+;
+; lsn = logical sector number to find. HASHFIND presumes it
+; has already been rounded to a multiple of SPB
+; buf = register where buffer is returned
+; sr1 = scratch register
+; fnd = where to go if found
+; NOTE: falls through if not found
+
+
+HASHFIND MACRO lsn,buf,sr1,fnd
+ local l1,l2
+
+ mov sr1,lsn
+ and sr1,(HASHCNT-1)*4 ; (sr1) = hash index
+ mov buf,Hashtab[sr1]
+ifidn <buf>,<ecx>
+ jecxz l2
+else
+ and buf,buf
+ jz short l2 ; no entries in chain, block not there
+endif
+ mov sr1,buf ; save address of first guy
+
+; Run through circular chain, looking for a match.
+;
+; (buf) = next guy to check out
+; (lsn) = sector value to match
+; (sr1) = address of first guy in chain
+
+ align 4
+l1: cmp lsn,B_SEC[buf]
+ je fnd ; got him
+ mov buf,B_HASH.FWD[buf] ; go to next buffer
+ cmp buf,sr1 ; have we gone around yet?
+ jne l1 ; no, go examine buffer
+l2:
+ ENDM
+
+
+
+;** FALLTHRU - Verifies Fallthrough Validity
+
+FALLTHRU MACRO labl
+ align 4 ; don't have errnz fail due to alignment
+ IF2 ; of following label
+ .errnz labl-$
+ ENDIF
+ ENDM
+
+
+;** INTERR - Internal Error
+; INTERRnz - Internal error iff 'Z' clear
+; INTERRzr - Internal error iff 'Z' set
+; INTERRc - Internal error if 'C' set
+
+ifdef DEBUG
+INTERR MACRO
+ local l
+l: int 3
+ jmp l
+ ENDM
+
+INTERRzr MACRO
+ local l
+ jnz short l
+ int 3
+ jmp $-1
+l:
+ ENDM
+
+INTERRc MACRO
+ local l
+ jnc short l
+ int 3
+ jmp $-1
+l:
+ ENDM
+
+INTERRnz MACRO
+ local l
+ jz short l
+ int 3
+ jmp $-1
+l:
+ ENDM
+else
+INTERR MACRO
+ ENDM
+INTERRzr MACRO
+ ENDM
+INTERRc MACRO
+ ENDM
+INTERRnz MACRO
+ ENDM
+endif
+
+;* Debug Traps
+;
+; These are removed as the code is exercised
+
+TRAPC macro
+ local l
+ jnc short l
+ int 3
+l:
+ ENDM
+
+TRAPZ macro
+ local l
+ jnz short l
+ int 3
+l:
+ ENDM
+
+TRAPNZ macro
+ local l
+ jz short l
+ int 3
+l:
+ ENDM
+
+
+;** PANIC - Panic File System
+;
+; BUGBUG - fix me to do something besides trap
+
+PANIC macro
+ local l
+l: int 3
+ jmp l
+ ENDM
+
+;** Bulk Register Save/Restore
+;
+
+SAVE MACRO reglist
+IRP reg,<reglist>
+ PUSH reg
+ENDM
+ENDM
+.xcref SAVE
+
+RESTORE MACRO reglist ;; pop those registers
+IRP reg,<reglist>
+ POP reg
+ENDM
+ENDM
+.xcref RESTORE
+
+
+;* ret16 - perform a 16bit return
+;
+; If we are in a use32 segment then we must put out an operand size
+; override before the ret.
+
+ret16 macro stkfix
+ ife @WordSize - 4
+ db 66h ;; operand size override
+ endif
+ retf stkfix
+ endm
+.xcref ret16
+
+
+;* call1616 - perform an indirect 16bit far call
+;
+; If we are in a use32 segment then we must put out an operand size
+; override before the call and then cast the target to "FWORD" so that
+; MASM will generate the correct instruction.
+;
+; The target must be indirect.
+
+call1616 macro target
+ .errnz (type target) - 4
+ ife @WordSize - 4
+ db 66h ;; operand size override
+ call fword ptr target ;; force indirect far call
+ else
+ call target
+ endif
+ endm
+.xcref call1616
+
+
+;** Dpush - Push 32-bit constant
+;
+; MASM has no way of expressing this in USE16 mode.
+
+DPUSH macro a
+ifdef USE32
+ push a
+else
+ push a ; low order
+ push 0
+endif
+ ENDM
+
+;** Push16 - generate a 16bit push in a 32-bit code segment. This is
+; needed when pushing segment regs and immediate values as arguments
+; to 16bit procedures.
+
+push16 macro operand
+ db 66h
+ push operand
+ endm
+
+
+;** STATINC - Do an INC if STAT gathering is enabled
+;
+; Preserves 'C'
+
+STATINC macro a
+ifdef STATS
+ inc a
+endif
+ ENDM
+
+;** STATDEC - Do an DEC if STAT gathering is enabled
+;
+; Preserves 'C'
+
+STATDEC macro a
+ifdef STATS
+ dec a
+endif
+ ENDM
+
+
+;** LogHCNT - Log OFT holding/unholding
+;
+
+ifdef DEBUG
+
+LOGHCNT MACRO reg
+ifndef DoLogHcnt
+ EXTRN DoLogHcnt:near
+endif
+ pushfd
+ push eax
+ mov eax,reg
+ call DoLogHcnt
+ pop eax
+ popfd
+ ENDM
+
+;** LogSCNT - Lock SBDIR holding/unholding
+;
+
+LOGSCNT MACRO REG
+ifndef DoLogScnt
+ EXTRN DoLogScnt:near
+endif
+ pushfd
+ push eax
+ifdif <REG>,<eax>
+ mov eax,reg
+endif
+ call DoLogScnt
+ pop eax
+ popfd
+ ENDM
+else
+LOGHCNT MACRO
+ ENDM
+LOGSCNT MACRO
+ ENDM
+endif
+
+ifdef DEBUG
+ CALLVBS MACRO
+ ifndef VBS
+ EXTRN VBS:NEAR
+ endif
+ call VBS
+ ENDM
+else
+ CALLVBS MACRO
+ ENDM
+endif
+
+;** cBUFZAP - Call DoZap iff debug mode set
+;
+
+cBUFZAP Macro
+ifdef DEBUG
+ifndef DoZap
+ EXTRN DoZap:near
+endif
+ call DoZap
+endif
+ endm
+
+
+;** Stack Frame Macros
+;
+; These macros are used to allow a stack frame to be setup by
+; simple PUSHES and yet guarantee that the pushes won't drift
+; out of sync with the frame declaration.
+
+LASTEL MACRO struc,elem
+ .errnz size struc - elem - size elem
+?frof = elem
+ ENDM
+
+NEXTEL MACRO elem
+ .errnz ?frof - elem - size elem
+?frof = elem
+ ENDM
+
+DUMYEL MACRO si
+?frof = ?frof - si
+ ENDM
+
+FIRSTEL MACRO elem
+ .errnz ?frof - size elem
+?frof = elem
+ .errnz elem
+ ENDM
+
+
+;** CHKSECNUM - Check Sector number
+;
+; CHKSECNUM reg
+;
+; Make sure that reg has a sector number in it without the high order
+; volume ID bits
+
+
+CHKSECNUM MACRO reg
+ local l1
+ifdef DEBUG
+ test reg,NOT SECMASK
+ jz l1
+ INTERR
+l1:
+endif
+ ENDM
diff --git a/private/ntos/boot/bootcode/hpfs/i386/makefile b/private/ntos/boot/bootcode/hpfs/i386/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/boot/bootcode/hpfs/i386/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/boot/bootcode/hpfs/i386/misc.inc b/private/ntos/boot/bootcode/hpfs/i386/misc.inc
new file mode 100644
index 000000000..7135cf542
--- /dev/null
+++ b/private/ntos/boot/bootcode/hpfs/i386/misc.inc
@@ -0,0 +1,64 @@
+;static char *SCCSID = "@(#)misc.h 12.2 88/12/19";
+; #define DEBUG 1
+
+ifdef MASM
+
+ include filemode.inc
+
+ BREAK <Misc. Definitions>
+
+endif
+
+ERROR_OPLOCKED equ 0eeh
+
+
+;* MISC.INC - Miscelaneous structure definitions.
+;
+; These need to be included first because other structures
+; make use of them.
+;
+
+
+;* SecPtr - Sector Pointer Structure
+;
+; Structures which contain a sector number usually use the
+; SecPtr structure, which contains an advisory pointer. The
+; pointer points to a buffer header, which is *probably* the
+; header for the sector named in SecPtr, but the user must check.
+;
+
+SECPTR struc
+ SNUM dd ? ; VSector number
+ SHINT dw ? ; hint address, 0 if none
+SECPTR ends
+
+
+
+
+;* Write type flags for SDW
+;
+
+WT_CACH equ 01h ; write via cache
+WT_DIR equ 02h ; write direct as much as possible
+WT_EXT equ 04h ; write is extending the file
+
+
+;* Bit Map Sets
+
+BITMAPL equ -4 ; bit map length preceeds table
+BITMAPC equ -8 ; count of sectors left in bitmap
+
+
+;* conditional short value
+
+ifdef MASM
+ifdef USE16
+SHRT EQU < >
+else
+ifdef DEBUG
+SHRT EQU < >
+else
+SHRT EQU <short>
+endif
+endif
+endif
diff --git a/private/ntos/boot/bootcode/hpfs/i386/pinboot.asm b/private/ntos/boot/bootcode/hpfs/i386/pinboot.asm
new file mode 100644
index 000000000..412280f14
--- /dev/null
+++ b/private/ntos/boot/bootcode/hpfs/i386/pinboot.asm
@@ -0,0 +1,727 @@
+ page ,132
+ title pinboot - Pinball boot loader
+ name pinboot
+
+; The ROM in the IBM PC starts the boot process by performing a hardware
+; initialization and a verification of all external devices. If all goes
+; well, it will then load from the boot drive the sector from track 0, head 0,
+; sector 1. This sector is placed at physical address 07C00h.
+;
+; The boot code's sole resposiblity is to find NTLDR, load it at
+; address 2000:0000, and then jump to it.
+;
+; The boot code understands the structure of the Pinball root directory,
+; and is capable of reading files. There is no contiguity restriction.
+;
+; The boot sector does not understand the Pinball file system's hotfixing --
+; there isn't enough room. So if NTLDR is hotfixed, we're out of luck.
+;
+
+MASM equ 1
+ .xlist
+ .286
+ include macro.inc
+;
+A_DEFINED equ 1 ; don't "extrn" A_xxxx functions
+
+ .386
+ include const.inc ;get the file system's headers.
+ include chain.inc
+ include misc.inc
+ include fnode.inc
+ include dir.inc
+ include superb.inc
+ .286
+ .list
+
+DoubleWord struc
+lsw dw ?
+msw dw ?
+DoubleWord ends
+
+;
+; The following are various segments used by the boot loader. The first
+; two are the segments where the boot sector is initially loaded and where
+; the boot sector is relocated to. The others are the static locations
+; where the mini-FSD and OS2KRNL are loaded. There is no segment definition
+; for where OS2LDR is loaded, since its position is variable (it comes right
+; after the end of OS2KRNL).
+;
+
+BootSeg segment at 07c0h ; this is where the ROM loads us initially.
+BootSeg ends
+
+NewSeg segment at 0d00h ; this is where we'll relocate to.
+NewSeg ends ; enough for 16 boot sectors +
+ ; 4-sector scratch
+ ; below where we'll load OS2KRNL.
+
+LdrSeg segment at 2000h ; we want to load the loader at 2000:0000
+LdrSeg ends
+
+ScrOfs equ 0f800h - 0d000h ; offset of 2K scratch area.
+
+MOVEDD macro dest, src ; macro to copy a doubleword memory variable.
+ mov ax, src.lsw
+ mov dest.lsw, ax
+ mov ax, src.msw
+ mov dest.msw, ax
+ ENDM
+
+;/********************** START OF SPECIFICATIONS ************************/
+;/* */
+;/* SUBROUTINE NAME: pinboot */
+;/* */
+;/* DESCRIPTIVE NAME: Bootstrap loader */
+;/* */
+;/* FUNCTION: To load NTLDR into memory. */
+;/* */
+;/* NOTES: pinboot is loaded by the ROM BIOS (Int 19H) at */
+;/* physical memory location 0000:7C00H. */
+;/* pinboot runs in real mode. */
+;/* This boot record is for Pinball file systems only. */
+;/* Allocation information for NTLDR may not */
+;/* exceed an FNODE. */
+;/* */
+;/* ENTRY POINT: pinboot */
+;/* LINKAGE: Jump (far) from Int 19H */
+;/* */
+;/* INPUT: CS:IP = 0000:7C00H */
+;/* SS:SP = 0030:00FAH (CBIOS dependent) */
+;/* */
+;/* EXIT-NORMAL: */
+;/* DL = INT 13 drive number we booted from */
+;/* Jmp to main in OS2LDR */
+;/* */
+;/* EXIT-ERROR: None */
+;/* */
+;/* EFFECTS: Pinball mini-FSD is loaded into the physical */
+;/* memory location 000007C0H */
+;/* NTLDR is loaded into the physical memory */
+;/* location 00020000H */
+;/* */
+;/* MESSAGES: */
+;/* A disk read error occurred. */
+;/* The file NTLDR cannot be found. */
+;/* Insert a system diskette and restart the system. */
+;/* */
+;/*********************** END OF SPECIFICATIONS *************************/
+BootCode segment ;would like to use BootSeg here, but LINK flips its lid
+ assume cs:BootCode,ds:nothing,es:nothing,ss:nothing
+
+ org 0 ; start at beginning of segment, not 0100h.
+
+ public _pinboot
+_pinboot proc far
+ jmp start
+;
+; The following is the default BPB for Pinball hard disks. It may
+; be modified by FORMAT or SYS before being installed on the disk.
+;
+; Parameters such as Heads, SectorsPerTrack, and SectorsLong are
+; set up for a 20MB hard disk, so that a binary image of this boot
+; record may be written directly to a test hard disk without having
+; to reformat the drive.
+;
+; Note that this is really just a place-holder--anyone who writes
+; the boot code should preserve the volume's existing BPB.
+;
+Version db "IBM 10.2"
+BPB label byte
+BytesPerSector dw SECSIZE ; Size of a physical sector
+SectorsPerCluster db 4 ; Sectors per allocation unit
+ReservedSectors dw 1 ; Number of reserved sectors
+Fats db 2 ; Number of fats
+DirectoryEntries dw 0200h ; Number of directory entries
+Sectors dw 0 ; No. of sectors - no. of hidden sectors
+Media db 0f8h ; Media byte
+FatSectors dw 0029h ; Number of fat sectors
+SectorsPerTrack dw 17 ; Sectors per track
+Heads dw 4 ; Number of surfaces
+HiddenSectors dd 0011h ; Number of hidden sectors
+SectorsLong dd 0a2c3h ; Number of sectors iff Sectors = 0
+;
+; The following is the rest of the Extended BPB for the volume.
+; The position and order of DriveNumber and CurrentHead are especially
+; important, since those two variables are loaded into a single 16-bit
+; register for the BIOS with one instruction.
+;
+DriveNumber db 80h ; Physical drive number (0 or 80h)
+CurrentHead db ? ; Variable to store current head number
+
+Signature db 28h ; Signature Byte for bootsector
+BootID dd 64d59c15h ; Boot ID field.
+Boot_Vol_Label db 'C-DRIVE',0,0,0,0 ;volume label.
+Boot_System_ID db 'HPFS ' ; Identifies the IFS that owns the vol.
+;
+; The following variables are not part of the Extended BPB; they're just
+; scratch variables for the boot code.
+;
+SectorBase dd ? ; next sector to read
+CurrentTrack dw ? ; current track
+CurrentSector db ? ; current sector
+SectorCount dw ? ; number of sectors to read
+lsnSaveChild dd ? ; sector to continue directory search
+
+;****************************************************************************
+start:
+;
+; First of all, set up the segments we need (stack and data).
+;
+ cli
+ xor ax, ax ; Set up the stack to just before
+ mov ss, ax ; this code. It'll be moved after
+ mov sp, 7c00h ; we relocate.
+ sti
+
+ mov ax, Bootseg ; Address our BPB with DS.
+ mov ds, ax
+ assume ds:BootCode
+;
+; Now read the 16-sector boot block into memory. Then jump to that
+; new version of the boot block, starting in the second sector
+; (after the bootrecord sig).
+;
+ mov SectorBase.lsw, 0 ; read sector zero.
+ mov SectorBase.msw, 0
+ mov word ptr [SectorCount], SEC_SUPERB+4 ; read boot/superblock.
+ mov ax, NewSeg ; read it at NewSeg.
+ mov es, ax
+ sub bx, bx ; at NewSeg:0000.
+ call DoReadLL ; Call low-level DoRead routine
+;
+ push NewSeg ; we'll jump to NewSeg:0200h.
+ push offset mainboot ; (the second sector).
+ ret ; "return" to the second sector.
+_pinboot endp
+
+;*******************************************************************************
+;
+; Low-level read routine that doesn't work across a 64k addr boundary.
+;
+; Read SectorCount sectors (starting at SectorBase) to es:bx.
+;
+; As a side effect, SectorBase is updated (but es:bx are not)
+; and SectorCount is reduced to zero.
+;
+DoReadLL proc
+ push ax ; save important registers
+ push bx
+ push cx
+ push dx
+ push es
+
+DoRead$Loop:
+ mov ax, SectorBase.lsw ; (DX:AX) = start sector of next track
+ mov dx, SectorBase.msw
+ add ax, HiddenSectors.lsw ; adjust for partition's base sector
+ adc dx, HiddenSectors.msw
+ div SectorsPerTrack ; (DX) = sector within track, (AX)=track
+ inc dl ; sector numbers are 1-based, not 0
+ mov CurrentSector, dl
+ xor dx, dx ; prepare for 32-bit divide
+ div Heads ; (DX) = head no., (AX) = cylinder
+ mov CurrentHead, dl
+ mov CurrentTrack, ax
+
+; CurrentHead is the head for this next disk request
+; CurrentTrack is the track for this next request
+; CurrentSector is the beginning sector number for this request
+;
+; Compute the number of sectors that we may be able to read in a single ROM
+; request.
+;
+ mov ax, SectorsPerTrack ; could read up to this much
+ sub al, CurrentSector ; offset within this track
+ inc ax ; CurrentSector was 1-based
+;
+; AX is the number of sectors that we may read.
+;
+ cmp ax, SectorCount ; do we need to read whole trk?
+ jbe DoRead$FullTrack ; yes we do.
+ mov ax, SectorCount ; no, read a partial track.
+;
+; AX is now the number of sectors that we SHOULD read.
+;
+DoRead$FullTrack:
+ push ax ; save sector count for later calc.
+ mov ah, 2 ; "read sectors"
+ mov dx, CurrentTrack ; at this cylinder
+ mov cl, 6
+ shl dh, cl ; high 2 bits of DH = bits 8,9 of DX
+ or dh, CurrentSector ; (DH)=cyl bits | 6-bit sector no.
+ mov cx, dx ; (CX)=cylinder/sector no. combination
+ xchg ch, cl ; in the right order
+ mov dx, word ptr DriveNumber ; drive to read from, head no.
+ int 13h ; call BIOS.
+
+ pop ax
+ jb BootErr$he ; If errors report
+ add SectorBase.lsw, ax ; increment logical sector position
+ adc SectorBase.msw, 0
+ sub SectorCount, ax ; exhausted entire sector run?
+ jbe DoRead$Exit ; yes, we're all done.
+ shl ax, 9 - 4 ; (AX)=paragraphs read from last track
+ mov dx, es ; (DX)=segment we last read at
+ add dx, ax ; (DX)=segment right after last read
+ mov es, dx ; (ES)=segment to read next track at
+ jmp DoRead$Loop
+;
+DoRead$Exit:
+ pop es
+ pop dx
+ pop cx
+ pop bx
+ pop ax
+ ret
+
+DoReadLL endp
+
+;****************************************************************************
+;
+; BootErr - print error message and hang the system.
+;
+BootErr proc
+BootErr$fnf:
+ mov si,offset TXT_MSG_SYSINIT_FILE_NOT_FD +2
+ jmp short BootErr2
+BootErr$he:
+ mov si,offset TXT_MSG_SYSINIT_BOOT_ERROR +2
+BootErr2:
+ call BootErr$print
+ mov si,offset TXT_MSG_SYSINIT_INSER_DK +2
+ call BootErr$print
+ sti
+ jmp $ ;Wait forever
+BootErr$print:
+ lodsb ; Get next character
+ cmp al, 0
+ je BootErr$Done
+ mov ah,14 ; Write teletype
+ mov bx,7 ; Attribute
+ int 10h ; Print it
+ jmp BootErr$print
+BootErr$Done:
+ ret
+BootErr endp
+
+;****************************************************************************
+ include pinboot.inc ;suck in the message text
+;
+; Names of the files we look for. Each consists of a length byte
+; followed by the filename as it should appear in a directory entry.
+;
+ntldr db 5, "NTLDR"
+
+
+ReservedForFuture DB 22 dup(?) ;reserve remaining bytes to prevent NLS
+ ;messages from using them
+
+ .errnz ($-_pinboot) GT (SECSIZE-2),<FATAL PROBLEM: first sector is too large>
+
+ org SECSIZE-2
+ db 55h,0aah
+
+;****************************************************************************
+;
+; mainboot -
+;
+mainboot proc far
+ mov ax, cs ; get the new DS.
+ mov ds, ax
+ add ax, ((SEC_SUPERB + 4) * SECSIZE) / 16 ; address of scratch.
+ mov es, ax
+ mov ax, ds ; get DS again.
+ shl ax, 4 ; convert to an offset.
+ cli
+ mov sp, ax ; load new stack, just before boot code.
+ sti
+;
+; First find the root FNODE on disk and read it in.
+;
+ mov bx, SEC_SUPERB * SECSIZE + SB_ROOT
+ MOVEDD SectorBase, [bx] ; SectorBase = sblk.SB_ROOT.
+ mov SectorCount, 1 ; it's one sector long.
+ sub bx, bx ; read at scratch segment:0.
+ call DoRead
+;
+; Now find the root DIRBLK on disk and save its address.
+;
+ MOVEDD RootDB, es:[bx].FN_ALREC.AL_POF ; RootDB = f.FN_ALREC.AL_POF.
+;
+; Load NTLDR at 20000h.
+;
+ mov si, offset ntldr ; point to name of NTLDR.
+ MOVEDD SectorBase, RootDB ; start at root dirblk
+ call FindFile
+ mov ax, LdrSeg ; load at this segment.
+ call LoadFile ; find it and load it.
+;
+; We've loaded NTLDR--jump to it. Jump to NTLDR. Note that NTLDR's segment
+; address was stored on the stack above, so all we need to push is the offset.
+;
+; Before we go to NTLDR, set up the registers the way it wants them:
+; DL = INT 13 drive number we booted from
+;
+
+ mov dl, DriveNumber
+ mov ax,1000
+ mov es, ax ; we don't really need this
+ lea si, BPB
+ sub ax,ax
+ push LdrSeg
+ push ax
+ ret ; "return" to OS2LDR.
+mainboot endp
+
+;****************************************************************************
+;
+; DoRead - read SectorCount sectors into ES:BX starting from sector
+; SectorBase.
+;
+; NOTE: This code WILL NOT WORK if ES:BX does not point to an address whose
+; physical address (ES * 16 + BX) MOD 512 != 0.
+;
+; DoRead adds to ES rather than BX in the main loop so that runs longer than
+; 64K can be read with a single call to DoRead.
+;
+; Note that DoRead (unlike DoReadLL) saves and restores SectorCount
+; and SectorBase
+;
+DoRead proc
+ push ax ; save important registers
+ push bx
+ push cx
+ push dx
+ push es
+ push SectorCount ; save state variables too
+ push SectorBase.lsw
+ push SectorBase.msw
+;
+; Calculate how much we can read into what's left of the current 64k
+; physical address block, and read it.
+;
+;
+ mov ax,bx
+
+ shr ax,4
+ mov cx,es
+ add ax,cx ; ax = paragraph addr
+
+;
+; Now calc maximum number of paragraphs that we can read safely:
+; 4k - ( ax mod 4k )
+;
+
+ and ax,0fffh
+ sub ax,1000h
+ neg ax
+
+;
+; Calc CX = number of paragraphs to be read
+;
+ mov cx,SectorCount ; convert SectorCount to paragraph cnt
+ shl cx,9-4
+
+DoRead$Loop64:
+ push cx ; save cpRead
+
+ cmp ax,cx ; ax = min(cpReadSafely, cpRead)
+ jbe @F
+ mov ax,cx
+@@:
+ push ax
+;
+; Calculate new SectorCount from amount we can read
+;
+ shr ax,9-4
+ mov SectorCount,ax
+
+ call DoReadLL
+
+ pop ax ; ax = cpActuallyRead
+ pop cx ; cx = cpRead
+
+ sub cx,ax ; Any more to read?
+ jbe DoRead$Exit64 ; Nope.
+;
+; Adjust ES:BX by amount read
+;
+ mov dx,es
+ add dx,ax
+ mov es,dx
+;
+; Since we're now reading on a 64k byte boundary, cpReadSafely == 4k.
+;
+ mov ax,01000h ; 16k paragraphs per 64k segment
+ jmp short DoRead$Loop64 ; and go read some more.
+
+DoRead$Exit64:
+ pop SectorBase.msw ; restore all this crap
+ pop SectorBase.lsw
+ pop SectorCount
+ pop es
+ pop dx
+ pop cx
+ pop bx
+ pop ax
+ ret
+DoRead endp
+;****************************************************************************
+;
+; ReadScratch - reads a block of 4 sectors into the scratch area.
+;
+; ENTRY: SectorBase = LSN to read.
+;
+; EXIT: 4 sectors at AX read at BootSeg:ScrOfs
+;
+; USES: all
+;
+ReadScratch proc near
+ push es
+ push bx
+ mov word ptr SectorCount, 4 ; read 4 sectors.
+ push ds ; address scratch area.
+ pop es
+ mov bx, ScrOfs ; with ES:BX.
+ call DoRead
+ pop bx
+ pop es
+ ret
+ReadScratch endp
+;****************************************************************************
+;
+; FindFile - finds a file in the root directory
+;
+; ENTRY: DS:SI -> name of file to find.
+; SectorBase = LSN of first DirBlk to read
+;
+; EXIT: ES:BX -> dirent of file
+; SectorBase = lsn of current DirBlk (for next directory search)
+;
+; USES: all
+;
+FindFile proc near
+ push ds
+ pop es ; address data with ES too.
+ call ReadScratch ; read DirBlk (SectorBase already set)
+ sub cx, cx ; prepare to store name length.
+ mov cl, [si] ; fetch the length byte.
+ inc si ; and skip to the name.
+ mov dx, cx ; save a copy of it.
+
+ff1: mov bx, DB_START + ScrOfs ; point to first DIRENT, in scratch.
+ jmp short ff12
+;
+; bx -> last entry examined
+; cx = length of the name we're looking for
+; si -> name we're looking for, without the count byte ("search name")
+;
+ff10: add bx, [bx].DIR_ELEN ; move to next entry.
+ call UpcaseName
+
+ff12: mov ax, si ; save search name address.
+ mov cx, dx ; reload search name length.
+ lea di, [bx].DIR_NAMA ; point to current DIRENT name.
+ repe cmpsb ; compare bytes while equal.
+ mov si, ax ; restore search name address.
+ jne ff20 ; not equal, search on
+;
+; Looks like the names match, as far as we compared them. But if
+; the current name was longer than the search name, we didn't compare
+; them completely. Check the lengths.
+;
+ cmp dl, [bx].DIR_NAML
+ jne ff20 ; not equal, try downpointer if any
+
+ ret ; equal - Found the file
+
+
+; Names don't match. If the current entry has a downpointer,
+; search it.
+;
+ff20: test byte ptr [bx].DIR_FLAG, DF_BTP
+ jz ff30 ; no downpointer, check for end
+
+; Follow the DownPointer.
+; Load the child DIRBLK and search it.
+;
+ add bx, [bx].DIR_ELEN ; move to next entry.
+ MOVEDD SectorBase, [bx-4] ; fetch last 4 bytes of prev entry.
+ call ReadScratch ; read child DIRBLK
+ jmp short ff1 ; search this dirblk
+
+;
+; We don't have a downpointer.
+; If this is the end entry in the dirblk, then we have to go up to the parent,
+; if any.
+
+ff30: test byte ptr [bx].DIR_FLAG, DF_END
+ jz ff10 ; not end of dirblk - check next DirEnt
+;
+; Check to see if we have a parent (not the top block). If so, read
+; the parent dirblk and find the downpointer that matches the current
+; sector. Then continue searching after that point.
+;
+ mov bx, ScrOfs ; point to dirblk header
+ test byte ptr [bx].DB_CCNT, 1 ; 1 means top block
+ jz ff40 ; not top, continue with parent
+ jmp FileNotFound ; top block - not found
+
+;
+; read in parent dirblk and find the dirent with this downpointer -
+; then continue after that point
+;
+ff40: MOVEDD lsnSaveChild, SectorBase ; save this sector number
+ MOVEDD SectorBase, [bx].DB_PAR
+ call ReadScratch ; read the parent
+
+ mov bx, DB_START + ScrOfs ; start at first entry of child
+ jmp short ff44
+
+; find our current downpointer
+
+ff42: add bx, di ; move to the next dirent
+
+ff44: mov di, [bx].DIR_ELEN ; downptr is 4 bytes from end of dirent
+ mov ax, [bx+di-4].lsw
+ cmp ax, lsnSaveChild.lsw ; compare low 2 bytes
+ jne ff42 ; not equal, try next DirEnt
+ mov ax, [bx+di-4].msw
+ cmp ax, lsnSaveChild.msw ; compare high 2 bytes
+ jne ff42 ; not equal, try next DirEnt
+
+ jmp ff30 ; continue from here
+
+FindFile endp
+;****************************************************************************
+;
+; LoadFile - reads file in at the specified segment.
+;
+; ENTRY: ES:BX -> fnode of file to load
+; AX = segment address to load at.
+;
+; USES: all
+;
+LoadFile proc near
+ push ax ; save segment to load at.
+;
+; Here, we have found the file we want to read. Fetch relevant info
+; out of the DIRENT: the file's FNODE number and its size in bytes.
+;
+ sub bp, bp ; a zero register is handy.
+ MOVEDD FileSize, [bx].DIR_SIZE ; get file size
+ MOVEDD SectorBase, [bx].DIR_FN ; prepare to read FNODE
+ call ReadScratch ; read in the FNODE
+;
+ pop es ; restore segment to read at.
+ mov si, ScrOfs + FN_ALREC ; address the FNODE's array.
+ mov bx, ScrOfs + FN_AB ; address the FNODE's ALBLK.
+
+lf_go:
+ test byte ptr [bx].AB_FLAG, ABF_NODE ; are records nodes?
+ jnz lf_donode ; yes, go get a child.
+;
+; Here, we have a leaf block. Loop through the ALLEAF records,
+; reading each one's data run.
+;
+ mov cl, [bx].AB_OCNT ; get count of leaf records.
+ mov ch, 0 ; zero-extend.
+lf_loop:
+ MOVEDD SectorBase, [si].AL_POF ; load run start.
+ mov ax, word ptr [si].AL_LEN ; load run length.
+ mov SectorCount, ax
+ push bx ; save ALBLK pointer.
+ sub bx, bx ; read at ES:0000.
+ call DoRead
+ pop bx ; restore ALBLK pointer.
+ mov ax, es ; get segment we just used
+ shl SectorCount, 9 - 4 ; cvt sectors to paragraphs
+ add ax, SectorCount ; get new segment address
+ mov es, ax ; store new segadr in ES
+ add si, size ALLEAF ; point to next leaf
+ loop lf_loop ; go get another run
+;
+; Here, we've exhausted an array of records. If we exhausted the
+; FNODE, we're done. Otherwise, we re-read our parent block, restore
+; where we were in it, and advance to the next record.
+;
+lf_blockdone:
+ cmp word ptr ds:[ScrOfs+FN_SIG+2], FNSIGVAL shr 16 ; in FNODE?
+ je lf_alldone ; yes, we've read the whole file.
+ MOVEDD SectorBase, ds:[ScrOfs+AS_RENT] ; fetch parent sector pointer.
+ call ReadScratch ; read in our parent.
+ pop si ; restore where we left off.
+ pop bx ; restore ALBLK pointer.
+ add si, size ALNODE ; move to next node.
+;
+; Here the block contains downpointers. Read in the next child
+; block and process it as a node or leaf block, saving where we were
+; in the current block.
+;
+lf_donode:
+ mov al, [bx].AB_OCNT ; get number of records.
+ mov ah, 0 ; zero-extend.
+ shl ax, 3 ; (AX)=size of array.
+ add ax, bx
+ add ax, size ALBLK ; (AX)->after end of array.
+ cmp si, ax ; are we done?
+ jae lf_blockdone ; yes, we've exhausted this blk.
+ push bx ; save ALBLK offset.
+ push si ; save current record offset.
+ MOVEDD SectorBase, [si].AN_SEC ; get child downpointer.
+ call ReadScratch ; read the child ALSEC.
+ mov si, size ALSEC + ScrOfs ; address the ALSEC's array.
+ mov bx, AS_ALBLK + ScrOfs ; address the ALSEC's ALBLK.
+ jmp short lf_go
+;
+; All done, return to caller.
+;
+lf_alldone:
+ ret
+LoadFile endp
+
+;****************************************************************************
+;
+; UpcaseName - Converts the name of the file to all upper-case
+;
+; ENTRY: ES:BX -> dirent of file
+;
+; USES: CX, DI
+;
+UpcaseName proc near
+ mov cl,[bx].DIR_NAML
+ xor ch,ch ; (cx) = # of bytes in name
+ lea di, [bx].DIR_NAMA ; (es:di) = pointer to start of name
+UN10:
+ cmp byte ptr es:[di], 'Z' ; Is letter lowercase?
+ jbe UN20
+
+ sub byte ptr es:[di], 'a'-'A' ; Yes, convert to uppercase
+UN20:
+ inc di
+ loop UN10
+
+ ret
+UpcaseName endp
+
+FileNotFound:
+ jmp BootErr$fnf
+
+;******************************************************************************
+RootDB dd ? ; LSN of root DIRBLK.
+
+Flag db ? ; used to store AB_FLAG.
+
+AllocInfo db size ALLEAF * ALCNT dup (0) ; copy of FNODE alloc info.
+
+FileSize dd ? ; size of file that was read.
+
+
+ .errnz ($-_pinboot) GT (SEC_SUPERB*SECSIZE),<FATAL PROBLEM: main boot record exceeds available space>
+
+ org SEC_SUPERB*SECSIZE
+
+BootCode ends
+
+ end _pinboot
diff --git a/private/ntos/boot/bootcode/hpfs/i386/sources b/private/ntos/boot/bootcode/hpfs/i386/sources
new file mode 100644
index 000000000..e877d5d35
--- /dev/null
+++ b/private/ntos/boot/bootcode/hpfs/i386/sources
@@ -0,0 +1,38 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=utils
+MINORCOMP=pinboot
+
+TARGETNAME=pinboot
+TARGETPATH=obj
+TARGETTYPE=LIBRARY
+
+SOURCES=pinboot.asm
+
+INCLUDES=\nt\public\sdk\inc
+C_DEFINES=-DDBG -DMEMLEAK -DCONDITION_HANDLING=1 -DNOMINMAX
+UMLIBS=obj\*\chkdsk.lib
+
+UMTYPE=console
diff --git a/private/ntos/boot/bootcode/hpfs/i386/superb.inc b/private/ntos/boot/bootcode/hpfs/i386/superb.inc
new file mode 100644
index 000000000..e670b800b
--- /dev/null
+++ b/private/ntos/boot/bootcode/hpfs/i386/superb.inc
@@ -0,0 +1,242 @@
+;** SUPERB.H - Super Block and Spare Block definitions
+;
+; FILESYS
+; Gregory A. Jones
+; Copyright 1988 Microsoft Corporation
+;
+; Modification history:
+; P.A. Williams 06/01/89 Added fields SPB_CPSEC and SPB_CPCNT to
+; the spare block.
+; P.A. Williams 06/05/89 Changed base and functional version no. to 1.
+;
+
+SEC_SUPERB equ 16 ; superblock is after 8K boot block
+SEC_SPAREB equ 17 ; spareblock is after superblock
+SEC_BOOT equ 0 ; boot sector
+
+
+;* SUPERB.INC - Super Block Definition
+;
+; The Superblock is the first block of the file system.
+; It starts at sector #4, leaving 2K for boot sectors.
+;
+; Pointer to the root directory
+; Pointer to the bit map
+; Clean pointer
+; Pointer to the bad list
+;
+
+RSP struc
+ P dd ? ; main psector pointer
+ P2 dd ? ; spare pointer
+RSP ends
+
+
+SuperB struc
+ SB_SIG1 dd ? ; signature value 1
+ SB_SIG2 dd ? ; signature value 2
+
+ SB_VER db ? ; version # of filesystem structures
+ SB_FVER db ? ; functional version number - the smallest/
+ ; oldest version of the filesystem that can
+ ; understand this disk - some version
+ ; enhancements may define fields which can be
+ ; ignored by earlier versions
+
+ SB_DUMY dw ? ; free
+
+ SB_ROOT dd ? ; Psector # of root fnode
+
+ SB_SEC dd ? ; # of sectors on volume
+ SB_BSEC dd ? ; # of bad sectors on volume
+
+ SB_BII db (size RSP) dup (?) ; Bitmap Indirect Block
+ SB_BBL db (size RSP) dup (?) ; badblock list chain #1
+
+ SB_CDDAT dd ? ; date of last CHKDSK
+ SB_DODAT dd ? ; date of last Disk Optimize
+
+ SB_DBSIZE dd ? ; # of sectors in dirblk band
+ SB_DBLOW dd ? ; first Psector in DIRBLK band
+ SB_DBHIGH dd ? ; last Psector in DIRBLK band
+ SB_DBMAP dd ? ; first Psector of DIRBLK band bit map. Starts
+ ; on a 2K boundary, 2K bytes maximum
+
+ SB_VOLNAME db 32 dup (?) ; Volume name
+
+ SB_SIDSEC dd ? ; sector # of first sector in SIDTAB
+ ; ID map is 4K - 8 contiguous sectors
+
+ SB_FILL db 512-100 dup (?) ; fill definition out to 512 bytes
+ ; MUST BE ZERO
+
+SuperB ends
+
+
+
+;* SpareB - Spare Block Definitions
+;
+; SpareB contains various emergency supplies and fixup information.
+; This stuff isn't in the superblock in order for the superblock
+; to be read only and decrease the liklihood that a flakey write
+; will cause the superblock to become unreadable.
+;
+; This sector is located directly after the superblock - sector 5.
+;
+; Note that the number of spare DIRBLKs is a format option, given
+; that they all have to fit into the SpareB, giving us a max of
+; 101 of them.
+;
+; Access to the SpareB is complicated by the fact that we can't
+; access it via the cache, since the cache may be unavailable.
+; If every cache buffer is dirty, we could get a HotFix error when
+; writing the first one, which would deadlock us if we needed to
+; read this stuff via the cache. Instead, we read it directly into
+; a private buffer via RdHF.
+;
+; This means that the disk layout must be such that each cache cluster
+; that contains the SpareB or the hotfix list must not contain any
+; other writable sector, to prevent us from having a modified
+; direct-written sector overwritten by an earlier unmodified copy
+; which was in a cache block. It's ok for the SuperB to be in the
+; same cache group as the SpareB since the SuperB is RO to the filesys.
+;
+; Checksums. Done on both Super Block and the Spare Block.
+; Both checksums are stored in the Spare Block. The checksum
+; field for the Super Block (SPB_SUPERBSUM) must be set when
+; calculating the checksum for the Spare Block. The checksum
+; field for the Spare Block (SPB_SPAREBSUM) must be zero when
+; calculating the checksum for the Spare Block.
+; If both checksum fields are zero, the checksums have not been
+; calculated for the volume.
+;
+
+SPAREDB equ 20 ; 20 spare DIRBLKs
+
+SpareB struc
+
+ SPB_SIG1 dd ? ; signature value 1
+ SPB_SIG2 dd ? ; signature value 2
+
+ SPB_FLAG db ? ; cleanliness flag
+ SPB_ALIGN db 3 dup (?) ; alignment
+
+ SPB_HFSEC dd ? ; first hotfix list P sector
+ SPB_HFUSE dd ? ; # of hot fixes in effect
+ SPB_HFMAX dd ? ; max size of hot fix list
+
+ SPB_SDBCNT dd ? ; # of spare dirblks
+ SPB_SDBMAX dd ? ; maximum number of spare DB values.
+ SPB_CPSEC dd ? ; code page sector
+ SPB_CPCNT dd ? ; number of code pages
+ SPB_SUPERBSUM dd ? ; Checksum of Super Block
+ SPB_SPAREBSUM dd ? ; Checksum of Spare Block
+ SPB_DUMY dd 15 dup (?) ; some extra space for future use
+ SPB_SPARDB dd 101 dup (?) ; Psector #s of spare dirblks
+SpareB ends
+
+
+; Super Block Signature
+
+SBSIG1 equ 0f995e849h ; two signatures cause we got lotsa
+SBSIG2 equ 0FA53E9C5h ; space
+SPSIG1 equ 0f9911849h ; two signatures cause we got lotsa
+SPSIG2 equ 0FA5229C5h ; space
+
+
+
+; Superblock Versions
+
+SBBASEV equ 2 ; base version
+SBBASEFV equ 2 ; base functional version
+
+; Spare Block Flags
+;
+
+SPF_DIRT equ 0001h ; file system is dirty
+SPF_SPARE equ 0002h ; spare DIRBLKs have been used
+SPF_HFUSED equ 0004h ; hot fix sectors have been used
+SPF_BADSEC equ 0008h ; bad sector, corrupt disk
+SPF_BADBM equ 0010h ; bad bitmap block
+SPF_VER equ 0080h ; file system was written by a version
+ ; < SB_VER, so some of the new fields
+ ; may have not been updated
+
+
+;* Bit maps
+;
+; PFS keeps track of free space in a series of bit maps.
+; Currently, each bit map is 2048 bytes, which covers about
+; 8 megabytes of disk space. We could rearrange these to be
+; more cylinder sensitive...
+;
+; The superblock has the address of a section of contiguous sectors
+; that contains a double word sector # for each bit map block. This
+; will be a maximum of 2048 bytes (4 sectors)
+;
+; Max # of size RAM (K) size 2nd lvl
+; bitmaps (meg) to reside bitmap
+; bitmap (bytes)
+;
+; 1 8.39 2 256
+; 2 16.78 4 512
+; 3 25.17 6 768
+; 4 33.55 8 1024
+; 5 41.94 10 1280
+; 6 50.33 12 1536
+; 7 58.72 14 1792
+; 8 67.11 16 2048
+; 9 75.50 18 2304
+; 10 83.89 20 2560
+; 15 125.83 30 3840
+; 20 167.77 40 5120
+; 30 251.66 60 7680
+; 40 335.54 80 10240
+; 50 419.43 100 12800
+; 100 838.86 200 25600
+; 200 1677.72 400 51200
+; 300 2516.58 600 76800
+; 400 3355.44 800 102400
+; 500 4194.30 1000 128000
+;
+
+
+
+;* Hot Fixing
+;
+; Each file system maintains a structure listing N "hot fix"
+; disk clusters of HOTFIXSIZ sectors each, each starting on
+; a multiple of HOTFIXSIZ. Whenever the file system discovers
+; that it's trying to write to a bad spot on the disk it will
+; instead select a free hot fix cluster and write there, instead.
+; The substitution will be recorded in the hot fix list, and the
+; SBF_SPARE bit will be set. The file system sill describes the
+; data as being in the bad old sectors; the disk interface will
+; do a mapping between the `believed' location and the true location.
+;
+; CHKDSK will be run as soon as possible; it will move the
+; hot fixed data from the hot fix cluster to somewhere else,
+; freeing that hot fix cluster, and adjusting the disk structure
+; to point to the new location of the data. As a result, entrys
+; on the hot fix list should be transient and few.
+;
+; The superblock contains the first sector of the hot fix list
+; which takes the following format:
+;
+; long oldsec[SB_HFMAX]; sector # of start of bad clusters
+; long newsec[SB_HFMAX]; sector # of start of subst. cluster
+; long fnode [SB_HFMAX]; fnode sector of file/directory
+; involved with bad cluster. May be
+; 0 (don't know) or invalid. The
+; repair program must verify that it
+; *is* an FNODE and must see if other
+; structures might also involve this
+; bad cluster.
+;
+; the SB_HFUSE field describes the number of these records which is
+; in use - unused ones should have oldsec[i] = 0. The list will
+; be 'dense' - no oldsec[i] will be 0 where i < SB_HFUSE.
+;
+; The sector(s) which contain the hot fix list must be contiguous
+; and may not themselves be defective.
+;
diff --git a/private/ntos/boot/bootcode/hpfs/i386/tables.inc b/private/ntos/boot/bootcode/hpfs/i386/tables.inc
new file mode 100644
index 000000000..07cf61244
--- /dev/null
+++ b/private/ntos/boot/bootcode/hpfs/i386/tables.inc
@@ -0,0 +1,201 @@
+;static char *SCCSID = "@(#)tables.h 12.2 88/12/19";
+ifdef MASM
+ BREAK <OFT - Open File Table>
+endif
+
+;* OFT - Open File Table
+;
+; The OFT contains file specific information which is independent
+; of an instance of use of the file.
+;
+; If the file is open for write access, we keep a pointer to
+; it's directory entry, not just it's
+; FNODE, so that we can update the length and modification time when it's
+; written.
+;
+; We store the directory's FNODE number and the file name, with these
+; we can find the directory entry again even if the directory has
+; been shuffled by creates or deletes of other files. Two advisorys
+; are kept - the Vsector number, cache block address, and cache block
+; offset of the actual directory entry. This information has three
+; levels of validity:
+;
+; 1) Vsector, header address, and offset are valid
+; you can find the dir entry easily
+; 2) the header address is invalid due to cache flushing.
+; Vsector # and offset are still valid, so read the
+; cache block and go directly to the entry
+; In this case the header address points to the wrong
+; Vsector
+; 3) the directory has been altered since we opened the file,
+; so none of this info is accurate. In this case the
+; directory alteration routines located this OFT
+; entry and zeroed the Vsector number. Go to the directory
+; and search the name again.
+;
+
+OFT struc
+ OFT_P db (size DCHDR) dup (?) ; double chain of OFT structures, rooted in OFTHead[i]
+ OFT_FHT db (size DCHDR) dup (?) ; double chain of FHT structures
+ OFT_RLCK db (size DCHDR) dup (?) ; double chain of RECLOCK structures
+ OFT_FN db (size SECPTR) dup (?) ; pointer to file FNODE
+ OFT_SBD dw ? ; pointer to SBDIR structure
+ OFT_DIRE db (size SECPTR) dup (?) ; pointer to directory block
+
+ OFT_CCNT dd ? ; DB_CCNT value for OFT_DIRE to check OFT_DIRO validity
+ OFT_FREEDCNT dd ? ; SD_FREEDCNT value for DIRE to be valid
+
+;
+; These length fields are used when writing the file.
+; The OFN_ entries will reflect the OFT_ALEN value. These
+; aren't updated in the FNODE until the file closes, whereup
+; they are trimmed back to OFT_LEN which is itself propigated
+; to the file's DIR entry. If write-through is set then the
+; OFN_ entries below will be propigated to the FNODE and
+; then to the disk, but if we crash the cleanup program
+; will deallocate the "extra" sectors.
+;
+
+ OFT_LEN dd ? ; file actual length
+ OFT_ALEN dd ? ; file allocated length (SECSIZE multiple)
+ OFT_WLEN dd ? ; last byte+1 of valid data in the file
+ ; (optimization for writing into extended areas
+ OFT_LAST dd ? ; Psector # of last sector in file, or 0
+ OFT_LRP db (size SECPTR) dup (?) ; last run pointer. Valid if OFT_LAST !=0
+ ; if OFN_AB.ABF_NODE ==0 this is the address of
+ ; an OFN_SEC record in this OFT
+ ; else this is a SECPTR to the SIB
+ ; containing the last run record
+
+ OFT_VOL dd ? ; pointer to VOLTAB for this guy
+
+ OFT_NAME dd ? ; address of name string len byte
+ ; followed by name string itself
+ ; len doesn't include len byte
+
+ OFT_DIRO dw ? ; offset into directory block for entry
+ OFT_FILL dw ? ; unused, fill
+
+ OFT_LCKCNT dw ? ; count of guys in OFT_RLCK
+
+ OFT_WCNT dw ? ; # of threads blocked on this OFT
+
+ ; the following three fields are used to
+ ; control access. They're identical in use
+ ; to the equivalent fields in SBDIR. The
+ ; Flag byte only contains locking/holding
+ ; flags, so if DWORD PTR OFT_HCNT is 0 then
+ ; the OFT is known to be free and clear
+
+ OFT_HCNT dw ? ; held count, has OTF_PND bit also
+ OFT_DMY db ? ; unused, must be 0
+ OFT_FLAG db ? ; flag byte, high order in OFT_HCNT dword
+
+ OFT_WAITC dd ? ; head of wait chain if locked
+
+ OFT_OPLOCK dd ? ; Oplock value, 0 if none
+
+ OFT_BANDP dd ? ; pointer to BandTab structure in BandList
+ ; for our last allocation. =0 if unused
+
+; The following 5 fields hold the accumulation of all FHTs for this OFT.
+; This saves us from having to scan the FHTs to do a sharing check upon
+; open. An OFT is unused when OFT_RD and OFT_WT and OFT_FIND are zero
+
+ OFT_RD dw ? ; # of opens for read
+ OFT_WT dw ? ; # of opens for write
+ OFT_DR dw ? ; # of opens with deny read
+ OFT_DW dw ? ; # of opens with deny write
+ OFT_COMPAT dw ? ; # of opens for compatibility mode
+ OFT_FIND dw ? ; count of active FINDs using this OFT
+
+ OFT_REALLYBAD db ? ; non-zero if file is unusable due to
+ ; corrupt disk BUGBUG - FOLD INTO BITS
+ OFT_SFLAG db ? ; special flag byte
+ OFT_DMY2 dw ? ; unused
+
+
+; BUGBUG - rearrange these fields for er offsets dw ?
+;
+; Info copied from the file's FNODE
+;
+; The ALLEAF blocks must follow the ALBLK value
+;
+
+ OFN_AB db (size ALBLK) dup (?) ; allocation block structure
+ OFN_ALREC db (8*size ALLEAF) dup (?) ; referenced from FN_AB
+
+OFT ends
+
+; flag bits for OFT_FLAG
+
+OTF_LCK equ 01h ; file is locked against access
+OTF_PLK equ 02h ; pending lock
+OTF_PSO equ 04h ; pending solo
+OTF_PND equ 80h ; lock pending bit
+
+; flag bits for OFT_SFLAG
+
+OFS_OPLK equ 01h ; oplocked
+OFS_OPBA equ 02h ; oplock BATCH flag set
+OFS_DASD equ 04h ; DASD file
+ifdef DEBUG
+OFS_SAC equ 08h ; supress OFT_ALEN debug check
+endif
+
+; The file storage information from the fnode is replicated
+; in the OFT. This saves us from having to blow a cache block
+; keeping the FNODE in ram for every open file. The FNODE
+; is only accessed when a file is open, and when it's closed.
+; (If write-through is set, it's accessed for every growth)
+;
+; These statements are to keep the FNODE and the OFT in sync.
+
+ifdef MASM
+ .errnz (size OFN_ALREC - size FN_ALREC)
+endif
+
+
+;* FHT - File Handle Table
+;
+; The FHT contains per-handle informatiuon
+
+FHT struc
+ FHT_SEEK dd ? ; seek pointer
+ FHT_OFT dd ? ; pointer to OFT
+ FHT_CHN db (size DCHDR) dup (?) ; chain of FHTs for an OFT
+ FHT_UID dd ? ; UID and Session ID
+ FHT_MODE dw ? ; mode bits from OPEN
+ FHT_RAA dw ? ; read ahead advisory
+ FHT_HINT dd ? ; hint flags
+FHT ends
+
+ifdef MASM
+ .errnz FHT_CHN-OFT_FHT ; same offset used for both
+endif
+
+;* FHT_HINT flags
+
+FHH_SEQ equ 01 ; sequential file
+
+
+;* RecLock - Record Locking Records
+;
+; One record per lock, chained to the OFT. These are chained
+; in order RL_BEG
+;
+
+RECLOCK struc
+ RL_BEG dd ? ; begining byte of locked range
+ RL_END dd ? ; end byte of locked range
+ RL_TYPE db ? ; =1 if read allowed, =0 if full lock
+ RL_MEM db ? ; =0 if from heap, =1 if from special list
+ RL_DMY dw ? ; padding
+ RL_SPID dd ? ; Session/Pid
+ RL_CHN db (size DCHDR) dup (?) ; double chain of RECLOCK structures
+RECLOCK ends
+
+ifdef MASM
+ .errnz RL_CHN-OFT_RLCK ; must have same offset to work
+endif
+ \ No newline at end of file
diff --git a/private/ntos/boot/bootcode/hpfs/i386/usa/boothpfs.h b/private/ntos/boot/bootcode/hpfs/i386/usa/boothpfs.h
new file mode 100644
index 000000000..b9ff8c722
--- /dev/null
+++ b/private/ntos/boot/bootcode/hpfs/i386/usa/boothpfs.h
@@ -0,0 +1,517 @@
+#define HPFSBOOTCODE_SIZE 8192
+
+
+unsigned char HpfsBootCode[] = {
+235,73,144,73,66,77,32,49,48,46,50,0,2,4,1,0,
+2,0,2,0,0,248,41,0,17,0,4,0,17,0,0,0,
+195,162,0,0,128,0,40,21,156,213,100,67,45,68,82,73,
+86,69,0,0,0,0,72,80,70,83,32,32,32,32,0,0,
+0,0,0,0,0,0,0,0,0,0,0,250,51,192,142,208,
+188,0,124,251,184,192,7,142,216,199,6,62,0,0,0,199,
+6,64,0,0,0,199,6,69,0,20,0,184,0,13,142,192,
+43,219,232,7,0,104,0,13,104,0,2,203,80,83,81,82,
+6,161,62,0,139,22,64,0,3,6,28,0,19,22,30,0,
+247,54,24,0,254,194,136,22,68,0,51,210,247,54,26,0,
+136,22,37,0,163,66,0,161,24,0,42,6,68,0,64,59,
+6,69,0,118,3,161,69,0,80,180,2,139,22,66,0,177,
+6,210,230,10,54,68,0,139,202,134,233,139,22,36,0,205,
+19,88,114,37,1,6,62,0,131,22,64,0,0,41,6,69,
+0,118,11,193,224,5,140,194,3,208,142,194,235,147,7,90,
+89,91,88,195,190,57,1,235,3,190,25,1,232,9,0,190,
+141,1,232,3,0,251,235,254,172,60,0,116,9,180,14,187,
+7,0,205,16,235,242,195,29,0,65,32,100,105,115,107,32,
+114,101,97,100,32,101,114,114,111,114,32,111,99,99,117,114,
+114,101,100,46,13,10,0,41,0,65,32,107,101,114,110,101,
+108,32,102,105,108,101,32,105,115,32,109,105,115,115,105,110,
+103,32,102,114,111,109,32,116,104,101,32,100,105,115,107,46,
+13,10,0,37,0,65,32,107,101,114,110,101,108,32,102,105,
+108,101,32,105,115,32,116,111,111,32,100,105,115,99,111,110,
+116,105,103,117,111,117,115,46,13,10,0,51,0,73,110,115,
+101,114,116,32,97,32,115,121,115,116,101,109,32,100,105,115,
+107,101,116,116,101,32,97,110,100,32,114,101,115,116,97,114,
+116,13,10,116,104,101,32,115,121,115,116,101,109,46,13,10,
+0,5,78,84,76,68,82,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,85,170,
+140,200,142,216,5,128,2,142,192,140,216,193,224,4,250,139,
+224,251,187,12,32,139,7,163,62,0,139,71,2,163,64,0,
+199,6,69,0,1,0,43,219,232,58,0,38,139,71,72,163,
+27,4,38,139,71,74,163,29,4,190,193,1,161,27,4,163,
+62,0,161,29,4,163,64,0,232,138,0,184,0,32,232,16,
+1,138,22,36,0,184,232,3,142,192,141,54,11,0,43,192,
+104,0,32,80,203,80,83,81,82,6,255,54,69,0,255,54,
+62,0,255,54,64,0,139,195,193,232,4,140,193,3,193,37,
+255,15,45,0,16,247,216,139,14,69,0,193,225,5,81,59,
+193,118,2,139,193,80,193,232,5,163,69,0,232,221,253,88,
+89,43,200,118,11,140,194,3,208,142,194,184,0,16,235,222,
+143,6,64,0,143,6,62,0,143,6,69,0,7,90,89,91,
+88,195,6,83,199,6,69,0,4,0,30,7,187,0,40,232,
+147,255,91,7,195,30,7,232,232,255,43,201,138,12,70,139,
+209,187,20,40,235,5,3,31,232,23,1,139,198,139,202,141,
+127,31,243,166,139,240,117,6,58,87,30,117,1,195,246,71,
+2,4,116,19,3,31,139,71,252,163,62,0,139,71,254,163,
+64,0,232,173,255,235,202,246,71,2,8,116,201,187,0,40,
+246,71,8,1,116,3,233,239,0,161,62,0,163,71,0,161,
+64,0,163,73,0,139,71,12,163,62,0,139,71,14,163,64,
+0,232,126,255,187,20,40,235,2,3,223,139,63,139,65,252,
+59,6,71,0,117,243,139,65,254,59,6,73,0,117,234,235,
+182,80,43,237,139,71,12,163,128,4,139,71,14,163,130,4,
+139,71,4,163,62,0,139,71,6,163,64,0,232,67,255,7,
+190,64,40,187,56,40,246,7,128,117,76,138,79,5,181,0,
+139,68,8,163,62,0,139,68,10,163,64,0,139,68,4,163,
+69,0,83,43,219,232,189,254,91,140,192,193,38,69,0,5,
+3,6,69,0,142,192,131,198,12,226,213,129,62,2,40,228,
+247,116,62,161,8,40,163,62,0,161,10,40,163,64,0,232,
+240,254,94,91,131,198,8,138,71,5,180,0,193,224,3,3,
+195,5,8,0,59,240,115,211,83,86,139,68,4,163,62,0,
+139,68,6,163,64,0,232,201,254,190,20,40,187,12,40,235,
+133,195,138,79,30,50,237,141,127,31,38,128,61,90,118,4,
+38,128,45,32,71,226,243,195,233,217,252,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+};
diff --git a/private/ntos/boot/bootcode/hpfs/i386/usa/pinboot.inc b/private/ntos/boot/bootcode/hpfs/i386/usa/pinboot.inc
new file mode 100644
index 000000000..6a2925984
--- /dev/null
+++ b/private/ntos/boot/bootcode/hpfs/i386/usa/pinboot.inc
@@ -0,0 +1,30 @@
+; SCCSID = @(#)pinboot.inc 12.1 88/12/19
+; Message data area
+TXT_MSG_SYSINIT_BOOT_ERROR LABEL WORD
+ DW END_MSG_SYSINIT_BOOT_ERROR - TXT_MSG_SYSINIT_BOOT_ERROR - 2
+ DB 'A disk read erro'
+ DB 'r occurred.',0DH,0AH
+END_MSG_SYSINIT_BOOT_ERROR LABEL WORD
+ DB 0
+TXT_MSG_SYSINIT_FILE_NOT_FD LABEL WORD
+ DW END_MSG_SYSINIT_FILE_NOT_FD - TXT_MSG_SYSINIT_FILE_NOT_FD - 2
+ DB 'A kernel file is'
+ DB ' missing from th'
+ DB 'e disk.', 0DH, 0AH
+END_MSG_SYSINIT_FILE_NOT_FD LABEL WORD
+ DB 0
+TXT_MSG_SYSINIT_NODE LABEL WORD
+ DW END_MSG_SYSINIT_NODE - TXT_MSG_SYSINIT_NODE - 2
+ DB 'A kernel file is'
+ DB ' too discontiguo'
+ DB 'us.', 0DH, 0AH
+END_MSG_SYSINIT_NODE LABEL WORD
+ DB 0
+TXT_MSG_SYSINIT_INSER_DK LABEL WORD
+ DW END_MSG_SYSINIT_INSER_DK - TXT_MSG_SYSINIT_INSER_DK - 2
+ DB 'Insert a system '
+ DB 'diskette and res'
+ DB 'tart',0DH,0AH
+ DB 'the system.',0DH,0AH
+END_MSG_SYSINIT_INSER_DK LABEL WORD
+ DB 0
diff --git a/private/ntos/boot/bootcode/hpfs/i386/volume.inc b/private/ntos/boot/bootcode/hpfs/i386/volume.inc
new file mode 100644
index 000000000..dbeba1b9d
--- /dev/null
+++ b/private/ntos/boot/bootcode/hpfs/i386/volume.inc
@@ -0,0 +1,102 @@
+;static char *SCCSID = "@(#)volume.h 12.2 89/09/19";
+; Maximum number of volumes that we can mount
+;
+; The volume ID is kept in the high bits of the sector numbers
+; kept in our RAM structures,
+; so there is a tradeoff between max volumes and max sectors.
+;
+; 32 max volumes gives us a 65 billion byte volume limit,
+; which should last us for a while. Since sector numbers
+; are stored on the disk without their volume upper bits
+; this is strictly an implimentation detail; we can adjust
+; the number of volumes or eliminate this tradeoff in other
+; implimentations which will be 100% media compatable.
+;
+; We use the term VSector to indicate a vol/sector combination
+; and PSector to indicate just the physical absolute sector #
+;
+;
+
+
+; Bitmap related numbers
+
+BANDSHIFT equ BSHIFT+3 ; right shift sector # to band index
+BANDMASK equ SPB*SECSIZE*8L-1 ; mask for within band bits
+BANDSIZE equ SPB*SECSIZE*8L ; # of sectors in a full band
+
+
+;* BandTab - Disk Band Table
+;
+; The disk is broken up into logical bands, each band being
+; the amount of space that is addressed in 2K of bitmap.
+;
+; This structure tracks the bands: the location of their respective
+; bit maps, the amount of free space, etc.
+;
+
+BANDTAB struc
+ BT_MAP db (size SECPTR) dup (?) ; Vsector # and hint pointer for map
+ BT_FREE dw ? ; # of free sectors in this band
+ BT_OFC dw ? ; # of files allocating from this band
+ BT_BASE dd ? ; Psector # of first sector in map
+ BT_LEN dd ? ; byte length of this map
+ BT_HWO dd ? ; high water offset to 1st non-zero byte
+ ; BUGBUG - use BT_HWO
+BANDTAB ends
+
+
+;* VolTab - Volume Table
+;
+; VolPtr[i] points to the VolTab structure for that volume.
+; This table contains volume specific information.
+;
+; Nearly all file system API refers to a single particular volume.
+; The proper volume is determined when the file system is entered
+; and the TDB structure contains a pointer to it. Most code ignores
+; volumes and deals with 32 bit physical sector #'s. When we're about
+; to interface with the device driver we then peek at the "global"
+; volume value pointed to by TDB.
+;
+; There are two exceptions to this, where per-volume structures are
+; pooled, the buffer pool and the OFT pool. In these two cases the
+; sector number has the volume index set in it's high order VOLLSHIFT
+; bits so that a single DWORD compare will qualify a sector on both
+; a volume and sector basis.
+;
+
+VOLTAB struc
+ VOL_FFLAG db ? ; Fault flags - checked on most calls
+ VOL_SFLAG db ? ; status flags
+ VOL_PAD dw ? ; unused - bugbug
+ VOL_SECVAL dd ? ; value to set on high order part of sector #
+ VOL_BCNT dw ? ; # of bitmap bands in this volume
+ VOL_VDBCnt dw ? ; count of outstanding VerifyDB calls *.
+ VOL_SDBcnt dd ? ; count of spare DIRBLKs left for volume, if
+ ; all are unused, else 0
+ VOL_SBSEC dd ? ; SB_SEC value from superblock
+ VOL_DB db (size BANDTAB) dup (?) ; DIRBLK bandtab
+ VOL_ROOT dw ? ; Root SBDIR pointer
+ VOL_SPACE dd ? ; alloctable space limit
+ VOL_DBSIZE dd ? ; copy of SP_DBSIZE value
+ VOL_HFUSE dd ? ; # of hot fixes in effect
+ VOL_HFMAX dd ?
+ VOL_HFPTR dd ? ; address of hotfix heap array - bad sectors
+ VOL_HFNEW dd ? ; address of substitute list - replacement sectors
+ VOL_BPTR dw 1 dup (?) ; first of VOL_BCNT pointers
+ ; one per band. The BANDTABs that they
+ ; point to must be physically contiguous
+VOLTAB ends
+
+; VOL_FFLAG fault flags
+;
+; these represent conditions that we're trying to repair,
+; we check these on most major file system calls
+;
+
+VF_NEEDHOT equ 01h ; hotfix list is partially used
+VF_NEEDDIR equ 02h ; dirblk reserved list is partially used
+
+; VOL_SFLAG status flags
+;
+
+VS_BADSEC equ 01h ; we have at least one bad sector on there
diff --git a/private/ntos/boot/bootcode/mbr/i386/usa/bootmbr.h b/private/ntos/boot/bootcode/mbr/i386/usa/bootmbr.h
new file mode 100644
index 000000000..f735c6160
--- /dev/null
+++ b/private/ntos/boot/bootcode/mbr/i386/usa/bootmbr.h
@@ -0,0 +1,37 @@
+#define X86BOOTCODE_SIZE 512
+
+
+unsigned char x86BootCode[] = {
+250,51,192,142,208,188,0,124,139,244,80,7,80,31,251,252,
+191,0,6,185,0,1,243,165,234,29,6,0,0,190,190,7,
+179,4,128,60,128,116,14,128,60,0,117,28,131,198,16,254,
+203,117,239,205,24,139,20,139,76,2,139,238,131,198,16,254,
+203,116,26,128,60,0,116,244,190,139,6,172,60,0,116,11,
+86,187,7,0,180,14,205,16,94,235,240,235,254,191,5,0,
+187,0,124,184,1,2,87,205,19,95,115,12,51,192,205,19,
+79,117,237,190,163,6,235,211,190,194,6,191,254,125,129,61,
+85,170,117,199,139,245,234,0,124,0,0,73,110,118,97,108,
+105,100,32,112,97,114,116,105,116,105,111,110,32,116,97,98,
+108,101,0,69,114,114,111,114,32,108,111,97,100,105,110,103,
+32,111,112,101,114,97,116,105,110,103,32,115,121,115,116,101,
+109,0,77,105,115,115,105,110,103,32,111,112,101,114,97,116,
+105,110,103,32,115,121,115,116,101,109,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,85,170
+};
diff --git a/private/ntos/boot/bootcode/mbr/i386/usa/x86mboot.msg b/private/ntos/boot/bootcode/mbr/i386/usa/x86mboot.msg
new file mode 100644
index 000000000..18bfbe446
--- /dev/null
+++ b/private/ntos/boot/bootcode/mbr/i386/usa/x86mboot.msg
@@ -0,0 +1,5 @@
+;******** messages for the Fixed Disk Boot Record ******
+;
+m1: db "Invalid partition table",0
+m2: db "Error loading operating system",0
+m3: db "Missing operating system",0
diff --git a/private/ntos/boot/bootcode/mbr/i386/x86mboot.asm b/private/ntos/boot/bootcode/mbr/i386/x86mboot.asm
new file mode 100644
index 000000000..117f16296
--- /dev/null
+++ b/private/ntos/boot/bootcode/mbr/i386/x86mboot.asm
@@ -0,0 +1,133 @@
+;/*
+; * Microsoft Confidential
+; * Copyright (C) Microsoft Corporation 1983 - 1991
+; * All Rights Reserved.
+; */
+; BOOT - IBM hard disk boot record 6/8/82
+;
+;
+; This is the standard boot record that will be shipped on all hard disks. It contains:
+;
+; 1. Code to load (and give control to) the boot record for 1 of 4 possible
+; operating systems.
+;
+; 2. A partition table at the end of the boot record, followed by the required signature.
+;
+;
+
+relocated_org equ 0600h
+buildtime_org equ 0100h
+org_delta equ (relocated_org - buildtime_org)
+
+_data segment public
+ assume cs:_data,ds:_data
+
+;
+; /tiny programs start at 100h.
+;
+
+ org buildtime_org
+start:
+
+ cli ;no interrupts for now
+ xor ax,ax
+ mov ss,ax
+ mov sp,7c00h ;new stack at 0:7c00
+ mov si,sp ;where this boot record starts - 0:7c00
+ push ax
+ pop es ;seg regs the same
+ push ax
+ pop ds
+ sti ;interrupts ok now
+ cld
+ mov di,relocated_org ;where to relocate this boot record to
+ mov cx,100h
+ rep movsw ;relocate to 0:0600
+; jmp entry2 + org_delta
+ db 0eah
+ dw $+4+org_delta,0
+entry2:
+ mov si,(offset tab) + org_delta ;partition table
+ mov bl,4 ;number of table entries
+next:
+ cmp byte ptr[si],80h ;is this a bootable entry?
+ je boot ;yes
+ cmp byte ptr[si],0 ;no, is boot indicator zero?
+ jne bad ;no, it must be x"00" or x"80" to be valid
+ add si,16 ;yes, go to next entry
+ dec bl
+ jnz next
+ int 18h ;no bootable entries - go to rom basic
+boot:
+ mov dx,[si] ;head and drive to boot from
+ mov cx,[si+2] ;cyl, sector to boot from
+ mov bp,si ;save table entry address to pass to partition boot record
+next1:
+ add si,16 ;next table entry
+ dec bl ;# entries left
+ jz tabok ;all entries look ok
+ cmp byte ptr[si],0 ;all remaining entries should begin with zero
+ je next1 ;this one is ok
+bad:
+ mov si,(offset m1) + org_delta ;oops - found a non-zero entry - the table is bad
+msg:
+ lodsb ;get a message character
+ cmp al,0
+ je hold
+ push si
+ mov bx,7
+ mov ah,14
+ int 10h ;and display it
+ pop si
+ jmp msg ;do the entire message
+;
+hold: jmp hold ;spin here - nothing more to do
+tabok:
+ mov di,5 ;retry count
+rdboot:
+ mov bx,7c00h ;where to read system boot record
+ mov ax,0201h ;read 1 sector
+ push di
+ int 13h ;get the boot record
+ pop di
+ jnc goboot ;successful - now give it control
+ xor ax,ax ;had an error, so
+ int 13h ;recalibrate
+ dec di ;reduce retry count
+ jnz rdboot ;if retry count above zero, go retry
+ mov si,(offset m2) + org_delta ;all retries done - permanent error - point to message,
+ jmp msg ;go display message and loop
+goboot:
+ mov si,(offset m3) + org_delta ;prepare for invalid boot record
+ mov di,07dfeh
+ cmp word ptr [di],0aa55h ;does the boot record have the
+ ; required signature?
+ jne msg ;no, display invalid system boot record message
+ mov si,bp ;yes, pass partition table entry address
+ db 0eah
+ dw 7c00h,0
+
+include x86mboot.msg
+
+ org 2beh
+tab: ;partition table
+ dw 0,0 ;partition 1 begin
+ dw 0,0 ;partition 1 end
+ dw 0,0 ;partition 1 relative sector (low, high parts)
+ dw 0,0 ;partition 1 # of sectors (low, high parts)
+ dw 0,0 ;partition 2 begin
+ dw 0,0 ;partition 2 end
+ dw 0,0 ;partition 2 relative sector
+ dw 0,0 ;partition 2 # of sectors
+ dw 0,0 ;partition 3 begin
+ dw 0,0 ;partition 3 end
+ dw 0,0 ;partition 3 relative sector
+ dw 0,0 ;partition 3 # of sectors
+ dw 0,0 ;partition 4 begin
+ dw 0,0 ;partition 4 end
+ dw 0,0 ;partition 4 relative sector
+ dw 0,0 ;partition 4 # of sectors
+signa db 55h,0aah ;signature
+
+_data ends
+ end start
diff --git a/private/ntos/boot/bootcode/ntfs/i386/ntfs.inc b/private/ntos/boot/bootcode/ntfs/i386/ntfs.inc
new file mode 100644
index 000000000..1782f4fc9
--- /dev/null
+++ b/private/ntos/boot/bootcode/ntfs/i386/ntfs.inc
@@ -0,0 +1,214 @@
+;
+; Copyright (c) 1991 Microsoft Corporation
+;
+; Module Name:
+;
+; ntfs.inc
+;
+; Abstract:
+;
+; This module contains declarations for the NTFS on-disk
+; structures needed by the boot code.
+;
+; Author:
+;
+; Bill McJohn (billmc) 12-May-1992
+;
+MASTER_FILE_TABLE_NUMBER EQU 0d
+MASTER_FILE_TABLE2_NUMBER EQU 1d
+LOG_FILE_NUMBER EQU 2d
+VOLUME_DASD_NUMBER EQU 3d
+ATTRIBUTE_DEF_TABLE_NUMBER EQU 4d
+ROOT_FILE_NAME_INDEX_NUMBER EQU 5d
+BIT_MAP_FILE_NUMBER EQU 6d
+BOOT_FILE_NUMBER EQU 7d
+BAD_CLUSTER_FILE_NUMBER EQU 8d
+QUOTA_TABLE_NUMBER EQU 9d
+UPCASE_TABLE_NUMBER EQU 10d
+
+$STANDARD_INFORMATION EQU 010h
+$ATTRIBUTE_LIST EQU 020h
+$FILE_NAME EQU 030h
+$VOLUME_VERSION EQU 040h
+$SECURITY_DESCRIPTOR EQU 050h
+$VOLUME_NAME EQU 060h
+$VOLUME_INFORMATION EQU 070h
+$DATA EQU 080h
+$INDEX_ROOT EQU 090h
+$INDEX_ALLOCATION EQU 0A0h
+$BITMAP EQU 0B0h
+$SYMBOLIC_LINK EQU 0C0h
+$EA_INFORMATION EQU 0D0h
+$EA_DATA EQU 0E0h
+$FIRST_USER_DEFINED_ATTRIBUTE EQU 0100h
+$END EQU 0FFFFFFFFh
+
+SEQUENCE_NUMBER_STRIDE EQU 512d
+
+
+LARGE_INTEGER struc
+ LowPart dd ?;
+ HighPart dd ?;
+LARGE_INTEGER ends;
+
+MFT_SEGMENT_REFERENCE struc
+ REF_LowPart dd ?;
+ REF_HighPart dw ?;
+ REF_SeqNo dw ?;
+MFT_SEGMENT_REFERENCE ends;
+
+MULTI_SECTOR_HEADER struc
+ MSH_Signature dd ?;
+ MSH_UpdateArrayOfs dw ?;
+ MSH_UpdateArraySize dw ?;
+MULTI_SECTOR_HEADER ends;
+
+FILE_RECORD_SEGMENT struc
+ FRS_Header db (size MULTI_SECTOR_HEADER) dup (?);
+ FRS_Lsn db (size LARGE_INTEGER) dup (?);
+ FRS_SequenceNumber dw ?;
+ FRS_ReferenceCount dw ?;
+ FRS_FirstAttribute dw ?;
+ FRS_Flags dw ?;
+ FRS_FirstFreeByte dd ?;
+ FRS_BytesAvailable dd ?;
+ FRS_BaseFRS db (size MFT_SEGMENT_REFERENCE) dup (?);
+ FRS_NextInstance dw ?;
+FILE_RECORD_SEGMENT ends;
+
+FILE_RECORD_SEGMENT_IN_USE EQU 0001h
+FILE_FILE_NAME_INDEX_PRESENT EQU 0002h
+
+ATTRIBUTE_RECORD struc
+ ATTR_TypeCode dd ?;
+ ATTR_RecordLength dd ?;
+ ATTR_FormCode db ?;
+ ATTR_NameLength db ?;
+ ATTR_NameOffset dw ?;
+ ATTR_Flags dw ?;
+ ATTR_Instance dw ?;
+ ATTR_FormUnion db ?;
+ATTRIBUTE_RECORD ends
+
+RESIDENT_ATTRIBUTE_FORM struc
+ RES_ValueLength dd ?;
+ RES_ValueOffset dw ?;
+ RES_ResidentFlags db ?;
+ RES_Reserved db ?;
+RESIDENT_ATTRIBUTE_FORM ends
+
+NONRESIDENT_ATTRIBUTE_FORM struc
+ NONRES_LowestVcn db (size LARGE_INTEGER) dup (?);
+ NONRES_HighestVcn db (size LARGE_INTEGER) dup (?);
+ NONRES_MappingPairOffset dw ?;
+ NONRES_Reserved dw 3 dup (?);
+ NONRES_AllocatedLength db (size LARGE_INTEGER) dup (?);
+ NONRES_FileSize db (size LARGE_INTEGER) dup (?);
+ NONRES_ValidDataLength db (size LARGE_INTEGER) dup (?);
+NONRESIDENT_ATTRIBUTE_FORM ends
+
+; Attribute Form Codes
+
+RESIDENT_FORM EQU 0
+NONRESIDENT_FORM EQU 1
+
+; Attribute Record Flag Values
+
+ATTRIBUTE_FLAG_COMPRESSION_MASK EQU 00FFh
+
+
+; Attribute list entry structure:
+;
+ATTRIBUTE_LIST_ENTRY struc
+ ATTRLIST_TypeCode dd ?;
+ ATTRLIST_Length dw ?;
+ ATTRLIST_NameLength db ?;
+ ATTRLIST_NameOffset db ?;
+ ATTRLIST_LowestVcn db (size LARGE_INTEGER) dup (?);
+ ATTRLIST_SegmentReference db (size MFT_SEGMENT_REFERENCE) dup (?);
+ ATTRLIST_Instance dw ?;
+ ATTRLIST_Name dw ?;
+ATTRIBUTE_LIST_ENTRY ends
+
+
+FAT_DIRENT_ATTR_READ_ONLY EQU 01h
+FAT_DIRENT_ATTR_HIDDEN EQU 02h
+FAT_DIRENT_ATTR_SYSTEM EQU 04h
+FAT_DIRENT_ATTR_VOLUME_ID EQU 08h
+FAT_DIRENT_ATTR_ARCHIVE EQU 20h
+FAT_DIRENT_ATTR_DEVICE EQU 40h
+
+DUPLICATED_INFORMATION struc
+ DUPINFO_CreationTime db (size LARGE_INTEGER) dup (?);
+ DUPINFO_LastModificationTime db (size LARGE_INTEGER) dup (?);
+ DUPINFO_LastChangeTime db (size LARGE_INTEGER) dup (?);
+ DUPINFO_LastAccessTime db (size LARGE_INTEGER) dup (?);
+ DUPINFO_AllocatedLength db (size LARGE_INTEGER) dup (?);
+ DUPINFO_FileSize db (size LARGE_INTEGER) dup (?);
+ DUPINFO_FileAttributes dd ?;
+ DUPINFO_PackedEaSize dw ?;
+DUPLICATED_INFORMATION ends
+
+
+FILE_NAME struc
+ FN_ParentDirectory db (size MFT_SEGMENT_REFERENCE) dup (?);
+ FN_Info db (size DUPLICATED_INFORMATION) dup (?);
+ FN_Pad dw ?;
+ FN_FileNameLength db ?; Length in chars
+ FN_Flags db ?;
+ FN_FileName dw ?; First char of name.
+FILE_NAME ends
+
+FILE_NAME_NTFS EQU 1
+FILE_NAME_DOS EQU 2
+FILE_NAME_LINK EQU 4
+
+
+INDEX_HEADER struc
+
+ IH_FirstIndexEntry dd ?;
+ IH_FirstFreeByte dd ?;
+ IH_BytesAvailable dd ?;
+ IH_Flags db ?; INDEX_xxx flags
+ IH_Reserved db 3 dup (?);
+INDEX_HEADER ends
+
+; INDEX_xxx flags
+
+INDEX_NODE EQU 1
+
+
+INDEX_ROOT struc
+
+ IR_IndexedAttributeType dd ?;
+ IR_CollationRule dd ?;
+ IR_BytesPerBuffer dd ?;
+ IR_ClustersPerBuffer db ?;
+ IR_Reserved db 3 dup (?);
+ IR_IndexHeader db (size INDEX_HEADER) dup (?);
+INDEX_ROOT ends;
+
+INDEX_ALLOCATION_BUFFER struc
+
+ IB_Header db (size MULTI_SECTOR_HEADER) dup (?);
+ IB_Lsn db (size LARGE_INTEGER) dup (?);
+ IB_ThisVcn db (size LARGE_INTEGER) dup (?);
+ IB_IndexHeader db (size INDEX_HEADER) dup (?);
+INDEX_ALLOCATION_BUFFER ends;
+
+
+INDEX_ENTRY struc
+
+ IE_FileReference db (size MFT_SEGMENT_REFERENCE) dup (?);
+ IE_Length dw ?;
+ IE_AttributeLength dw ?;
+ IE_Flags dw ?;
+ IE_Reserved dw ?;
+ IE_Value db ?;
+INDEX_ENTRY ends;
+
+
+; INDEX_ENTRY_xxx flags
+;
+INDEX_ENTRY_NODE EQU 1
+INDEX_ENTRY_END EQU 2
diff --git a/private/ntos/boot/bootcode/ntfs/i386/ntfsboot.asm b/private/ntos/boot/bootcode/ntfs/i386/ntfsboot.asm
new file mode 100644
index 000000000..a07e341e2
--- /dev/null
+++ b/private/ntos/boot/bootcode/ntfs/i386/ntfsboot.asm
@@ -0,0 +1,2740 @@
+ page ,132
+ title ntfsboot - NTFS boot loader
+ name ntfsboot
+
+; The ROM in the IBM PC starts the boot process by performing a hardware
+; initialization and a verification of all external devices. If all goes
+; well, it will then load from the boot drive the sector from track 0, head 0,
+; sector 1. This sector is placed at physical address 07C00h.
+;
+; The boot code's sole resposiblity is to find NTLDR, load it at
+; address 2000:0000, and then jump to it.
+;
+; The boot code understands the structure of the NTFS root directory,
+; and is capable of reading files. There is no contiguity restriction.
+;
+
+MASM equ 1
+ .xlist
+ .286
+
+A_DEFINED EQU 1
+
+ include ntfs.inc
+
+DoubleWord struc
+lsw dw ?
+msw dw ?
+DoubleWord ends
+
+;
+; The following are various segments used by the boot loader. The first
+; two are the segments where the boot sector is initially loaded and where
+; the boot sector is relocated to. The third is the static location
+; where the NTLDR is loaded.
+;
+
+BootSeg segment at 07c0h ; this is where the ROM loads us initially.
+BootSeg ends
+
+NewSeg segment at 0d00h ; this is where we'll relocate to.
+NewSeg ends ; enough for 16 boot sectors +
+ ; 4-sector scratch
+ ; below where we'll load NTLDR.
+
+LdrSeg segment at 2000h ; we want to load the loader at 2000:0000
+LdrSeg ends
+
+;/********************** START OF SPECIFICATIONS ************************/
+;/* */
+;/* SUBROUTINE NAME: ntfsboot */
+;/* */
+;/* DESCRIPTIVE NAME: Bootstrap loader */
+;/* */
+;/* FUNCTION: To load NTLDR into memory. */
+;/* */
+;/* NOTES: ntfsboot is loaded by the ROM BIOS (Int 19H) at */
+;/* physical memory location 0000:7C00H. */
+;/* ntfsboot runs in real mode. */
+;/* This boot record is for NTFS volumes only. */
+;/* */
+;/* ENTRY POINT: ntfsboot */
+;/* LINKAGE: Jump (far) from Int 19H */
+;/* */
+;/* INPUT: CS:IP = 0000:7C00H */
+;/* SS:SP = 0030:00FAH (CBIOS dependent) */
+;/* */
+;/* EXIT-NORMAL: DL = INT 13 drive number we booted from */
+;/* Jmp to main in NTLDR */
+;/* */
+;/* EXIT-ERROR: None */
+;/* */
+;/* EFFECTS: NTLDR is loaded into the physical memory */
+;/* location 00020000H */
+;/* */
+;/* MESSAGES: A disk read error occurred. */
+;/* The file NTLDR cannot be found. */
+;/* Insert a system diskette and restart the system. */
+;/* */
+;/*********************** END OF SPECIFICATIONS *************************/
+BootCode segment ;would like to use BootSeg here, but LINK flips its lid
+ assume cs:BootCode,ds:nothing,es:nothing,ss:nothing
+
+ org 0 ; start at beginning of segment, not 0100h.
+
+ public _ntfsboot
+_ntfsboot proc far
+ jmp start
+ .errnz ($-_ntfsboot) GT (3),<FATAL PROBLEM: JMP is more than three bytes>
+
+ org 3
+;
+; This is a template BPB--anyone who writes boot code to disk
+; should either preserve the existing BPB and NTFS information
+; or create it anew.
+;
+Version db "NTFS " ; Must be 8 characters
+BPB label byte
+BytesPerSector dw 0 ; Size of a physical sector
+SectorsPerCluster db 0 ; Sectors per allocation unit
+ReservedSectors dw 0 ; Number of reserved sectors
+Fats db 0 ; Number of fats
+DirectoryEntries dw 0 ; Number of directory entries
+Sectors dw 0 ; No. of sectors - no. of hidden sectors
+Media db 0 ; Media byte
+FatSectors dw 0 ; Number of fat sectors
+SectorsPerTrack dw 0 ; Sectors per track
+Heads dw 0 ; Number of surfaces
+HiddenSectors dd 0 ; Number of hidden sectors
+SectorsLong dd 0 ; Number of sectors iff Sectors = 0
+;
+; The following is the rest of the NTFS Sector Zero information.
+; The position and order of DriveNumber and CurrentHead are especially
+; important, since those two variables are loaded into a single 16-bit
+; register for the BIOS with one instruction.
+;
+DriveNumber db 80h ; Physical drive number (0 or 80h)
+CurrentHead db ? ; Variable to store current head no.
+
+SectorZeroPad1 dw 0
+SectorsOnVolume db (size LARGE_INTEGER) dup (0)
+MftStartLcn db (size LARGE_INTEGER) dup (0)
+Mft2StartLcn db (size LARGE_INTEGER) dup (0)
+ClustersPerFrs dd 0
+DefClustersPerBuf dd 0
+SerialNumber db (size LARGE_INTEGER) dup (0)
+CheckSum dd 0
+;
+; The following variables are not part of the Extended BPB; they're just
+; scratch variables for the boot code.
+;
+SectorBase dd ? ; next sector to read
+CurrentTrack dw ? ; current track
+CurrentSector db ? ; current sector
+SectorCount dw ? ; number of sectors to read
+
+;****************************************************************************
+start:
+;
+; First of all, set up the segments we need (stack and data).
+;
+ cli
+ xor ax, ax ; Set up the stack to just before
+ mov ss, ax ; this code. It'll be moved after
+ mov sp, 7c00h ; we relocate.
+ sti
+
+ mov ax, Bootseg ; Address our BPB with DS.
+ mov ds, ax
+ assume ds:BootCode
+;
+; Now read the 16-sector boot block into memory. Then jump to that
+; new version of the boot block, starting in the second sector
+; (after the bootrecord sig).
+;
+ mov SectorBase.lsw, 0 ; read sector zero.
+ mov SectorBase.msw, 0
+
+ mov word ptr [SectorCount], 16 ; read boot area
+ mov ax, NewSeg ; read it at NewSeg.
+ mov es, ax
+ sub bx, bx ; at NewSeg:0000.
+ call DoReadLL ; Call low-level DoRead routine
+
+;
+ push NewSeg ; we'll jump to NewSeg:0200h.
+ push offset mainboot ; (the second sector).
+ ret ; "return" to the second sector.
+_ntfsboot endp
+
+;*******************************************************************************
+;
+; Low-level read routine that doesn't work across a 64k addr boundary.
+;
+; Read SectorCount sectors (starting at SectorBase) to es:bx.
+;
+; As a side effect, SectorBase is updated (but es:bx are not)
+; and SectorCount is reduced to zero.
+;
+DoReadLL proc
+ push ax ; save important registers
+ push bx
+ push cx
+ push dx
+ push es
+
+DoRead$Loop:
+
+.386
+ mov eax, SectorBase
+ add eax, HiddenSectors
+ xor edx,edx
+;EDX:EAX = absolute sector number
+ movzx ecx,word ptr SectorsPerTrack ; get into 32 bit value
+ div ecx ; (EDX) = sector within track, (EAX)=track
+ inc dl ; sector numbers are 1-based, not 0
+ mov CurrentSector, dl
+ mov edx,eax
+ shr edx,16
+.286
+ div Heads ; (DX) = head no., (AX) = cylinder
+ mov CurrentHead, dl
+ mov CurrentTrack, ax
+
+; CurrentHead is the head for this next disk request
+; CurrentTrack is the track for this next request
+; CurrentSector is the beginning sector number for this request
+;
+; Compute the number of sectors that we may be able to read in a single ROM
+; request.
+;
+ mov ax, SectorsPerTrack ; could read up to this much
+ sub al, CurrentSector ; offset within this track
+ inc ax ; CurrentSector was 1-based
+;
+; AX is the number of sectors that we may read.
+;
+ cmp ax, SectorCount ; do we need to read whole trk?
+ jbe DoRead$FullTrack ; yes we do.
+ mov ax, SectorCount ; no, read a partial track.
+;
+; AX is now the number of sectors that we SHOULD read.
+;
+DoRead$FullTrack:
+ push ax ; save sector count for later calc.
+ mov ah, 2 ; "read sectors"
+ mov dx, CurrentTrack ; at this cylinder
+ mov cl, 6
+ shl dh, cl ; high 2 bits of DH = bits 8,9 of DX
+ or dh, CurrentSector ; (DH)=cyl bits | 6-bit sector no.
+ mov cx, dx ; (CX)=cylinder/sector no. combination
+ xchg ch, cl ; in the right order
+ mov dh, CurrentHead
+ mov dl, 80h ; should be DriveNumber, but...
+
+ int 13h ; call BIOS.
+
+ pop ax
+ jb BootErr$he ; If errors report
+ add SectorBase.lsw, ax ; increment logical sector position
+ adc SectorBase.msw, 0
+ sub SectorCount, ax ; exhausted entire sector run?
+ jbe DoRead$Exit ; yes, we're all done.
+ shl ax, 9 - 4 ; (AX)=paragraphs read from last track
+ mov dx, es ; (DX)=segment we last read at
+ add dx, ax ; (DX)=segment right after last read
+ mov es, dx ; (ES)=segment to read next track at
+ jmp DoRead$Loop
+;
+DoRead$Exit:
+ pop es
+ pop dx
+ pop cx
+ pop bx
+ pop ax
+ ret
+
+DoReadLL endp
+
+
+;****************************************************************************
+;
+; BootErr - print error message and hang the system.
+;
+BootErr proc
+BootErr$fnf:
+ mov si,offset TXT_MSG_SYSINIT_FILE_NOT_FD +2
+ jmp short BootErr2
+BootErr$ntc:
+ mov si,offset TXT_MSG_SYSINIT_NTLDR_CMPRS +2
+ jmp short BootErr2
+BootErr$he:
+ mov si,offset TXT_MSG_SYSINIT_BOOT_ERROR +2
+BootErr2:
+ call BootErr$print
+ mov si,offset TXT_MSG_SYSINIT_INSER_DK +2
+ call BootErr$print
+ sti
+ jmp $ ;Wait forever
+BootErr$print:
+ lodsb ; Get next character
+ cmp al, 0
+ je BootErr$Done
+ mov ah,14 ; Write teletype
+ mov bx,7 ; Attribute
+ int 10h ; Print it
+ jmp BootErr$print
+BootErr$Done:
+ ret
+BootErr endp
+
+;****************************************************************************
+ include ntfsboot.inc ;suck in the message text
+
+
+ReservedForFuture DB 2 dup(?) ;reserve remaining bytes to prevent NLS
+ ;messages from using them
+
+ .errnz ($-_ntfsboot) GT (512-2),<FATAL PROBLEM: first sector is too large>
+
+ org 512-2
+ db 55h,0aah
+
+; Name we look for. ntldr_length is the number of characters,
+; ntldr_name is the name itself. Note that it is not NULL
+; terminated, and doesn't need to be.
+;
+ntldr_name_length dw 5
+ntldr_name dw 'N', 'T', 'L', 'D', 'R'
+
+; Predefined name for index-related attributes associated with an
+; index over $FILE_NAME
+;
+index_name_length dw 4
+index_name dw '$', 'I', '3', '0'
+
+; Global variables. These offsets are all relative to NewSeg.
+;
+AttrList dd 0e000h; Offset of buffer to hold attribute list
+MftFrs dd 3000h; Offset of first MFT FRS
+SegmentsInMft dd ? ; number of FRS's with MFT Data attribute records
+RootIndexFrs dd ? ; Offset of Root Index FRS
+AllocationIndexFrs dd ? ; Offset of Allocation Index FRS ; KPeery
+BitmapIndexFrs dd ? ; Offset of Bitmap Index FRS ; KPeery
+IndexRoot dd ? ; Offset of Root Index $INDEX_ROOT attribute
+IndexAllocation dd ? ; Offset of Root Index $INDEX_ALLOCATION attribute
+IndexBitmap dd ? ; Offset of Root Index $BITMAP attribute
+NtldrFrs dd ? ; Offset of NTLDR FRS
+NtldrData dd ? ; Offset of NTLDR $DATA attribute
+IndexBlockBuffer dd ? ; Offset of current index buffer
+IndexBitmapBuffer dd ? ; Offset of index bitmap buffer
+NextBuffer dd ? ; Offset of next free byte in buffer space
+
+BytesPerCluster dd ? ; Bytes per cluster
+BytesPerFrs dd ? ; Bytes per File Record Segment
+SectorsPerFrs dd ? ; Sectors per File Record Segment
+BytesPerIndexBlock dd ? ; Bytes per index alloc block in root index
+ClustersPerIndexBlock dd ? ; Clusters per index alloc block in root index
+SectorsPerIndexBlock dd ? ; Sectors per index block in root index
+
+.386
+
+SAVE_ALL macro
+
+ push es
+ push ds
+ pushad
+
+endm
+
+RESTORE_ALL macro
+
+ popad
+ nop
+ pop ds
+ pop es
+
+endm
+
+
+;****************************************************************************
+;
+; mainboot -
+;
+;
+mainboot proc far
+
+; Get the new ds and the new stack. Note that ss is zero.
+;
+ mov ax, cs ; Set DS to CS
+ mov ds, ax
+
+ shl ax, 4 ; convert to an offset.
+ cli
+ mov sp, ax ; load new stack, just before boot code.
+ sti
+
+; Set up the FRS buffers. The MFT buffer is in a fixed
+; location, and the other three come right after it. The
+; buffer for index allocation blocks comes after that.
+;
+
+; Compute the useful constants associated with the volume
+;
+ movzx eax, BytesPerSector ; eax = Bytes per Sector
+ movzx ebx, SectorsPerCluster ; ebx = Sectors Per Cluster
+ mul ebx ; eax = Bytes per Cluster
+ mov BytesPerCluster, eax
+
+ mov ecx, ClustersPerFrs ; ecx = clusters per frs
+ cmp cl, 0 ; is ClustersPerFrs less than zero?
+ jg mainboot$1
+
+; If the ClustersPerFrs field is negative, we calculate the number
+; of bytes per FRS by negating the value and using that as a shif count.
+;
+
+ neg cl
+ mov eax, 1
+ shl eax, cl ; eax = bytes per frs
+ jmp mainboot$2
+
+mainboot$1:
+
+; Otherwise if ClustersPerFrs was positive, we multiply by bytes
+; per cluster.
+
+ mov eax, BytesPerCluster
+ mul ecx ; eax = bytes per frs
+
+mainboot$2:
+
+ mov BytesPerFrs, eax
+ movzx ebx, BytesPerSector
+ xor edx, edx ; zero high part of dividend
+ div ebx ; eax = sectors per frs
+ mov SectorsPerFrs, eax
+
+
+; Set up the MFT FRS's---this will read all the $DATA attribute
+; records for the MFT.
+;
+
+ call SetupMft
+
+; Set up the remaining FRS buffers. The RootIndex FRS comes
+; directly after the last MFT FRS, followed by the NTLdr FRS
+; and the Index Block buffer.
+;
+ mov ecx, NextBuffer
+ mov RootIndexFrs, ecx
+
+ add ecx, BytesPerFrs ; AllocationFrs may be different
+ mov AllocationIndexFrs, ecx ; from RootIndexFrs - KPeery
+
+ add ecx, BytesPerFrs ; BitmapFrs may be different
+ mov BitmapIndexFrs, ecx ; from RootIndexFrs - KPeery
+
+ add ecx, BytesPerFrs
+ mov NtldrFrs, ecx
+
+ add ecx, BytesPerFrs
+ mov IndexBlockBuffer, ecx
+
+;
+; Read the root index, allocation index and bitmap FRS's and locate
+; the interesting attributes.
+;
+
+ mov eax, $INDEX_ROOT
+ mov ecx, RootIndexFrs
+ call LoadIndexFrs
+
+ or eax, eax
+ jz BootErr$he
+
+ mov IndexRoot, eax ; offset in Frs buffer
+
+ mov eax, $INDEX_ALLOCATION ; Attribute type code
+ mov ecx, AllocationIndexFrs ; FRS to search
+ call LoadIndexFrs
+
+ mov IndexAllocation, eax
+
+ mov eax, $BITMAP ; Attribute type code
+ mov ecx, BitmapIndexFrs ; FRS to search
+ call LoadIndexFrs
+
+ mov IndexBitmap, eax
+
+; Consistency check: the index root must exist, and it
+; must be resident.
+;
+ mov eax, IndexRoot
+ or eax, eax
+ jz BootErr$he
+
+
+ cmp [eax].ATTR_FormCode, RESIDENT_FORM
+ jne BootErr$he
+
+
+; Determine the size of the index allocation buffer based
+; on information in the $INDEX_ROOT attribute. The index
+; bitmap buffer comes immediately after the index block buffer.
+;
+; eax -> $INDEX_ROOT attribute record
+;
+ lea edx, [eax].ATTR_FormUnion ; edx -> resident info
+ add ax, [edx].RES_ValueOffset ; eax -> value of $INDEX_ROOT
+
+ movzx ecx, [eax].IR_ClustersPerBuffer
+ mov ClustersPerIndexBlock, ecx
+
+ mov ecx, [eax].IR_BytesPerBuffer
+ mov BytesPerIndexBlock, ecx
+
+ mov eax, BytesPerIndexBlock
+ movzx ecx, BytesPerSector
+ xor edx, edx
+ div ecx ; eax = sectors per index block
+ mov SectorsPerIndexBlock, eax
+
+ mov eax, IndexBlockBuffer
+ add eax, BytesPerIndexBlock
+ mov IndexBitmapBuffer, eax
+
+; Next consistency check: if the $INDEX_ALLOCATION attribute
+; exists, the $INDEX_BITMAP attribute must also exist.
+;
+ cmp IndexAllocation, 0
+ je mainboot30
+
+ cmp IndexBitmap, 0 ; since IndexAllocation exists, the
+ je BootErr$he ; bitmap must exist, too.
+
+; Since the bitmap exists, we need to read it into the bitmap
+; buffer. If it's resident, we can just copy the data.
+;
+
+ mov ebx, IndexBitmap ; ebx -> index bitmap attribute
+ push ds
+ pop es
+ mov edi, IndexBitmapBuffer ; es:edi -> index bitmap buffer
+
+ call ReadWholeAttribute
+
+mainboot30:
+;
+; OK, we've got the index-related attributes.
+;
+ movzx ecx, ntldr_name_length ; ecx = name length in characters
+ mov eax, offset ntldr_name ; eax -> name
+
+ call FindFile
+
+ or eax, eax
+ jz BootErr$fnf
+
+; Read the FRS for NTLDR and find its data attribute.
+;
+; eax -> Index Entry for NTLDR.
+;
+ mov eax, [eax].IE_FileReference.REF_LowPart
+
+
+ push ds
+ pop es ; es:edi = target buffer
+ mov edi, NtldrFrs
+
+ call ReadFrs
+
+ mov eax, NtldrFrs ; pointer to FRS
+ mov ebx, $DATA ; requested attribute type
+ mov ecx, 0 ; attribute name length in characters
+ mov edx, 0 ; attribute name (NULL if none)
+
+ call LocateAttributeRecord
+
+; eax -> $DATA attribute for NTLDR
+;
+ or eax, eax ; if eax is zero, attribute not found.
+ jz BootErr$fnf
+
+; Get the attribute record header flags, and make sure none of the
+; `compressed' bits are set
+
+ movzx ebx, [eax].ATTR_Flags
+ and ebx, ATTRIBUTE_FLAG_COMPRESSION_MASK
+ jnz BootErr$ntc
+
+ mov ebx, eax ; ebx -> $DATA attribute for NTLDR
+
+ push LdrSeg
+ pop es ; es = segment addres to read into
+ sub edi, edi ; es:edi = buffer address
+
+ call ReadWholeAttribute
+
+;
+; We've loaded NTLDR--jump to it.
+;
+; Before we go to NTLDR, set up the registers the way it wants them:
+; DL = INT 13 drive number we booted from
+;
+ mov dl, DriveNumber
+ mov ax,1000
+ mov es, ax ; we don't really need this
+ lea si, BPB
+ sub ax,ax
+ push LdrSeg
+ push ax
+ retf ; "return" to NTLDR.
+
+
+mainboot endp
+
+;****************************************************************************
+;
+; DoRead - read SectorCount sectors into ES:BX starting from sector
+; SectorBase.
+;
+; NOTE: This code WILL NOT WORK if ES:BX does not point to an address whose
+; physical address (ES * 16 + BX) MOD 512 != 0.
+;
+; DoRead adds to ES rather than BX in the main loop so that runs longer than
+; 64K can be read with a single call to DoRead.
+;
+; Note that DoRead (unlike DoReadLL) saves and restores SectorCount
+; and SectorBase
+;
+.286
+DoRead proc
+ push ax ; save important registers
+ push bx
+ push cx
+ push dx
+ push es
+ push SectorCount ; save state variables too
+ push SectorBase.lsw
+ push SectorBase.msw
+;
+; Calculate how much we can read into what's left of the current 64k
+; physical address block, and read it.
+;
+;
+ mov ax,bx
+
+ shr ax,4
+ mov cx,es
+ add ax,cx ; ax = paragraph addr
+
+;
+; Now calc maximum number of paragraphs that we can read safely:
+; 4k - ( ax mod 4k )
+;
+
+ and ax,0fffh
+ sub ax,1000h
+ neg ax
+
+;
+; Calc CX = number of paragraphs to be read
+;
+ mov cx,SectorCount ; convert SectorCount to paragraph cnt
+ shl cx,9-4
+
+DoRead$Loop64:
+ push cx ; save cpRead
+
+ cmp ax,cx ; ax = min(cpReadSafely, cpRead)
+ jbe @F
+ mov ax,cx
+@@:
+ push ax
+;
+; Calculate new SectorCount from amount we can read
+;
+ shr ax,9-4
+ mov SectorCount,ax
+
+ call DoReadLL
+
+ pop ax ; ax = cpActuallyRead
+ pop cx ; cx = cpRead
+
+ sub cx,ax ; Any more to read?
+ jbe DoRead$Exit64 ; Nope.
+;
+; Adjust ES:BX by amount read
+;
+ mov dx,es
+ add dx,ax
+ mov es,dx
+;
+; Since we're now reading on a 64k byte boundary, cpReadSafely == 4k.
+;
+ mov ax,01000h ; 16k paragraphs per 64k segment
+ jmp short DoRead$Loop64 ; and go read some more.
+
+DoRead$Exit64:
+ pop SectorBase.msw ; restore all this crap
+ pop SectorBase.lsw
+ pop SectorCount
+ pop es
+ pop dx
+ pop cx
+ pop bx
+ pop ax
+ ret
+DoRead endp
+
+.386
+;****************************************************************************
+;
+; ReadClusters - Reads a run of clusters from the disk.
+;
+; ENTRY: eax == LCN to read
+; edx == clusters to read
+; es:edi -> Target buffer
+;
+; USES: none (preserves all registers)
+;
+ReadClusters proc near
+
+ SAVE_ALL
+
+ mov ebx, edx ; ebx = clusters to read.
+ movzx ecx, SectorsPerCluster ; ecx = cluster factor
+
+ mul ecx ; Convert LCN to sectors (wipes out edx!)
+ mov SectorBase, eax ; Store starting sector in SectorBase
+
+ mov eax, ebx ; eax = number of clusters
+ mul ecx ; Convert EAX to sectors (wipes out edx!)
+ mov SectorCount, ax ; Store number of sectors in SectorCount
+
+
+; Note that ReadClusters gets its target buffer in es:edi but calls
+; the DoRead worker function that takes a target in es:bx--we need
+; to normalize es:edi so that we don't overflow bx.
+;
+ mov bx, di
+ and bx, 0Fh
+ mov ax, es
+ shr edi, 4
+ add ax, di ; ax:bx -> target buffer
+
+ push ax
+ pop es ; es:bx -> target buffer
+
+ call DoRead
+
+ RESTORE_ALL
+ ret
+
+ReadClusters endp
+
+;
+;****************************************************************************
+;
+; LocateAttributeRecord -- Find an attribute record in an FRS.
+;
+; ENTRY: EAX -- pointer to FRS
+; EBX -- desired attribute type code
+; ECX -- length of attribute name in characters
+; EDX -- pointer to attribute name
+;
+; EXIT: EAX points at attribute record (0 indicates not found)
+;
+; USES: All
+;
+LocateAttributeRecord proc near
+
+; get the first attribute record.
+;
+ add ax, word ptr[eax].FRS_FirstAttribute
+
+; eax -> next attribute record to investigate.
+; ebx == desired type
+; ecx == name length
+; edx -> pointer to name
+;
+lar10:
+ cmp [eax].ATTR_TypeCode, 0ffffffffh
+ je lar99
+
+ cmp dword ptr[eax].ATTR_TypeCode, ebx
+ jne lar80
+
+; this record is a potential match. Compare the names:
+;
+; eax -> candidate record
+; ebx == desired type
+; ecx == name length
+; edx -> pointer to name
+;
+ or ecx, ecx ; Did the caller pass in a name length?
+ jnz lar20
+
+; We want an attribute with no name--the current record is
+; a match if and only if it has no name.
+;
+ cmp [eax].ATTR_NameLength, 0
+ jne lar80 ; Not a match.
+
+; It's a match, and eax is set up correctly, so return.
+;
+ ret
+
+; We want a named attribute.
+;
+; eax -> candidate record
+; ebx == desired type
+; ecx == name length
+; edx -> pointer to name
+;
+lar20:
+ cmp cl, [eax].ATTR_NameLength
+ jne lar80 ; Not a match.
+
+; Convert name in current record to uppercase.
+;
+ mov esi, eax
+ add si, word ptr[eax].ATTR_NameOffset
+
+ call UpcaseName
+
+; eax -> candidate record
+; ebx == desired type
+; ecx == name length
+; edx -> pointer to name
+; esi -> Name in current record (upcased)
+;
+ push ecx ; save cx
+
+ push ds ; Copy data segment into es
+ pop es
+ mov edi, edx ; note that esi is already set up.
+
+ repe cmpsw ; zero flag is set if equal
+
+ pop ecx ; restore cx
+
+ jnz lar80 ; not a match
+
+; eax points at a matching record.
+;
+ ret
+
+;
+; This record doesn't match; go on to the next.
+;
+; eax -> rejected candidate attribute record
+; ebx == desired type
+; ecx == Name length
+; edx -> desired name
+;
+lar80: cmp [eax].ATTR_RecordLength, 0 ; if the record length is zero
+ je lar99 ; the FRS is corrupt.
+
+ add eax, [eax].ATTR_RecordLength; Go to next record
+ jmp lar10 ; and try again
+
+; Didn't find it.
+;
+lar99: sub eax, eax
+ ret
+
+LocateAttributeRecord endp
+
+;****************************************************************************
+;
+; LocateIndexEntry -- Find an index entry in a file name index
+;
+; ENTRY: EAX -> pointer to index header
+; EBX -> file name to find
+; ECX == length of file name in characters
+;
+; EXIT: EAX points at index entry. NULL to indicate failure.
+;
+; USES: All
+;
+LocateIndexEntry proc near
+
+; Convert the input name to upper-case
+;
+
+ mov esi, ebx
+ call UpcaseName
+
+; DEBUG CODE
+;
+; call PrintName
+; call Debug2
+;
+; END DEBUG CODE
+
+ add eax, [eax].IH_FirstIndexEntry
+
+; EAX -> current entry
+; EBX -> file name to find
+; ECX == length of file name in characters
+;
+lie10: test [eax].IE_Flags, INDEX_ENTRY_END ; Is it the end entry?
+ jnz lie99
+
+ lea edx, [eax].IE_Value ; edx -> FILE_NAME attribute value
+
+; DEBUG CODE -- list file names as they are examined
+;
+; SAVE_ALL
+;
+; call Debug3
+; movzx ecx, [edx].FN_FileNameLength ; ecx = chars in name
+; lea esi, [edx].FN_FileName ; esi -> name
+; call PrintName
+;
+; RESTORE_ALL
+;
+; END DEBUG CODE
+
+; EAX -> current entry
+; EBX -> file name to find
+; ECX == length of file name in characters
+; EDX -> FILE_NAME attribute
+;
+ cmp cl, [edx].FN_FileNameLength ; Is name the right length?
+ jne lie80
+
+ lea esi, [edx].FN_FileName ; Get name from FILE_NAME structure
+
+ call UpcaseName
+
+ push ecx ; save ecx
+
+ push ds
+ pop es ; copy data segment into es for cmpsw
+ mov edi, ebx ; edi->search name (esi already set up)
+ repe cmpsw ; zero flag is set if they're equal
+
+ pop ecx ; restore ecx
+
+ jnz lie80
+
+; the current entry matches the search name, and eax points at it.
+;
+ ret
+
+; The current entry is not a match--get the next one.
+; EAX -> current entry
+; EBX -> file name to find
+; ECX == length of file name in characters
+;
+lie80: cmp [eax].IE_Length, 0 ; If the entry length is zero
+ je lie99 ; then the index block is corrupt.
+
+ add ax, [eax].IE_Length ; Get the next entry.
+
+ jmp lie10
+
+
+; Name not found in this block. Set eax to zero and return
+;
+lie99: xor eax, eax
+ ret
+
+LocateIndexEntry endp
+
+;****************************************************************************
+;
+; ReadWholeAttribute - Read an entire attribute value
+;
+; ENTRY: ebx -> attribute
+; es:edi -> target buffer
+;
+; USES: ALL
+;
+ReadWholeAttribute proc near
+
+ cmp [ebx].ATTR_FormCode, RESIDENT_FORM
+ jne rwa10
+
+; The attribute is resident.
+; ebx -> attribute
+; es:edi -> target buffer
+;
+
+ SAVE_ALL
+
+ lea edx, [ebx].ATTR_FormUnion ; edx -> resident form info
+ mov ecx, [edx].RES_ValueLength ; ecx = bytes in value
+ mov esi, ebx ; esi -> attribute
+ add si, [edx].RES_ValueOffset ; esi -> attribute value
+
+ rep movsb ; copy bytes from value to buffer
+
+ RESTORE_ALL
+
+ ret ; That's all!
+
+rwa10:
+;
+; The attribute type is non-resident. Just call
+; ReadNonresidentAttribute starting at VCN 0 and
+; asking for the whole thing.
+;
+; ebx -> attribute
+; es:edi -> target buffer
+;
+ lea edx, [ebx].ATTR_FormUnion ; edx -> nonresident form info
+ mov ecx, [edx].NONRES_HighestVcn.LowPart; ecx = HighestVcn
+ inc ecx ; ecx = clusters in attribute
+
+ sub eax, eax ; eax = 0 (first VCN to read)
+
+ call ReadNonresidentAttribute
+
+ ret
+
+ReadWholeAttribute endp
+
+;****************************************************************************
+;
+; ReadNonresidentAttribute - Read clusters from a nonresident attribute
+;
+; ENTRY: EAX == First VCN to read
+; EBX -> Attribute
+; ECX == Number of clusters to read
+; ES:EDI == Target of read
+;
+; EXIT: None.
+;
+; USES: None (preserves all registers with SAVE_ALL/RESTORE_ALL)
+;
+ReadNonresidentAttribute proc near
+
+ SAVE_ALL
+
+ cmp [ebx].ATTR_FormCode, NONRESIDENT_FORM
+ je ReadNR10
+
+; This attribute is not resident--the disk is corrupt.
+
+ jmp BootErr$he
+
+
+ReadNR10:
+; eax == Next VCN to read
+; ebx -> Attribute
+; ecx -> Remaining clusters to read
+; es:edi -> Target of read
+;
+
+ cmp ecx, 0
+ jne ReadNR20
+
+; Nothing left to read--return success.
+;
+ RESTORE_ALL
+ ret
+
+ReadNR20:
+ push ebx ; pointer to attribute
+ push eax ; Current VCN
+
+ push ecx
+ push edi
+ push es
+
+ call ComputeLcn ; eax = LCN to read, ecx = run length
+ mov edx, ecx ; edx = remaining run length
+
+ pop es
+ pop edi
+ pop ecx
+
+
+; eax == LCN to read
+; ecx == remaining clusters to read
+; edx == remaining clusters in current run
+; es:edi == Target of read
+; TOS == Current VCN
+; TOS + 4 == pointer to attribute
+;
+ cmp ecx, edx
+ jge ReadNR30
+
+; Run length is greater than remaining request; only read
+; remaining request.
+;
+ mov edx, ecx ; edx = Remaining request
+
+ReadNR30:
+; eax == LCN to read
+; ecx == remaining clusters to read
+; edx == clusters to read in current run
+; es:edi == Target of read
+; TOS == Current VCN
+; TOS + == pointer to attribute
+;
+
+ call ReadClusters
+
+ sub ecx, edx ; Decrement clusters remaining in request
+ mov ebx, edx ; ebx = clusters read
+
+ mov eax, edx ; eax = clusters read
+ movzx edx, SectorsPerCluster
+ mul edx ; eax = sectors read (wipes out edx!)
+ movzx edx, BytesPerSector
+ mul edx ; eax = bytes read (wipes out edx!)
+
+ add edi, eax ; Update target of read
+
+ pop eax ; eax = previous VCN
+ add eax, ebx ; update VCN to read
+
+ pop ebx ; ebx -> attribute
+ jmp ReadNR10
+
+
+ReadNonresidentAttribute endp
+
+;****************************************************************************
+;
+; ReadIndexBlockSectors - Read sectors from an index allocation attribute
+;
+; ENTRY: EAX == First VBN to read
+; EBX -> Attribute
+; ECX == Number of sectors to read
+; ES:EDI == Target of read
+;
+; EXIT: None.
+;
+; USES: None (preserves all registers with SAVE_ALL/RESTORE_ALL)
+;
+ReadIndexBlockSectors proc near
+
+ SAVE_ALL
+
+ cmp [ebx].ATTR_FormCode, NONRESIDENT_FORM
+ je ReadIBS_10
+
+; This attribute is resident--the disk is corrupt.
+
+ jmp BootErr$he
+
+
+ReadIBS_10:
+; eax == Next VBN to read
+; ebx -> Attribute
+; ecx -> Remaining sectors to read
+; es:edi -> Target of read
+;
+
+ cmp ecx, 0
+ jne ReadIBS_20
+
+; Nothing left to read--return success.
+;
+
+
+ RESTORE_ALL
+ ret
+
+ReadIBS_20:
+ push ebx ; pointer to attribute
+ push eax ; Current VBN
+
+ push ecx
+ push edi
+ push es
+
+ ; Convert eax from a VBN back to a VCN by dividing by SectorsPerCluster.
+ ; The remainder of this division is the sector offset in the cluster we
+ ; want. Then use the mapping information to get the LCN for this VCN,
+ ; then multiply to get back to LBN.
+ ;
+
+ push ecx ; save remaining sectors in request
+
+ xor edx, edx ; zero high part of dividend
+ movzx ecx, SectorsPerCluster
+ div ecx ; edx = remainder
+ push edx ; save remainder
+
+ call ComputeLcn ; eax = LCN to read, ecx = remaining run length
+
+ movzx ebx, SectorsPerCluster
+ mul ebx ; eax = LBN of cluster, edx = 0
+ pop edx ; edx = remainder
+ add eax, edx ; eax = LBN we want
+ push eax ; save LBN
+
+ movzx eax, SectorsPerCluster
+ mul ecx ; eax = remaining run length in sectors, edx = 0
+ mov edx, eax ; edx = remaining run length
+
+ pop eax ; eax = LBN
+ pop ecx ; ecx = remaining sectors in request
+
+ pop es
+ pop edi
+ pop ecx
+
+
+; eax == LBN to read
+; ecx == remaining sectors to read
+; edx == remaining sectors in current run
+; es:edi == Target of read
+; TOS == Current VCN
+; TOS + 4 == pointer to attribute
+;
+ cmp ecx, edx
+ jge ReadIBS_30
+
+; Run length is greater than remaining request; only read
+; remaining request.
+;
+ mov edx, ecx ; edx = Remaining request
+
+ReadIBS_30:
+; eax == LBN to read
+; ecx == remaining sectors to read
+; edx == sectors to read in current run
+; es:edi == Target of read
+; TOS == Current VCN
+; TOS + == pointer to attribute
+;
+
+ mov SectorBase, eax
+ mov SectorCount, dx
+
+; We have a pointer to the target buffer in es:edi, but we want that
+; in es:bx for DoRead.
+;
+
+ SAVE_ALL
+
+ mov bx, di
+ and bx, 0Fh
+ mov ax, es
+ shr edi, 4
+ add ax, di ; ax:bx -> target buffer
+
+ push ax
+ pop es ; es:bx -> target buffer
+
+ call DoRead
+
+ RESTORE_ALL
+
+ sub ecx, edx ; Decrement sectors remaining in request
+ mov ebx, edx ; ebx = sectors read
+
+ mov eax, edx ; eax = sectors read
+ movzx edx, BytesPerSector
+ mul edx ; eax = bytes read (wipes out edx!)
+
+ add edi, eax ; Update target of read
+
+ pop eax ; eax = previous VBN
+ add eax, ebx ; update VBN to read
+
+ pop ebx ; ebx -> attribute
+ jmp ReadIBS_10
+
+
+ReadIndexBlockSectors endp
+
+
+;****************************************************************************
+;
+; MultiSectorFixup - fixup a structure read off the disk
+; to reflect Update Sequence Array.
+;
+; ENTRY: ES:EDI = Target buffer
+;
+; USES: none (preserves all registers with SAVE_ALL/RESTORE_ALL)
+;
+; Note: ES:EDI must point at a structure which is protected
+; by an update sequence array, and which begins with
+; a multi-sector-header structure.
+;
+MultiSectorFixup proc near
+
+ SAVE_ALL
+
+ movzx ebx, es:[edi].MSH_UpdateArrayOfs ; ebx = update array offset
+ movzx ecx, es:[edi].MSH_UpdateArraySize ; ecx = update array size
+
+ or ecx, ecx ; if the size of the update sequence array
+ jz BootErr$he ; is zero, this structure is corrupt.
+
+ add ebx, edi ; es:ebx -> update sequence array count word
+ add ebx, 2 ; es:ebx -> 1st entry of update array
+
+ add edi, SEQUENCE_NUMBER_STRIDE - 2 ; es:edi->last word of first chunk
+ dec ecx ; decrement to reflect count word
+
+MSF10:
+
+; ecx = number of entries remaining in update sequence array
+; es:ebx -> next entry in update sequence array
+; es:edi -> next target word for update sequence array
+
+ or ecx, ecx
+ jz MSF30
+
+ mov ax, word ptr es:[ebx] ; copy next update sequence array entry
+ mov word ptr es:[edi], ax ; to next target word
+
+ add ebx, 2 ; go on to next entry
+ add edi, SEQUENCE_NUMBER_STRIDE ; go on to next target
+
+ dec ecx
+
+
+ jmp MSF10
+
+MSF30:
+
+ RESTORE_ALL
+
+ ret
+
+MultiSectorFixup endp
+
+;****************************************************************************
+;
+; SetupMft - Reads MFT File Record Segments into memory.
+;
+; ENTRY: none.
+;
+; EXIT: NextBuffer is set to the free byte after the last MFT FRS
+; SegmentsInMft is initialized
+;
+;
+SetupMft proc near
+
+ SAVE_ALL
+
+; Initialize SegmentsInMft and NextBuffer as if the MFT
+; had only one FRS.
+;
+ mov eax, 1
+ mov SegmentsInMft, eax
+
+ mov eax, MftFrs
+ add eax, BytesPerFrs
+ mov NextBuffer, eax
+
+; Read FRS 0 into the first MFT FRS buffer, being sure
+; to resolve the Update Sequence Array.
+;
+
+ mov eax, MftStartLcn.LowPart
+ movzx ebx, SectorsPerCluster
+ mul ebx ; eax = mft starting sector
+ mov SectorBase, eax ; SectorBase = mft starting sector
+
+ mov eax, SectorsPerFrs
+ mov SectorCount, ax ; SectorCount = SectorsPerFrs
+
+ mov ebx, MftFrs
+
+ push ds
+ pop es
+
+ call DoRead
+ movzx edi, bx ; es:edi = buffer
+ call MultiSectorFixup
+
+; Determine whether the MFT has an Attribute List attribute
+
+ mov eax, MftFrs
+ mov ebx, $ATTRIBUTE_LIST
+ mov ecx, 0
+ mov edx, 0
+
+ call LocateAttributeRecord
+
+ or eax, eax ; If there's no Attribute list,
+ jz SetupMft99 ; we're done!
+
+; Read the attribute list.
+; eax -> attribute list attribute
+;
+ mov ebx, eax ; ebx -> attribute list attribute
+ push ds
+ pop es ; copy ds into es
+ mov edi, AttrList ; ds:edi->attribute list buffer
+
+ call ReadWholeAttribute
+
+ mov ebx, AttrList ; ebx -> first attribute list entry
+
+; Now, traverse the attribute list looking for the first
+; entry for the $DATA type. We know it must have at least
+; one.
+;
+; ebx -> first attribute list entry
+;
+SetupMft10:
+ cmp [ebx].ATTRLIST_TypeCode, $DATA
+ je SetupMft20
+
+ add bx,[ebx].ATTRLIST_Length
+ jmp SetupMft10
+
+
+SetupMft20:
+; Scan forward through the attribute list entries for the
+; $DATA attribute, reading each referenced FRS. Note that
+; there will be at least one non-$DATA entry after the entries
+; for the $DATA attribute, since there's a $BITMAP.
+;
+; ebx -> Next attribute list entry
+; NextBuffer -> Target for next read
+; SegmentsInMft == number of MFT segments read so far
+;
+ cmp [ebx].ATTRLIST_TypeCode, $DATA
+ jne SetupMft99
+
+; Read the FRS referred to by this attribute list entry into
+; the next buffer, and increment NextBuffer and SegmentsInMft.
+;
+ push ebx
+
+ mov eax, [ebx].ATTRLIST_SegmentReference.REF_LowPart
+ mov edi, NextBuffer
+ push ds
+ pop es ; copy ds into es
+
+ call ReadFrs
+
+ pop ebx
+
+; Increment NextBuffer and SegmentsInMft
+
+ mov eax, BytesPerFrs
+ add NextBuffer, eax
+
+ inc SegmentsInMft
+
+; Go on to the next attribute list entry
+
+ add bx, [ebx].ATTRLIST_Length
+ jmp SetupMft20
+
+SetupMft99:
+
+ RESTORE_ALL
+ ret
+
+SetupMft endp
+
+;****************************************************************************
+;
+; ComputeMftLcn -- Computes the LCN for a cluster of the MFT
+;
+;
+; ENTRY: EAX == VCN
+;
+; EXIT: EAX == LCN
+;
+; USES: ALL
+;
+ComputeMftLcn proc near
+
+ mov edx, eax ; edx = VCN
+
+ mov ecx, SegmentsInMft ; ecx = # of FRS's to search
+ mov eax, MftFrs ; eax -> first FRS to search
+
+MftLcn10:
+; EAX -> Next FRS to search
+; ECX == number of remaining FRS's to search
+; EDX == VCN
+;
+ push edx
+ push eax
+ push ecx
+ push edx ; Yes, I meant to push it twice
+
+ mov ebx, $DATA
+ mov ecx, 0
+ mov edx, 0
+
+ call LocateAttributeRecord
+
+; EAX -> $DATA attribute
+; TOS == VCN
+; TOS + 4 == number of remaining FRS's to search
+; TOS + 8 -> FRS being searched
+; TOS +12 == VCN
+
+ or eax, eax
+ jz BootErr$he ; No $DATA attribute in this FRS!
+
+ mov ebx, eax ; ebx -> attribute
+ pop eax ; eax = VCN
+
+; EAX == VCN
+; EBX -> $DATA attribute
+; TOS number of remaining FRS's to search
+; TOS + 4 == FRS being searched
+; TOS + 8 == VCN
+
+ call ComputeLcn
+
+ or eax, eax
+ jz MftLcn20
+
+; Found our LCN. Clean up the stack and return.
+;
+; EAX == LCN
+; TOS number of remaining FRS's to search
+; TOS + 4 == FRS being searched
+; TOS + 8 == VCN
+;
+ pop ebx
+ pop ebx
+ pop ebx ; clean up the stack
+
+ ret
+
+MftLcn20:
+;
+; Didn't find the VCN in this FRS; try the next one.
+;
+; TOS number of remaining FRS's to search
+; TOS + 4 -> FRS being searched
+; TOS + 8 == VCN
+;
+ pop ecx ; ecx = number of FRS's remaining, including current
+ pop eax ; eax -> current FRS
+ pop edx ; edx = VCN
+
+ add eax, BytesPerFrs ; eax -> next FRS
+ loop MftLcn10 ; decrement ecx and try next FRS
+
+; This VCN was not found.
+;
+ xor eax, eax
+ ret
+
+
+ComputeMftLcn endp
+
+;****************************************************************************
+;
+; ReadMftSectors - Read sectors from the MFT
+;
+; ENTRY: EAX == starting VBN
+; ECX == number of sectors to read
+; ES:EDI == Target buffer
+;
+; USES: none (preserves all registers with SAVE_ALL/RESTORE_ALL)
+;
+ReadMftSectors proc near
+
+ SAVE_ALL
+
+RMS$Again:
+
+ push eax ; save starting VBN
+ push ecx ; save sector count
+
+
+; Divide the VBN by SectorsPerCluster to get the VCN
+
+ xor edx, edx ; zero high part of dividend
+ movzx ebx, SectorsPerCluster
+ div ebx ; eax = VCN
+ push edx ; save remainder
+
+ call ComputeMftLcn ; eax = LCN
+
+ or eax, eax ; LCN equal to zero?
+ jz BootErr$he ; zero is not a possible LCN
+
+; Change the LCN back into a LBN and add the remainder back in to get
+; the sector we want to read, which goes into SectorBase.
+;
+
+ movzx ebx, SectorsPerCluster
+ mul ebx ; eax = cluster first LBN
+ pop edx ; edx = sector remainder
+ add eax, edx ; eax = desired LBN
+
+ mov SectorBase, eax
+
+;
+; Figure out how many sectors to read this time; we never attempt
+; to read more than one cluster at a time.
+;
+
+ pop ecx ; ecx = sectors to read
+
+ movzx ebx, SectorsPerCluster
+ cmp ecx,ebx
+ jle RMS10
+
+;
+; Read only a single cluster at a time, to avoid problems with fragmented
+; runs in the mft.
+;
+
+ mov SectorCount, bx ; this time read 1 cluster
+ sub ecx, ebx ; ecx = sectors remaining to read
+
+ pop eax ; eax = VBN
+ add eax, ebx ; VBN += sectors this read
+
+
+ push eax ; save next VBN
+ push ecx ; save remaining sector count
+
+
+
+ jmp RMS20
+
+RMS10:
+
+ pop eax ; eax = VBN
+ add eax, ecx ; VBN += sectors this read
+ push eax ; save next VBN
+
+ mov SectorCount, cx
+ mov ecx, 0
+ push ecx ; save remaining sector count (0)
+
+RMS20:
+
+
+; The target buffer was passed in es:edi, but we want it in es:bx.
+; Do the conversion.
+;
+
+ push es ; save buffer pointer
+ push edi
+
+ mov bx, di
+ and bx, 0Fh
+ mov ax, es
+ shr edi, 4
+ add ax, di ; ax:bx -> target buffer
+
+ push ax
+ pop es ; es:bx -> target buffer
+
+ call DoRead
+
+ pop edi ; restore buffer pointer
+ pop es
+
+ add edi, BytesPerCluster ; increment buf ptr by one cluster
+
+ pop ecx ; restore remaining sector count
+ pop eax ; restore starting VBN
+
+ cmp ecx, 0 ; are we done?
+ jg RMS$Again ; repeat until desired == 0
+
+
+ RESTORE_ALL
+ ret
+
+ReadMftSectors endp
+
+
+;****************************************************************************
+;
+; ReadFrs - Read an FRS
+;
+; ENTRY: EAX == FRS number
+; ES:EDI == Target buffer
+;
+; USES: none (preserves all registers with SAVE_ALL/RESTORE_ALL)
+;
+ReadFrs proc near
+
+ SAVE_ALL
+
+ mul SectorsPerFrs ; eax = sector number in MFT DATA attribute
+ ; (note that mul wipes out edx!)
+
+ mov ecx, SectorsPerFrs ; number of sectors to read
+
+ call ReadMftSectors
+ call MultiSectorFixup
+
+ RESTORE_ALL
+ ret
+
+ReadFrs endp
+
+;****************************************************************************
+;
+; ReadIndexBlock - read an index block from the root index.
+;
+; ENTRY: EAX == Block number
+;
+; USES: none (preserves all registers with SAVE_ALL/RESTORE_ALL)
+;
+ReadIndexBlock proc near
+
+ SAVE_ALL
+
+ mul SectorsPerIndexBlock ; eax = first VBN to read
+ ; (note that mul wipes out edx!)
+ mov ebx, IndexAllocation ; ebx -> $INDEX_ALLOCATION attribute
+ mov ecx, SectorsPerIndexBlock ; ecx == Sectors to read
+
+ push ds
+ pop es
+ mov edi, IndexBlockBuffer ; es:edi -> index block buffer
+
+ call ReadIndexBlockSectors
+ call MultiSectorFixup
+
+ RESTORE_ALL
+ ret
+
+ReadIndexBlock endp
+
+;****************************************************************************
+;
+; IsBlockInUse - Checks the index bitmap to see if an index
+; allocation block is in use.
+;
+; ENTRY: EAX == block number
+;
+; EXIT: Carry flag clear if block is in use
+; Carry flag set if block is not in use.
+;
+IsBlockInUse proc near
+
+ push eax
+ push ebx
+ push ecx
+
+ mov ebx, IndexBitmapBuffer
+
+ mov ecx, eax ; ecx = block number
+ shr eax, 3 ; eax = byte number
+ and ecx, 7 ; ecx = bit number in byte
+
+ add ebx, eax ; ebx -> byte to test
+
+ mov eax, 1
+ shl eax, cl ; eax = mask
+
+ test byte ptr[ebx], al
+
+ jz IBU10
+
+ clc ; Block is not in use.
+ jmp IBU20
+
+IBU10: stc ; Block is in use.
+
+IBU20:
+ pop ecx
+ pop ebx
+ pop eax ; restore registers
+
+ ret
+
+IsBlockInUse endp
+
+;****************************************************************************
+;
+; ComputeLcn - Converts a VCN into an LCN
+;
+; ENTRY: EAX -> VCN
+; EBX -> Attribute
+;
+; EXIT: EAX -> LCN (zero indicates not found)
+; ECX -> Remaining run length
+;
+; USES: ALL.
+;
+ComputeLcn proc near
+
+ cmp [ebx].ATTR_FormCode, NONRESIDENT_FORM
+ je clcn10
+
+ sub eax, eax ; This is a resident attribute.
+ ret
+
+clcn10: lea esi, [ebx].ATTR_FormUnion ; esi -> nonresident info of attrib
+
+; eax -> VCN
+; ebx -> Attribute
+; esi -> Nonresident information of attribute record
+;
+; See if the desired VCN is in range.
+
+ mov edx, [esi].NONRES_HighestVcn.LowPart ; edx = HighestVcn
+ cmp eax, edx
+ ja clcn15 ; VCN is greater than HighestVcn
+
+ mov edx, [esi].NONRES_LowestVcn.LowPart ; edx = LowestVcn
+ cmp eax, edx
+ jae clcn20
+
+clcn15:
+ sub eax, eax ; VCN is not in range
+ ret
+
+clcn20:
+; eax -> VCN
+; ebx -> Attribute
+; esi -> Nonresident information of attribute record
+; edx -> LowestVcn
+;
+ add bx, [esi].NONRES_MappingPairOffset ; ebx -> mapping pairs
+ sub esi, esi ; esi = 0
+
+clcn30:
+; eax == VCN to find
+; ebx -> Current mapping pair count byte
+; edx == Current VCN
+; esi == Current LCN
+;
+ cmp byte ptr[ebx], 0 ; if count byte is zero...
+ je clcn99 ; ... we're done (and didn't find it)
+
+; Update CurrentLcn
+;
+ call LcnFromMappingPair
+ add esi, ecx ; esi = current lcn for this mapping pair
+
+ call VcnFromMappingPair
+
+; eax == VCN to find
+; ebx -> Current mapping pair count byte
+; ecx == DeltaVcn for current mapping pair
+; edx == Current VCN
+; esi == Current LCN
+;
+ add ecx, edx ; ecx = NextVcn
+
+ cmp eax, ecx ; If target < NextVcn ...
+ jl clcn80 ; ... we found the right mapping pair.
+
+; Go on to next mapping pair.
+;
+ mov edx, ecx ; CurrentVcn = NextVcn
+
+ push eax
+
+ movzx ecx, byte ptr[ebx] ; ecx = count byte
+ mov eax, ecx ; eax = count byte
+ and eax, 0fh ; eax = number of vcn bytes
+ shr ecx, 4 ; ecx = number of lcn bytes
+
+ add ebx, ecx
+ add ebx, eax
+ inc ebx ; ebx -> next count byte
+
+ pop eax
+ jmp clcn30
+
+clcn80:
+; We found the mapping pair we want.
+;
+; eax == target VCN
+; ebx -> mapping pair count byte
+; edx == Starting VCN of run
+; ecx == Next VCN (ie. start of next run)
+; esi == starting LCN of run
+;
+ sub ecx, eax ; ecx = remaining run length
+ sub eax, edx ; eax = offset into run
+ add eax, esi ; eax = LCN to return
+
+ ret
+
+; The target VCN is not in this attribute.
+
+clcn99: sub eax, eax ; Not found.
+ ret
+
+
+ComputeLcn endp
+
+;****************************************************************************
+;
+; VcnFromMappingPair
+;
+; ENTRY: EBX -> Mapping Pair count byte
+;
+; EXIT: ECX == DeltaVcn from mapping pair
+;
+; USES: ECX
+;
+VcnFromMappingPair proc near
+
+ sub ecx, ecx ; ecx = 0
+ mov cl, byte ptr[ebx] ; ecx = count byte
+ and cl, 0fh ; ecx = v
+
+ cmp ecx, 0 ; if ecx is zero, volume is corrupt.
+ jne VFMP5
+
+ sub ecx, ecx
+ ret
+
+VFMP5:
+ push ebx
+ push edx
+
+ add ebx, ecx ; ebx -> last byte of compressed vcn
+
+ movsx edx, byte ptr[ebx]
+ dec ecx
+ dec ebx
+
+; ebx -> Next byte to add in
+; ecx == Number of bytes remaining
+; edx == Accumulated value
+;
+VFMP10: cmp ecx, 0 ; When ecx == 0, we're done.
+ je VFMP20
+
+ shl edx, 8
+ mov dl, byte ptr[ebx]
+
+ dec ebx ; Back up through bytes to process.
+ dec ecx ; One less byte to process.
+
+ jmp VFMP10
+
+VFMP20:
+; edx == Accumulated value to return
+
+ mov ecx, edx
+
+ pop edx
+ pop ebx
+
+ ret
+
+VcnFromMappingPair endp
+
+
+;****************************************************************************
+;
+; LcnFromMappingPair
+;
+; ENTRY: EBX -> Mapping Pair count byte
+;
+; EXIT: ECX == DeltaLcn from mapping pair
+;
+; USES: ECX
+;
+LcnFromMappingPair proc near
+
+ push ebx
+ push edx
+
+ sub edx, edx ; edx = 0
+ mov dl, byte ptr[ebx] ; edx = count byte
+ and edx, 0fh ; edx = v
+
+ sub ecx, ecx ; ecx = 0
+ mov cl, byte ptr[ebx] ; ecx = count byte
+ shr cl, 4 ; ecx = l
+
+ cmp ecx, 0 ; if ecx is zero, volume is corrupt.
+ jne LFMP5
+
+ sub ecx, ecx
+
+ pop edx
+ pop ebx
+ ret
+
+LFMP5:
+; ebx -> count byte
+; ecx == l
+; edx == v
+;
+
+ add ebx, edx ; ebx -> last byte of compressed vcn
+ add ebx, ecx ; ebx -> last byte of compressed lcn
+
+ movsx edx, byte ptr[ebx]
+ dec ecx
+ dec ebx
+
+; ebx -> Next byte to add in
+; ecx == Number of bytes remaining
+; edx == Accumulated value
+;
+LFMP10: cmp ecx, 0 ; When ecx == 0, we're done.
+ je LFMP20
+
+ shl edx, 8
+ mov dl, byte ptr[ebx]
+
+ dec ebx ; Back up through bytes to process.
+ dec ecx ; One less byte to process.
+
+ jmp LFMP10
+
+LFMP20:
+; edx == Accumulated value to return
+
+ mov ecx, edx
+
+ pop edx
+ pop ebx
+
+ ret
+
+LcnFromMappingPair endp
+
+;****************************************************************************
+;
+; UpcaseName - Converts the name of the file to all upper-case
+;
+; ENTRY: ESI -> Name
+; ECX -> Length of name
+;
+; USES: none
+;
+UpcaseName proc near
+
+
+ or ecx, ecx
+ jnz UN5
+
+ ret
+
+UN5:
+ push ecx
+ push esi
+
+UN10:
+ cmp word ptr[esi], 'a' ; if it's less than 'a'
+ jl UN20 ; leave it alone
+
+ cmp word ptr[esi], 'z' ; if it's greater than 'z'
+ jg UN20 ; leave it alone.
+
+ sub word ptr[esi], 'a'-'A' ; the letter is lower-case--convert it.
+UN20:
+ add esi, 2 ; move on to next unicode character
+ loop UN10
+
+ pop esi
+ pop ecx
+
+ ret
+UpcaseName endp
+
+;****************************************************************************
+;
+; FindFile - Locates the index entry for a file in the root index.
+;
+; ENTRY: EAX -> name to find
+; ECX == length of file name in characters
+;
+; EXIT: EAX -> Index Entry. NULL to indicate failure.
+;
+; USES: ALL
+;
+FindFile proc near
+
+ push eax ; name address
+ push ecx ; name length
+
+; First, search the index root.
+;
+; eax -> name to find
+; ecx == name length
+; TOS == name length
+; TOS+4 -> name to find
+;
+ mov edx, eax ; edx -> name to find
+ mov eax, IndexRoot ; eax -> &INDEX_ROOT attribute
+ lea ebx, [eax].ATTR_FormUnion ; ebx -> resident info
+ add ax, [ebx].RES_ValueOffset ; eax -> Index Root value
+
+ lea eax, [eax].IR_IndexHeader ; eax -> Index Header
+
+ mov ebx, edx ; ebx -> name to find
+
+ call LocateIndexEntry
+
+ or eax, eax
+ jz FindFile20
+
+; Found it in the root! The result is already in eax.
+; Clean up the stack and return.
+;
+ pop ecx
+ pop ecx
+ ret
+
+FindFile20:
+;
+; We didn't find the index entry we want in the root, so we have to
+; crawl through the index allocation buffers.
+;
+; TOS == name length
+; TOS+4 -> name to find
+;
+ mov eax, IndexAllocation
+ or eax, eax
+ jnz FindFile30
+
+; There is no index allocation attribute; clean up
+; the stack and return failure.
+;
+ pop ecx
+ pop ecx
+ xor eax, eax
+ ret
+
+FindFile30:
+;
+; Search the index allocation blocks for the name we want.
+; Instead of searching in tree order, we'll just start with
+; the last one and work our way backwards.
+;
+; TOS == name length
+; TOS+4 -> name to find
+;
+ mov edx, IndexAllocation ; edx -> index allocation attr.
+ lea edx, [edx].ATTR_FormUnion ; edx -> nonresident form info
+ mov eax, [edx].NONRES_HighestVcn.LowPart; eax = HighestVcn
+ inc eax ; eax = clusters in attribute
+
+ mov ebx, BytesPerCluster
+ mul ebx ; eax = bytes in attribute
+
+ xor edx, edx
+ div BytesPerIndexBlock ; convert bytes to index blocks
+
+ push eax ; number of blocks to process
+
+FindFile40:
+;
+; TOS == remaining index blocks to search
+; TOS + 4 == name length
+; TOS + 8 -> name to find
+;
+ pop eax ; eax == number of remaining blocks
+
+ or eax, eax
+ jz FindFile90
+
+ dec eax ; eax == number of next block to process
+ ; and number of remaining blocks
+
+ push eax
+
+; eax == block number to process
+; TOS == remaining index blocks to search
+; TOS + 4 == name length
+; TOS + 8 -> name to find
+;
+; See if the block is in use; if not, go on to next.
+
+ call IsBlockInUse
+ jc FindFile40 ; c set if not in use
+
+; eax == block number to process
+; TOS == remaining index blocks to search
+; TOS + 4 == name length
+; TOS + 8 -> name to find
+;
+
+ call ReadIndexBlock
+
+ pop edx ; edx == remaining buffers to search
+ pop ecx ; ecx == name length
+ pop ebx ; ebx -> name
+
+ push ebx
+ push ecx
+ push edx
+
+; ebx -> name to find
+; ecx == name length in characters
+; TOS == remaining blocks to process
+; TOS + 4 == name length
+; TOS + 8 -> name
+;
+; Index buffer to search is in index allocation block buffer.
+;
+ mov eax, IndexBlockBuffer ; eax -> Index allocation block
+ lea eax, [eax].IB_IndexHeader ; eax -> Index Header
+
+ call LocateIndexEntry ; eax -> found entry
+
+ or eax, eax
+ jz FindFile40
+
+; Found it!
+;
+; eax -> Found entry
+; TOS == remaining blocks to process
+; TOS + 4 == name length
+; TOS + 8 -> name
+;
+ pop ecx
+ pop ecx
+ pop ecx ; clean up stack
+ ret
+
+FindFile90:
+;
+; Name not found.
+;
+; TOS == name length
+; TOS + 4 -> name to find
+;
+ pop ecx
+ pop ecx ; clean up stack.
+ xor eax, eax ; zero out eax.
+ ret
+
+
+FindFile endp
+
+;****************************************************************************
+;
+; DumpIndexBlock - dumps the index block buffer
+;
+DumpIndexBlock proc near
+
+ SAVE_ALL
+
+ mov esi, IndexBlockBuffer
+
+ mov ecx, 20h ; dwords to dump
+
+DIB10:
+
+ test ecx, 3
+ jnz DIB20
+ call DebugNewLine
+
+DIB20:
+
+ lodsd
+ call PrintNumber
+ loop DIB10
+
+ RESTORE_ALL
+ ret
+
+DumpIndexBlock endp
+
+;****************************************************************************
+;
+; DebugNewLine
+;
+DebugNewLine proc near
+
+ SAVE_ALL
+
+ xor eax, eax
+ xor ebx, ebx
+
+ mov al, 0dh
+ mov ah, 14
+ mov bx, 7
+ int 10h
+
+ mov al, 0ah
+ mov ah, 14
+ mov bx, 7
+ int 10h
+
+ RESTORE_ALL
+ ret
+
+DebugNewLine endp
+
+
+;****************************************************************************
+;
+; PrintName - Display a unicode name
+;
+; ENTRY: DS:ESI -> null-terminated string
+; ECX == characters in string
+;
+; USES: None.
+;
+PrintName proc near
+
+
+ SAVE_ALL
+
+ or ecx, ecx
+ jnz PrintName10
+
+ call DebugNewLine
+
+ RESTORE_ALL
+
+ ret
+
+PrintName10:
+
+ xor eax, eax
+ xor ebx, ebx
+
+ lodsw
+
+ mov ah, 14 ; write teletype
+ mov bx, 7 ; attribute
+ int 10h ; print it
+ loop PrintName10
+
+ call DebugNewLine
+
+ RESTORE_ALL
+ ret
+
+PrintName endp
+
+;****************************************************************************
+;
+; DebugPrint - Display a debug string.
+;
+; ENTRY: DS:SI -> null-terminated string
+;
+; USES: None.
+;
+.286
+DebugPrint proc near
+
+ pusha
+
+DbgPr20:
+
+ lodsb
+ cmp al, 0
+ je DbgPr30
+
+ mov ah, 14 ; write teletype
+ mov bx, 7 ; attribute
+ int 10h ; print it
+ jmp DbgPr20
+
+DbgPr30:
+
+ popa
+ nop
+ ret
+
+DebugPrint endp
+
+;****************************************************************************
+;
+;
+; PrintNumber
+;
+; ENTRY: EAX == number to print
+;
+; PRESERVES ALL REGISTERS
+;
+.386
+PrintNumber proc near
+
+
+ SAVE_ALL
+
+ mov ecx, 8 ; number of digits in a DWORD
+
+PrintNumber10:
+
+ mov edx, eax
+ and edx, 0fh ; edx = lowest-order digit
+ push edx ; put it on the stack
+ shr eax, 4 ; drop low-order digit
+ loop PrintNumber10
+
+ mov ecx, 8 ; number of digits on stack.
+
+PrintNumber20:
+
+ pop eax ; eax = next digit to print
+ cmp eax, 9
+ jg PrintNumber22
+
+ add eax, '0'
+ jmp PrintNumber25
+
+PrintNumber22:
+
+ sub eax, 10
+ add eax, 'A'
+
+PrintNumber25:
+
+ xor ebx, ebx
+
+ mov ah, 14
+ mov bx, 7
+ int 10h
+ loop PrintNumber20
+
+; Print a space to separate numbers
+
+ mov al, ' '
+ mov ah, 14
+ mov bx, 7
+ int 10h
+
+ RESTORE_ALL
+
+ call Pause
+
+ ret
+
+PrintNumber endp
+
+
+;****************************************************************************
+;
+; Debug0 - Print debug string 0 -- used for checkpoints in mainboot
+;
+Debug0 proc near
+
+ SAVE_ALL
+
+ mov esi, offset DbgString0
+ call BootErr$Print
+
+ RESTORE_ALL
+
+ ret
+
+Debug0 endp
+
+;****************************************************************************
+;
+; Debug1 - Print debug string 1 --
+;
+Debug1 proc near
+
+ SAVE_ALL
+
+ mov esi, offset DbgString1
+ call BootErr$Print
+
+ RESTORE_ALL
+
+ ret
+
+Debug1 endp
+
+;****************************************************************************
+;
+; Debug2 - Print debug string 2
+;
+Debug2 proc near
+
+ SAVE_ALL
+
+ mov esi, offset DbgString2
+ call BootErr$Print
+
+ RESTORE_ALL
+
+ ret
+
+Debug2 endp
+
+;****************************************************************************
+;
+; Debug3 - Print debug string 3 --
+;
+Debug3 proc near
+
+ SAVE_ALL
+
+ mov esi, offset DbgString3
+ call BootErr$Print
+
+ RESTORE_ALL
+
+ ret
+
+Debug3 endp
+
+;****************************************************************************
+;
+; Debug4 - Print debug string 4
+;
+Debug4 proc near
+
+ SAVE_ALL
+
+ mov esi, offset DbgString4
+ call BootErr$Print
+
+ RESTORE_ALL
+
+ ret
+
+Debug4 endp
+
+;****************************************************************************
+;
+; Pause - Pause for about 1/2 a second. Simply count until you overlap
+; to zero.
+;
+Pause proc near
+
+ push eax
+ mov eax, 0fff50000h
+
+PauseLoopy:
+ inc eax
+
+ or eax, eax
+ jnz PauseLoopy
+
+ pop eax
+ ret
+
+Pause endp
+
+
+;*************************************************************************
+;
+; LoadIndexFrs - For the requested index type code locate and
+; load the associated Frs.
+;
+; ENTRY: EAX - requested index type code
+; ECX - Points to empty Frs buffer
+;
+; EXIT: EAX - points to offset in Frs buffer of requested index type
+; code or Zero if not found.
+; USES: All
+;
+LoadIndexFrs proc near
+
+ push ecx ; save FRS buffer for later
+ push eax ; save index type code for later
+
+ mov eax, ROOT_FILE_NAME_INDEX_NUMBER
+ push ds
+ pop es
+ mov edi, ecx ; es:edi = target buffer
+
+ call ReadFrs
+
+ mov eax, ecx ; FRS to search
+
+ pop ebx ; Attribute type code
+ push ebx
+ movzx ecx, index_name_length ; Attribute name length
+ mov edx, offset index_name ; Attribute name
+
+ call LocateAttributeRecord
+
+ pop ebx
+ pop ecx
+
+ or eax, eax
+ jnz LoadIndexFrs$Exit ; if found in root return
+
+;
+; if not found in current Frs, search in attribute list
+;
+ ; EBX - holds Attribute type code
+ mov eax, ecx ; FRS to search
+ mov ecx, ebx ; type code
+ push eax ; save Frs
+ push ebx ; save type code
+
+ call SearchAttrList ; search attribute list for FRN
+ ; of specified ($INDEX_ROOT,
+ ; $INDEX_ALLOCATION, or $BITMAP)
+
+ ; EAX - holds FRN for Frs, or Zero
+
+ pop ebx ; Attribute type code (used later)
+ pop edi ; es:edi = target buffer
+
+ or eax, eax ; if we cann't find it in attribute
+ jz LoadIndexFrs$Exit ; list then we are hosed
+
+
+; We should now have the File Record Number where the index for the
+; specified type code we are searching for is, load this into the
+; Frs target buffer.
+;
+; EAX - holds FRN
+; EBX - holds type code
+; EDI - holds target buffer
+
+ push ds
+ pop es
+
+ call ReadFrs
+
+;
+; Now determine the offset in the Frs of the index
+;
+
+; EBX - holds type code
+
+ mov eax, edi ; Frs to search
+ movzx ecx, index_name_length ; Attribute name length
+ mov edx, offset index_name ; Attribute name
+
+ call LocateAttributeRecord
+
+; EAX - holds offset or Zero.
+
+
+LoadIndexFrs$Exit:
+ ret
+
+LoadIndexFrs endp
+
+
+;****************************************************************************
+;
+; SearchAttrList
+;
+; Search the Frs for the attribute list. Then search the attribute list
+; for the specifed type code. When you find it return the FRN in the
+; attribute list entry found or Zero if no match found.
+;
+; ENTRY: ECX - type code to search attrib list for
+; EAX - Frs buffer holding head of attribute list
+; EXIT: EAX - FRN file record number to load, Zero if none.
+;
+; USES: All
+;
+SearchAttrList proc near
+
+ push ecx ; type code to search for in
+ ; attrib list
+
+ ; EAX - holds Frs to search
+ mov ebx, $ATTRIBUTE_LIST ; Attribute type code
+ mov ecx, 0 ; Attribute name length
+ mov edx, 0 ; Attribute name
+
+ call LocateAttributeRecord
+
+ or eax, eax ; If there's no Attribute list,
+ jz SearchAttrList$NotFoundIndex1 ; We are done
+
+; Read the attribute list.
+; eax -> attribute list attribute
+
+ mov ebx, eax ; ebx -> attribute list attribute
+ push ds
+ pop es ; copy ds into es
+ mov edi, AttrList ; ds:edi->attribute list buffer
+
+ call ReadWholeAttribute
+
+ push ds
+ pop es
+ mov ebx, AttrList ; es:ebx -> first attribute list entry
+
+; Now, traverse the attribute list looking for the entry for
+; the Index type code.
+;
+; ebx -> first attribute list entry
+;
+
+ pop ecx ; Get Index Type code
+
+
+SearchAttrList$LookingForIndex:
+
+; DEBUG CODE
+; SAVE_ALL
+;
+; mov eax, es:[bx].ATTRLIST_TypeCode
+; call PrintNumber
+; movzx eax, es:[bx].ATTRLIST_Length
+; call PrintNumber
+; mov eax, es
+; call PrintNumber
+; mov eax, ebx
+; call PrintNumber
+; push es
+; pop ds
+; movzx ecx, es:[bx].ATTRLIST_NameLength ; ecx = chars in name
+; lea esi, es:[bx].ATTRLIST_Name ; esi -> name
+; call PrintName
+;
+; RESTORE_ALL
+; END DEBUG CODE
+
+ cmp es:[bx].ATTRLIST_TypeCode, ecx
+ je SearchAttrList$FoundIndex
+
+ cmp es:[bx].ATTRLIST_TypeCode, $END ; reached invalid attribute
+ je SearchAttrList$NotFoundIndex2 ; so must be at end
+
+ cmp es:[bx].ATTRLIST_Length, 0
+ je SearchAttrList$NotFoundIndex2 ; reached end of list and
+ ; nothing found
+ movzx eax, es:[bx].ATTRLIST_Length
+ add bx, ax
+
+ mov ax, bx
+ and ax, 08000h ; test for roll over
+ jz SearchAttrList$LookingForIndex
+
+ ; If we rolled over then increment to the next es 32K segment and
+ ; zero off the high bits of bx
+
+ mov ax, es
+ add ax, 800h
+ mov es, ax
+
+ and bx, 07fffh
+
+ jmp SearchAttrList$LookingForIndex
+
+SearchAttrList$FoundIndex:
+
+ ; found the index, return the FRN
+
+ mov eax, es:[bx].ATTRLIST_SegmentReference.REF_LowPart
+ ret
+
+
+SearchAttrList$NotFoundIndex1:
+ pop ecx
+SearchAttrList$NotFoundIndex2:
+ xor eax, eax
+ ret
+
+SearchAttrList endp
+
+
+DbgString0 db "Debug Point 0", 0Dh, 0Ah, 0
+DbgString1 db "Debug Point 1", 0Dh, 0Ah, 0
+DbgString2 db "Debug Point 2", 0Dh, 0Ah, 0
+DbgString3 db "Debug Point 3", 0Dh, 0Ah, 0
+DbgString4 db "Debug Point 4", 0Dh, 0Ah, 0
+
+ .errnz ($-_ntfsboot) GT 8192,<FATAL PROBLEM: main boot record exceeds available space>
+
+ org 8192
+
+BootCode ends
+
+ end _ntfsboot
diff --git a/private/ntos/boot/bootcode/ntfs/i386/usa/bootntfs.h b/private/ntos/boot/bootcode/ntfs/i386/usa/bootntfs.h
new file mode 100644
index 000000000..ac6b63ded
--- /dev/null
+++ b/private/ntos/boot/bootcode/ntfs/i386/usa/bootntfs.h
@@ -0,0 +1,517 @@
+#define NTFSBOOTCODE_SIZE 8192
+
+
+unsigned char NtfsBootCode[] = {
+235,91,144,78,84,70,83,32,32,32,32,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,250,51,192,
+142,208,188,0,124,251,184,192,7,142,216,199,6,84,0,0,
+0,199,6,86,0,0,0,199,6,91,0,16,0,184,0,13,
+142,192,43,219,232,7,0,104,0,13,104,102,2,203,80,83,
+81,82,6,102,161,84,0,102,3,6,28,0,102,51,210,102,
+15,183,14,24,0,102,247,241,254,194,136,22,90,0,102,139,
+208,102,193,234,16,247,54,26,0,136,22,37,0,163,88,0,
+161,24,0,42,6,90,0,64,59,6,91,0,118,3,161,91,
+0,80,180,2,139,22,88,0,177,6,210,230,10,54,90,0,
+139,202,134,233,138,54,37,0,178,128,205,19,88,114,42,1,
+6,84,0,131,22,86,0,0,41,6,91,0,118,11,193,224,
+5,140,194,3,208,142,194,235,138,7,90,89,91,88,195,190,
+89,1,235,8,190,227,1,235,3,190,57,1,232,9,0,190,
+173,1,232,3,0,251,235,254,172,60,0,116,9,180,14,187,
+7,0,205,16,235,242,195,29,0,65,32,100,105,115,107,32,
+114,101,97,100,32,101,114,114,111,114,32,111,99,99,117,114,
+114,101,100,46,13,10,0,41,0,65,32,107,101,114,110,101,
+108,32,102,105,108,101,32,105,115,32,109,105,115,115,105,110,
+103,32,102,114,111,109,32,116,104,101,32,100,105,115,107,46,
+13,10,0,37,0,65,32,107,101,114,110,101,108,32,102,105,
+108,101,32,105,115,32,116,111,111,32,100,105,115,99,111,110,
+116,105,103,117,111,117,115,46,13,10,0,51,0,73,110,115,
+101,114,116,32,97,32,115,121,115,116,101,109,32,100,105,115,
+107,101,116,116,101,32,97,110,100,32,114,101,115,116,97,114,
+116,13,10,116,104,101,32,115,121,115,116,101,109,46,13,10,
+0,23,0,92,78,84,76,68,82,32,105,115,32,99,111,109,
+112,114,101,115,115,101,100,46,13,10,0,0,0,0,85,170,
+5,0,78,0,84,0,76,0,68,0,82,0,4,0,36,0,
+73,0,51,0,48,0,0,224,0,0,0,48,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,140,200,142,216,193,224,4,250,139,224,
+251,102,15,183,6,11,0,102,15,182,30,13,0,102,247,227,
+102,163,78,2,102,139,14,64,0,128,249,0,15,143,14,0,
+246,217,102,184,1,0,0,0,102,211,224,235,8,144,102,161,
+78,2,102,247,225,102,163,82,2,102,15,183,30,11,0,102,
+51,210,102,247,243,102,163,86,2,232,44,4,102,139,14,74,
+2,102,137,14,34,2,102,3,14,82,2,102,137,14,38,2,
+102,3,14,82,2,102,137,14,42,2,102,3,14,82,2,102,
+137,14,58,2,102,3,14,82,2,102,137,14,66,2,102,184,
+144,0,0,0,102,139,14,34,2,232,65,9,102,11,192,15,
+132,22,254,102,163,46,2,102,184,160,0,0,0,102,139,14,
+38,2,232,40,9,102,163,50,2,102,184,176,0,0,0,102,
+139,14,42,2,232,22,9,102,163,54,2,102,161,46,2,102,
+11,192,15,132,227,253,103,128,120,8,0,15,133,218,253,103,
+102,141,80,16,103,3,66,4,103,102,15,182,72,12,102,137,
+14,94,2,103,102,139,72,8,102,137,14,90,2,102,161,90,
+2,102,15,183,14,11,0,102,51,210,102,247,241,102,163,98,
+2,102,161,66,2,102,3,6,90,2,102,163,70,2,102,131,
+62,50,2,0,15,132,25,0,102,131,62,54,2,0,15,132,
+135,253,102,139,30,54,2,30,7,102,139,62,70,2,232,177,
+1,102,15,183,14,0,2,102,184,2,2,0,0,232,153,6,
+102,11,192,15,132,88,253,103,102,139,0,30,7,102,139,62,
+58,2,232,209,4,102,161,58,2,102,187,128,0,0,0,102,
+185,0,0,0,0,102,186,0,0,0,0,232,203,0,102,11,
+192,15,132,42,253,103,102,15,183,88,12,102,129,227,255,0,
+0,0,15,133,30,253,102,139,216,104,0,32,7,102,43,255,
+232,79,1,138,22,36,0,184,232,3,142,192,141,54,11,0,
+43,192,104,0,32,80,203,80,83,81,82,6,255,54,91,0,
+255,54,84,0,255,54,86,0,139,195,193,232,4,140,193,3,
+193,37,255,15,45,0,16,247,216,139,14,91,0,193,225,5,
+81,59,193,118,2,139,193,80,193,232,5,163,91,0,232,61,
+252,88,89,43,200,118,11,140,194,3,208,142,194,184,0,16,
+235,222,143,6,86,0,143,6,84,0,143,6,91,0,7,90,
+89,91,88,195,6,30,102,96,102,139,218,102,15,182,14,13,
+0,102,247,225,102,163,84,0,102,139,195,102,247,225,163,91,
+0,139,223,131,227,15,140,192,102,193,239,4,3,199,80,7,
+232,116,255,102,97,144,31,7,195,103,3,64,20,103,102,131,
+56,255,15,132,76,0,103,102,57,24,15,133,51,0,102,11,
+201,15,133,10,0,103,128,120,9,0,15,133,35,0,195,103,
+58,72,9,15,133,26,0,102,139,240,103,3,112,10,232,61,
+5,102,81,30,7,102,139,250,243,167,102,89,15,133,1,0,
+195,103,102,131,120,4,0,15,132,7,0,103,102,3,64,4,
+235,171,102,43,192,195,102,139,243,232,18,5,103,102,3,0,
+103,247,64,12,2,0,15,133,52,0,103,102,141,80,16,103,
+58,74,64,15,133,24,0,103,102,141,114,66,232,239,4,102,
+81,30,7,102,139,251,243,167,102,89,15,133,1,0,195,103,
+131,120,8,0,15,132,6,0,103,3,64,8,235,194,102,51,
+192,195,103,128,123,8,0,15,133,28,0,6,30,102,96,103,
+102,141,83,16,103,102,139,10,102,139,243,103,3,114,4,243,
+164,102,97,144,31,7,195,103,102,141,83,16,103,102,139,74,
+8,102,65,102,43,192,232,1,0,195,6,30,102,96,103,128,
+123,8,1,15,132,3,0,233,127,251,102,131,249,0,15,133,
+6,0,102,97,144,31,7,195,102,83,102,80,102,81,102,87,
+6,232,87,3,102,139,209,7,102,95,102,89,102,59,202,15,
+141,3,0,102,139,209,232,171,254,102,43,202,102,139,218,102,
+139,194,102,15,182,22,13,0,102,247,226,102,15,183,22,11,
+0,102,247,226,102,3,248,102,88,102,3,195,102,91,235,170,
+6,30,102,96,103,128,123,8,1,15,132,3,0,233,25,251,
+102,131,249,0,15,133,6,0,102,97,144,31,7,195,102,83,
+102,80,102,81,102,87,6,102,81,102,51,210,102,15,182,14,
+13,0,102,247,241,102,82,232,225,2,102,15,182,30,13,0,
+102,247,227,102,90,102,3,194,102,80,102,15,182,6,13,0,
+102,247,225,102,139,208,102,88,102,89,7,102,95,102,89,102,
+59,202,15,141,3,0,102,139,209,102,163,84,0,137,22,91,
+0,6,30,102,96,139,223,131,227,15,140,192,102,193,239,4,
+3,199,80,7,232,160,253,102,97,144,31,7,102,43,202,102,
+139,218,102,139,194,102,15,183,22,11,0,102,247,226,102,3,
+248,102,88,102,3,195,102,91,233,101,255,6,30,102,96,38,
+103,102,15,183,95,4,38,103,102,15,183,79,6,102,11,201,
+15,132,101,250,102,3,223,102,131,195,2,102,129,199,254,1,
+0,0,102,73,102,11,201,15,132,23,0,38,103,139,3,38,
+103,137,7,102,131,195,2,102,129,199,0,2,0,0,102,73,
+235,226,102,97,144,31,7,195,6,30,102,96,102,184,1,0,
+0,0,102,163,30,2,102,161,26,2,102,3,6,82,2,102,
+163,74,2,102,161,48,0,102,15,182,30,13,0,102,247,227,
+102,163,84,0,102,161,86,2,163,91,0,102,139,30,26,2,
+30,7,232,242,252,102,15,183,251,232,111,255,102,161,26,2,
+102,187,32,0,0,0,102,185,0,0,0,0,102,186,0,0,
+0,0,232,100,253,102,11,192,15,132,87,0,102,139,216,30,
+7,102,139,62,22,2,232,249,253,102,139,30,22,2,103,102,
+129,59,128,0,0,0,15,132,6,0,103,3,91,4,235,238,
+103,102,129,59,128,0,0,0,15,133,39,0,102,83,103,102,
+139,67,16,102,139,62,74,2,30,7,232,9,1,102,91,102,
+161,82,2,102,1,6,74,2,102,255,6,30,2,103,3,91,
+4,235,205,102,97,144,31,7,195,102,139,208,102,139,14,30,
+2,102,161,26,2,102,82,102,80,102,81,102,82,102,187,128,
+0,0,0,102,185,0,0,0,0,102,186,0,0,0,0,232,
+215,252,102,11,192,15,132,64,249,102,139,216,102,88,232,42,
+1,102,11,192,15,132,7,0,102,91,102,91,102,91,195,102,
+89,102,88,102,90,102,3,6,82,2,226,185,102,51,192,195,
+6,30,102,96,102,80,102,81,102,51,210,102,15,182,30,13,
+0,102,247,243,102,82,232,144,255,102,11,192,15,132,249,248,
+102,15,182,30,13,0,102,247,227,102,90,102,3,194,102,163,
+84,0,102,89,102,15,182,30,13,0,102,59,203,15,142,19,
+0,137,30,91,0,102,43,203,102,88,102,3,195,102,80,102,
+81,235,20,144,102,88,102,3,193,102,80,137,14,91,0,102,
+185,0,0,0,0,102,81,6,102,87,139,223,131,227,15,140,
+192,102,193,239,4,3,199,80,7,232,155,251,102,95,7,102,
+3,62,78,2,102,89,102,88,102,131,249,0,15,143,116,255,
+102,97,144,31,7,195,6,30,102,96,102,247,38,86,2,102,
+139,14,86,2,232,89,255,232,241,253,102,97,144,31,7,195,
+6,30,102,96,102,247,38,98,2,102,139,30,50,2,102,139,
+14,98,2,30,7,102,139,62,66,2,232,35,253,232,203,253,
+102,97,144,31,7,195,102,80,102,83,102,81,102,139,30,70,
+2,102,139,200,102,193,232,3,102,131,225,7,102,3,216,102,
+184,1,0,0,0,102,211,224,103,132,3,15,132,4,0,248,
+235,2,144,249,102,89,102,91,102,88,195,103,128,123,8,1,
+15,132,4,0,102,43,192,195,103,102,141,115,16,103,102,139,
+86,8,102,59,194,15,135,11,0,103,102,139,22,102,59,194,
+15,131,4,0,102,43,192,195,103,3,94,16,102,43,246,103,
+128,59,0,15,132,62,0,232,129,0,102,3,241,232,57,0,
+102,3,202,102,59,193,15,140,33,0,102,139,209,102,80,103,
+102,15,182,11,102,139,193,102,131,224,15,102,193,233,4,102,
+3,217,102,3,216,102,67,102,88,235,196,102,43,200,102,43,
+194,102,3,198,195,102,43,192,195,102,43,201,103,138,11,128,
+225,15,102,131,249,0,15,133,4,0,102,43,201,195,102,83,
+102,82,102,3,217,103,102,15,190,19,102,73,102,75,102,131,
+249,0,15,132,13,0,102,193,226,8,103,138,19,102,75,102,
+73,235,235,102,139,202,102,90,102,91,195,102,83,102,82,102,
+43,210,103,138,19,102,131,226,15,102,43,201,103,138,11,192,
+233,4,102,131,249,0,15,133,8,0,102,43,201,102,90,102,
+91,195,102,3,218,102,3,217,103,102,15,190,19,102,73,102,
+75,102,131,249,0,15,132,13,0,102,193,226,8,103,138,19,
+102,75,102,73,235,235,102,139,202,102,90,102,91,195,102,11,
+201,15,133,1,0,195,102,81,102,86,103,131,62,97,15,140,
+12,0,103,131,62,122,15,143,4,0,103,131,46,32,102,131,
+198,2,226,230,102,94,102,89,195,102,80,102,81,102,139,208,
+102,161,46,2,103,102,141,88,16,103,3,67,4,103,102,141,
+64,16,102,139,218,232,158,250,102,11,192,15,132,5,0,102,
+89,102,89,195,102,161,50,2,102,11,192,15,133,8,0,102,
+89,102,89,102,51,192,195,102,139,22,50,2,103,102,141,82,
+16,103,102,139,66,8,102,64,102,139,30,78,2,102,247,227,
+102,51,210,102,247,54,90,2,102,80,102,88,102,11,192,15,
+132,48,0,102,72,102,80,232,28,254,114,238,232,241,253,102,
+90,102,89,102,91,102,83,102,81,102,82,102,161,66,2,103,
+102,141,64,24,232,47,250,102,11,192,116,206,102,89,102,89,
+102,89,195,102,89,102,89,102,51,192,195,6,30,102,96,102,
+139,54,66,2,102,185,32,0,0,0,102,247,193,3,0,0,
+0,15,133,3,0,232,13,0,102,173,232,105,0,226,235,102,
+97,144,31,7,195,6,30,102,96,102,51,192,102,51,219,176,
+13,180,14,187,7,0,205,16,176,10,180,14,187,7,0,205,
+16,102,97,144,31,7,195,6,30,102,96,102,11,201,15,133,
+9,0,232,208,255,102,97,144,31,7,195,102,51,192,102,51,
+219,173,180,14,187,7,0,205,16,226,240,232,183,255,102,97,
+144,31,7,195,96,172,60,0,116,9,180,14,187,7,0,205,
+16,235,242,97,144,195,6,30,102,96,102,185,8,0,0,0,
+102,139,208,102,131,226,15,102,82,102,193,232,4,226,241,102,
+185,8,0,0,0,102,88,102,131,248,9,15,143,7,0,102,
+131,192,48,235,9,144,102,131,232,10,102,131,192,65,102,51,
+219,180,14,187,7,0,205,16,226,219,176,32,180,14,187,7,
+0,205,16,102,97,144,31,7,232,96,0,195,6,30,102,96,
+102,190,22,13,0,0,232,79,245,102,97,144,31,7,195,6,
+30,102,96,102,190,38,13,0,0,232,60,245,102,97,144,31,
+7,195,6,30,102,96,102,190,54,13,0,0,232,41,245,102,
+97,144,31,7,195,6,30,102,96,102,190,70,13,0,0,232,
+22,245,102,97,144,31,7,195,6,30,102,96,102,190,86,13,
+0,0,232,3,245,102,97,144,31,7,195,102,80,102,184,0,
+0,245,255,102,64,102,11,192,117,249,102,88,195,102,81,102,
+80,102,184,5,0,0,0,30,7,102,139,249,232,71,252,102,
+139,193,102,91,102,83,102,15,183,14,12,2,102,186,14,2,
+0,0,232,68,248,102,91,102,89,102,11,192,15,133,47,0,
+102,139,193,102,139,203,102,80,102,83,232,35,0,102,91,102,
+95,102,11,192,15,132,23,0,30,7,232,9,252,102,139,199,
+102,15,183,14,12,2,102,186,14,2,0,0,232,10,248,195,
+102,81,102,187,32,0,0,0,102,185,0,0,0,0,102,186,
+0,0,0,0,232,242,247,102,11,192,15,132,82,0,102,139,
+216,30,7,102,139,62,22,2,232,135,248,30,7,102,139,30,
+22,2,102,89,38,102,57,15,15,132,46,0,38,102,131,63,
+255,15,132,45,0,38,131,127,4,0,15,132,36,0,38,102,
+15,183,71,4,3,216,139,195,37,0,128,116,215,140,192,5,
+0,8,142,192,129,227,255,127,235,202,38,102,139,71,16,195,
+102,89,102,51,192,195,68,101,98,117,103,32,80,111,105,110,
+116,32,48,13,10,0,68,101,98,117,103,32,80,111,105,110,
+116,32,49,13,10,0,68,101,98,117,103,32,80,111,105,110,
+116,32,50,13,10,0,68,101,98,117,103,32,80,111,105,110,
+116,32,51,13,10,0,68,101,98,117,103,32,80,111,105,110,
+116,32,52,13,10,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+};
diff --git a/private/ntos/boot/bootcode/ntfs/i386/usa/ntfsboot.inc b/private/ntos/boot/bootcode/ntfs/i386/usa/ntfsboot.inc
new file mode 100644
index 000000000..429e7d133
--- /dev/null
+++ b/private/ntos/boot/bootcode/ntfs/i386/usa/ntfsboot.inc
@@ -0,0 +1,36 @@
+; SCCSID = @(#)pinboot.inc 12.1 88/12/19
+; Message data area
+TXT_MSG_SYSINIT_BOOT_ERROR LABEL WORD
+ DW END_MSG_SYSINIT_BOOT_ERROR - TXT_MSG_SYSINIT_BOOT_ERROR - 2
+ DB 'A disk read erro'
+ DB 'r occurred.',0DH,0AH
+END_MSG_SYSINIT_BOOT_ERROR LABEL WORD
+ DB 0
+TXT_MSG_SYSINIT_FILE_NOT_FD LABEL WORD
+ DW END_MSG_SYSINIT_FILE_NOT_FD - TXT_MSG_SYSINIT_FILE_NOT_FD - 2
+ DB 'A kernel file is'
+ DB ' missing from th'
+ DB 'e disk.', 0DH, 0AH
+END_MSG_SYSINIT_FILE_NOT_FD LABEL WORD
+ DB 0
+TXT_MSG_SYSINIT_NODE LABEL WORD
+ DW END_MSG_SYSINIT_NODE - TXT_MSG_SYSINIT_NODE - 2
+ DB 'A kernel file is'
+ DB ' too discontiguo'
+ DB 'us.', 0DH, 0AH
+END_MSG_SYSINIT_NODE LABEL WORD
+ DB 0
+TXT_MSG_SYSINIT_INSER_DK LABEL WORD
+ DW END_MSG_SYSINIT_INSER_DK - TXT_MSG_SYSINIT_INSER_DK - 2
+ DB 'Insert a system '
+ DB 'diskette and res'
+ DB 'tart',0DH,0AH
+ DB 'the system.',0DH,0AH
+END_MSG_SYSINIT_INSER_DK LABEL WORD
+ DB 0
+TXT_MSG_SYSINIT_NTLDR_CMPRS LABEL WORD
+ DW END_MSG_SYSINIT_NTLDR_CMPRS - TXT_MSG_SYSINIT_NTLDR_CMPRS - 2
+ DB '\NTLDR is '
+ DB 'compressed.',0DH,0AH
+END_MSG_SYSINIT_NTLDR_CMPRS LABEL WORD
+ DB 0
diff --git a/private/ntos/boot/bootfont/jpn/bootfont.bin b/private/ntos/boot/bootfont/jpn/bootfont.bin
new file mode 100644
index 000000000..ff106567a
--- /dev/null
+++ b/private/ntos/boot/bootfont/jpn/bootfont.bin
Binary files differ
diff --git a/private/ntos/boot/bootfont/jpn/fntjapan.h b/private/ntos/boot/bootfont/jpn/fntjapan.h
new file mode 100644
index 000000000..95d7c026d
--- /dev/null
+++ b/private/ntos/boot/bootfont/jpn/fntjapan.h
@@ -0,0 +1,3776 @@
+#define MAX_SBCS_NUM 190
+#define MAX_SBCS_BYTES 17
+#define MAX_DBCS_NUM 3573
+#define MAX_DBCS_BYTES 34
+
+unsigned char LeadByteTable[] = { 0x81, 0x84, 0x87, 0x9f, 0xe0, 0xea, 0xfa, 0xfc, 0x00, 0x00 };
+
+unsigned char SBCSImage[MAX_SBCS_NUM][MAX_SBCS_BYTES] = {
+{ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0x20, 0x27, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24 },
+{ 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfc, 0x4, 0xe4, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24 },
+{ 0x3, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x27, 0x20, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x4, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0xe4, 0x4, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x5, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24 },
+{ 0x6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x7, 0x0, 0x0, 0x0, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x3e, 0x1c, 0x1c, 0x8 },
+{ 0x8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x9, 0x0, 0x0, 0x0, 0x0, 0x18, 0x24, 0x24, 0x42, 0x42, 0x42, 0x42, 0x24, 0x24, 0x18, 0x0, 0x0 },
+{ 0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0xb, 0x0, 0x0, 0x0, 0x0, 0xfe, 0x82, 0xc6, 0xaa, 0xaa, 0x92, 0x92, 0xaa, 0xaa, 0xc6, 0x82, 0xfe },
+{ 0xc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0xd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0xe, 0x0, 0x0, 0x0, 0x0, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe },
+{ 0xf, 0x0, 0x0, 0x49, 0x49, 0x2a, 0x36, 0x14, 0x22, 0xe3, 0x22, 0x14, 0x36, 0x2a, 0x49, 0x49, 0x0 },
+{ 0x10, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0xe7, 0x0, 0xe7, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24 },
+{ 0x11, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x12, 0x0, 0x0, 0x0, 0x8, 0x1c, 0x1c, 0x3e, 0x8, 0x8, 0x8, 0x8, 0x8, 0x3e, 0x1c, 0x1c, 0x8 },
+{ 0x13, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x14, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa },
+{ 0x15, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0xe7, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x16, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0xe7, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24 },
+{ 0x17, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0xe4, 0x4, 0xe4, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24 },
+{ 0x18, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x19, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x27, 0x20, 0x27, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24 },
+{ 0x1a, 0x0, 0x55, 0x0, 0xaa, 0x0, 0x55, 0x0, 0xaa, 0x0, 0x55, 0x0, 0xaa, 0x0, 0x55, 0x0, 0xaa },
+{ 0x1b, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x22, 0x62, 0xfe, 0x60, 0x20, 0x0, 0x0, 0x0, 0x0 },
+{ 0x1c, 0x0, 0x0, 0x0, 0x8, 0x1c, 0x1c, 0x3e, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8 },
+{ 0x1d, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8 },
+{ 0x1e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x6, 0x7f, 0x6, 0x4, 0x0, 0x0, 0x0, 0x0 },
+{ 0x1f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20, 0x60, 0xfe, 0x60, 0x20, 0x0, 0x0, 0x0, 0x0 },
+{ 0x20, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x21, 0x0, 0x0, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x0, 0x0, 0x10, 0x38, 0x10, 0x0, 0x0 },
+{ 0x22, 0x0, 0x0, 0x6c, 0x6c, 0x24, 0x48, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x23, 0x0, 0x0, 0x24, 0x24, 0x24, 0x7e, 0x24, 0x24, 0x24, 0x24, 0x7e, 0x24, 0x24, 0x24, 0x0, 0x0 },
+{ 0x24, 0x0, 0x0, 0x10, 0x38, 0x54, 0x54, 0x50, 0x38, 0x14, 0x54, 0x54, 0x54, 0x38, 0x10, 0x0, 0x0 },
+{ 0x25, 0x0, 0x0, 0x22, 0x56, 0x54, 0x2c, 0x8, 0x18, 0x10, 0x30, 0x24, 0x6a, 0x4a, 0x44, 0x0, 0x0 },
+{ 0x26, 0x0, 0x0, 0x30, 0x48, 0x48, 0x50, 0x20, 0x66, 0x66, 0x94, 0x94, 0x88, 0x8c, 0x76, 0x0, 0x0 },
+{ 0x27, 0x0, 0x0, 0x18, 0x18, 0x8, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x28, 0x0, 0x0, 0x8, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x8, 0x0, 0x0 },
+{ 0x29, 0x0, 0x0, 0x10, 0x8, 0x8, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x8, 0x8, 0x10, 0x0, 0x0 },
+{ 0x2a, 0x0, 0x0, 0x0, 0x0, 0x10, 0x92, 0x54, 0x38, 0x38, 0x54, 0x92, 0x10, 0x0, 0x0, 0x0, 0x0 },
+{ 0x2b, 0x0, 0x0, 0x0, 0x0, 0x10, 0x10, 0x10, 0xfe, 0x10, 0x10, 0x10, 0x10, 0x0, 0x0, 0x0, 0x0 },
+{ 0x2c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x18, 0x18, 0x8, 0x10 },
+{ 0x2d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x2e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x18, 0x18, 0x0, 0x0 },
+{ 0x2f, 0x0, 0x0, 0x2, 0x4, 0x4, 0x8, 0x8, 0x10, 0x10, 0x20, 0x20, 0x40, 0x40, 0x80, 0x0, 0x0 },
+{ 0x30, 0x0, 0x0, 0x18, 0x24, 0x24, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x24, 0x24, 0x18, 0x0, 0x0 },
+{ 0x31, 0x0, 0x0, 0x10, 0x30, 0x50, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x7c, 0x0, 0x0 },
+{ 0x32, 0x0, 0x0, 0x3c, 0x42, 0x42, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x42, 0x42, 0x7e, 0x0, 0x0 },
+{ 0x33, 0x0, 0x0, 0x3c, 0x42, 0x42, 0x2, 0x2, 0x1c, 0x2, 0x2, 0x42, 0x42, 0x42, 0x3c, 0x0, 0x0 },
+{ 0x34, 0x0, 0x0, 0x4, 0xc, 0xc, 0x14, 0x24, 0x24, 0x44, 0x44, 0xfe, 0x4, 0x4, 0xe, 0x0, 0x0 },
+{ 0x35, 0x0, 0x0, 0x7e, 0x40, 0x40, 0x40, 0x7c, 0x42, 0x2, 0x2, 0x42, 0x42, 0x42, 0x3c, 0x0, 0x0 },
+{ 0x36, 0x0, 0x0, 0x3c, 0x42, 0x42, 0x40, 0x40, 0x7c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x0, 0x0 },
+{ 0x37, 0x0, 0x0, 0x7e, 0x42, 0x42, 0x4, 0x4, 0x8, 0x8, 0x10, 0x10, 0x10, 0x10, 0x10, 0x0, 0x0 },
+{ 0x38, 0x0, 0x0, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x0, 0x0 },
+{ 0x39, 0x0, 0x0, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3e, 0x2, 0x2, 0x42, 0x42, 0x3c, 0x0, 0x0 },
+{ 0x3a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x18, 0x18, 0x0, 0x0, 0x0, 0x0, 0x18, 0x18, 0x0, 0x0 },
+{ 0x3b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x18, 0x18, 0x0, 0x0, 0x0, 0x0, 0x18, 0x18, 0x8, 0x10 },
+{ 0x3c, 0x0, 0x0, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x0, 0x0, 0x0 },
+{ 0x3d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7e, 0x0, 0x7e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x3e, 0x0, 0x0, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x0, 0x0, 0x0 },
+{ 0x3f, 0x0, 0x0, 0x38, 0x44, 0x82, 0x82, 0x44, 0x8, 0x10, 0x10, 0x0, 0x10, 0x38, 0x10, 0x0, 0x0 },
+{ 0x40, 0x0, 0x0, 0x3c, 0x42, 0x42, 0x2, 0x2, 0x32, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x3c, 0x0, 0x0 },
+{ 0x41, 0x0, 0x0, 0x18, 0x24, 0x42, 0x42, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x42, 0x42, 0x0, 0x0 },
+{ 0x42, 0x0, 0x0, 0xfc, 0x42, 0x42, 0x42, 0x42, 0x7c, 0x42, 0x42, 0x42, 0x42, 0x42, 0xfc, 0x0, 0x0 },
+{ 0x43, 0x0, 0x0, 0x3a, 0x46, 0x42, 0x42, 0x40, 0x40, 0x40, 0x40, 0x42, 0x42, 0x42, 0x3c, 0x0, 0x0 },
+{ 0x44, 0x0, 0x0, 0xf8, 0x44, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x44, 0xf8, 0x0, 0x0 },
+{ 0x45, 0x0, 0x0, 0xfe, 0x42, 0x40, 0x40, 0x44, 0x7c, 0x44, 0x40, 0x40, 0x40, 0x42, 0xfe, 0x0, 0x0 },
+{ 0x46, 0x0, 0x0, 0xfe, 0x42, 0x40, 0x40, 0x44, 0x7c, 0x44, 0x40, 0x40, 0x40, 0x40, 0xe0, 0x0, 0x0 },
+{ 0x47, 0x0, 0x0, 0x3a, 0x46, 0x42, 0x42, 0x40, 0x40, 0x4e, 0x42, 0x42, 0x42, 0x46, 0x3a, 0x0, 0x0 },
+{ 0x48, 0x0, 0x0, 0xee, 0x44, 0x44, 0x44, 0x44, 0x7c, 0x44, 0x44, 0x44, 0x44, 0x44, 0xee, 0x0, 0x0 },
+{ 0x49, 0x0, 0x0, 0x7c, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x7c, 0x0, 0x0 },
+{ 0x4a, 0x0, 0x0, 0x3c, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x88, 0x70, 0x0, 0x0 },
+{ 0x4b, 0x0, 0x0, 0xee, 0x44, 0x48, 0x50, 0x60, 0x60, 0x50, 0x50, 0x48, 0x48, 0x44, 0xee, 0x0, 0x0 },
+{ 0x4c, 0x0, 0x0, 0x70, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x7e, 0x0, 0x0 },
+{ 0x4d, 0x0, 0x0, 0xc6, 0x44, 0x6c, 0x6c, 0x54, 0x54, 0x54, 0x44, 0x44, 0x44, 0x44, 0xee, 0x0, 0x0 },
+{ 0x4e, 0x0, 0x0, 0xee, 0x44, 0x64, 0x64, 0x74, 0x54, 0x5c, 0x4c, 0x4c, 0x44, 0x44, 0xee, 0x0, 0x0 },
+{ 0x4f, 0x0, 0x0, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x0, 0x0 },
+{ 0x50, 0x0, 0x0, 0xf8, 0x44, 0x42, 0x42, 0x42, 0x44, 0x78, 0x40, 0x40, 0x40, 0x40, 0xe0, 0x0, 0x0 },
+{ 0x51, 0x0, 0x0, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x72, 0x4a, 0x44, 0x3a, 0x0, 0x0 },
+{ 0x52, 0x0, 0x0, 0xfc, 0x42, 0x42, 0x42, 0x44, 0x78, 0x4c, 0x44, 0x44, 0x44, 0x44, 0xee, 0x0, 0x0 },
+{ 0x53, 0x0, 0x0, 0x3a, 0x46, 0x42, 0x40, 0x20, 0x18, 0x4, 0x2, 0x42, 0x42, 0x62, 0x5c, 0x0, 0x0 },
+{ 0x54, 0x0, 0x0, 0xfe, 0x92, 0x92, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x0, 0x0 },
+{ 0x55, 0x0, 0x0, 0xee, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38, 0x0, 0x0 },
+{ 0x56, 0x0, 0x0, 0xee, 0x44, 0x44, 0x44, 0x44, 0x44, 0x28, 0x28, 0x28, 0x10, 0x10, 0x10, 0x0, 0x0 },
+{ 0x57, 0x0, 0x0, 0xee, 0x44, 0x44, 0x44, 0x44, 0x54, 0x54, 0x7c, 0x6c, 0x6c, 0x44, 0x44, 0x0, 0x0 },
+{ 0x58, 0x0, 0x0, 0xee, 0x44, 0x44, 0x28, 0x28, 0x10, 0x10, 0x28, 0x28, 0x44, 0x44, 0xee, 0x0, 0x0 },
+{ 0x59, 0x0, 0x0, 0xee, 0x44, 0x44, 0x44, 0x28, 0x28, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x0, 0x0 },
+{ 0x5a, 0x0, 0x0, 0xfe, 0x82, 0x82, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, 0x82, 0x82, 0xfe, 0x0, 0x0 },
+{ 0x5b, 0x0, 0x0, 0x1c, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1c, 0x0, 0x0 },
+{ 0x5c, 0x0, 0x0, 0xee, 0x44, 0x44, 0x28, 0x10, 0x7c, 0x10, 0x10, 0x7c, 0x10, 0x10, 0x38, 0x0, 0x0 },
+{ 0x5d, 0x0, 0x0, 0x38, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x38, 0x0, 0x0 },
+{ 0x5e, 0x0, 0x0, 0x18, 0x24, 0x42, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x5f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0 },
+{ 0x60, 0x0, 0x0, 0x30, 0x30, 0x20, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x61, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x38, 0x44, 0x4, 0x3c, 0x44, 0x44, 0x4c, 0x36, 0x0, 0x0 },
+{ 0x62, 0x0, 0x0, 0xc0, 0x40, 0x40, 0x40, 0x58, 0x64, 0x42, 0x42, 0x42, 0x42, 0x64, 0xd8, 0x0, 0x0 },
+{ 0x63, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x38, 0x44, 0x44, 0x40, 0x40, 0x44, 0x44, 0x38, 0x0, 0x0 },
+{ 0x64, 0x0, 0x0, 0xc, 0x4, 0x4, 0x4, 0x34, 0x4c, 0x44, 0x44, 0x44, 0x44, 0x4c, 0x36, 0x0, 0x0 },
+{ 0x65, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x38, 0x44, 0x44, 0x7c, 0x40, 0x44, 0x44, 0x38, 0x0, 0x0 },
+{ 0x66, 0x0, 0x0, 0xc, 0x12, 0x10, 0x10, 0x7c, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x0, 0x0 },
+{ 0x67, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3e, 0x44, 0x44, 0x44, 0x4c, 0x34, 0x4, 0x44, 0x44, 0x38 },
+{ 0x68, 0x0, 0x0, 0xc0, 0x40, 0x40, 0x40, 0x58, 0x64, 0x44, 0x44, 0x44, 0x44, 0x44, 0xee, 0x0, 0x0 },
+{ 0x69, 0x0, 0x0, 0x0, 0x10, 0x10, 0x0, 0x30, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x0, 0x0 },
+{ 0x6a, 0x0, 0x0, 0x0, 0x8, 0x8, 0x0, 0x38, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x48, 0x48, 0x30 },
+{ 0x6b, 0x0, 0x0, 0xc0, 0x40, 0x40, 0x40, 0x40, 0x4c, 0x48, 0x50, 0x60, 0x50, 0x48, 0xee, 0x0, 0x0 },
+{ 0x6c, 0x0, 0x0, 0x30, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x0, 0x0 },
+{ 0x6d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe8, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0xd6, 0x0, 0x0 },
+{ 0x6e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xd8, 0x64, 0x44, 0x44, 0x44, 0x44, 0x44, 0xee, 0x0, 0x0 },
+{ 0x6f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x0, 0x0 },
+{ 0x70, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7c, 0x22, 0x22, 0x22, 0x22, 0x3c, 0x20, 0x20, 0x20, 0x70 },
+{ 0x71, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3e, 0x44, 0x44, 0x44, 0x44, 0x3c, 0x4, 0x4, 0x4, 0xe },
+{ 0x72, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6c, 0x32, 0x22, 0x20, 0x20, 0x20, 0x20, 0x70, 0x0, 0x0 },
+{ 0x73, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3c, 0x42, 0x42, 0x30, 0xc, 0x42, 0x42, 0x3c, 0x0, 0x0 },
+{ 0x74, 0x0, 0x0, 0x0, 0x10, 0x10, 0x10, 0x7c, 0x10, 0x10, 0x10, 0x10, 0x12, 0x12, 0xc, 0x0, 0x0 },
+{ 0x75, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xcc, 0x44, 0x44, 0x44, 0x44, 0x44, 0x4c, 0x36, 0x0, 0x0 },
+{ 0x76, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xee, 0x44, 0x44, 0x44, 0x28, 0x28, 0x10, 0x10, 0x0, 0x0 },
+{ 0x77, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc6, 0x44, 0x44, 0x54, 0x54, 0x54, 0x6c, 0x44, 0x0, 0x0 },
+{ 0x78, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc6, 0x44, 0x28, 0x10, 0x10, 0x28, 0x44, 0xc6, 0x0, 0x0 },
+{ 0x79, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xee, 0x44, 0x44, 0x24, 0x28, 0x18, 0x8, 0x10, 0x90, 0x60 },
+{ 0x7a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7e, 0x42, 0x4, 0x8, 0x10, 0x20, 0x42, 0x7e, 0x0, 0x0 },
+{ 0x7b, 0x0, 0x0, 0xc, 0x10, 0x10, 0x10, 0x10, 0x20, 0x10, 0x10, 0x10, 0x10, 0x10, 0xc, 0x0, 0x0 },
+{ 0x7c, 0x0, 0x0, 0x0, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x0, 0x0 },
+{ 0x7d, 0x0, 0x0, 0x30, 0x8, 0x8, 0x8, 0x8, 0x4, 0x8, 0x8, 0x8, 0x8, 0x8, 0x30, 0x0, 0x0 },
+{ 0x7e, 0x0, 0x0, 0x32, 0x4c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0xa1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30, 0x48, 0x48, 0x30 },
+{ 0xa2, 0x3e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0xa3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x3e },
+{ 0xa4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x30, 0x10 },
+{ 0xa5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x18, 0x18, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0xa6, 0x0, 0x0, 0x7e, 0x2, 0x2, 0x2, 0x7e, 0x2, 0x2, 0x2, 0x4, 0x4, 0x8, 0x10, 0x60, 0x0 },
+{ 0xa7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7e, 0x2, 0x14, 0x18, 0x10, 0x10, 0x10, 0x20, 0x20, 0x40, 0x0 },
+{ 0xa8, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x4, 0x8, 0x18, 0x68, 0x8, 0x8, 0x8, 0x8, 0x8, 0x0 },
+{ 0xa9, 0x0, 0x0, 0x0, 0x0, 0x8, 0x8, 0x8, 0x7f, 0x41, 0x41, 0x1, 0x2, 0x2, 0x4, 0x18, 0x0 },
+{ 0xaa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3e, 0x8, 0x8, 0x8, 0x8, 0x8, 0x7f, 0x0, 0x0, 0x0 },
+{ 0xab, 0x0, 0x0, 0x0, 0x0, 0x4, 0x4, 0x4, 0x7f, 0x4, 0xc, 0x14, 0x24, 0x44, 0x4, 0xc, 0x0 },
+{ 0xac, 0x0, 0x0, 0x0, 0x0, 0x20, 0x20, 0x27, 0x79, 0x12, 0x12, 0x10, 0x8, 0x8, 0x8, 0x8, 0x0 },
+{ 0xad, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3c, 0x4, 0x4, 0x4, 0x4, 0x4, 0x7f, 0x0, 0x0, 0x0 },
+{ 0xae, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7e, 0x2, 0x2, 0x7e, 0x2, 0x2, 0x7e, 0x0, 0x0, 0x0 },
+{ 0xaf, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0x9, 0x49, 0x21, 0x21, 0x2, 0x2, 0x4, 0x8, 0x30, 0x0 },
+{ 0xb0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0xb1, 0x0, 0x0, 0x7f, 0x1, 0x9, 0xa, 0xa, 0x8, 0x8, 0x8, 0x8, 0x10, 0x10, 0x20, 0x20, 0x0 },
+{ 0xb2, 0x0, 0x1, 0x1, 0x1, 0x2, 0x2, 0x4, 0xc, 0x14, 0x64, 0x4, 0x4, 0x4, 0x4, 0x4, 0x0 },
+{ 0xb3, 0x0, 0x8, 0x8, 0x8, 0x7f, 0x41, 0x41, 0x41, 0x1, 0x1, 0x1, 0x2, 0x2, 0x4, 0x18, 0x0 },
+{ 0xb4, 0x0, 0x0, 0x0, 0x3e, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x7f, 0x0, 0x0, 0x0 },
+{ 0xb5, 0x0, 0x4, 0x4, 0x4, 0x7f, 0xc, 0xc, 0x14, 0x14, 0x14, 0x24, 0x24, 0x44, 0x4, 0xc, 0x0 },
+{ 0xb6, 0x0, 0x8, 0x8, 0x8, 0x7f, 0x9, 0x9, 0x9, 0x9, 0x11, 0x11, 0x11, 0x22, 0x22, 0x4c, 0x0 },
+{ 0xb7, 0x0, 0x10, 0x10, 0x10, 0x1e, 0x68, 0x8, 0x8, 0xf, 0x78, 0x4, 0x4, 0x4, 0x4, 0x4, 0x0 },
+{ 0xb8, 0x0, 0x8, 0x8, 0x1f, 0x11, 0x11, 0x21, 0x41, 0x2, 0x2, 0x4, 0x4, 0x8, 0x10, 0x60, 0x0 },
+{ 0xb9, 0x0, 0x20, 0x20, 0x20, 0x3f, 0x24, 0x24, 0x44, 0x4, 0x4, 0x4, 0x8, 0x8, 0x10, 0x20, 0x0 },
+{ 0xba, 0x0, 0x0, 0x0, 0x7e, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x7e, 0x0, 0x0, 0x0 },
+{ 0xbb, 0x0, 0x24, 0x24, 0x24, 0x7f, 0x24, 0x24, 0x24, 0x24, 0x4, 0x4, 0x8, 0x8, 0x10, 0x20, 0x0 },
+{ 0xbc, 0x0, 0x30, 0x8, 0x0, 0x0, 0x60, 0x11, 0x1, 0x1, 0x1, 0x2, 0x2, 0x4, 0x18, 0x60, 0x0 },
+{ 0xbd, 0x0, 0x0, 0x7e, 0x2, 0x2, 0x4, 0x4, 0x4, 0x8, 0x8, 0x14, 0x12, 0x22, 0x21, 0x41, 0x0 },
+{ 0xbe, 0x0, 0x10, 0x10, 0x10, 0x10, 0x17, 0x79, 0x11, 0x12, 0x12, 0x10, 0x10, 0x10, 0x8, 0x7, 0x0 },
+{ 0xbf, 0x0, 0x2, 0x42, 0x22, 0x22, 0x2, 0x2, 0x2, 0x4, 0x4, 0x4, 0x8, 0x8, 0x10, 0x20, 0x0 },
+{ 0xc0, 0x0, 0x20, 0x20, 0x3e, 0x22, 0x22, 0x5a, 0x46, 0x2, 0x2, 0x4, 0x4, 0x8, 0x10, 0x60, 0x0 },
+{ 0xc1, 0x0, 0x2, 0x4, 0x38, 0x8, 0x8, 0x8, 0x7f, 0x8, 0x8, 0x8, 0x8, 0x10, 0x10, 0x60, 0x0 },
+{ 0xc2, 0x0, 0x10, 0x9, 0x9, 0x49, 0x21, 0x21, 0x1, 0x2, 0x2, 0x4, 0x4, 0x8, 0x10, 0x20, 0x0 },
+{ 0xc3, 0x0, 0x0, 0x3e, 0x0, 0x0, 0x0, 0x7f, 0x8, 0x8, 0x8, 0x8, 0x8, 0x10, 0x10, 0x20, 0x0 },
+{ 0xc4, 0x0, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1c, 0x12, 0x11, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x0 },
+{ 0xc5, 0x0, 0x8, 0x8, 0x8, 0x8, 0x7f, 0x8, 0x8, 0x8, 0x8, 0x8, 0x10, 0x10, 0x20, 0x40, 0x0 },
+{ 0xc6, 0x0, 0x0, 0x0, 0x3e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7f, 0x0, 0x0, 0x0 },
+{ 0xc7, 0x0, 0x0, 0x3f, 0x1, 0x1, 0x2, 0x22, 0x1a, 0x4, 0x6, 0xa, 0x9, 0x11, 0x21, 0x40, 0x0 },
+{ 0xc8, 0x0, 0x8, 0x8, 0x8, 0x7f, 0x2, 0x4, 0x4, 0xa, 0x19, 0x29, 0x48, 0x8, 0x8, 0x8, 0x0 },
+{ 0xc9, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x4, 0x4, 0x4, 0x8, 0x8, 0x10, 0x20, 0x40, 0x0 },
+{ 0xca, 0x0, 0x0, 0x12, 0x12, 0x12, 0x12, 0x12, 0x11, 0x11, 0x21, 0x21, 0x21, 0x21, 0x41, 0x41, 0x0 },
+{ 0xcb, 0x0, 0x20, 0x20, 0x20, 0x20, 0x20, 0x23, 0x3c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x10, 0xf, 0x0 },
+{ 0xcc, 0x0, 0x0, 0x7e, 0x2, 0x2, 0x2, 0x2, 0x2, 0x4, 0x4, 0x4, 0x8, 0x8, 0x10, 0x20, 0x0 },
+{ 0xcd, 0x0, 0x0, 0x10, 0x28, 0x28, 0x44, 0x44, 0x4, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x0, 0x0 },
+{ 0xce, 0x0, 0x8, 0x8, 0x8, 0x7f, 0x8, 0x8, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x8, 0x8, 0x0 },
+{ 0xcf, 0x0, 0x0, 0x7e, 0x2, 0x2, 0x2, 0x4, 0x44, 0x28, 0x10, 0x10, 0x8, 0x8, 0x8, 0x8, 0x0 },
+{ 0xd0, 0x0, 0x0, 0x38, 0x6, 0x1, 0x0, 0x30, 0xc, 0x2, 0x0, 0x70, 0xc, 0x2, 0x1, 0x0, 0x0 },
+{ 0xd1, 0x0, 0x8, 0x8, 0x8, 0x8, 0x8, 0x10, 0x10, 0x10, 0x12, 0x22, 0x21, 0x27, 0x59, 0x61, 0x0 },
+{ 0xd2, 0x0, 0x1, 0x1, 0x1, 0x2, 0x32, 0xa, 0x4, 0x6, 0xa, 0x9, 0x11, 0x11, 0x20, 0x40, 0x0 },
+{ 0xd3, 0x0, 0x0, 0x3e, 0x8, 0x8, 0x8, 0x8, 0x7f, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x7, 0x0 },
+{ 0xd4, 0x0, 0x20, 0x20, 0x23, 0x1d, 0x71, 0x12, 0x12, 0x8, 0x8, 0x8, 0x4, 0x4, 0x4, 0x4, 0x0 },
+{ 0xd5, 0x0, 0x0, 0x0, 0x3c, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x7f, 0x0, 0x0, 0x0 },
+{ 0xd6, 0x0, 0x0, 0x0, 0x7e, 0x2, 0x2, 0x2, 0x7e, 0x2, 0x2, 0x2, 0x2, 0x7e, 0x0, 0x0, 0x0 },
+{ 0xd7, 0x0, 0x0, 0x3c, 0x0, 0x0, 0x0, 0x7e, 0x2, 0x2, 0x2, 0x4, 0x4, 0x8, 0x10, 0x20, 0x0 },
+{ 0xd8, 0x0, 0x0, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x2, 0x2, 0x4, 0x4, 0x8, 0x10, 0x0 },
+{ 0xd9, 0x0, 0x0, 0x8, 0x28, 0x28, 0x28, 0x28, 0x29, 0x29, 0x29, 0x2a, 0x2a, 0x4c, 0x4c, 0x48, 0x0 },
+{ 0xda, 0x0, 0x0, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21, 0x22, 0x22, 0x24, 0x28, 0x30, 0x0 },
+{ 0xdb, 0x0, 0x0, 0x0, 0x7e, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x7e, 0x42, 0x0, 0x0 },
+{ 0xdc, 0x0, 0x0, 0x7e, 0x42, 0x42, 0x42, 0x42, 0x2, 0x4, 0x4, 0x4, 0x8, 0x8, 0x10, 0x20, 0x0 },
+{ 0xdd, 0x0, 0x0, 0x60, 0x10, 0x0, 0x1, 0x1, 0x1, 0x2, 0x2, 0x2, 0x4, 0x8, 0x10, 0x60, 0x0 },
+{ 0xde, 0x0, 0x0, 0x8, 0x24, 0x12, 0x8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0xdf, 0x0, 0x0, 0x18, 0x24, 0x24, 0x18, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+};
+
+unsigned char DBCSImage[MAX_DBCS_NUM][MAX_DBCS_BYTES] = {
+{ 0x81, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0x41, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30, 0x0, 0x18, 0x0, 0x8, 0x0 },
+{ 0x81, 0x42, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30, 0x0, 0x48, 0x0, 0x48, 0x0, 0x30, 0x0 },
+{ 0x81, 0x43, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30, 0x0, 0x30, 0x0, 0x10, 0x0, 0x20, 0x0 },
+{ 0x81, 0x44, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30, 0x0, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x80, 0x1, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0x46, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x80, 0x1, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x80, 0x1, 0x80, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0x47, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x80, 0x1, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x80, 0x1, 0x80, 0x0, 0x80, 0x1, 0x0 },
+{ 0x81, 0x48, 0x0, 0x0, 0x3, 0xe0, 0x4, 0x10, 0x8, 0x8, 0x8, 0x8, 0x4, 0x8, 0x0, 0x30, 0x0, 0xc0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x80, 0x1, 0x80, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0x49, 0x0, 0x0, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x80, 0x1, 0x80, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0x4a, 0x28, 0x0, 0x28, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0x4b, 0x0, 0x0, 0x0, 0x0, 0x30, 0x0, 0x48, 0x0, 0x48, 0x0, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0x4c, 0x0, 0xc0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0x4d, 0x3, 0x0, 0x0, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0x4e, 0x3, 0x60, 0x3, 0x60, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0x4f, 0x1, 0x80, 0x6, 0x60, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0x50, 0x7f, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0x51, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xff },
+{ 0x81, 0x52, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6, 0x0, 0x3, 0x0, 0x1, 0x80, 0x0, 0xc0, 0x0, 0x60, 0x0, 0x20, 0x0, 0x30, 0x0, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0x53, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x28, 0x6, 0x28, 0x3, 0x0, 0x1, 0x80, 0x0, 0xc0, 0x0, 0x60, 0x0, 0x20, 0x0, 0x30, 0x0, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0x54, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x0, 0x6, 0x0, 0x3, 0x0, 0x1, 0x80, 0x0, 0xe0, 0x0, 0x30, 0x0, 0x18, 0x0, 0x30, 0x0, 0xe0, 0x1, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0x55, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0x28, 0xc, 0x28, 0x6, 0x0, 0x3, 0x0, 0x1, 0xc0, 0x0, 0x60, 0x0, 0x30, 0x0, 0x60, 0x1, 0xc0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0x56, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x4, 0x40, 0x4, 0x40, 0x8, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0x57, 0x0, 0x80, 0x1, 0xc0, 0x3, 0x60, 0x6, 0x30, 0xc, 0x18, 0x18, 0xc, 0x70, 0x7, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x81, 0x58, 0x0, 0x0, 0x1, 0x0, 0x1, 0x0, 0x3, 0x0, 0x3, 0xf8, 0x6, 0x8, 0x4, 0x18, 0xc, 0x10, 0x8, 0x30, 0x13, 0x60, 0x1, 0xc0, 0x0, 0x60, 0x0, 0x30, 0x0, 0x10, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0x59, 0x0, 0x0, 0x0, 0x6, 0x0, 0xc, 0x0, 0x18, 0x3, 0xb0, 0x4, 0xe0, 0x8, 0xe0, 0x9, 0xb0, 0x1b, 0x18, 0x12, 0x0, 0x16, 0x0, 0x14, 0x0, 0x1c, 0x0, 0x18, 0x0, 0x30, 0x0, 0x0, 0x0 },
+{ 0x81, 0x5a, 0x0, 0x0, 0x3, 0xe0, 0xe, 0x38, 0x18, 0xc, 0x10, 0x4, 0x30, 0x6, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x30, 0x6, 0x10, 0x4, 0x18, 0xc, 0xe, 0x38, 0x3, 0xe0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0x5b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20, 0x0, 0x3f, 0xfe, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0x5c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0x5d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0x5e, 0x0, 0x1, 0x0, 0x2, 0x0, 0x4, 0x0, 0x8, 0x0, 0x10, 0x0, 0x20, 0x0, 0x40, 0x0, 0x80, 0x1, 0x0, 0x2, 0x0, 0x4, 0x0, 0x8, 0x0, 0x10, 0x0, 0x20, 0x0, 0x40, 0x0, 0x0, 0x0 },
+{ 0x81, 0x5f, 0x40, 0x0, 0x20, 0x0, 0x10, 0x0, 0x8, 0x0, 0x4, 0x0, 0x2, 0x0, 0x1, 0x0, 0x0, 0x80, 0x0, 0x40, 0x0, 0x20, 0x0, 0x10, 0x0, 0x8, 0x0, 0x4, 0x0, 0x2, 0x0, 0x1, 0x0, 0x0 },
+{ 0x81, 0x60, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1e, 0x0, 0x23, 0x81, 0x40, 0xe2, 0x0, 0x3c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0x61, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20 },
+{ 0x81, 0x62, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80 },
+{ 0x81, 0x63, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x31, 0x8c, 0x31, 0x8c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0x64, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc, 0x18, 0xc, 0x18, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0x65, 0x0, 0x8, 0x0, 0x10, 0x0, 0x18, 0x0, 0x18, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0x66, 0xc, 0x0, 0xc, 0x0, 0x4, 0x0, 0x8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0x67, 0x0, 0x12, 0x0, 0x24, 0x0, 0x36, 0x0, 0x36, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0x68, 0x1b, 0x0, 0x1b, 0x0, 0x9, 0x0, 0x12, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0x69, 0x0, 0x4, 0x0, 0x8, 0x0, 0x18, 0x0, 0x10, 0x0, 0x30, 0x0, 0x20, 0x0, 0x20, 0x0, 0x20, 0x0, 0x20, 0x0, 0x20, 0x0, 0x20, 0x0, 0x30, 0x0, 0x10, 0x0, 0x18, 0x0, 0x8, 0x0, 0x4 },
+{ 0x81, 0x6a, 0x10, 0x0, 0x8, 0x0, 0xc, 0x0, 0x4, 0x0, 0x6, 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x6, 0x0, 0x4, 0x0, 0xc, 0x0, 0x8, 0x0, 0x10, 0x0 },
+{ 0x81, 0x6b, 0x0, 0x4, 0x0, 0x18, 0x0, 0x60, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x60, 0x0, 0x18, 0x0, 0x4 },
+{ 0x81, 0x6c, 0x10, 0x0, 0xc, 0x0, 0x3, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x3, 0x0, 0xc, 0x0, 0x10, 0x0 },
+{ 0x81, 0x6d, 0x0, 0x7c, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x7c },
+{ 0x81, 0x6e, 0x1f, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1f, 0x0 },
+{ 0x81, 0x6f, 0x0, 0x4, 0x0, 0x8, 0x0, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x20, 0x0, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x8, 0x0, 0x4 },
+{ 0x81, 0x70, 0x10, 0x0, 0x8, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x2, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x8, 0x0, 0x10, 0x0 },
+{ 0x81, 0x71, 0x0, 0x4, 0x0, 0x8, 0x0, 0x8, 0x0, 0x10, 0x0, 0x20, 0x0, 0x20, 0x0, 0x40, 0x0, 0x80, 0x0, 0x80, 0x0, 0x40, 0x0, 0x20, 0x0, 0x20, 0x0, 0x10, 0x0, 0x8, 0x0, 0x8, 0x0, 0x4 },
+{ 0x81, 0x72, 0x10, 0x0, 0x8, 0x0, 0x8, 0x0, 0x4, 0x0, 0x2, 0x0, 0x2, 0x0, 0x1, 0x0, 0x0, 0x80, 0x0, 0x80, 0x1, 0x0, 0x2, 0x0, 0x2, 0x0, 0x4, 0x0, 0x8, 0x0, 0x8, 0x0, 0x10, 0x0 },
+{ 0x81, 0x73, 0x0, 0x12, 0x0, 0x24, 0x0, 0x24, 0x0, 0x48, 0x0, 0x90, 0x0, 0x90, 0x1, 0x20, 0x2, 0x40, 0x2, 0x40, 0x1, 0x20, 0x0, 0x90, 0x0, 0x90, 0x0, 0x48, 0x0, 0x24, 0x0, 0x24, 0x0, 0x12 },
+{ 0x81, 0x74, 0x24, 0x0, 0x12, 0x0, 0x12, 0x0, 0x9, 0x0, 0x4, 0x80, 0x4, 0x80, 0x2, 0x40, 0x1, 0x20, 0x1, 0x20, 0x2, 0x40, 0x4, 0x80, 0x4, 0x80, 0x9, 0x0, 0x12, 0x0, 0x12, 0x0, 0x24, 0x0 },
+{ 0x81, 0x75, 0x0, 0x7c, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0x76, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1f, 0x0 },
+{ 0x81, 0x77, 0x0, 0x7e, 0x0, 0x42, 0x0, 0x5e, 0x0, 0x50, 0x0, 0x50, 0x0, 0x50, 0x0, 0x50, 0x0, 0x50, 0x0, 0x50, 0x0, 0x50, 0x0, 0x50, 0x0, 0x50, 0x0, 0x50, 0x0, 0x50, 0x0, 0x70, 0x0, 0x0 },
+{ 0x81, 0x78, 0x0, 0x0, 0x7, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x3d, 0x0, 0x21, 0x0, 0x3f, 0x0 },
+{ 0x81, 0x79, 0x0, 0x7c, 0x0, 0x78, 0x0, 0x70, 0x0, 0x60, 0x0, 0x60, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x60, 0x0, 0x60, 0x0, 0x70, 0x0, 0x78, 0x0, 0x7c },
+{ 0x81, 0x7a, 0x1f, 0x0, 0xf, 0x0, 0x7, 0x0, 0x3, 0x0, 0x3, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x3, 0x0, 0x3, 0x0, 0x7, 0x0, 0xf, 0x0, 0x1f, 0x0 },
+{ 0x81, 0x7b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0x7c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0x7d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0x7e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0x8, 0x8, 0x10, 0x4, 0x20, 0x2, 0x40, 0x1, 0x80, 0x1, 0x80, 0x2, 0x40, 0x4, 0x20, 0x8, 0x10, 0x10, 0x8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x80, 0x1, 0x80, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x1, 0x80, 0x1, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0x81, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0x82, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20, 0x0, 0x20, 0x0, 0x20, 0x1f, 0xfc, 0x0, 0x40, 0x0, 0x40, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0x83, 0x0, 0x0, 0x0, 0x2, 0x0, 0xc, 0x0, 0x30, 0x0, 0xc0, 0x3, 0x0, 0xc, 0x0, 0x30, 0x0, 0xc, 0x0, 0x3, 0x0, 0x0, 0xc0, 0x0, 0x30, 0x0, 0xc, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0x84, 0x0, 0x0, 0x20, 0x0, 0x18, 0x0, 0x6, 0x0, 0x1, 0x80, 0x0, 0x60, 0x0, 0x18, 0x0, 0x6, 0x0, 0x18, 0x0, 0x60, 0x1, 0x80, 0x6, 0x0, 0x18, 0x0, 0x20, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0x85, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe, 0x0, 0x70, 0x3, 0x80, 0x3c, 0x0, 0x3, 0x80, 0x0, 0x70, 0x0, 0xe, 0x0, 0x0, 0x3f, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xfe, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0x86, 0x0, 0x0, 0x0, 0x0, 0x38, 0x0, 0x7, 0x0, 0x0, 0xe0, 0x0, 0x1e, 0x0, 0xe0, 0x7, 0x0, 0x38, 0x0, 0x0, 0x0, 0x3f, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xfe, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0x87, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1e, 0x3c, 0x21, 0x42, 0x40, 0x81, 0x40, 0x81, 0x40, 0x81, 0x40, 0x81, 0x21, 0x42, 0x1e, 0x3c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0x88, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x80, 0x1, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x18, 0xc, 0x18, 0xc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0x89, 0x0, 0x0, 0x0, 0x7e, 0x0, 0x6, 0x0, 0xa, 0x0, 0x12, 0x0, 0x22, 0x0, 0x42, 0xe, 0x80, 0x11, 0x0, 0x20, 0x80, 0x20, 0x80, 0x20, 0x80, 0x11, 0x0, 0xe, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0x8a, 0x0, 0x0, 0x1, 0xc0, 0x2, 0x20, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x2, 0x20, 0x1, 0xc0, 0x0, 0x80, 0xf, 0xf8, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x0 },
+{ 0x81, 0x8b, 0x0, 0x0, 0x18, 0x0, 0x24, 0x0, 0x24, 0x0, 0x18, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0x8c, 0x0, 0x0, 0x4, 0x0, 0xc, 0x0, 0x18, 0x0, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0x8d, 0x0, 0x0, 0x8, 0x80, 0x19, 0x80, 0x33, 0x0, 0x22, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0x8e, 0x0, 0x0, 0x30, 0x70, 0x49, 0x8c, 0x4b, 0x2, 0x32, 0x2, 0x6, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x6, 0x0, 0x2, 0x2, 0x3, 0x2, 0x1, 0x8c, 0x0, 0x70, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0x8f, 0x0, 0x0, 0x20, 0x2, 0x10, 0x4, 0x8, 0x8, 0x4, 0x10, 0x2, 0x20, 0x1, 0x40, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x0 },
+{ 0x81, 0x90, 0x0, 0x0, 0x0, 0x80, 0x3, 0xf0, 0x4, 0x98, 0x8, 0x88, 0x8, 0x80, 0x4, 0x80, 0x3, 0x80, 0x0, 0xf0, 0x0, 0x88, 0x10, 0x84, 0x18, 0x84, 0xc, 0x88, 0x7, 0xf0, 0x0, 0x80, 0x0, 0x0 },
+{ 0x81, 0x91, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x0, 0x80, 0x1, 0xe0, 0x2, 0x90, 0x4, 0x90, 0x4, 0x80, 0x4, 0x80, 0x4, 0x90, 0x2, 0x90, 0x1, 0xe0, 0x0, 0x80, 0x0, 0x0 },
+{ 0x81, 0x92, 0x0, 0x0, 0x0, 0xf0, 0x1, 0x8, 0x2, 0x4, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x3f, 0xf8, 0x1, 0x0, 0x1, 0x0, 0x1d, 0x0, 0x23, 0x2, 0x22, 0xc4, 0x1c, 0x38, 0x0, 0x0 },
+{ 0x81, 0x93, 0x0, 0x0, 0x1c, 0x2, 0x22, 0x4, 0x22, 0x8, 0x22, 0x10, 0x22, 0x20, 0x22, 0x40, 0x1c, 0x80, 0x1, 0x1c, 0x2, 0x22, 0x4, 0x22, 0x8, 0x22, 0x10, 0x22, 0x20, 0x22, 0x40, 0x1c, 0x0, 0x0 },
+{ 0x81, 0x94, 0x0, 0x0, 0x1, 0x10, 0x1, 0x10, 0x1, 0x10, 0x1, 0x10, 0x1f, 0xfc, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x1f, 0xfc, 0x4, 0x40, 0x4, 0x40, 0x4, 0x40, 0x4, 0x40, 0x0, 0x0 },
+{ 0x81, 0x95, 0x0, 0x0, 0x3, 0xc0, 0x6, 0x20, 0x4, 0x20, 0x4, 0x60, 0x6, 0xc0, 0x3, 0x80, 0x7, 0x0, 0xd, 0x84, 0x18, 0xcc, 0x10, 0x68, 0x10, 0x38, 0x10, 0x38, 0x8, 0xec, 0x7, 0x86, 0x0, 0x0 },
+{ 0x81, 0x96, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0xc, 0x98, 0x6, 0xb0, 0x3, 0xe0, 0x0, 0x80, 0x3, 0xe0, 0x6, 0xb0, 0xc, 0x98, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0x97, 0x0, 0x0, 0x0, 0x0, 0x1, 0xe0, 0x6, 0x30, 0x8, 0x8, 0x9, 0xa8, 0x12, 0x64, 0x14, 0x44, 0x14, 0x44, 0x14, 0xc8, 0xb, 0x70, 0x8, 0x4, 0x6, 0x18, 0x1, 0xe0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0x98, 0x0, 0x0, 0x3, 0xe0, 0x6, 0x30, 0x4, 0x10, 0x6, 0x0, 0x3, 0x80, 0x6, 0xe0, 0x4, 0x30, 0x6, 0x10, 0x3, 0xb0, 0x0, 0xe0, 0x0, 0x30, 0x4, 0x10, 0x6, 0x30, 0x3, 0xe0, 0x0, 0x0 },
+{ 0x81, 0x99, 0x0, 0x0, 0x0, 0x80, 0x0, 0x80, 0x1, 0x40, 0x1, 0x40, 0x2, 0x20, 0x3e, 0x3e, 0x10, 0x4, 0x8, 0x8, 0x4, 0x10, 0x4, 0x10, 0x8, 0x88, 0x9, 0x48, 0x16, 0x34, 0x18, 0xc, 0x0, 0x0 },
+{ 0x81, 0x9a, 0x0, 0x0, 0x0, 0x80, 0x0, 0x80, 0x1, 0xc0, 0x1, 0xc0, 0x3, 0xe0, 0x3f, 0xfe, 0x1f, 0xfc, 0xf, 0xf8, 0x7, 0xf0, 0x7, 0xf0, 0xf, 0x78, 0xe, 0x38, 0x1c, 0x1c, 0x10, 0x4, 0x0, 0x0 },
+{ 0x81, 0x9b, 0x0, 0x0, 0x3, 0xc0, 0xc, 0x30, 0x10, 0x8, 0x20, 0x4, 0x20, 0x4, 0x40, 0x2, 0x40, 0x2, 0x40, 0x2, 0x40, 0x2, 0x20, 0x4, 0x20, 0x4, 0x10, 0x8, 0xc, 0x30, 0x3, 0xc0, 0x0, 0x0 },
+{ 0x81, 0x9c, 0x0, 0x0, 0x3, 0xc0, 0xf, 0xf0, 0x1f, 0xf8, 0x3f, 0xfc, 0x3f, 0xfc, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x3f, 0xfc, 0x3f, 0xfc, 0x1f, 0xf8, 0xf, 0xf0, 0x3, 0xc0, 0x0, 0x0 },
+{ 0x81, 0x9d, 0x0, 0x0, 0x3, 0xc0, 0xc, 0x30, 0x10, 0x8, 0x23, 0xc4, 0x24, 0x24, 0x48, 0x12, 0x48, 0x12, 0x48, 0x12, 0x48, 0x12, 0x24, 0x24, 0x23, 0xc4, 0x10, 0x8, 0xc, 0x30, 0x3, 0xc0, 0x0, 0x0 },
+{ 0x81, 0x9e, 0x0, 0x80, 0x1, 0x40, 0x2, 0x20, 0x4, 0x10, 0x8, 0x8, 0x10, 0x4, 0x20, 0x2, 0x40, 0x1, 0x40, 0x1, 0x20, 0x2, 0x10, 0x4, 0x8, 0x8, 0x4, 0x10, 0x2, 0x20, 0x1, 0x40, 0x0, 0x80 },
+{ 0x81, 0x9f, 0x0, 0x80, 0x1, 0xc0, 0x3, 0xe0, 0x7, 0xf0, 0xf, 0xf8, 0x1f, 0xfc, 0x3f, 0xfe, 0x7f, 0xff, 0x7f, 0xff, 0x3f, 0xfe, 0x1f, 0xfc, 0xf, 0xf8, 0x7, 0xf0, 0x3, 0xe0, 0x1, 0xc0, 0x0, 0x80 },
+{ 0x81, 0xa0, 0x0, 0x0, 0x3f, 0xfe, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x3f, 0xfe, 0x0, 0x0 },
+{ 0x81, 0xa1, 0x0, 0x0, 0x3f, 0xfe, 0x3f, 0xfe, 0x3f, 0xfe, 0x3f, 0xfe, 0x3f, 0xfe, 0x3f, 0xfe, 0x3f, 0xfe, 0x3f, 0xfe, 0x3f, 0xfe, 0x3f, 0xfe, 0x3f, 0xfe, 0x3f, 0xfe, 0x3f, 0xfe, 0x3f, 0xfe, 0x0, 0x0 },
+{ 0x81, 0xa2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x1, 0x40, 0x1, 0x40, 0x2, 0x20, 0x2, 0x20, 0x4, 0x10, 0x4, 0x10, 0x8, 0x8, 0x8, 0x8, 0x10, 0x4, 0x10, 0x4, 0x3f, 0xfe, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0xa3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x1, 0xc0, 0x1, 0xc0, 0x3, 0xe0, 0x3, 0xe0, 0x7, 0xf0, 0x7, 0xf0, 0xf, 0xf8, 0xf, 0xf8, 0x1f, 0xfc, 0x1f, 0xfc, 0x3f, 0xfe, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0xa4, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xfe, 0x10, 0x4, 0x10, 0x4, 0x8, 0x8, 0x8, 0x8, 0x4, 0x10, 0x4, 0x10, 0x2, 0x20, 0x2, 0x20, 0x1, 0x40, 0x1, 0x40, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0xa5, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xfe, 0x1f, 0xfc, 0x1f, 0xfc, 0xf, 0xf8, 0xf, 0xf8, 0x7, 0xf0, 0x7, 0xf0, 0x3, 0xe0, 0x3, 0xe0, 0x1, 0xc0, 0x1, 0xc0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0xa6, 0x0, 0x0, 0x0, 0x0, 0x21, 0x84, 0x11, 0x88, 0x8, 0x10, 0x4, 0x20, 0x2, 0x40, 0x31, 0x8c, 0x31, 0x8c, 0x2, 0x40, 0x4, 0x20, 0x8, 0x10, 0x11, 0x88, 0x21, 0x84, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0xa7, 0x0, 0x0, 0x3f, 0xfe, 0x3f, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xfe, 0x3f, 0xfe, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x0, 0x0 },
+{ 0x81, 0xa8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0x0, 0x4, 0x7f, 0xff, 0x0, 0x4, 0x0, 0x8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0xa9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0x0, 0x10, 0x0, 0x7f, 0xff, 0x10, 0x0, 0x8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0xaa, 0x0, 0x80, 0x0, 0x80, 0x1, 0xc0, 0x2, 0xa0, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80 },
+{ 0x81, 0xab, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x2, 0xa0, 0x1, 0xc0, 0x0, 0x80, 0x0, 0x80 },
+{ 0x81, 0xac, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xfe, 0x3f, 0xfe, 0x3f, 0xfe, 0x3f, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xfe, 0x3f, 0xfe, 0x3f, 0xfe, 0x3f, 0xfe, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0xb8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xfc, 0x8, 0x0, 0x10, 0x0, 0x10, 0x0, 0x1f, 0xfc, 0x10, 0x0, 0x10, 0x0, 0x8, 0x0, 0x7, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0xb9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xf0, 0x0, 0x8, 0x0, 0x4, 0x0, 0x4, 0x1f, 0xfc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x8, 0x1f, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0xba, 0x0, 0x0, 0x0, 0x0, 0x7, 0xfc, 0x8, 0x0, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x8, 0x0, 0x7, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0xbb, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xf0, 0x0, 0x8, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x8, 0x1f, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0xbc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xfc, 0x4, 0x0, 0x8, 0x0, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x8, 0x0, 0x4, 0x0, 0x3, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0xbd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xe0, 0x0, 0x10, 0x0, 0x8, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x8, 0x0, 0x10, 0x1f, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0xbe, 0x0, 0x0, 0x0, 0x0, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x8, 0x8, 0x4, 0x10, 0x3, 0xe0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0xbf, 0x0, 0x0, 0x0, 0x0, 0x3, 0xe0, 0x4, 0x10, 0x8, 0x8, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0xc8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x0, 0x80, 0x1, 0x40, 0x1, 0x40, 0x2, 0x20, 0x2, 0x20, 0x4, 0x10, 0x4, 0x10, 0x8, 0x8, 0x8, 0x8, 0x10, 0x4, 0x10, 0x4, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0xc9, 0x0, 0x0, 0x0, 0x0, 0x10, 0x4, 0x10, 0x4, 0x8, 0x8, 0x8, 0x8, 0x4, 0x10, 0x4, 0x10, 0x2, 0x20, 0x2, 0x20, 0x1, 0x40, 0x1, 0x40, 0x0, 0x80, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0xca, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xfe, 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0xcb, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0x0, 0x8, 0x7f, 0xfc, 0x0, 0x2, 0x0, 0x1, 0x0, 0x2, 0x7f, 0xfc, 0x0, 0x8, 0x0, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0xcc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x10, 0x8, 0x8, 0x1f, 0xfc, 0x20, 0x2, 0x40, 0x1, 0x20, 0x2, 0x1f, 0xfc, 0x8, 0x8, 0x4, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0xcd, 0x0, 0x0, 0x20, 0x2, 0x20, 0x2, 0x10, 0x4, 0x10, 0x4, 0xf, 0xf8, 0x8, 0x8, 0x4, 0x10, 0x4, 0x10, 0x2, 0x20, 0x2, 0x20, 0x1, 0x40, 0x1, 0x40, 0x0, 0x80, 0x0, 0x80, 0x0, 0x0 },
+{ 0x81, 0xce, 0x0, 0x0, 0x0, 0x0, 0xf, 0xf8, 0x0, 0x8, 0x0, 0x8, 0x0, 0x8, 0x0, 0x8, 0xf, 0xf8, 0x0, 0x8, 0x0, 0x8, 0x0, 0x8, 0x0, 0x8, 0xf, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0xda, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0x0, 0x10, 0x0, 0x20, 0x0, 0x40, 0x0, 0x80, 0x1, 0x0, 0x2, 0x0, 0x4, 0x0, 0x8, 0x0, 0x1f, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0xdb, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0xdc, 0x3, 0xe0, 0x1c, 0x1c, 0x60, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0xdd, 0x0, 0x0, 0x0, 0xf0, 0x1, 0x98, 0x2, 0x8, 0x0, 0x8, 0x0, 0x8, 0x1, 0xd8, 0x2, 0x30, 0x4, 0x10, 0xc, 0x30, 0x8, 0x20, 0x8, 0x60, 0xc, 0xc0, 0x7, 0x80, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0xde, 0x0, 0x0, 0x3f, 0xfe, 0x3f, 0xfc, 0x18, 0x4, 0x18, 0x8, 0xc, 0x8, 0xc, 0x10, 0x6, 0x10, 0x6, 0x20, 0x3, 0x20, 0x3, 0x40, 0x1, 0xc0, 0x1, 0x80, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0xdf, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0xe0, 0x0, 0x0, 0x0, 0x0, 0xc, 0x0, 0xc, 0x0, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x0, 0x0, 0x18, 0x0, 0x18, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0xe1, 0x0, 0x0, 0x0, 0x22, 0x0, 0x44, 0x1, 0x98, 0x2, 0x20, 0xc, 0xc0, 0x11, 0x0, 0x22, 0x0, 0x11, 0x0, 0x8, 0x80, 0x4, 0x40, 0x3, 0x30, 0x0, 0x88, 0x0, 0x44, 0x0, 0x22, 0x0, 0x0 },
+{ 0x81, 0xe2, 0x0, 0x0, 0x22, 0x0, 0x11, 0x0, 0xc, 0xc0, 0x2, 0x20, 0x1, 0x98, 0x0, 0x44, 0x0, 0x22, 0x0, 0x44, 0x0, 0x88, 0x1, 0x10, 0x6, 0x60, 0x8, 0x80, 0x11, 0x0, 0x22, 0x0, 0x0, 0x0 },
+{ 0x81, 0xe3, 0x0, 0x7f, 0x0, 0x40, 0x0, 0x40, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x11, 0x0, 0x3a, 0x0, 0x5a, 0x0, 0xe, 0x0, 0xc, 0x0, 0x4, 0x0 },
+{ 0x81, 0xe4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe, 0x38, 0x10, 0x44, 0x20, 0x42, 0x20, 0x82, 0x20, 0x82, 0x21, 0x2, 0x11, 0x4, 0xe, 0x38, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0xe5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe, 0x1c, 0x11, 0x22, 0x20, 0xc0, 0x20, 0xc0, 0x20, 0xc0, 0x20, 0xc0, 0x11, 0x22, 0xe, 0x1c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0xe6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x18, 0x6, 0x18, 0x6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0, 0x0, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0xe7, 0x1, 0xc0, 0x2, 0x40, 0x2, 0x0, 0x3, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0xc0, 0x0, 0x40, 0x0, 0x40, 0x0, 0x60, 0x0, 0x20, 0x1, 0x20, 0x1, 0xc0 },
+{ 0x81, 0xe8, 0xe, 0x38, 0x12, 0x48, 0x10, 0x40, 0x18, 0x60, 0x8, 0x20, 0x8, 0x20, 0xc, 0x30, 0x4, 0x10, 0x4, 0x10, 0x6, 0x18, 0x2, 0x8, 0x2, 0x8, 0x3, 0xc, 0x1, 0x4, 0x9, 0x24, 0xe, 0x38 },
+{ 0x81, 0xf0, 0x1, 0xc0, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x1, 0xc0, 0x0, 0x80, 0x1, 0x40, 0x1, 0x40, 0x2, 0x20, 0x2, 0x20, 0x7, 0xf0, 0x4, 0x10, 0x8, 0x8, 0x8, 0x8, 0x0, 0x0, 0x0, 0x0 },
+{ 0x81, 0xf1, 0x0, 0x0, 0x30, 0x40, 0x48, 0x40, 0x48, 0x80, 0x49, 0x0, 0x49, 0x0, 0x4a, 0x0, 0x34, 0x0, 0x5, 0x8c, 0xa, 0x52, 0x12, 0x52, 0x12, 0x52, 0x22, 0x52, 0x42, 0x52, 0x41, 0x8c, 0x0, 0x0 },
+{ 0x81, 0xf2, 0x0, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x3e, 0x3, 0xe0, 0x3e, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x3e, 0x3, 0xe0, 0x3e, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x0 },
+{ 0x81, 0xf3, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0xf0, 0x3, 0x18, 0x2, 0x18, 0x2, 0x18, 0x2, 0x18, 0x2, 0x30, 0x2, 0x60, 0x2, 0x80, 0x3, 0x0, 0x2, 0x0 },
+{ 0x81, 0xf4, 0x0, 0x80, 0x0, 0x80, 0x0, 0xc0, 0x0, 0xe0, 0x0, 0xb0, 0x0, 0x98, 0x0, 0x8c, 0x0, 0x84, 0x0, 0x84, 0x0, 0x88, 0x0, 0x90, 0x0, 0x80, 0xf, 0x80, 0x1f, 0x80, 0x1f, 0x0, 0xe, 0x0 },
+{ 0x81, 0xf5, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0xf, 0xf0, 0xf, 0xf0, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80 },
+{ 0x81, 0xf6, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0xf, 0xf0, 0xf, 0xf0, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0xf, 0xf0, 0xf, 0xf0, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80 },
+{ 0x81, 0xf7, 0x0, 0x0, 0x3, 0xf0, 0x7, 0x90, 0xf, 0x90, 0xf, 0x90, 0xf, 0x90, 0x7, 0x90, 0x3, 0x90, 0x0, 0x90, 0x0, 0x90, 0x0, 0x90, 0x0, 0x90, 0x0, 0x90, 0x0, 0x90, 0x0, 0x90, 0x0, 0x90 },
+{ 0x81, 0xfc, 0x1, 0xc0, 0x6, 0x30, 0x8, 0x8, 0x10, 0x4, 0x20, 0x2, 0x20, 0x2, 0x40, 0x1, 0x40, 0x1, 0x40, 0x1, 0x40, 0x1, 0x20, 0x2, 0x20, 0x2, 0x10, 0x4, 0x8, 0x8, 0x6, 0x30, 0x1, 0xc0 },
+{ 0x82, 0x4f, 0x0, 0x0, 0x1, 0xc0, 0x2, 0x20, 0x4, 0x10, 0x4, 0x10, 0xc, 0x18, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xc, 0x18, 0x4, 0x10, 0x4, 0x10, 0x2, 0x20, 0x1, 0xc0, 0x0, 0x0 },
+{ 0x82, 0x50, 0x0, 0x0, 0x0, 0x40, 0x0, 0xc0, 0x3, 0xc0, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x0 },
+{ 0x82, 0x51, 0x0, 0x0, 0x3, 0xe0, 0x6, 0x30, 0xc, 0x18, 0x8, 0x8, 0x0, 0x8, 0x0, 0x18, 0x0, 0x10, 0x0, 0x30, 0x0, 0x60, 0x0, 0xc0, 0x1, 0x80, 0x3, 0x0, 0x6, 0x0, 0xf, 0xf8, 0x0, 0x0 },
+{ 0x82, 0x52, 0x0, 0x0, 0x3, 0xe0, 0x6, 0x30, 0xc, 0x18, 0x0, 0x8, 0x0, 0x8, 0x0, 0x10, 0x3, 0xe0, 0x0, 0x10, 0x0, 0x8, 0x0, 0x8, 0x0, 0x8, 0x0, 0x18, 0x0, 0x30, 0xf, 0xe0, 0x0, 0x0 },
+{ 0x82, 0x53, 0x0, 0x0, 0x0, 0x20, 0x0, 0x60, 0x0, 0xe0, 0x1, 0xa0, 0x3, 0x20, 0x6, 0x20, 0xc, 0x20, 0x18, 0x20, 0x10, 0x20, 0x1f, 0xfc, 0x0, 0x20, 0x0, 0x20, 0x0, 0x20, 0x0, 0x20, 0x0, 0x0 },
+{ 0x82, 0x54, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x0, 0x8, 0x0, 0x8, 0x0, 0x8, 0x0, 0xb, 0xe0, 0xc, 0x10, 0x8, 0x8, 0x0, 0x8, 0x0, 0x8, 0x0, 0x18, 0x0, 0x30, 0x0, 0xe0, 0xf, 0x80, 0x0, 0x0 },
+{ 0x82, 0x55, 0x0, 0x0, 0x0, 0x70, 0x1, 0xc0, 0x3, 0x0, 0x6, 0x0, 0x4, 0x0, 0xd, 0xc0, 0xa, 0x30, 0xc, 0x18, 0x8, 0x8, 0x8, 0x8, 0xc, 0x8, 0x4, 0x18, 0x6, 0x30, 0x1, 0xc0, 0x0, 0x0 },
+{ 0x82, 0x56, 0x0, 0x0, 0xf, 0xf8, 0x0, 0x8, 0x0, 0x8, 0x0, 0x18, 0x0, 0x10, 0x0, 0x30, 0x0, 0x20, 0x0, 0x60, 0x0, 0x40, 0x0, 0xc0, 0x0, 0x80, 0x1, 0x80, 0x1, 0x0, 0x1, 0x0, 0x0, 0x0 },
+{ 0x82, 0x57, 0x0, 0x0, 0x1, 0xc0, 0x6, 0x30, 0xc, 0x18, 0x8, 0x8, 0x8, 0x8, 0x4, 0x10, 0x3, 0xe0, 0x4, 0x10, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xc, 0x18, 0x6, 0x30, 0x1, 0xc0, 0x0, 0x0 },
+{ 0x82, 0x58, 0x0, 0x0, 0x1, 0xc0, 0x6, 0x30, 0xc, 0x10, 0x8, 0x18, 0x8, 0x8, 0x8, 0x8, 0xc, 0x18, 0x6, 0x28, 0x1, 0xd8, 0x0, 0x10, 0x0, 0x30, 0x0, 0x60, 0x1, 0xc0, 0x7, 0x0, 0x0, 0x0 },
+{ 0x82, 0x60, 0x0, 0x0, 0x0, 0x80, 0x1, 0xc0, 0x1, 0x40, 0x3, 0x60, 0x2, 0x20, 0x6, 0x30, 0x4, 0x10, 0x4, 0x10, 0xf, 0xf8, 0x8, 0x8, 0x18, 0xc, 0x10, 0x4, 0x10, 0x4, 0x0, 0x0, 0x0, 0x0 },
+{ 0x82, 0x61, 0x0, 0x0, 0xf, 0xc0, 0x8, 0x20, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10, 0x8, 0x20, 0xf, 0xc0, 0x8, 0x30, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x10, 0xf, 0xe0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x82, 0x62, 0x0, 0x0, 0x1, 0xc0, 0x6, 0x30, 0xc, 0x18, 0x8, 0x8, 0x18, 0x0, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x18, 0x0, 0x8, 0x8, 0xc, 0x18, 0x6, 0x30, 0x1, 0xc0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x82, 0x63, 0x0, 0x0, 0xf, 0x80, 0x8, 0x60, 0x8, 0x30, 0x8, 0x10, 0x8, 0x18, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x18, 0x8, 0x10, 0x8, 0x30, 0x8, 0x60, 0xf, 0x80, 0x0, 0x0, 0x0, 0x0 },
+{ 0x82, 0x64, 0x0, 0x0, 0x7, 0xf8, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x7, 0xf0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x7, 0xf8, 0x0, 0x0, 0x0, 0x0 },
+{ 0x82, 0x65, 0x0, 0x0, 0x7, 0xf8, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x7, 0xf0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x82, 0x66, 0x0, 0x0, 0x1, 0xc0, 0x6, 0x30, 0xc, 0x18, 0x8, 0x8, 0x18, 0x0, 0x10, 0x0, 0x10, 0xf8, 0x10, 0x8, 0x18, 0x8, 0x8, 0x8, 0xc, 0x18, 0x6, 0x28, 0x1, 0xc8, 0x0, 0x0, 0x0, 0x0 },
+{ 0x82, 0x67, 0x0, 0x0, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x0, 0x0, 0x0, 0x0 },
+{ 0x82, 0x68, 0x0, 0x0, 0x3, 0xe0, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x3, 0xe0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x82, 0x69, 0x0, 0x0, 0x0, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x10, 0x8, 0x10, 0x8, 0x10, 0x4, 0x20, 0x3, 0xc0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x82, 0x6a, 0x0, 0x0, 0x8, 0x18, 0x8, 0x30, 0x8, 0x60, 0x8, 0xc0, 0x9, 0x80, 0xb, 0x0, 0xf, 0x0, 0xd, 0x80, 0x8, 0xc0, 0x8, 0x60, 0x8, 0x30, 0x8, 0x18, 0x8, 0xc, 0x0, 0x0, 0x0, 0x0 },
+{ 0x82, 0x6b, 0x0, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x7, 0xf8, 0x0, 0x0, 0x0, 0x0 },
+{ 0x82, 0x6c, 0x0, 0x0, 0x30, 0x6, 0x38, 0xe, 0x28, 0xa, 0x2c, 0x1a, 0x24, 0x12, 0x24, 0x12, 0x26, 0x32, 0x22, 0x22, 0x23, 0x62, 0x21, 0x42, 0x21, 0xc2, 0x20, 0x82, 0x20, 0x82, 0x0, 0x0, 0x0, 0x0 },
+{ 0x82, 0x6d, 0x0, 0x0, 0xc, 0x8, 0xe, 0x8, 0xa, 0x8, 0xb, 0x8, 0x9, 0x8, 0x9, 0x88, 0x8, 0x88, 0x8, 0xc8, 0x8, 0x48, 0x8, 0x68, 0x8, 0x28, 0x8, 0x38, 0x8, 0x18, 0x0, 0x0, 0x0, 0x0 },
+{ 0x82, 0x6e, 0x0, 0x0, 0x3, 0xe0, 0xc, 0x18, 0x18, 0xc, 0x10, 0x4, 0x30, 0x6, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x30, 0x6, 0x10, 0x4, 0x18, 0xc, 0xc, 0x18, 0x3, 0xe0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x82, 0x6f, 0x0, 0x0, 0x7, 0xe0, 0x4, 0x10, 0x4, 0x8, 0x4, 0x8, 0x4, 0x8, 0x4, 0x10, 0x7, 0xe0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x82, 0x70, 0x0, 0x0, 0x3, 0xe0, 0xc, 0x18, 0x18, 0xc, 0x10, 0x4, 0x30, 0x6, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x30, 0x6, 0x10, 0x44, 0x18, 0x2c, 0xc, 0x18, 0x3, 0xec, 0x0, 0x4, 0x0, 0x0 },
+{ 0x82, 0x71, 0x0, 0x0, 0x7, 0xe0, 0x4, 0x10, 0x4, 0x8, 0x4, 0x8, 0x4, 0x8, 0x4, 0x10, 0x7, 0xe0, 0x4, 0x40, 0x4, 0x60, 0x4, 0x30, 0x4, 0x10, 0x4, 0x8, 0x4, 0xc, 0x0, 0x0, 0x0, 0x0 },
+{ 0x82, 0x72, 0x0, 0x0, 0x3, 0xe0, 0x4, 0x10, 0x8, 0x8, 0x8, 0x8, 0x8, 0x0, 0x6, 0x0, 0x1, 0xc0, 0x0, 0x30, 0x0, 0x8, 0x8, 0x8, 0x8, 0x8, 0x4, 0x10, 0x3, 0xe0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x82, 0x73, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0 },
+{ 0x82, 0x74, 0x0, 0x0, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xc, 0x18, 0x6, 0x30, 0x1, 0xc0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x82, 0x75, 0x0, 0x0, 0x10, 0x4, 0x10, 0x4, 0x18, 0xc, 0x8, 0x8, 0xc, 0x18, 0x4, 0x10, 0x6, 0x30, 0x2, 0x20, 0x3, 0x60, 0x1, 0x40, 0x1, 0xc0, 0x0, 0x80, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0 },
+{ 0x82, 0x76, 0x0, 0x0, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x31, 0xc6, 0x11, 0x44, 0x11, 0x44, 0x13, 0x64, 0x1a, 0x2c, 0xa, 0x28, 0xa, 0x28, 0xe, 0x38, 0x4, 0x10, 0x4, 0x10, 0x0, 0x0, 0x0, 0x0 },
+{ 0x82, 0x77, 0x0, 0x0, 0x10, 0x4, 0x18, 0xc, 0xc, 0x18, 0x6, 0x30, 0x3, 0x60, 0x1, 0xc0, 0x1, 0xc0, 0x3, 0x60, 0x6, 0x30, 0xc, 0x18, 0x18, 0xc, 0x30, 0x6, 0x20, 0x2, 0x0, 0x0, 0x0, 0x0 },
+{ 0x82, 0x78, 0x0, 0x0, 0x10, 0x4, 0x18, 0xc, 0x8, 0x8, 0xc, 0x18, 0x6, 0x30, 0x2, 0x20, 0x3, 0x60, 0x1, 0xc0, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0 },
+{ 0x82, 0x79, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0xc, 0x0, 0x18, 0x0, 0x30, 0x0, 0x20, 0x0, 0x60, 0x0, 0xc0, 0x1, 0x80, 0x1, 0x0, 0x3, 0x0, 0x6, 0x0, 0xc, 0x0, 0x1f, 0xfc, 0x0, 0x0, 0x0, 0x0 },
+{ 0x82, 0x81, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xc0, 0x0, 0x20, 0x0, 0x20, 0x7, 0xe0, 0x8, 0x20, 0x8, 0x20, 0x8, 0x68, 0x7, 0x98, 0x0, 0x0, 0x0, 0x0 },
+{ 0x82, 0x82, 0x0, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x5, 0xc0, 0x6, 0x20, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x6, 0x20, 0x5, 0xc0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x82, 0x83, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xe0, 0x2, 0x10, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x2, 0x10, 0x1, 0xe0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x82, 0x84, 0x0, 0x0, 0x0, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x10, 0x1, 0xd0, 0x2, 0x30, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x2, 0x30, 0x1, 0xd0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x82, 0x85, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xc0, 0x2, 0x20, 0x4, 0x10, 0x7, 0xf0, 0x4, 0x0, 0x4, 0x0, 0x2, 0x10, 0x1, 0xe0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x82, 0x86, 0x0, 0x0, 0x0, 0x70, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7, 0xf0, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0 },
+{ 0x82, 0x87, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xd8, 0x4, 0x20, 0x4, 0x20, 0x4, 0x20, 0x3, 0xc0, 0x4, 0x0, 0x7, 0xf0, 0x8, 0x8, 0x8, 0x8, 0x7, 0xf0 },
+{ 0x82, 0x88, 0x0, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x5, 0xe0, 0x6, 0x30, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x0, 0x0, 0x0, 0x0 },
+{ 0x82, 0x89, 0x0, 0x0, 0x0, 0x80, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0 },
+{ 0x82, 0x8a, 0x0, 0x0, 0x0, 0x40, 0x0, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x4, 0x40, 0x3, 0x80 },
+{ 0x82, 0x8b, 0x0, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x30, 0x4, 0x60, 0x4, 0xc0, 0x5, 0x80, 0x7, 0xc0, 0x4, 0x60, 0x4, 0x30, 0x4, 0x18, 0x0, 0x0, 0x0, 0x0 },
+{ 0x82, 0x8c, 0x0, 0x0, 0x3, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0 },
+{ 0x82, 0x8d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x17, 0x38, 0x18, 0xc4, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x0, 0x0, 0x0, 0x0 },
+{ 0x82, 0x8e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5, 0xe0, 0x6, 0x30, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x0, 0x0, 0x0, 0x0 },
+{ 0x82, 0x8f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xc0, 0x4, 0x20, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10, 0x4, 0x20, 0x3, 0xc0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x82, 0x90, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5, 0xc0, 0x6, 0x20, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x6, 0x20, 0x5, 0xc0, 0x4, 0x0, 0x4, 0x0 },
+{ 0x82, 0x91, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xd0, 0x2, 0x30, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x2, 0x30, 0x1, 0xd0, 0x0, 0x10, 0x0, 0x10 },
+{ 0x82, 0x92, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x30, 0x1, 0x40, 0x1, 0x80, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x82, 0x93, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xc0, 0x4, 0x20, 0x4, 0x0, 0x3, 0x80, 0x0, 0x60, 0x0, 0x10, 0x4, 0x10, 0x3, 0xe0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x82, 0x94, 0x0, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x7, 0xe0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0xe0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x82, 0x95, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x6, 0x30, 0x3, 0xd0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x82, 0x96, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc, 0x18, 0x4, 0x10, 0x6, 0x30, 0x2, 0x20, 0x3, 0x60, 0x1, 0x40, 0x1, 0xc0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0 },
+{ 0x82, 0x97, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0x84, 0x18, 0x8c, 0x9, 0xc8, 0xd, 0x58, 0x5, 0x50, 0x7, 0x70, 0x2, 0x20, 0x2, 0x20, 0x0, 0x0, 0x0, 0x0 },
+{ 0x82, 0x98, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x10, 0x6, 0x30, 0x3, 0x60, 0x1, 0xc0, 0x1, 0xc0, 0x3, 0x60, 0x6, 0x30, 0xc, 0x18, 0x0, 0x0, 0x0, 0x0 },
+{ 0x82, 0x99, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc, 0x18, 0x4, 0x10, 0x6, 0x30, 0x2, 0x20, 0x3, 0x60, 0x1, 0x40, 0x1, 0xc0, 0x0, 0x80, 0x1, 0x80, 0x7, 0x0 },
+{ 0x82, 0x9a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xf0, 0x0, 0x20, 0x0, 0x40, 0x0, 0x80, 0x1, 0x0, 0x2, 0x0, 0x4, 0x0, 0x7, 0xf0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x82, 0x9f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1f, 0xf8, 0x2, 0x40, 0x3, 0xf0, 0x6, 0x58, 0xa, 0x4c, 0x12, 0x84, 0x12, 0x84, 0x11, 0xc, 0xe, 0x18, 0x0, 0x60 },
+{ 0x82, 0xa0, 0x1, 0x0, 0x1, 0x0, 0x1f, 0xfc, 0x2, 0x0, 0x2, 0x40, 0x3, 0xf0, 0xe, 0x5c, 0x1a, 0x44, 0x12, 0xc6, 0x32, 0x82, 0x22, 0x82, 0x23, 0x6, 0x23, 0x4, 0x1c, 0x1c, 0x0, 0x70, 0x0, 0x0 },
+{ 0x82, 0xa1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0x0, 0x10, 0x30, 0x10, 0x18, 0x10, 0x8, 0x10, 0xc, 0x18, 0x4, 0xa, 0x4, 0xe, 0x0, 0x4, 0x0, 0x0, 0x0 },
+{ 0x82, 0xa2, 0x0, 0x0, 0x0, 0x0, 0x20, 0x0, 0x20, 0x10, 0x20, 0x18, 0x20, 0xc, 0x20, 0x4, 0x20, 0x6, 0x20, 0x2, 0x20, 0x2, 0x32, 0x2, 0x16, 0x0, 0x1c, 0x0, 0x8, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x82, 0xa3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6, 0x0, 0x3, 0x80, 0x0, 0xe0, 0x0, 0x0, 0xf, 0xe0, 0x0, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x30, 0x0, 0x60, 0x1, 0xc0, 0x7, 0x0 },
+{ 0x82, 0xa4, 0x3, 0x0, 0x1, 0xc0, 0x0, 0x60, 0x0, 0x0, 0x0, 0x0, 0xf, 0xf0, 0x0, 0x18, 0x0, 0x8, 0x0, 0x8, 0x0, 0x8, 0x0, 0x18, 0x0, 0x30, 0x0, 0x60, 0x1, 0xc0, 0x7, 0x0, 0x0, 0x0 },
+{ 0x82, 0xa5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x0, 0x1, 0xc0, 0x0, 0x60, 0x0, 0x0, 0x7, 0xf0, 0x0, 0x20, 0x0, 0x40, 0x0, 0x80, 0x3, 0xc0, 0x6, 0x40, 0xc, 0x40, 0x0, 0x38 },
+{ 0x82, 0xa6, 0x3, 0x0, 0x1, 0xc0, 0x0, 0x70, 0x0, 0x0, 0xf, 0xf8, 0x0, 0x10, 0x0, 0x20, 0x0, 0x40, 0x0, 0x80, 0x1, 0xc0, 0x3, 0x40, 0x6, 0x40, 0xc, 0x40, 0x18, 0x70, 0x0, 0x1e, 0x0, 0x0 },
+{ 0x82, 0xa7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x1, 0x10, 0x1, 0xd8, 0xf, 0x8, 0x1, 0x0, 0x1, 0xe0, 0x3, 0x10, 0x5, 0x8, 0x9, 0x8, 0x9, 0x18, 0x6, 0x70, 0x0, 0x0 },
+{ 0x82, 0xa8, 0x2, 0x0, 0x2, 0x0, 0x2, 0xc, 0x3, 0xc6, 0x3e, 0x2, 0x2, 0x0, 0x2, 0x0, 0x2, 0xf8, 0x3, 0x8c, 0xe, 0x6, 0x1a, 0x2, 0x32, 0x2, 0x22, 0x6, 0x26, 0xc, 0x1c, 0x38, 0x0, 0x0 },
+{ 0x82, 0xa9, 0x2, 0x0, 0x2, 0x0, 0x2, 0x8, 0x2, 0xc, 0x3f, 0xc6, 0x2, 0x22, 0x2, 0x23, 0x6, 0x21, 0x4, 0x21, 0x4, 0x20, 0xc, 0x20, 0x8, 0x20, 0x18, 0x60, 0x30, 0x40, 0x1, 0xc0, 0x0, 0x0 },
+{ 0x82, 0xaa, 0x2, 0x5, 0x2, 0x5, 0x2, 0x10, 0x2, 0x18, 0x3f, 0xcc, 0x2, 0x24, 0x2, 0x26, 0x6, 0x22, 0x4, 0x22, 0x4, 0x20, 0xc, 0x20, 0x8, 0x20, 0x18, 0x60, 0x30, 0x40, 0x1, 0xc0, 0x0, 0x0 },
+{ 0x82, 0xab, 0x1, 0x0, 0x1, 0x0, 0x1f, 0xf8, 0x1, 0x0, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x40, 0x7, 0xf0, 0x8, 0x18, 0x10, 0x0, 0x10, 0x0, 0x18, 0x0, 0xe, 0x0, 0x3, 0xf0, 0x0, 0x0 },
+{ 0x82, 0xac, 0x1, 0x5, 0x1, 0x5, 0x1f, 0xf0, 0x1, 0x0, 0x0, 0x80, 0x1f, 0xf8, 0x0, 0x80, 0x0, 0x40, 0x7, 0xf0, 0x8, 0x18, 0x10, 0x0, 0x10, 0x0, 0x18, 0x0, 0xe, 0x0, 0x3, 0xf0, 0x0, 0x0 },
+{ 0x82, 0xad, 0x0, 0x10, 0x0, 0x30, 0x0, 0x60, 0x0, 0xc0, 0x1, 0x80, 0x3, 0x0, 0xc, 0x0, 0x18, 0x0, 0xc, 0x0, 0x6, 0x0, 0x3, 0x0, 0x1, 0x80, 0x0, 0xc0, 0x0, 0x60, 0x0, 0x30, 0x0, 0x10 },
+{ 0x82, 0xae, 0x0, 0x10, 0x0, 0x35, 0x0, 0x65, 0x0, 0xc0, 0x1, 0x80, 0x3, 0x0, 0xc, 0x0, 0x18, 0x0, 0xc, 0x0, 0x6, 0x0, 0x3, 0x0, 0x1, 0x80, 0x0, 0xc0, 0x0, 0x60, 0x0, 0x30, 0x0, 0x10 },
+{ 0x82, 0xaf, 0x0, 0x10, 0x10, 0x10, 0x10, 0x10, 0x30, 0x10, 0x23, 0xfe, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x28, 0x10, 0x30, 0x30, 0x10, 0x20, 0x0, 0x60, 0x0, 0xc0, 0x0, 0x0 },
+{ 0x82, 0xb0, 0x0, 0x15, 0x10, 0x15, 0x10, 0x10, 0x30, 0x10, 0x23, 0xfe, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x28, 0x10, 0x30, 0x30, 0x10, 0x20, 0x0, 0x60, 0x1, 0xc0, 0x0, 0x0 },
+{ 0x82, 0xb1, 0x0, 0x0, 0x0, 0x0, 0xf, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0x0, 0x18, 0x0, 0xe, 0x0, 0x3, 0xfc, 0x0, 0x0, 0x0, 0x0 },
+{ 0x82, 0xb2, 0x0, 0x5, 0x0, 0x5, 0xf, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0x0, 0x18, 0x0, 0xe, 0x0, 0x3, 0xfc, 0x0, 0x0, 0x0, 0x0 },
+{ 0x82, 0xb3, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x3f, 0xf8, 0x1, 0x0, 0x0, 0x80, 0x0, 0xc0, 0x0, 0x60, 0x7, 0xf8, 0x8, 0xc, 0x10, 0x0, 0x10, 0x0, 0x18, 0x0, 0xe, 0x0, 0x3, 0xf8, 0x0, 0x0 },
+{ 0x82, 0xb4, 0x2, 0x5, 0x2, 0x5, 0x2, 0x0, 0x3f, 0xfc, 0x1, 0x0, 0x0, 0x80, 0x0, 0xc0, 0x0, 0x60, 0x7, 0xf8, 0x8, 0xc, 0x10, 0x0, 0x10, 0x0, 0x18, 0x0, 0xe, 0x0, 0x3, 0xf0, 0x0, 0x0 },
+{ 0x82, 0xb5, 0x0, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x4, 0x4, 0xc, 0x4, 0x18, 0x2, 0x70, 0x1, 0xc0, 0x0, 0x0 },
+{ 0x82, 0xb6, 0x0, 0x0, 0x4, 0x0, 0x4, 0x28, 0x4, 0x28, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x4, 0x4, 0xc, 0x4, 0x18, 0x2, 0x70, 0x1, 0xc0, 0x0, 0x0 },
+{ 0x82, 0xb7, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x7f, 0xff, 0x0, 0x40, 0x0, 0x40, 0x3, 0xc0, 0x6, 0x60, 0x4, 0x20, 0x4, 0x20, 0x6, 0x20, 0x3, 0xe0, 0x0, 0x40, 0x0, 0xc0, 0x1, 0x80, 0x7, 0x0 },
+{ 0x82, 0xb8, 0x0, 0x45, 0x0, 0x45, 0x0, 0x40, 0x7f, 0xff, 0x0, 0x40, 0x0, 0x40, 0x3, 0xc0, 0x6, 0x60, 0x4, 0x20, 0x4, 0x20, 0x6, 0x20, 0x3, 0xe0, 0x0, 0x40, 0x0, 0xc0, 0x1, 0x80, 0x7, 0x0 },
+{ 0x82, 0xb9, 0x0, 0x0, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x60, 0x4, 0x0, 0x4, 0x0, 0x2, 0x0, 0x1, 0xfc, 0x0, 0x0 },
+{ 0x82, 0xba, 0x0, 0x5, 0x4, 0x15, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x60, 0x4, 0x0, 0x4, 0x0, 0x2, 0x0, 0x1, 0xfc, 0x0, 0x0 },
+{ 0x82, 0xbb, 0x0, 0x0, 0xf, 0xf0, 0x0, 0x20, 0x0, 0x60, 0x0, 0xc0, 0x1, 0x80, 0x6, 0x0, 0x3f, 0xfe, 0x1, 0x80, 0x3, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x3, 0x80, 0x0, 0xf0 },
+{ 0x82, 0xbc, 0x0, 0x0, 0xf, 0xf0, 0x0, 0x25, 0x0, 0x65, 0x0, 0xc0, 0x1, 0x80, 0x6, 0x0, 0x3f, 0xfe, 0x1, 0x80, 0x3, 0x0, 0x6, 0x0, 0x4, 0x0, 0x4, 0x0, 0x6, 0x0, 0x3, 0x80, 0x0, 0xf0 },
+{ 0x82, 0xbd, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x3f, 0x80, 0x4, 0x0, 0x4, 0x7c, 0x4, 0x0, 0xc, 0x0, 0x8, 0x0, 0x8, 0x0, 0x18, 0x0, 0x10, 0x0, 0x10, 0x80, 0x30, 0xc0, 0x20, 0x7e, 0x0, 0x0 },
+{ 0x82, 0xbe, 0x2, 0x5, 0x2, 0x5, 0x2, 0x0, 0x3f, 0x80, 0x4, 0x0, 0x4, 0x7c, 0x4, 0x0, 0xc, 0x0, 0x8, 0x0, 0x8, 0x0, 0x18, 0x0, 0x10, 0x0, 0x10, 0x80, 0x30, 0xc0, 0x20, 0x7e, 0x0, 0x0 },
+{ 0x82, 0xbf, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x3f, 0xfc, 0x2, 0x0, 0x2, 0x0, 0x6, 0x0, 0x7, 0xf0, 0xc, 0x8, 0x18, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0xc, 0x0, 0x38, 0x3, 0xe0, 0x0, 0x0 },
+{ 0x82, 0xc0, 0x1, 0x5, 0x1, 0x5, 0x1, 0x0, 0x3f, 0xfc, 0x2, 0x0, 0x2, 0x0, 0x6, 0x0, 0x7, 0xf0, 0xc, 0x8, 0x18, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0xc, 0x0, 0x38, 0x3, 0xe0, 0x0, 0x0 },
+{ 0x82, 0xc1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xe0, 0x7, 0x10, 0x1c, 0x8, 0x0, 0x8, 0x0, 0x8, 0x0, 0x18, 0x0, 0x30, 0x0, 0xe0, 0x0, 0x0 },
+{ 0x82, 0xc2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xf8, 0xf, 0x4, 0x38, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x6, 0x0, 0xc, 0x0, 0x38, 0x0, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x82, 0xc3, 0x0, 0x5, 0x0, 0x5, 0x0, 0x0, 0x1, 0xf8, 0xf, 0x4, 0x38, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x6, 0x0, 0xc, 0x0, 0x38, 0x0, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x82, 0xc4, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xfe, 0x0, 0x30, 0x0, 0x60, 0x0, 0xc0, 0x0, 0x80, 0x1, 0x80, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x80, 0x0, 0xc0, 0x0, 0x70, 0x0, 0x1c, 0x0, 0x0 },
+{ 0x82, 0xc5, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xfc, 0x0, 0x30, 0x0, 0x65, 0x0, 0xc5, 0x0, 0x80, 0x1, 0x80, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x80, 0x0, 0xc0, 0x0, 0x70, 0x0, 0x1c, 0x0, 0x0 },
+{ 0x82, 0xc6, 0x0, 0x0, 0x8, 0x0, 0xc, 0x0, 0x4, 0x0, 0x6, 0xc, 0x2, 0x38, 0x2, 0xe0, 0x3, 0x80, 0x6, 0x0, 0xc, 0x0, 0x18, 0x0, 0x10, 0x0, 0x10, 0x0, 0x18, 0x0, 0xf, 0xfc, 0x0, 0x0 },
+{ 0x82, 0xc7, 0x0, 0x5, 0x8, 0x5, 0xc, 0x0, 0x4, 0x0, 0x6, 0xc, 0x2, 0x38, 0x2, 0xe0, 0x3, 0x80, 0x7, 0x0, 0xc, 0x0, 0x18, 0x0, 0x10, 0x0, 0x10, 0x0, 0x18, 0x0, 0xf, 0xfc, 0x0, 0x0 },
+{ 0x82, 0xc8, 0x4, 0x0, 0x4, 0x0, 0x4, 0x18, 0x3f, 0x8c, 0x4, 0x6, 0xc, 0x0, 0x8, 0x20, 0x8, 0x20, 0x18, 0x20, 0x10, 0x20, 0x30, 0x20, 0x1, 0xe0, 0x2, 0x38, 0x2, 0x6c, 0x1, 0xc0, 0x0, 0x0 },
+{ 0x82, 0xc9, 0x0, 0x0, 0x8, 0x0, 0x8, 0x0, 0x18, 0xfc, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x11, 0x0, 0x11, 0x0, 0x15, 0x80, 0x18, 0xfe, 0x8, 0x0, 0x0, 0x0 },
+{ 0x82, 0xca, 0x0, 0x80, 0x0, 0x80, 0x10, 0x80, 0x10, 0x80, 0x17, 0xf0, 0x1c, 0x9c, 0x8, 0x84, 0x19, 0x86, 0x1d, 0x2, 0x35, 0x2, 0x27, 0x2, 0x22, 0x3a, 0x27, 0x44, 0x25, 0x4e, 0x1c, 0x3a, 0x0, 0x0 },
+{ 0x82, 0xcb, 0x8, 0x0, 0x8, 0x0, 0x8, 0x0, 0x8, 0xf8, 0x39, 0x8c, 0xb, 0x6, 0xe, 0x2, 0xc, 0x2, 0xc, 0x2, 0x18, 0x2, 0x38, 0x3a, 0x28, 0x44, 0x8, 0x4e, 0x8, 0x3b, 0x8, 0x0, 0x0, 0x0 },
+{ 0x82, 0xcc, 0x0, 0x0, 0x0, 0x0, 0x3, 0xe0, 0xe, 0xb8, 0x18, 0x8c, 0x10, 0x84, 0x31, 0x86, 0x21, 0x2, 0x21, 0x2, 0x23, 0x2, 0x22, 0x6, 0x26, 0x4, 0x1c, 0x1c, 0x0, 0x70, 0x0, 0x0, 0x0, 0x0 },
+{ 0x82, 0xcd, 0x0, 0x0, 0x10, 0x10, 0x10, 0x10, 0x30, 0x10, 0x23, 0xfe, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x21, 0xf0, 0x22, 0x18, 0x2a, 0x14, 0x32, 0x32, 0x11, 0xe0, 0x0, 0x0 },
+{ 0x82, 0xce, 0x0, 0x5, 0x10, 0x15, 0x10, 0x10, 0x30, 0x10, 0x23, 0xfe, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x21, 0xf0, 0x22, 0x18, 0x2a, 0x14, 0x32, 0x32, 0x11, 0xe0, 0x0, 0x0 },
+{ 0x82, 0xcf, 0x0, 0x0, 0x10, 0x20, 0x10, 0x26, 0x30, 0x29, 0x23, 0xf9, 0x20, 0x26, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0xe0, 0x22, 0x38, 0x2a, 0x2c, 0x32, 0x66, 0x11, 0xc0, 0x0, 0x0 },
+{ 0x82, 0xd0, 0x0, 0x0, 0x1, 0x10, 0x3f, 0x10, 0x2, 0x18, 0x6, 0x1c, 0xc, 0x16, 0x8, 0x13, 0x18, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x30, 0x18, 0x20, 0xc, 0xe0, 0x7, 0x80, 0x0, 0x0 },
+{ 0x82, 0xd1, 0x0, 0x5, 0x1, 0x15, 0x3f, 0x10, 0x2, 0x18, 0x6, 0x1c, 0xc, 0x16, 0x8, 0x13, 0x18, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x30, 0x18, 0x20, 0xc, 0xe0, 0x7, 0x80, 0x0, 0x0 },
+{ 0x82, 0xd2, 0x0, 0x0, 0x4, 0x40, 0x7c, 0x46, 0x8, 0x49, 0x18, 0x69, 0x10, 0x76, 0x10, 0x58, 0x30, 0x40, 0x20, 0x40, 0x20, 0x40, 0x20, 0x40, 0x20, 0x40, 0x30, 0xc0, 0x19, 0x80, 0xf, 0x0, 0x0, 0x0 },
+{ 0x82, 0xd3, 0x0, 0x0, 0x2, 0x0, 0x3, 0x0, 0x1, 0xc0, 0x0, 0x60, 0x0, 0x0, 0x3, 0x0, 0x1, 0x80, 0x0, 0xcc, 0x20, 0x46, 0x20, 0x62, 0x2c, 0x23, 0x38, 0x21, 0x10, 0x60, 0x1, 0xc0, 0x0, 0x0 },
+{ 0x82, 0xd4, 0x0, 0x0, 0x2, 0xa, 0x3, 0xa, 0x1, 0xc0, 0x0, 0x60, 0x0, 0x0, 0x3, 0x0, 0x1, 0x80, 0x0, 0xcc, 0x20, 0x46, 0x20, 0x62, 0x2c, 0x23, 0x38, 0x21, 0x10, 0x60, 0x1, 0xc0, 0x0, 0x0 },
+{ 0x82, 0xd5, 0x0, 0x0, 0x4, 0x0, 0x6, 0xc, 0x3, 0x92, 0x0, 0xd2, 0x0, 0xc, 0x6, 0x0, 0x3, 0x0, 0x1, 0x8c, 0x20, 0xc6, 0x20, 0x42, 0x2c, 0x63, 0x38, 0x21, 0x10, 0x60, 0x3, 0xc0, 0x0, 0x0 },
+{ 0x82, 0xd6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x0, 0x4, 0x80, 0xc, 0x80, 0x8, 0x40, 0x18, 0x40, 0x30, 0x20, 0x0, 0x30, 0x0, 0x18, 0x0, 0xc, 0x0, 0x6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x82, 0xd7, 0x0, 0x0, 0x0, 0x14, 0x0, 0x14, 0x3, 0x0, 0x4, 0x80, 0xc, 0x80, 0x8, 0x40, 0x18, 0x40, 0x30, 0x20, 0x0, 0x30, 0x0, 0x18, 0x0, 0xc, 0x0, 0x6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x82, 0xd8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xc, 0x4, 0x92, 0xc, 0x92, 0x8, 0x4c, 0x18, 0x40, 0x30, 0x20, 0x0, 0x30, 0x0, 0x18, 0x0, 0xc, 0x0, 0x6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x82, 0xd9, 0x0, 0x0, 0x10, 0x0, 0x13, 0xfe, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x23, 0xfe, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0xe0, 0x22, 0x38, 0x2a, 0x2c, 0x32, 0x66, 0x11, 0xc0, 0x0, 0x0 },
+{ 0x82, 0xda, 0x0, 0x5, 0x10, 0x5, 0x13, 0xf8, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x23, 0xfc, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0xe0, 0x22, 0x38, 0x2a, 0x2c, 0x32, 0x66, 0x11, 0xc0, 0x0, 0x0 },
+{ 0x82, 0xdb, 0x0, 0x0, 0x10, 0x0, 0x13, 0xf6, 0x30, 0x29, 0x20, 0x29, 0x20, 0x26, 0x23, 0xf8, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0xe0, 0x22, 0x38, 0x2a, 0x2c, 0x32, 0x66, 0x11, 0xc0, 0x0, 0x0 },
+{ 0x82, 0xdc, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0xf, 0x80, 0x10, 0xe0, 0x10, 0xb8, 0x11, 0x8c, 0xf, 0x0, 0x0, 0x0 },
+{ 0x82, 0xdd, 0x0, 0x0, 0x0, 0x0, 0xf, 0x80, 0x0, 0x80, 0x0, 0x88, 0x0, 0x88, 0x0, 0x88, 0xf, 0xf8, 0x19, 0xe, 0x33, 0xb, 0x22, 0x18, 0x26, 0x10, 0x2c, 0x30, 0x18, 0x60, 0x0, 0xc0, 0x0, 0x0 },
+{ 0x82, 0xde, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x3f, 0x98, 0x4, 0xc, 0x4, 0x6, 0x4, 0x2, 0x1c, 0x0, 0x24, 0x0, 0x24, 0x0, 0x24, 0x0, 0x24, 0x8, 0x1c, 0x8, 0x6, 0x18, 0x3, 0xf0, 0x0, 0x0 },
+{ 0x82, 0xdf, 0x0, 0x40, 0x0, 0x40, 0x10, 0x40, 0x10, 0x40, 0x1b, 0xf0, 0xe, 0x5c, 0x8, 0xc4, 0x1c, 0x86, 0x14, 0x82, 0x35, 0x82, 0x27, 0x2, 0x22, 0x6, 0x27, 0x4, 0x1d, 0x1c, 0x0, 0x70, 0x0, 0x0 },
+{ 0x82, 0xe0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1f, 0xf0, 0x1, 0x0, 0x1, 0x0, 0x1f, 0xf0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x3, 0xc, 0x1, 0x98, 0x0, 0xf0, 0x0, 0x0 },
+{ 0x82, 0xe1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0, 0x4, 0x60, 0x6, 0x20, 0x2, 0x78, 0x3, 0xc4, 0xf, 0x4, 0x19, 0x84, 0x0, 0x98, 0x0, 0x80, 0x0, 0xc0, 0x0, 0x40, 0x0, 0x40 },
+{ 0x82, 0xe2, 0x0, 0x0, 0x8, 0xc0, 0xc, 0x60, 0x4, 0x20, 0x6, 0x7c, 0x3, 0xc2, 0x1e, 0x2, 0x73, 0x6, 0x1, 0x1c, 0x1, 0x0, 0x1, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0xc0, 0x0, 0x40, 0x0, 0x40 },
+{ 0x82, 0xe3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x8, 0x40, 0x9, 0xf0, 0x12, 0x48, 0x14, 0x44, 0x14, 0x44, 0x18, 0x44, 0xa, 0x48, 0x9, 0xf0, 0x0, 0x40, 0x0, 0xc0, 0x1, 0x80 },
+{ 0x82, 0xe4, 0x0, 0x0, 0x0, 0x40, 0x10, 0x40, 0x11, 0xf8, 0x33, 0x4c, 0x26, 0x46, 0x24, 0x42, 0x28, 0x42, 0x28, 0x42, 0x30, 0x46, 0x16, 0x4c, 0x13, 0xf8, 0x0, 0x40, 0x0, 0xc0, 0x1, 0x80, 0x0, 0x0 },
+{ 0x82, 0xe5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0xf8, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7, 0x80, 0x8, 0xf0, 0x8, 0x98, 0x7, 0x0 },
+{ 0x82, 0xe6, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0xfc, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0xf, 0x80, 0x10, 0xe0, 0x10, 0xb8, 0x11, 0x8c, 0xf, 0x0, 0x0, 0x0 },
+{ 0x82, 0xe7, 0x1, 0x80, 0x0, 0xc0, 0x4, 0x60, 0x4, 0x0, 0xc, 0x0, 0x8, 0x0, 0x8, 0x0, 0x9, 0xf0, 0xf, 0x1c, 0x18, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0xc, 0x0, 0x38, 0x1, 0xe0, 0x0, 0x0 },
+{ 0x82, 0xe8, 0x0, 0x0, 0x4, 0x8, 0x4, 0x8, 0x4, 0x8, 0x4, 0x8, 0x4, 0x8, 0x4, 0x8, 0x5, 0x8, 0x6, 0x8, 0x4, 0x8, 0x0, 0x18, 0x0, 0x10, 0x0, 0x30, 0x0, 0x60, 0x1, 0xc0, 0x0, 0x0 },
+{ 0x82, 0xe9, 0x0, 0x0, 0xf, 0xf8, 0x0, 0x30, 0x0, 0x60, 0x0, 0xc0, 0x1, 0x80, 0x3, 0xf0, 0x6, 0x18, 0xc, 0xc, 0x18, 0x4, 0x3, 0x84, 0x4, 0xc4, 0x4, 0x4c, 0x6, 0x58, 0x3, 0xf0, 0x0, 0x0 },
+{ 0x82, 0xea, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0xe0, 0x3d, 0x90, 0x7, 0x10, 0x6, 0x10, 0xc, 0x10, 0xc, 0x10, 0x1c, 0x10, 0x14, 0x11, 0x34, 0x11, 0x4, 0x13, 0x4, 0xe, 0x4, 0x0, 0x0, 0x0 },
+{ 0x82, 0xeb, 0x0, 0x0, 0xf, 0xf8, 0x0, 0x30, 0x0, 0x60, 0x0, 0xc0, 0x1, 0x80, 0x3, 0xf0, 0x6, 0x18, 0xc, 0xc, 0x18, 0x4, 0x0, 0x4, 0x0, 0xc, 0x0, 0x18, 0x0, 0x70, 0x3, 0xc0, 0x0, 0x0 },
+{ 0x82, 0xec, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x1e, 0x70, 0x3, 0x88, 0x2, 0x4, 0x6, 0x4, 0xe, 0x4, 0xa, 0x4, 0x12, 0x8, 0x2, 0x30, 0x2, 0x0 },
+{ 0x82, 0xed, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0xf8, 0x3d, 0x8c, 0x7, 0x6, 0x6, 0x2, 0xc, 0x2, 0xc, 0x2, 0x1c, 0x2, 0x14, 0x2, 0x34, 0x6, 0x4, 0xc, 0x4, 0x38, 0x4, 0x0, 0x0, 0x0 },
+{ 0x82, 0xee, 0x0, 0x0, 0xf, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x3, 0xf8, 0x5, 0xc, 0xd, 0x6, 0x19, 0x2, 0x13, 0x2, 0x32, 0x62, 0x26, 0xb2, 0x2c, 0x96, 0x18, 0xcc, 0x0, 0x78, 0x0, 0x0 },
+{ 0x82, 0xef, 0x0, 0x0, 0xf, 0xf0, 0x0, 0x60, 0x1, 0x80, 0x7, 0xf0, 0x1c, 0x18, 0x0, 0x8, 0x7, 0x8, 0x9, 0x98, 0xc, 0xb0, 0x7, 0xe0, 0x4, 0x0, 0x1f, 0x3c, 0x31, 0xe6, 0x60, 0x43, 0x0, 0x0 },
+{ 0x82, 0xf0, 0x2, 0x0, 0x2, 0x0, 0x3, 0xe0, 0x3e, 0x0, 0x4, 0x0, 0x4, 0x6, 0xf, 0x9c, 0x18, 0x70, 0x31, 0xc0, 0x3, 0x40, 0x6, 0x40, 0xc, 0x40, 0x8, 0x0, 0xc, 0x0, 0x7, 0xfc, 0x0, 0x0 },
+{ 0x82, 0xf1, 0x1, 0x0, 0x1, 0x0, 0x3, 0x0, 0x2, 0x0, 0x6, 0x0, 0x4, 0x0, 0x4, 0x0, 0xd, 0x80, 0xa, 0x40, 0xc, 0x40, 0x18, 0x40, 0x10, 0x42, 0x10, 0x46, 0x30, 0x4c, 0x20, 0x38, 0x0, 0x0 },
+{ 0x83, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xfc, 0x0, 0xc, 0x0, 0x98, 0x0, 0xb0, 0x0, 0x80, 0x0, 0x80, 0x1, 0x80, 0x1, 0x0, 0x3, 0x0, 0x6, 0x0 },
+{ 0x83, 0x41, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xfe, 0x0, 0x6, 0x0, 0x8c, 0x0, 0x98, 0x0, 0xb0, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x1, 0x80, 0x1, 0x0, 0x3, 0x0, 0x6, 0x0, 0x1c, 0x0, 0x0, 0x0 },
+{ 0x83, 0x42, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0x0, 0x18, 0x0, 0x30, 0x0, 0xe0, 0x3, 0x80, 0x1e, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80 },
+{ 0x83, 0x43, 0x0, 0x0, 0x0, 0x4, 0x0, 0xc, 0x0, 0x18, 0x0, 0x30, 0x0, 0x60, 0x1, 0xc0, 0x7, 0x80, 0x3c, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x0 },
+{ 0x83, 0x44, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x0, 0x80, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x0, 0x18, 0x0, 0x10, 0x0, 0x30, 0x0, 0x60, 0x0, 0xc0, 0x3, 0x80 },
+{ 0x83, 0x45, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xfc, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0xc, 0x0, 0x8, 0x0, 0x18, 0x0, 0x10, 0x0, 0x30, 0x0, 0x60, 0x0, 0xc0, 0x3, 0x80, 0x0, 0x0 },
+{ 0x83, 0x46, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xf0, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0xf, 0xf8, 0x0, 0x0 },
+{ 0x83, 0x47, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0x48, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0xf, 0xfc, 0x0, 0xc0, 0x1, 0xc0, 0x3, 0x40, 0x6, 0x40, 0x1c, 0x40, 0x0, 0x40, 0x1, 0xc0 },
+{ 0x83, 0x49, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x3f, 0xfe, 0x0, 0xc0, 0x1, 0xc0, 0x1, 0x40, 0x3, 0x40, 0x6, 0x40, 0xc, 0x40, 0x18, 0x40, 0x30, 0x40, 0x0, 0x40, 0x1, 0xc0, 0x0, 0x0 },
+{ 0x83, 0x4a, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1f, 0xfc, 0x1, 0x4, 0x1, 0x4, 0x1, 0x4, 0x3, 0x4, 0x2, 0x4, 0x2, 0x4, 0x6, 0xc, 0x4, 0x8, 0xc, 0x8, 0x18, 0x78, 0x0, 0x0 },
+{ 0x83, 0x4b, 0x1, 0x5, 0x1, 0x5, 0x1, 0x0, 0x1, 0x0, 0x1f, 0xfc, 0x1, 0x4, 0x1, 0x4, 0x1, 0x4, 0x3, 0x4, 0x2, 0x4, 0x2, 0x4, 0x6, 0xc, 0x4, 0x8, 0xc, 0x8, 0x18, 0x78, 0x0, 0x0 },
+{ 0x83, 0x4c, 0x2, 0x0, 0x2, 0x0, 0x3, 0x0, 0x1, 0x38, 0x1, 0xe0, 0x7, 0x80, 0x3c, 0x80, 0x0, 0x9e, 0x0, 0xf0, 0x3, 0xc0, 0x1e, 0x40, 0x0, 0x60, 0x0, 0x20, 0x0, 0x20, 0x0, 0x30, 0x0, 0x10 },
+{ 0x83, 0x4d, 0x2, 0x5, 0x2, 0x5, 0x3, 0x0, 0x1, 0x38, 0x1, 0xe0, 0x7, 0x80, 0x3c, 0x80, 0x0, 0x9e, 0x0, 0xf0, 0x3, 0xc0, 0x1e, 0x40, 0x0, 0x60, 0x0, 0x20, 0x0, 0x20, 0x0, 0x30, 0x0, 0x10 },
+{ 0x83, 0x4e, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x3, 0xf8, 0x2, 0x8, 0x6, 0x8, 0xc, 0x18, 0x18, 0x10, 0x0, 0x30, 0x0, 0x20, 0x0, 0x60, 0x0, 0xc0, 0x1, 0x80, 0x7, 0x0, 0x1c, 0x0, 0x0, 0x0 },
+{ 0x83, 0x4f, 0x1, 0x5, 0x1, 0x5, 0x1, 0x0, 0x3, 0xf8, 0x2, 0x8, 0x6, 0x8, 0xc, 0x18, 0x18, 0x10, 0x0, 0x30, 0x0, 0x20, 0x0, 0x60, 0x0, 0xc0, 0x1, 0x80, 0x7, 0x0, 0x1c, 0x0, 0x0, 0x0 },
+{ 0x83, 0x50, 0x2, 0x0, 0x2, 0x0, 0x6, 0x0, 0x4, 0x0, 0xf, 0xfe, 0x8, 0x20, 0x18, 0x20, 0x30, 0x20, 0x0, 0x20, 0x0, 0x60, 0x0, 0x40, 0x0, 0xc0, 0x1, 0x80, 0x3, 0x0, 0xe, 0x0, 0x0, 0x0 },
+{ 0x83, 0x51, 0x2, 0x5, 0x2, 0x5, 0x6, 0x0, 0x4, 0x0, 0xf, 0xfe, 0x8, 0x20, 0x18, 0x20, 0x30, 0x20, 0x0, 0x20, 0x0, 0x60, 0x0, 0x40, 0x0, 0xc0, 0x1, 0x80, 0x3, 0x0, 0xe, 0x0, 0x0, 0x0 },
+{ 0x83, 0x52, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x1f, 0xfc, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0x53, 0x0, 0x5, 0x0, 0x5, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x1f, 0xfc, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0x54, 0x0, 0x0, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x0, 0x30, 0x0, 0x20, 0x0, 0x60, 0x0, 0xc0, 0x1, 0x80, 0x7, 0x0, 0x0, 0x0 },
+{ 0x83, 0x55, 0x0, 0x5, 0x4, 0x15, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x0, 0x30, 0x0, 0x20, 0x0, 0x60, 0x0, 0xc0, 0x1, 0x80, 0x7, 0x0, 0x0, 0x0 },
+{ 0x83, 0x56, 0x0, 0x0, 0x0, 0x0, 0x6, 0x0, 0x3, 0x0, 0x1, 0x0, 0x0, 0x0, 0x18, 0x2, 0xc, 0x6, 0x4, 0xc, 0x0, 0x18, 0x0, 0x30, 0x0, 0x60, 0x1, 0xc0, 0x7, 0x0, 0x1c, 0x0, 0x0, 0x0 },
+{ 0x83, 0x57, 0x0, 0x0, 0x0, 0xa, 0x6, 0xa, 0x3, 0x0, 0x1, 0x0, 0x0, 0x0, 0x18, 0x2, 0xc, 0x6, 0x4, 0xc, 0x0, 0x18, 0x0, 0x30, 0x0, 0x60, 0x1, 0xc0, 0x7, 0x0, 0x1c, 0x0, 0x0, 0x0 },
+{ 0x83, 0x58, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xf0, 0x0, 0x10, 0x0, 0x30, 0x0, 0x20, 0x0, 0x60, 0x0, 0x40, 0x0, 0xc0, 0x0, 0xc0, 0x1, 0xe0, 0x3, 0x30, 0x6, 0x18, 0xc, 0xc, 0x38, 0x6, 0x0, 0x0 },
+{ 0x83, 0x59, 0x0, 0x5, 0x0, 0x5, 0x1f, 0xf0, 0x0, 0x10, 0x0, 0x30, 0x0, 0x20, 0x0, 0x60, 0x0, 0x40, 0x0, 0xc0, 0x0, 0xc0, 0x1, 0xe0, 0x3, 0x30, 0x6, 0x18, 0xc, 0xc, 0x38, 0x6, 0x0, 0x0 },
+{ 0x83, 0x5a, 0x0, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x7e, 0x7, 0xc6, 0x7c, 0xc, 0x4, 0x18, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x6, 0x0, 0x3, 0xfe, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0x5b, 0x0, 0x5, 0x4, 0x5, 0x4, 0x0, 0x4, 0x0, 0x4, 0x7e, 0x7, 0xc6, 0x7c, 0xc, 0x4, 0x18, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x6, 0x0, 0x3, 0xfe, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0x5c, 0x0, 0x0, 0x0, 0x0, 0x10, 0x4, 0x18, 0x4, 0x8, 0x4, 0xc, 0x4, 0x4, 0xc, 0x0, 0x8, 0x0, 0x18, 0x0, 0x10, 0x0, 0x30, 0x0, 0x60, 0x0, 0xc0, 0x3, 0x80, 0xe, 0x0, 0x0, 0x0 },
+{ 0x83, 0x5d, 0x0, 0x5, 0x0, 0x5, 0x10, 0x8, 0x18, 0x8, 0x8, 0x8, 0xc, 0x8, 0x4, 0x18, 0x0, 0x10, 0x0, 0x30, 0x0, 0x20, 0x0, 0x60, 0x0, 0xc0, 0x1, 0x80, 0x3, 0x0, 0xe, 0x0, 0x0, 0x0 },
+{ 0x83, 0x5e, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x3, 0xfc, 0x2, 0x4, 0x6, 0xc, 0xd, 0x88, 0x18, 0xd8, 0x0, 0x50, 0x0, 0x30, 0x0, 0x60, 0x0, 0xc0, 0x1, 0x80, 0x7, 0x0, 0x1c, 0x0, 0x0, 0x0 },
+{ 0x83, 0x5f, 0x1, 0x5, 0x1, 0x5, 0x1, 0x0, 0x3, 0xfc, 0x2, 0x4, 0x6, 0xc, 0xd, 0x88, 0x18, 0xd8, 0x0, 0x50, 0x0, 0x30, 0x0, 0x60, 0x0, 0xc0, 0x1, 0x80, 0x7, 0x0, 0x1c, 0x0, 0x0, 0x0 },
+{ 0x83, 0x60, 0x0, 0x0, 0x0, 0x18, 0x0, 0x70, 0xf, 0xc0, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x3f, 0xfe, 0x0, 0x40, 0x0, 0x40, 0x0, 0xc0, 0x0, 0x80, 0x1, 0x80, 0x3, 0x0, 0xe, 0x0, 0x0, 0x0 },
+{ 0x83, 0x61, 0x0, 0x5, 0x0, 0x35, 0x0, 0xe0, 0xf, 0xc0, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x3f, 0xfe, 0x0, 0x40, 0x0, 0x40, 0x0, 0xc0, 0x0, 0x80, 0x1, 0x80, 0x3, 0x0, 0xe, 0x0, 0x0, 0x0 },
+{ 0x83, 0x62, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x13, 0x8, 0x19, 0x8, 0x8, 0x18, 0x0, 0x10, 0x0, 0x30, 0x0, 0x60, 0x0, 0xc0, 0x1, 0x80, 0x7, 0x0 },
+{ 0x83, 0x63, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x23, 0x2, 0x31, 0x2, 0x11, 0x86, 0x18, 0x84, 0x8, 0xc, 0x0, 0x8, 0x0, 0x18, 0x0, 0x30, 0x0, 0x60, 0x0, 0xc0, 0x3, 0x80, 0xe, 0x0, 0x0, 0x0 },
+{ 0x83, 0x64, 0x0, 0x5, 0x0, 0x5, 0x2, 0x0, 0x23, 0x4, 0x31, 0x4, 0x11, 0x84, 0x18, 0x8c, 0x8, 0x8, 0x0, 0x18, 0x0, 0x10, 0x0, 0x30, 0x0, 0x60, 0x0, 0xc0, 0x3, 0x80, 0xe, 0x0, 0x0, 0x0 },
+{ 0x83, 0x65, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xfe, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0xc0, 0x0, 0x80, 0x1, 0x80, 0x3, 0x0, 0xe, 0x0, 0x0, 0x0 },
+{ 0x83, 0x66, 0x0, 0x5, 0x0, 0x5, 0x1f, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xfe, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0xc0, 0x0, 0x80, 0x1, 0x80, 0x3, 0x0, 0xe, 0x0, 0x0, 0x0 },
+{ 0x83, 0x67, 0x0, 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x3, 0xc0, 0x2, 0x70, 0x2, 0x1c, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x0, 0x0 },
+{ 0x83, 0x68, 0x0, 0x0, 0x2, 0xa, 0x2, 0xa, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x3, 0xc0, 0x2, 0x70, 0x2, 0x1c, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x0, 0x0 },
+{ 0x83, 0x69, 0x0, 0x0, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x3f, 0xfe, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0xc0, 0x0, 0x80, 0x1, 0x80, 0x3, 0x0, 0xe, 0x0, 0x0, 0x0 },
+{ 0x83, 0x6a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0x6b, 0x0, 0x0, 0x0, 0x0, 0xf, 0xfc, 0x0, 0x4, 0x0, 0xc, 0x0, 0x8, 0x6, 0x18, 0x3, 0xb0, 0x0, 0xe0, 0x0, 0x70, 0x0, 0xd8, 0x1, 0x8c, 0x3, 0x4, 0x6, 0x0, 0x1c, 0x0, 0x0, 0x0 },
+{ 0x83, 0x6c, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x18, 0x0, 0x30, 0x0, 0x60, 0x0, 0xc0, 0x3, 0xb0, 0xe, 0x9c, 0x38, 0x86, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x0 },
+{ 0x83, 0x6d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x0, 0x4, 0x0, 0xc, 0x0, 0x8, 0x0, 0x18, 0x0, 0x30, 0x0, 0x20, 0x0, 0x60, 0x0, 0xc0, 0x1, 0x80, 0x3, 0x0, 0x6, 0x0, 0x1c, 0x0, 0x0, 0x0 },
+{ 0x83, 0x6e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x20, 0x2, 0x30, 0x2, 0x10, 0x6, 0x18, 0x4, 0x8, 0x4, 0xc, 0x4, 0x4, 0xc, 0x6, 0x8, 0x2, 0x18, 0x2, 0x30, 0x2, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0x6f, 0x0, 0x5, 0x0, 0x5, 0x0, 0x0, 0x2, 0x20, 0x2, 0x30, 0x2, 0x10, 0x6, 0x18, 0x4, 0x8, 0x4, 0xc, 0x4, 0x4, 0xc, 0x6, 0x8, 0x2, 0x18, 0x2, 0x30, 0x2, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0x70, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6, 0x4, 0x49, 0x4, 0x69, 0x4, 0x26, 0xc, 0x30, 0x8, 0x10, 0x8, 0x18, 0x8, 0x8, 0x18, 0xc, 0x10, 0x4, 0x30, 0x4, 0x60, 0x4, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0x71, 0x0, 0x0, 0x8, 0x0, 0x8, 0x0, 0x8, 0x0, 0x8, 0x18, 0x8, 0xf0, 0xf, 0x80, 0x8, 0x0, 0x8, 0x0, 0x8, 0x0, 0x8, 0x0, 0x8, 0x0, 0xc, 0x0, 0x7, 0xfc, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0x72, 0x0, 0x5, 0x8, 0x5, 0x8, 0x0, 0x8, 0x0, 0x8, 0x18, 0x8, 0xf0, 0xf, 0x80, 0x8, 0x0, 0x8, 0x0, 0x8, 0x0, 0x8, 0x0, 0x8, 0x0, 0xc, 0x0, 0x7, 0xfc, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0x73, 0x0, 0x0, 0x10, 0x0, 0x10, 0x6, 0x10, 0x9, 0x10, 0x69, 0x13, 0xc6, 0x1e, 0x0, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x18, 0x0, 0xf, 0xf8, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0x74, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x4, 0x0, 0xc, 0x0, 0x8, 0x0, 0x18, 0x0, 0x10, 0x0, 0x30, 0x0, 0x60, 0x0, 0xc0, 0x1, 0x80, 0x7, 0x0, 0x1c, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0x75, 0x0, 0x5, 0x0, 0x5, 0x3f, 0xf8, 0x0, 0x8, 0x0, 0x18, 0x0, 0x10, 0x0, 0x30, 0x0, 0x20, 0x0, 0x60, 0x0, 0xc0, 0x1, 0x80, 0x3, 0x0, 0xe, 0x0, 0x38, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0x76, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xe6, 0x0, 0x29, 0x0, 0x29, 0x0, 0x66, 0x0, 0x40, 0x0, 0xc0, 0x0, 0x80, 0x1, 0x80, 0x3, 0x0, 0x6, 0x0, 0x1c, 0x0, 0x70, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0x77, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x7, 0x0, 0x5, 0x0, 0xc, 0x80, 0x8, 0xc0, 0x18, 0x60, 0x30, 0x30, 0x0, 0x18, 0x0, 0xc, 0x0, 0x6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0x78, 0x0, 0x0, 0x0, 0x28, 0x0, 0x28, 0x2, 0x0, 0x7, 0x0, 0x5, 0x0, 0xc, 0x80, 0x8, 0xc0, 0x18, 0x60, 0x30, 0x30, 0x0, 0x18, 0x0, 0xc, 0x0, 0x6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0x79, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x18, 0x7, 0x24, 0x5, 0x24, 0xc, 0x98, 0x8, 0xc0, 0x18, 0x60, 0x30, 0x30, 0x0, 0x18, 0x0, 0xc, 0x0, 0x6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0x7a, 0x0, 0x0, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x0, 0x80, 0x0, 0x80, 0x4, 0x90, 0x4, 0x98, 0xc, 0x8c, 0x8, 0x84, 0x18, 0x86, 0x30, 0x82, 0x0, 0x80, 0x0, 0x80, 0x0, 0x0 },
+{ 0x83, 0x7b, 0x0, 0xa, 0x0, 0x8a, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x0, 0x80, 0x0, 0x80, 0x4, 0x90, 0x4, 0x98, 0xc, 0x8c, 0x8, 0x84, 0x18, 0x86, 0x30, 0x82, 0x0, 0x80, 0x0, 0x80, 0x0, 0x0 },
+{ 0x83, 0x7c, 0x0, 0x0, 0x0, 0x80, 0x0, 0x86, 0x0, 0x89, 0x3f, 0xf9, 0x0, 0x86, 0x0, 0x80, 0x4, 0x90, 0x4, 0x98, 0xc, 0x8c, 0x8, 0x84, 0x18, 0x86, 0x30, 0x82, 0x0, 0x80, 0x0, 0x80, 0x0, 0x0 },
+{ 0x83, 0x7d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xfe, 0x0, 0xc, 0x0, 0x18, 0x0, 0x30, 0xc, 0x60, 0x3, 0x40, 0x1, 0x80, 0x0, 0xc0, 0x0, 0x60, 0x0, 0x20, 0x0, 0x20, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0x7e, 0x0, 0x0, 0x7, 0x0, 0x1, 0xe0, 0x0, 0x30, 0x0, 0x0, 0x0, 0x0, 0x7, 0x0, 0x1, 0xc0, 0x0, 0x60, 0x0, 0x0, 0x0, 0x0, 0xe, 0x0, 0x3, 0x80, 0x0, 0xe0, 0x0, 0x30, 0x0, 0x0 },
+{ 0x83, 0x80, 0x0, 0x0, 0x0, 0x80, 0x0, 0x80, 0x1, 0x80, 0x1, 0x0, 0x1, 0x0, 0x3, 0x0, 0x2, 0x10, 0x2, 0x10, 0x6, 0x18, 0x4, 0x8, 0x4, 0x7c, 0xf, 0xc4, 0x38, 0x6, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0x81, 0x0, 0x0, 0x0, 0x4, 0x0, 0x4, 0x0, 0xc, 0x0, 0x8, 0x6, 0x18, 0x3, 0xb0, 0x0, 0xe0, 0x0, 0x70, 0x0, 0xd8, 0x1, 0x8c, 0x3, 0x4, 0x6, 0x0, 0xc, 0x0, 0x38, 0x0, 0x0, 0x0 },
+{ 0x83, 0x82, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xfc, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x3f, 0xfe, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x80, 0x0, 0xfe, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0x83, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x3, 0x0, 0x1, 0x3c, 0x1, 0xe4, 0x7, 0x8c, 0x1c, 0x88, 0x0, 0xc0, 0x0, 0x40, 0x0, 0x60, 0x0, 0x20, 0x0, 0x20 },
+{ 0x83, 0x84, 0x0, 0x0, 0x4, 0x0, 0x6, 0x0, 0x2, 0x1e, 0x2, 0xf2, 0xf, 0x86, 0x79, 0xc, 0x1, 0x88, 0x0, 0x80, 0x0, 0xc0, 0x0, 0x40, 0x0, 0x40, 0x0, 0x60, 0x0, 0x20, 0x0, 0x20, 0x0, 0x0 },
+{ 0x83, 0x85, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xc0, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x1f, 0xfc, 0x0, 0x0 },
+{ 0x83, 0x86, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xe0, 0x0, 0x20, 0x0, 0x20, 0x0, 0x20, 0x0, 0x20, 0x0, 0x20, 0x0, 0x20, 0x0, 0x20, 0x0, 0x20, 0x3f, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0x87, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xf0, 0x0, 0x10, 0x0, 0x10, 0x0, 0x10, 0x7, 0xf0, 0x0, 0x10, 0x0, 0x10, 0x0, 0x10, 0x7, 0xf0, 0x0, 0x0 },
+{ 0x83, 0x88, 0x0, 0x0, 0x0, 0x0, 0xf, 0xf8, 0x0, 0x8, 0x0, 0x8, 0x0, 0x8, 0x0, 0x8, 0xf, 0xf8, 0x0, 0x8, 0x0, 0x8, 0x0, 0x8, 0x0, 0x8, 0x0, 0x8, 0xf, 0xf8, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0x89, 0x0, 0x0, 0x0, 0x0, 0xf, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x4, 0x0, 0xc, 0x0, 0x8, 0x0, 0x18, 0x0, 0x30, 0x0, 0x60, 0x1, 0xc0, 0x7, 0x0, 0x0, 0x0 },
+{ 0x83, 0x8a, 0x0, 0x0, 0x4, 0x8, 0x4, 0x8, 0x4, 0x8, 0x4, 0x8, 0x4, 0x8, 0x4, 0x8, 0x4, 0x8, 0x4, 0x8, 0x0, 0x8, 0x0, 0x18, 0x0, 0x10, 0x0, 0x30, 0x0, 0x60, 0x1, 0xc0, 0x0, 0x0 },
+{ 0x83, 0x8b, 0x0, 0x0, 0x0, 0x40, 0x4, 0x40, 0x4, 0x40, 0x4, 0x40, 0x4, 0x40, 0x4, 0x40, 0x4, 0x40, 0x4, 0x42, 0x4, 0x46, 0xc, 0x4c, 0x8, 0x58, 0x18, 0x70, 0x30, 0x60, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0x8c, 0x0, 0x0, 0x0, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x2, 0x4, 0x6, 0x4, 0xc, 0x4, 0x18, 0x4, 0x70, 0x5, 0xc0, 0x7, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0x8d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0x8e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x0, 0x18, 0x0, 0x10, 0x0, 0x30, 0x0, 0x60, 0x1, 0xc0, 0x7, 0x0 },
+{ 0x83, 0x8f, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x0, 0x4, 0x0, 0xc, 0x0, 0x8, 0x0, 0x18, 0x0, 0x30, 0x0, 0x60, 0x1, 0xc0, 0x7, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0x90, 0x0, 0x0, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x1f, 0xfc, 0x4, 0x40, 0x4, 0x40, 0x4, 0x40, 0x4, 0x40, 0x4, 0x40, 0x3f, 0xfe, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x0 },
+{ 0x83, 0x91, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0xc, 0x0, 0x18, 0x0, 0xb0, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0x92, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x1f, 0xfc, 0x0, 0x8, 0x0, 0x18, 0x0, 0x30, 0x0, 0x60, 0x0, 0xc0, 0x3, 0x80, 0xe, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0x93, 0x0, 0x0, 0x0, 0x0, 0x18, 0x0, 0xe, 0x0, 0x3, 0x0, 0x0, 0x2, 0x0, 0x6, 0x0, 0xc, 0x0, 0x18, 0x0, 0x30, 0x0, 0x60, 0x1, 0xc0, 0x7, 0x0, 0x1c, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0x94, 0x0, 0x85, 0x0, 0x85, 0x0, 0x80, 0x1f, 0xfc, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x0, 0xc, 0x0, 0x8, 0x0, 0x18, 0x0, 0x30, 0x0, 0x60, 0x1, 0xc0, 0x7, 0x0, 0x0, 0x0 },
+{ 0x83, 0x95, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0xf, 0xf8, 0x1, 0x8, 0x1, 0x8, 0x1, 0x8, 0x3, 0x8, 0x2, 0x18, 0x6, 0x10, 0xc, 0x70 },
+{ 0x83, 0x96, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x7, 0xfc, 0x4, 0x20, 0xc, 0x20, 0x18, 0x60, 0x0, 0x40, 0x0, 0xc0, 0x1, 0x80, 0x3, 0x0 },
+{ 0x83, 0x9f, 0x0, 0x0, 0x0, 0x80, 0x0, 0x80, 0x1, 0xc0, 0x1, 0x40, 0x3, 0x60, 0x2, 0x20, 0x6, 0x30, 0x4, 0x10, 0xf, 0xf8, 0x8, 0x8, 0x18, 0xc, 0x10, 0x4, 0x10, 0x4, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0xa0, 0x0, 0x0, 0xf, 0xc0, 0x8, 0x20, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10, 0x8, 0x20, 0xf, 0xc0, 0x8, 0x30, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x10, 0xf, 0xe0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0xa1, 0x0, 0x0, 0x7, 0xf8, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0xa2, 0x0, 0x0, 0x0, 0x80, 0x0, 0x80, 0x1, 0xc0, 0x1, 0x40, 0x3, 0x60, 0x2, 0x20, 0x6, 0x30, 0x4, 0x10, 0xc, 0x18, 0x8, 0x8, 0x18, 0xc, 0x10, 0x4, 0x3f, 0xfe, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0xa3, 0x0, 0x0, 0x7, 0xf0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x7, 0xe0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x7, 0xf8, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0xa4, 0x0, 0x0, 0xf, 0xfc, 0x0, 0x8, 0x0, 0x18, 0x0, 0x30, 0x0, 0x20, 0x0, 0x60, 0x0, 0xc0, 0x0, 0x80, 0x1, 0x80, 0x3, 0x0, 0x2, 0x0, 0x6, 0x0, 0xf, 0xfc, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0xa5, 0x0, 0x0, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0xa6, 0x0, 0x0, 0x1, 0xc0, 0x6, 0x30, 0xc, 0x18, 0x8, 0x8, 0x18, 0xc, 0x10, 0x4, 0x13, 0xe4, 0x10, 0x4, 0x18, 0xc, 0x8, 0x8, 0xc, 0x18, 0x6, 0x30, 0x1, 0xc0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0xa7, 0x0, 0x0, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0xa8, 0x0, 0x0, 0x8, 0x18, 0x8, 0x30, 0x8, 0x60, 0x8, 0xc0, 0x9, 0x80, 0xb, 0x0, 0xf, 0x80, 0x8, 0xc0, 0x8, 0x60, 0x8, 0x30, 0x8, 0x10, 0x8, 0x18, 0x8, 0xc, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0xa9, 0x0, 0x0, 0x0, 0x80, 0x0, 0x80, 0x1, 0xc0, 0x1, 0x40, 0x3, 0x60, 0x2, 0x20, 0x6, 0x30, 0x4, 0x10, 0xc, 0x18, 0x8, 0x8, 0x18, 0xc, 0x10, 0x4, 0x10, 0x4, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0xaa, 0x0, 0x0, 0x30, 0x6, 0x30, 0x6, 0x38, 0xe, 0x28, 0xa, 0x2c, 0x1a, 0x24, 0x12, 0x26, 0x32, 0x22, 0x22, 0x23, 0x62, 0x21, 0x42, 0x21, 0xc2, 0x20, 0x82, 0x20, 0x82, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0xab, 0x0, 0x0, 0x8, 0x8, 0xc, 0x8, 0xc, 0x8, 0xe, 0x8, 0xb, 0x8, 0x9, 0x8, 0x9, 0x88, 0x8, 0xc8, 0x8, 0x48, 0x8, 0x68, 0x8, 0x38, 0x8, 0x18, 0x8, 0x18, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0xac, 0x0, 0x0, 0xf, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xf8, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0xad, 0x0, 0x0, 0x1, 0xc0, 0x6, 0x30, 0xc, 0x18, 0x8, 0x8, 0x18, 0xc, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x18, 0xc, 0x8, 0x8, 0xc, 0x18, 0x6, 0x30, 0x1, 0xc0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0xae, 0x0, 0x0, 0x1f, 0xfc, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0xaf, 0x0, 0x0, 0x7, 0xe0, 0x4, 0x10, 0x4, 0x8, 0x4, 0x8, 0x4, 0x8, 0x4, 0x10, 0x7, 0xe0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0xb0, 0x0, 0x0, 0xf, 0xf8, 0xc, 0x0, 0x6, 0x0, 0x3, 0x0, 0x1, 0x80, 0x0, 0xc0, 0x0, 0x60, 0x0, 0xc0, 0x1, 0x80, 0x3, 0x0, 0x6, 0x0, 0xc, 0x0, 0xf, 0xf8, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0xb1, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0xb2, 0x0, 0x0, 0x10, 0x4, 0x18, 0xc, 0x8, 0x8, 0xc, 0x18, 0x6, 0x30, 0x2, 0x20, 0x3, 0x60, 0x1, 0xc0, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0xb3, 0x0, 0x0, 0x0, 0x80, 0x0, 0x80, 0x3, 0xe0, 0xc, 0x98, 0x18, 0x8c, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x18, 0x8c, 0xc, 0x98, 0x3, 0xe0, 0x0, 0x80, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0xb4, 0x0, 0x0, 0x10, 0x4, 0x18, 0xc, 0xc, 0x18, 0x6, 0x30, 0x3, 0x60, 0x1, 0xc0, 0x1, 0xc0, 0x3, 0x60, 0x6, 0x30, 0xc, 0x18, 0x18, 0xc, 0x30, 0x6, 0x20, 0x2, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0xb5, 0x0, 0x0, 0x10, 0x84, 0x8, 0x88, 0x8, 0x88, 0x8, 0x88, 0x8, 0x88, 0xc, 0x98, 0x4, 0x90, 0x3, 0xe0, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0xb6, 0x0, 0x0, 0x1, 0xc0, 0x6, 0x30, 0xc, 0x18, 0x8, 0x8, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x8, 0xc, 0xc, 0x18, 0x6, 0x30, 0x1, 0x40, 0x1, 0x40, 0xf, 0x78, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0xbf, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x88, 0x2, 0x48, 0x4, 0x50, 0x4, 0x60, 0x8, 0x40, 0x8, 0xc0, 0x9, 0x48, 0x6, 0x30, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0xc0, 0x0, 0x0, 0x0, 0x70, 0x0, 0xc8, 0x1, 0x88, 0x1, 0x8, 0x3, 0x8, 0x2, 0x10, 0x2, 0xe0, 0x6, 0x30, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0xd, 0x30, 0x8, 0xe0, 0x8, 0x0, 0x18, 0x0 },
+{ 0x83, 0xc1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xc, 0xc, 0x98, 0x18, 0xb0, 0x0, 0xe0, 0x0, 0xc0, 0x0, 0x80, 0x1, 0x80, 0x1, 0x0, 0x3, 0x0, 0x2, 0x0 },
+{ 0x83, 0xc2, 0x0, 0x0, 0x1, 0xc0, 0x2, 0x70, 0x2, 0x18, 0x1, 0x88, 0x0, 0x40, 0x1, 0xa0, 0x2, 0x10, 0x4, 0x10, 0x8, 0x10, 0x8, 0x30, 0x8, 0x20, 0x4, 0x40, 0x3, 0x80, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0xc3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xe0, 0x2, 0x10, 0x2, 0x0, 0x1, 0xc0, 0x2, 0x0, 0x4, 0x10, 0x4, 0x20, 0x3, 0xc0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0xc4, 0x2, 0x0, 0x4, 0x18, 0x4, 0x30, 0x3, 0xe0, 0x0, 0xc0, 0x1, 0x80, 0x3, 0x0, 0x6, 0x0, 0xc, 0x0, 0x8, 0x0, 0xc, 0x0, 0x7, 0x0, 0x1, 0x80, 0x0, 0x40, 0x0, 0x40, 0x3, 0x80 },
+{ 0x83, 0xc5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0x60, 0x9, 0x98, 0x1, 0x8, 0x3, 0x8, 0x2, 0x18, 0x2, 0x10, 0x6, 0x10, 0x4, 0x30, 0x0, 0x20, 0x0, 0x60 },
+{ 0x83, 0xc6, 0x0, 0x0, 0x0, 0x60, 0x1, 0x90, 0x3, 0x8, 0x6, 0x8, 0x4, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x18, 0x8, 0x10, 0x8, 0x30, 0x8, 0x60, 0x4, 0xc0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0xc7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x1, 0x0, 0x3, 0x0, 0x2, 0x0, 0x6, 0x0, 0x4, 0x10, 0x4, 0xe0, 0x3, 0x80, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0xc8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x18, 0x2, 0x68, 0x2, 0xc0, 0x7, 0x0, 0x4, 0x80, 0xc, 0x88, 0x8, 0x90, 0x18, 0x60, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0xc9, 0x0, 0x0, 0x1, 0x80, 0x0, 0xc0, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0xc0, 0x1, 0xc0, 0x1, 0x40, 0x3, 0x60, 0x2, 0x20, 0x6, 0x30, 0xc, 0x18, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0xca, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x20, 0x2, 0x20, 0x6, 0x60, 0x4, 0x40, 0x4, 0x40, 0x4, 0x40, 0xe, 0xc8, 0xb, 0xb0, 0x8, 0x0, 0x18, 0x0 },
+{ 0x83, 0xcb, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc, 0x8, 0x2, 0x8, 0x2, 0x10, 0x2, 0x10, 0x6, 0x20, 0x4, 0x60, 0x5, 0xc0, 0xf, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0xcc, 0x0, 0x0, 0x0, 0x78, 0x0, 0x80, 0x0, 0x40, 0x1, 0xf8, 0x2, 0x0, 0x2, 0x0, 0x1, 0x0, 0x7, 0xf8, 0x8, 0x0, 0x8, 0x0, 0x7, 0x0, 0x0, 0xe0, 0x0, 0x10, 0x0, 0x10, 0x7, 0xe0 },
+{ 0x83, 0xcd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xc0, 0x3, 0x20, 0x6, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x30, 0x2, 0x60, 0x1, 0x80, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0xce, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x7, 0xf8, 0x9, 0x20, 0x1, 0x20, 0x1, 0x20, 0x2, 0x40, 0x2, 0x40, 0x6, 0x48, 0xc, 0x30, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0xcf, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe0, 0x1, 0x10, 0x2, 0x8, 0x2, 0x8, 0x6, 0x8, 0x4, 0x8, 0x5, 0x10, 0xc, 0xe0, 0x8, 0x0, 0x8, 0x0 },
+{ 0x83, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0x1, 0xf8, 0x2, 0x20, 0x6, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x30, 0x2, 0x60, 0x1, 0x80, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0xd1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0x7, 0xf0, 0x8, 0x80, 0x1, 0x80, 0x1, 0x0, 0x3, 0x0, 0x2, 0x20, 0x2, 0x40, 0x1, 0x80, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0xd2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc, 0x10, 0x12, 0x10, 0x2, 0x10, 0x6, 0x30, 0x4, 0x20, 0x4, 0x60, 0x4, 0xc0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x83, 0xd3, 0x0, 0x0, 0x0, 0x20, 0x0, 0x20, 0x0, 0x60, 0x0, 0x40, 0x0, 0x40, 0x1, 0xe0, 0x6, 0x90, 0x8, 0x88, 0x9, 0x88, 0x9, 0x8, 0x5, 0x30, 0x3, 0xc0, 0x2, 0x0, 0x2, 0x0, 0x6, 0x0 },
+{ 0x83, 0xd4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xc, 0x4, 0x98, 0x0, 0xb0, 0x0, 0xe0, 0x0, 0xc0, 0x1, 0x80, 0x3, 0x80, 0x6, 0x80, 0xc, 0x48, 0x18, 0x30 },
+{ 0x83, 0xd5, 0x0, 0x0, 0x0, 0x20, 0x0, 0x20, 0x0, 0x60, 0x0, 0x40, 0x0, 0x40, 0xc, 0xc8, 0x14, 0x88, 0x4, 0x88, 0xd, 0x98, 0x9, 0x10, 0x9, 0x20, 0x7, 0xc0, 0x2, 0x0, 0x2, 0x0, 0x6, 0x0 },
+{ 0x83, 0xd6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x8, 0x4, 0x44, 0x8, 0x44, 0x8, 0xc4, 0x10, 0x84, 0x10, 0x84, 0x11, 0xc8, 0xe, 0x70, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0x40, 0x0, 0x0, 0x0, 0x80, 0x0, 0x80, 0x1, 0xc0, 0x1, 0x40, 0x3, 0x60, 0x2, 0x20, 0x6, 0x30, 0x4, 0x10, 0xf, 0xf8, 0x8, 0x8, 0x18, 0xc, 0x10, 0x4, 0x10, 0x4, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0x41, 0x0, 0x0, 0xf, 0xf0, 0x8, 0x0, 0x8, 0x0, 0x8, 0x0, 0x8, 0x0, 0x8, 0x0, 0xf, 0xe0, 0x8, 0x10, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x10, 0xf, 0xe0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0x42, 0x0, 0x0, 0xf, 0xc0, 0x8, 0x20, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10, 0x8, 0x20, 0xf, 0xc0, 0x8, 0x30, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x10, 0xf, 0xe0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0x43, 0x0, 0x0, 0x7, 0xf8, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0x44, 0x0, 0x0, 0x3, 0xf8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x4, 0x8, 0x4, 0x8, 0x8, 0x8, 0x1f, 0xfc, 0x10, 0x4, 0x10, 0x4 },
+{ 0x84, 0x45, 0x0, 0x0, 0x7, 0xf0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x7, 0xe0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x7, 0xf8, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0x46, 0x6, 0x30, 0x6, 0x30, 0x0, 0x0, 0x7, 0xf0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x7, 0xe0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x7, 0xf8, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0x47, 0x0, 0x0, 0x40, 0x81, 0x20, 0x82, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x8, 0x88, 0x7, 0xf0, 0xc, 0x98, 0x18, 0x8c, 0x10, 0x84, 0x30, 0x86, 0x60, 0x83, 0x40, 0x81, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0x48, 0x0, 0x0, 0x3, 0xc0, 0xe, 0x30, 0x8, 0x18, 0x0, 0x8, 0x0, 0x8, 0x0, 0x10, 0x1, 0xe0, 0x0, 0x10, 0x0, 0x8, 0x0, 0x8, 0x8, 0x18, 0xe, 0x30, 0x3, 0xc0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0x49, 0x0, 0x0, 0x8, 0x8, 0x8, 0x18, 0x8, 0x18, 0x8, 0x38, 0x8, 0x68, 0x8, 0x48, 0x8, 0xc8, 0x9, 0x88, 0x9, 0x8, 0xb, 0x8, 0xe, 0x8, 0xc, 0x8, 0xc, 0x8, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0x4a, 0x2, 0x20, 0x2, 0x20, 0x1, 0xc0, 0x8, 0x8, 0x8, 0x8, 0x8, 0x18, 0x8, 0x38, 0x8, 0x68, 0x8, 0xc8, 0x9, 0x88, 0xb, 0x8, 0xe, 0x8, 0xc, 0x8, 0x8, 0x8, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0x4b, 0x0, 0x0, 0x8, 0x38, 0x8, 0x60, 0x8, 0x40, 0x8, 0x40, 0x8, 0xc0, 0x9, 0x80, 0xf, 0x0, 0x9, 0x80, 0x8, 0xc0, 0x8, 0x60, 0x8, 0x30, 0x8, 0x18, 0x8, 0xc, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0x4c, 0x0, 0x0, 0x3, 0xf8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x6, 0x8, 0x4, 0x8, 0xc, 0x8, 0x38, 0x8, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0x4d, 0x0, 0x0, 0x30, 0x6, 0x30, 0x6, 0x38, 0xe, 0x28, 0xa, 0x2c, 0x1a, 0x24, 0x12, 0x26, 0x32, 0x22, 0x22, 0x23, 0x62, 0x21, 0x42, 0x21, 0xc2, 0x20, 0x82, 0x20, 0x82, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0x4e, 0x0, 0x0, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0x4f, 0x0, 0x0, 0x1, 0xc0, 0x6, 0x30, 0xc, 0x18, 0x8, 0x8, 0x18, 0xc, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x18, 0xc, 0x8, 0x8, 0xc, 0x18, 0x6, 0x30, 0x1, 0xc0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0x50, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0x51, 0x0, 0x0, 0x7, 0xe0, 0x4, 0x10, 0x4, 0x8, 0x4, 0x8, 0x4, 0x8, 0x4, 0x10, 0x7, 0xe0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0x52, 0x0, 0x0, 0x1, 0xe0, 0x6, 0x30, 0xc, 0x18, 0x8, 0x8, 0x18, 0x0, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x18, 0x0, 0x8, 0x8, 0xc, 0x18, 0x6, 0x30, 0x1, 0xe0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0x53, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0x54, 0x0, 0x0, 0x4, 0x4, 0x4, 0x4, 0x6, 0xc, 0x2, 0x8, 0x3, 0x18, 0x1, 0x10, 0x1, 0xb0, 0x0, 0xa0, 0x0, 0xe0, 0x0, 0x40, 0x0, 0xc0, 0x1, 0x80, 0xf, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0x55, 0x0, 0x0, 0x0, 0x80, 0x0, 0x80, 0x3, 0xe0, 0xc, 0x98, 0x18, 0x8c, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x18, 0x8c, 0xc, 0x98, 0x3, 0xe0, 0x0, 0x80, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0x56, 0x0, 0x0, 0x10, 0x4, 0x18, 0xc, 0xc, 0x18, 0x6, 0x30, 0x3, 0x60, 0x1, 0xc0, 0x1, 0xc0, 0x3, 0x60, 0x6, 0x30, 0xc, 0x18, 0x18, 0xc, 0x30, 0x6, 0x20, 0x2, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0x57, 0x0, 0x0, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10, 0xf, 0xfc, 0x0, 0x4, 0x0, 0x4 },
+{ 0x84, 0x58, 0x0, 0x0, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10, 0xc, 0x30, 0x7, 0xd0, 0x0, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0x59, 0x0, 0x0, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x3f, 0xfe, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0x5a, 0x0, 0x0, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x3f, 0xff, 0x0, 0x1, 0x0, 0x1 },
+{ 0x84, 0x5b, 0x0, 0x0, 0x3e, 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x3, 0xf0, 0x2, 0x8, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x8, 0x3, 0xf0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0x5c, 0x0, 0x0, 0x10, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10, 0x8, 0x1f, 0x8, 0x10, 0x88, 0x10, 0x48, 0x10, 0x48, 0x10, 0x48, 0x10, 0x48, 0x10, 0x88, 0x1f, 0x8, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0x5d, 0x0, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x7, 0xe0, 0x4, 0x10, 0x4, 0x8, 0x4, 0x8, 0x4, 0x8, 0x4, 0x8, 0x4, 0x10, 0x7, 0xe0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0x5e, 0x0, 0x0, 0x3, 0xc0, 0x6, 0x30, 0x8, 0x18, 0x8, 0x8, 0x0, 0xc, 0x0, 0x4, 0x1, 0xfc, 0x0, 0x4, 0x0, 0xc, 0x8, 0x8, 0x8, 0x18, 0x6, 0x30, 0x3, 0xc0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0x5f, 0x0, 0x0, 0x20, 0x70, 0x21, 0x8c, 0x21, 0x4, 0x23, 0x6, 0x22, 0x2, 0x22, 0x2, 0x3e, 0x2, 0x22, 0x2, 0x22, 0x2, 0x23, 0x6, 0x21, 0x4, 0x21, 0x8c, 0x20, 0x70, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0x60, 0x0, 0x0, 0x3, 0xf8, 0x4, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x4, 0x8, 0x3, 0xf8, 0x0, 0x88, 0x1, 0x88, 0x3, 0x8, 0x2, 0x8, 0x6, 0x8, 0xc, 0x8, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0x70, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xe0, 0x0, 0x10, 0x0, 0x10, 0x3, 0xf0, 0x4, 0x10, 0x4, 0x10, 0x4, 0x30, 0x3, 0xd8, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0x71, 0x0, 0x0, 0x0, 0x10, 0x1, 0xe0, 0x3, 0x0, 0x6, 0x0, 0x4, 0x0, 0x5, 0xc0, 0x6, 0x20, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x2, 0x20, 0x1, 0xc0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0x72, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xe0, 0x2, 0x10, 0x2, 0x10, 0x3, 0xe0, 0x2, 0x10, 0x2, 0x10, 0x2, 0x10, 0x3, 0xe0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0x73, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xe0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0x74, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xf0, 0x2, 0x10, 0x2, 0x10, 0x2, 0x10, 0x2, 0x10, 0x2, 0x10, 0x4, 0x10, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8 },
+{ 0x84, 0x75, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xc0, 0x2, 0x20, 0x4, 0x10, 0x7, 0xf0, 0x4, 0x0, 0x4, 0x0, 0x2, 0x10, 0x1, 0xe0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0x76, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x60, 0x3, 0x60, 0x0, 0x0, 0x1, 0xc0, 0x2, 0x20, 0x4, 0x10, 0x7, 0xf0, 0x4, 0x0, 0x4, 0x0, 0x2, 0x10, 0x1, 0xe0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0x77, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x18, 0x8c, 0x8, 0x88, 0x4, 0x90, 0x3, 0xe0, 0x6, 0xb0, 0x4, 0x90, 0xc, 0x98, 0x18, 0x8c, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0x78, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xc0, 0x4, 0x20, 0x0, 0x20, 0x1, 0xc0, 0x0, 0x20, 0x0, 0x20, 0x4, 0x20, 0x3, 0xc0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0x79, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0x10, 0x8, 0x30, 0x8, 0x50, 0x8, 0x90, 0x9, 0x10, 0xa, 0x10, 0xc, 0x10, 0x8, 0x10, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0x7a, 0x0, 0x0, 0x0, 0x0, 0x4, 0x20, 0x4, 0x20, 0x3, 0xc0, 0x0, 0x0, 0x8, 0x10, 0x8, 0x30, 0x8, 0x50, 0x8, 0x90, 0x9, 0x10, 0xa, 0x10, 0xc, 0x10, 0x8, 0x10, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0x7b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x30, 0x4, 0x40, 0x4, 0x40, 0x7, 0x80, 0x4, 0x80, 0x4, 0x40, 0x4, 0x20, 0x4, 0x10, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0x7c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xf0, 0x2, 0x10, 0x2, 0x10, 0x2, 0x10, 0x2, 0x10, 0x2, 0x10, 0x6, 0x10, 0xc, 0x10, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0x7d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc, 0x18, 0xc, 0x18, 0xa, 0x28, 0xa, 0x28, 0x9, 0x48, 0x9, 0x48, 0x8, 0x88, 0x8, 0x88, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0x7e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x7, 0xf0, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xc0, 0x2, 0x20, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x2, 0x20, 0x1, 0xc0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0x81, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xf0, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0x82, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5, 0xc0, 0x6, 0x20, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x6, 0x20, 0x5, 0xc0, 0x4, 0x0, 0x4, 0x0 },
+{ 0x84, 0x83, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xe0, 0x2, 0x10, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x2, 0x10, 0x1, 0xe0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0x84, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xf8, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0x85, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x8, 0x6, 0x8, 0x2, 0x18, 0x3, 0x10, 0x1, 0x30, 0x1, 0xa0, 0x0, 0xe0, 0x0, 0xc0, 0x1, 0x80, 0x7, 0x0 },
+{ 0x84, 0x86, 0x0, 0x0, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x6, 0xb0, 0x9, 0xc8, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x9, 0xc8, 0x6, 0xb0, 0x0, 0x80, 0x0, 0x80 },
+{ 0x84, 0x87, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x10, 0x6, 0x30, 0x3, 0x60, 0x1, 0xc0, 0x1, 0xc0, 0x3, 0x60, 0x6, 0x30, 0xc, 0x18, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0x88, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x20, 0x4, 0x20, 0x4, 0x20, 0x4, 0x20, 0x4, 0x20, 0x4, 0x20, 0x4, 0x20, 0x7, 0xf8, 0x0, 0x8, 0x0, 0x8 },
+{ 0x84, 0x89, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x30, 0x3, 0xd0, 0x0, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0x8a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0x8b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xff, 0x0, 0x1, 0x0, 0x1 },
+{ 0x84, 0x8c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1e, 0x0, 0x2, 0x0, 0x2, 0x0, 0x3, 0xe0, 0x2, 0x10, 0x2, 0x10, 0x2, 0x10, 0x3, 0xe0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0x8d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xf, 0x88, 0x8, 0x48, 0x8, 0x48, 0x8, 0x48, 0xf, 0x88, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0x8e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x3, 0xe0, 0x2, 0x10, 0x2, 0x10, 0x2, 0x10, 0x3, 0xe0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0x8f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xc0, 0x4, 0x20, 0x0, 0x10, 0x1, 0xf0, 0x0, 0x10, 0x0, 0x10, 0x4, 0x20, 0x3, 0xc0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0x90, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0x60, 0x8, 0x90, 0x9, 0x8, 0xf, 0x8, 0x9, 0x8, 0x9, 0x8, 0x8, 0x90, 0x8, 0x60, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0x91, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xf0, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x3, 0xf0, 0x1, 0x10, 0x2, 0x10, 0x4, 0x10, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0x9f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0xa0, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80 },
+{ 0x84, 0xa1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80 },
+{ 0x84, 0xa2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80 },
+{ 0x84, 0xa3, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0xff, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0xa4, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0xa5, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0xff, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80 },
+{ 0x84, 0xa6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80 },
+{ 0x84, 0xa7, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0xff, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80 },
+{ 0x84, 0xa8, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0xa9, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0xff, 0xff, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80 },
+{ 0x84, 0xaa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0xab, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80 },
+{ 0x84, 0xac, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xff, 0x1, 0xff, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80 },
+{ 0x84, 0xad, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x80, 0xff, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80 },
+{ 0x84, 0xae, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0xff, 0x80, 0xff, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0xaf, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0xff, 0x1, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0xb0, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0xff, 0x1, 0xff, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80 },
+{ 0x84, 0xb1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80 },
+{ 0x84, 0xb2, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0xff, 0x80, 0xff, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80 },
+{ 0x84, 0xb3, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0xb4, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0xff, 0xff, 0xff, 0xff, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80 },
+{ 0x84, 0xb5, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0xff, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80 },
+{ 0x84, 0xb6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80 },
+{ 0x84, 0xb7, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0xff, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80 },
+{ 0x84, 0xb8, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0xb9, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0xff, 0xff, 0xff, 0xff, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80 },
+{ 0x84, 0xba, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0xff, 0x0, 0xff, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80 },
+{ 0x84, 0xbb, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80 },
+{ 0x84, 0xbc, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0xff, 0x80, 0xff, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80 },
+{ 0x84, 0xbd, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x84, 0xbe, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0xff, 0xff, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80, 0x1, 0x80 },
+{ 0x87, 0x40, 0x3, 0xe0, 0xc, 0x18, 0x10, 0x84, 0x21, 0x82, 0x23, 0x82, 0x40, 0x81, 0x40, 0x81, 0x40, 0x81, 0x40, 0x81, 0x40, 0x81, 0x40, 0x81, 0x20, 0x82, 0x20, 0x82, 0x10, 0x4, 0xc, 0x18, 0x3, 0xe0 },
+{ 0x87, 0x41, 0x3, 0xe0, 0xc, 0x18, 0x13, 0xe4, 0x26, 0x32, 0x24, 0x12, 0x44, 0x11, 0x40, 0x31, 0x40, 0x61, 0x40, 0xc1, 0x41, 0x81, 0x43, 0x1, 0x26, 0x2, 0x27, 0xf2, 0x10, 0x4, 0xc, 0x18, 0x3, 0xe0 },
+{ 0x87, 0x42, 0x3, 0xe0, 0xc, 0x18, 0x11, 0xe4, 0x23, 0x32, 0x26, 0x12, 0x40, 0x11, 0x40, 0x31, 0x41, 0xe1, 0x40, 0x31, 0x40, 0x11, 0x44, 0x11, 0x26, 0x32, 0x23, 0xe2, 0x10, 0x4, 0xc, 0x18, 0x3, 0xe0 },
+{ 0x87, 0x43, 0x3, 0xe0, 0xc, 0x18, 0x10, 0xe4, 0x20, 0xa2, 0x21, 0xa2, 0x41, 0x21, 0x43, 0x21, 0x42, 0x21, 0x46, 0x21, 0x44, 0x21, 0x47, 0xf9, 0x20, 0x22, 0x20, 0x22, 0x10, 0x4, 0xc, 0x18, 0x3, 0xe0 },
+{ 0x87, 0x44, 0x3, 0xe0, 0xc, 0x18, 0x13, 0xe4, 0x22, 0x2, 0x22, 0x2, 0x42, 0x1, 0x42, 0xe1, 0x43, 0x31, 0x40, 0x11, 0x40, 0x11, 0x46, 0x11, 0x23, 0x32, 0x21, 0xe2, 0x10, 0x4, 0xc, 0x18, 0x3, 0xe0 },
+{ 0x87, 0x45, 0x3, 0xe0, 0xc, 0x18, 0x11, 0xe4, 0x23, 0x32, 0x22, 0x12, 0x46, 0x1, 0x44, 0xe1, 0x45, 0x31, 0x46, 0x11, 0x46, 0x11, 0x42, 0x11, 0x23, 0x32, 0x21, 0xe2, 0x10, 0x4, 0xc, 0x18, 0x3, 0xe0 },
+{ 0x87, 0x46, 0x3, 0xf0, 0xc, 0x8, 0x10, 0x4, 0x23, 0xf2, 0x20, 0x12, 0x40, 0x31, 0x40, 0x21, 0x40, 0x61, 0x40, 0x41, 0x40, 0xc1, 0x40, 0x81, 0x21, 0x82, 0x21, 0x2, 0x11, 0x4, 0xc, 0x8, 0x3, 0xf0 },
+{ 0x87, 0x47, 0x3, 0xe0, 0xc, 0x18, 0x11, 0xe4, 0x23, 0x32, 0x22, 0x12, 0x42, 0x11, 0x41, 0x21, 0x40, 0xc1, 0x41, 0x21, 0x42, 0x11, 0x42, 0x11, 0x23, 0x32, 0x21, 0xe2, 0x10, 0x4, 0xc, 0x18, 0x3, 0xe0 },
+{ 0x87, 0x48, 0x3, 0xe0, 0xc, 0x18, 0x11, 0xe4, 0x23, 0x32, 0x22, 0x12, 0x42, 0x19, 0x42, 0x19, 0x43, 0x29, 0x41, 0xc9, 0x40, 0x19, 0x42, 0x11, 0x23, 0x32, 0x21, 0xe2, 0x10, 0x4, 0xc, 0x18, 0x3, 0xe0 },
+{ 0x87, 0x49, 0x3, 0xe0, 0xc, 0x18, 0x10, 0x74, 0x2c, 0xda, 0x24, 0x8a, 0x44, 0x89, 0x44, 0x89, 0x44, 0x89, 0x44, 0x89, 0x44, 0x89, 0x44, 0x89, 0x24, 0xda, 0x24, 0x72, 0x10, 0x4, 0xc, 0x18, 0x3, 0xe0 },
+{ 0x87, 0x4a, 0x3, 0xe0, 0xc, 0x18, 0x10, 0x4, 0x2c, 0x32, 0x24, 0x12, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x24, 0x12, 0x24, 0x12, 0x10, 0x4, 0xc, 0x18, 0x3, 0xe0 },
+{ 0x87, 0x4b, 0x3, 0xe0, 0xc, 0x18, 0x10, 0x74, 0x2c, 0xda, 0x24, 0x8a, 0x44, 0x89, 0x44, 0x19, 0x44, 0x11, 0x44, 0x31, 0x44, 0x61, 0x44, 0xc1, 0x24, 0x82, 0x24, 0xfa, 0x10, 0x4, 0xc, 0x18, 0x3, 0xe0 },
+{ 0x87, 0x4c, 0x3, 0xe0, 0xc, 0x18, 0x10, 0x74, 0x2c, 0xda, 0x24, 0x8a, 0x44, 0x9, 0x44, 0x19, 0x44, 0x71, 0x44, 0x19, 0x44, 0x9, 0x44, 0x89, 0x24, 0xda, 0x24, 0x72, 0x10, 0x4, 0xc, 0x18, 0x3, 0xe0 },
+{ 0x87, 0x4d, 0x3, 0xe0, 0xc, 0x18, 0x10, 0x34, 0x2c, 0x32, 0x24, 0x52, 0x44, 0x51, 0x44, 0xd1, 0x44, 0x91, 0x45, 0x91, 0x45, 0x11, 0x45, 0xf9, 0x24, 0x12, 0x24, 0x12, 0x10, 0x4, 0xc, 0x18, 0x3, 0xe0 },
+{ 0x87, 0x4e, 0x3, 0xe0, 0xc, 0x18, 0x10, 0xf4, 0x2c, 0x82, 0x24, 0x82, 0x44, 0x81, 0x44, 0xb1, 0x44, 0xd9, 0x44, 0x89, 0x44, 0x9, 0x44, 0x9, 0x24, 0xda, 0x24, 0x72, 0x10, 0x4, 0xc, 0x18, 0x3, 0xe0 },
+{ 0x87, 0x4f, 0x3, 0xe0, 0xc, 0x18, 0x10, 0x74, 0x2c, 0xda, 0x24, 0x8a, 0x44, 0x81, 0x44, 0xb1, 0x44, 0xd9, 0x44, 0x89, 0x44, 0x89, 0x44, 0x89, 0x24, 0xda, 0x24, 0x72, 0x10, 0x4, 0xc, 0x18, 0x3, 0xe0 },
+{ 0x87, 0x50, 0x3, 0xe0, 0xc, 0x18, 0x11, 0xf4, 0x2c, 0x12, 0x24, 0x12, 0x44, 0x31, 0x44, 0x21, 0x44, 0x21, 0x44, 0x21, 0x44, 0x61, 0x44, 0x41, 0x24, 0x42, 0x24, 0x42, 0x10, 0x4, 0xc, 0x18, 0x3, 0xe0 },
+{ 0x87, 0x51, 0x3, 0xe0, 0xc, 0x18, 0x10, 0x74, 0x2c, 0xda, 0x24, 0x8a, 0x44, 0x89, 0x44, 0x89, 0x44, 0x71, 0x44, 0x89, 0x44, 0x89, 0x44, 0x89, 0x24, 0xda, 0x24, 0x72, 0x10, 0x4, 0xc, 0x18, 0x3, 0xe0 },
+{ 0x87, 0x52, 0x3, 0xe0, 0xc, 0x18, 0x10, 0x74, 0x2c, 0xda, 0x24, 0x8a, 0x44, 0x89, 0x44, 0x89, 0x44, 0xd9, 0x44, 0x69, 0x44, 0x9, 0x44, 0x89, 0x24, 0xda, 0x24, 0x72, 0x10, 0x4, 0xc, 0x18, 0x3, 0xe0 },
+{ 0x87, 0x53, 0x3, 0xe0, 0xc, 0x18, 0x17, 0x4, 0x2d, 0x9a, 0x28, 0xa6, 0x48, 0xa5, 0x41, 0xa5, 0x41, 0x25, 0x43, 0x25, 0x46, 0x25, 0x4c, 0x25, 0x28, 0x26, 0x2f, 0x9a, 0x10, 0x4, 0xc, 0x18, 0x3, 0xe0 },
+{ 0x87, 0x54, 0x0, 0x0, 0x3, 0xe0, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x3, 0xe0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x87, 0x55, 0x0, 0x0, 0xf, 0xf8, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0xf, 0xf8, 0x0, 0x0, 0x0, 0x0 },
+{ 0x87, 0x56, 0x0, 0x0, 0x1f, 0xfc, 0x4, 0x90, 0x4, 0x90, 0x4, 0x90, 0x4, 0x90, 0x4, 0x90, 0x4, 0x90, 0x4, 0x90, 0x4, 0x90, 0x4, 0x90, 0x4, 0x90, 0x4, 0x90, 0x1f, 0xfc, 0x0, 0x0, 0x0, 0x0 },
+{ 0x87, 0x57, 0x0, 0x0, 0x7f, 0x1f, 0x14, 0x4, 0x16, 0xc, 0x12, 0x8, 0x12, 0x8, 0x13, 0x18, 0x11, 0x10, 0x11, 0x10, 0x11, 0xb0, 0x10, 0xa0, 0x10, 0xa0, 0x10, 0xe0, 0x7c, 0x40, 0x0, 0x0, 0x0, 0x0 },
+{ 0x87, 0x58, 0x0, 0x0, 0x3e, 0x3e, 0x8, 0x8, 0xc, 0x18, 0x4, 0x10, 0x4, 0x10, 0x6, 0x30, 0x2, 0x20, 0x2, 0x20, 0x3, 0x60, 0x1, 0x40, 0x1, 0x40, 0x1, 0xc0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0 },
+{ 0x87, 0x59, 0x0, 0x0, 0x7c, 0x7f, 0x10, 0x14, 0x18, 0x34, 0x8, 0x24, 0x8, 0x24, 0xc, 0x64, 0x4, 0x44, 0x4, 0x44, 0x6, 0xc4, 0x2, 0x84, 0x2, 0x84, 0x3, 0x84, 0x1, 0x1f, 0x0, 0x0, 0x0, 0x0 },
+{ 0x87, 0x5a, 0x0, 0x0, 0x71, 0xff, 0x20, 0x92, 0x20, 0x92, 0x20, 0x92, 0x31, 0x92, 0x11, 0x12, 0x11, 0x12, 0x11, 0x12, 0x1b, 0x12, 0xa, 0x12, 0xa, 0x12, 0xe, 0x12, 0x4, 0x7f, 0x0, 0x0, 0x0, 0x0 },
+{ 0x87, 0x5b, 0x0, 0x0, 0x71, 0xff, 0x20, 0xaa, 0x20, 0xaa, 0x20, 0xaa, 0x31, 0xaa, 0x11, 0x2a, 0x11, 0x2a, 0x11, 0x2a, 0x1b, 0x2a, 0xa, 0x2a, 0xa, 0x2a, 0xe, 0x2a, 0x4, 0xff, 0x0, 0x0, 0x0, 0x0 },
+{ 0x87, 0x5c, 0x0, 0x0, 0x3f, 0xdf, 0x9, 0x4, 0x9, 0x8c, 0x8, 0x88, 0x8, 0xd8, 0x8, 0x50, 0x8, 0x70, 0x8, 0x50, 0x8, 0xd8, 0x8, 0x88, 0x9, 0x8c, 0x9, 0x4, 0x3f, 0xdf, 0x0, 0x0, 0x0, 0x0 },
+{ 0x87, 0x5d, 0x0, 0x0, 0x1f, 0x3e, 0x6, 0x18, 0x2, 0x10, 0x3, 0x30, 0x1, 0x20, 0x1, 0xe0, 0x0, 0xc0, 0x1, 0xe0, 0x1, 0x20, 0x3, 0x30, 0x2, 0x10, 0x6, 0x18, 0x1f, 0x3e, 0x0, 0x0, 0x0, 0x0 },
+{ 0x87, 0x5e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x87, 0x5f, 0x1c, 0x0, 0x7, 0x0, 0x0, 0x0, 0x1c, 0x0, 0x7, 0x0, 0x0, 0x0, 0x3c, 0x0, 0x7, 0x0, 0x0, 0x42, 0x0, 0x42, 0x0, 0x42, 0x0, 0x42, 0x0, 0x42, 0x0, 0x6, 0x0, 0xc, 0x0, 0x38 },
+{ 0x87, 0x60, 0x8, 0x0, 0xf, 0x0, 0x3c, 0x0, 0x4, 0x0, 0x7, 0xc0, 0x3e, 0x0, 0x2, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x7e, 0x0, 0x42, 0x0, 0x42, 0x0, 0x42, 0x0, 0x42, 0x0, 0x7e, 0x0, 0x0 },
+{ 0x87, 0x61, 0x10, 0x0, 0x10, 0x60, 0x1f, 0x31, 0x71, 0x1, 0x12, 0x3, 0x10, 0x6, 0x18, 0x1c, 0xf, 0x70, 0x0, 0x0, 0x7, 0x0, 0x3c, 0x0, 0x4, 0x0, 0x7f, 0x80, 0x4, 0x0, 0xc, 0x0, 0x38, 0x0 },
+{ 0x87, 0x62, 0x1, 0x0, 0x1, 0x0, 0x33, 0x0, 0x1a, 0x7e, 0xe, 0x0, 0x1b, 0x0, 0x31, 0x0, 0x60, 0x0, 0x0, 0x0, 0x20, 0x8, 0x20, 0x28, 0x3c, 0x29, 0x27, 0x29, 0x21, 0x2b, 0x20, 0x6e, 0x20, 0xcc },
+{ 0x87, 0x63, 0x1, 0x40, 0x11, 0x5e, 0x3e, 0x0, 0x62, 0x3f, 0x42, 0x1, 0x6, 0x3, 0xc, 0x6, 0x38, 0x1c, 0x0, 0x0, 0x8, 0x0, 0x18, 0x0, 0x10, 0x0, 0x32, 0x0, 0x22, 0x0, 0x7f, 0x0, 0x41, 0x0 },
+{ 0x87, 0x64, 0x20, 0x0, 0x20, 0x0, 0x20, 0x0, 0x3c, 0x0, 0x27, 0x0, 0x21, 0x0, 0x20, 0x0, 0x20, 0x0, 0x0, 0x0, 0x0, 0xc0, 0x0, 0x61, 0x0, 0x1, 0x0, 0x3, 0x0, 0x6, 0x0, 0x1c, 0x0, 0x70 },
+{ 0x87, 0x65, 0x0, 0x0, 0x7f, 0x0, 0x1, 0x0, 0xb, 0x7e, 0xc, 0x0, 0x8, 0x0, 0x18, 0x0, 0x30, 0x0, 0x0, 0x0, 0x4, 0x0, 0x14, 0x0, 0x14, 0x80, 0x14, 0x80, 0x15, 0x80, 0x37, 0x0, 0x66, 0x0 },
+{ 0x87, 0x66, 0x0, 0x10, 0x10, 0x1e, 0x38, 0x32, 0x6c, 0x62, 0x46, 0x2, 0x3, 0x6, 0x1, 0x8c, 0x0, 0x38, 0x10, 0x0, 0x1e, 0x14, 0x32, 0x14, 0x6a, 0x15, 0xa, 0xd5, 0x6, 0x15, 0xc, 0x37, 0x38, 0x66 },
+{ 0x87, 0x67, 0x0, 0x0, 0x21, 0x0, 0x21, 0x10, 0x21, 0x49, 0x21, 0x21, 0x3, 0x3, 0x6, 0x6, 0x1c, 0x1c, 0x0, 0x0, 0x20, 0x8, 0x20, 0x28, 0x3c, 0x29, 0x27, 0x29, 0x21, 0x2b, 0x20, 0x6e, 0x20, 0xcc },
+{ 0x87, 0x68, 0x0, 0x0, 0x7e, 0x0, 0x42, 0x20, 0x42, 0x92, 0x2, 0x42, 0x6, 0x6, 0xc, 0xc, 0x18, 0x38, 0x0, 0x0, 0x20, 0x0, 0x20, 0x0, 0x38, 0x0, 0x2e, 0x0, 0x22, 0x0, 0x20, 0x0, 0x20, 0x0 },
+{ 0x87, 0x69, 0x8, 0x0, 0x8, 0x0, 0x3f, 0x3e, 0x9, 0x22, 0x9, 0x22, 0x19, 0x22, 0x31, 0x22, 0x63, 0x3e, 0x0, 0x0, 0x21, 0x0, 0x21, 0x0, 0x21, 0x3e, 0x21, 0x0, 0x3, 0x0, 0x6, 0x0, 0x1c, 0x0 },
+{ 0x87, 0x6a, 0x25, 0x0, 0x25, 0x0, 0x20, 0x0, 0x3c, 0x0, 0x27, 0x0, 0x21, 0x0, 0x20, 0x0, 0x20, 0x0, 0x0, 0x0, 0x0, 0x8, 0x0, 0x28, 0x0, 0x29, 0x0, 0x29, 0x0, 0x2b, 0x0, 0x6e, 0x0, 0xcc },
+{ 0x87, 0x6b, 0x10, 0x0, 0x10, 0x60, 0x1f, 0x31, 0x71, 0x1, 0x12, 0x3, 0x10, 0x6, 0x18, 0x1c, 0xf, 0x70, 0x0, 0x0, 0x10, 0x0, 0x10, 0x0, 0x1c, 0x0, 0x17, 0x0, 0x11, 0x0, 0x10, 0x0, 0x10, 0x0 },
+{ 0x87, 0x6c, 0x1, 0x80, 0x11, 0x40, 0x12, 0xc0, 0x12, 0x3e, 0x33, 0x0, 0x21, 0x0, 0x61, 0x0, 0x0, 0x0, 0x20, 0x8, 0x21, 0x8, 0x7d, 0xa8, 0x24, 0x2e, 0x28, 0x6b, 0x20, 0x48, 0x30, 0xc8, 0x1d, 0x88 },
+{ 0x87, 0x6d, 0x38, 0x42, 0xe, 0x42, 0x0, 0x42, 0x38, 0x42, 0xe, 0x42, 0x0, 0x6, 0x78, 0xc, 0xe, 0x38, 0x0, 0x0, 0x2a, 0x94, 0x2a, 0x94, 0x2c, 0x14, 0x25, 0xd5, 0x24, 0x15, 0x66, 0x37, 0x42, 0x66 },
+{ 0x87, 0x6e, 0x1, 0x80, 0x2, 0x80, 0x3b, 0x0, 0x6c, 0x0, 0x46, 0x3f, 0x3, 0x0, 0x1, 0x80, 0x0, 0x0, 0x0, 0xa0, 0x30, 0xa0, 0x8, 0x0, 0x60, 0x80, 0x11, 0x80, 0x3, 0x0, 0xe, 0x0, 0x38, 0x0 },
+{ 0x87, 0x6f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5b, 0x5b, 0x6d, 0x6d, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x0, 0x0, 0x0, 0x0 },
+{ 0x87, 0x70, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1e, 0x5b, 0x21, 0x6d, 0x40, 0x49, 0x40, 0x49, 0x40, 0x49, 0x40, 0x49, 0x21, 0x49, 0x1e, 0x49, 0x0, 0x0, 0x0, 0x0 },
+{ 0x87, 0x71, 0x0, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x46, 0xb6, 0x4c, 0xda, 0x58, 0x92, 0x70, 0x92, 0x58, 0x92, 0x4c, 0x92, 0x46, 0x92, 0x42, 0x92, 0x0, 0x0, 0x0, 0x0 },
+{ 0x87, 0x72, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x5b, 0x3a, 0x6d, 0x44, 0x49, 0x42, 0x49, 0x42, 0x49, 0x3c, 0x49, 0x40, 0x49, 0x3e, 0x49, 0x41, 0x0, 0x41, 0x0, 0x3e },
+{ 0x87, 0x73, 0x0, 0x0, 0x20, 0x0, 0x20, 0x0, 0x20, 0x0, 0x20, 0x0, 0x20, 0x1, 0x23, 0x3d, 0x26, 0x46, 0x2c, 0x42, 0x38, 0x42, 0x2c, 0x3c, 0x26, 0x40, 0x23, 0x3e, 0x21, 0x41, 0x0, 0x41, 0x0, 0x3e },
+{ 0x87, 0x74, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1e, 0x1e, 0x21, 0x21, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x21, 0x21, 0x1e, 0x1e, 0x0, 0x0, 0x0, 0x0 },
+{ 0x87, 0x75, 0x0, 0x6, 0x0, 0x9, 0x0, 0x1, 0x0, 0x2, 0x0, 0x4, 0x0, 0x8, 0x2c, 0xcf, 0x33, 0x20, 0x22, 0x20, 0x22, 0x20, 0x22, 0x20, 0x22, 0x20, 0x22, 0x20, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0 },
+{ 0x87, 0x7e, 0x0, 0x5, 0x7f, 0x5, 0x8, 0x7e, 0x2a, 0x44, 0x2a, 0x44, 0x2a, 0x45, 0x2a, 0x75, 0x8, 0x55, 0x7f, 0x56, 0x8, 0xd6, 0x8, 0x94, 0x8, 0xb6, 0x8, 0xaa, 0x9, 0x8b, 0x9, 0x11, 0x0, 0x0 },
+{ 0x87, 0x80, 0x0, 0x0, 0x0, 0x36, 0x0, 0x36, 0x0, 0x12, 0x0, 0x24, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x87, 0x81, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x36, 0x0, 0x36, 0x0, 0x12, 0x0, 0x24, 0x0, 0x0, 0x0 },
+{ 0x87, 0x82, 0x0, 0x0, 0x42, 0x0, 0x42, 0x0, 0x62, 0x0, 0x62, 0x0, 0x72, 0x70, 0x52, 0xd8, 0x5a, 0x88, 0x4a, 0x88, 0x4e, 0x88, 0x46, 0x88, 0x46, 0x88, 0x42, 0xdb, 0x42, 0x73, 0x0, 0x0, 0x0, 0x0 },
+{ 0x87, 0x83, 0x0, 0x0, 0x44, 0x44, 0x44, 0x44, 0x4c, 0x4c, 0x48, 0x48, 0x58, 0x58, 0x50, 0x50, 0x70, 0x70, 0x58, 0x58, 0x48, 0x48, 0x48, 0x48, 0x4c, 0x4c, 0x45, 0x45, 0x45, 0x45, 0x0, 0x0, 0x0, 0x0 },
+{ 0x87, 0x84, 0x0, 0x0, 0x7f, 0x0, 0x8, 0x0, 0x8, 0x0, 0x8, 0x0, 0x8, 0x0, 0x9, 0xe8, 0x9, 0x8, 0x9, 0x8, 0x9, 0xe8, 0x9, 0x8, 0x9, 0x8, 0x9, 0x8, 0x9, 0xef, 0x0, 0x0, 0x0, 0x0 },
+{ 0x87, 0x85, 0x3, 0xe0, 0xc, 0x18, 0x10, 0x4, 0x20, 0x82, 0x20, 0x82, 0x40, 0x81, 0x40, 0xf1, 0x40, 0x81, 0x40, 0x81, 0x40, 0x81, 0x40, 0x81, 0x2f, 0xfa, 0x20, 0x2, 0x10, 0x4, 0xc, 0x18, 0x3, 0xe0 },
+{ 0x87, 0x86, 0x3, 0xe0, 0xc, 0x18, 0x10, 0x4, 0x20, 0x82, 0x20, 0x82, 0x4f, 0xf9, 0x48, 0x89, 0x48, 0x89, 0x48, 0x89, 0x4f, 0xf9, 0x40, 0x81, 0x20, 0x82, 0x20, 0x82, 0x10, 0x4, 0xc, 0x18, 0x3, 0xe0 },
+{ 0x87, 0x87, 0x3, 0xe0, 0xc, 0x18, 0x10, 0x4, 0x20, 0x2, 0x2f, 0xfa, 0x40, 0x81, 0x40, 0x81, 0x40, 0xe1, 0x40, 0xb1, 0x40, 0x81, 0x40, 0x81, 0x20, 0x82, 0x20, 0x82, 0x10, 0x4, 0xc, 0x18, 0x3, 0xe0 },
+{ 0x87, 0x88, 0x3, 0xe0, 0xc, 0x18, 0x10, 0x84, 0x20, 0x82, 0x2f, 0xfa, 0x41, 0x1, 0x41, 0x1, 0x43, 0xf1, 0x42, 0x41, 0x46, 0x41, 0x4c, 0x41, 0x20, 0x42, 0x23, 0xfa, 0x10, 0x4, 0xc, 0x18, 0x3, 0xe0 },
+{ 0x87, 0x89, 0x3, 0xe0, 0xc, 0x18, 0x10, 0x84, 0x20, 0x82, 0x2f, 0xfa, 0x41, 0x1, 0x41, 0x1, 0x43, 0xf1, 0x43, 0x11, 0x47, 0x11, 0x4d, 0x11, 0x21, 0x12, 0x21, 0xf2, 0x10, 0x4, 0xc, 0x18, 0x3, 0xe0 },
+{ 0x87, 0x8a, 0x10, 0x4, 0x24, 0xa2, 0x24, 0xa2, 0x5e, 0xf9, 0x44, 0xa1, 0x4c, 0x21, 0x4e, 0xfd, 0x5f, 0x21, 0x55, 0x71, 0x54, 0x79, 0x44, 0xed, 0x45, 0xa5, 0x45, 0x21, 0x24, 0x22, 0x24, 0x22, 0x10, 0x4 },
+{ 0x87, 0x8b, 0x10, 0x4, 0x21, 0x2, 0x21, 0x2, 0x4f, 0xf9, 0x42, 0x1, 0x42, 0x1, 0x47, 0xf1, 0x4e, 0x11, 0x5a, 0x11, 0x53, 0xf1, 0x42, 0x11, 0x42, 0x11, 0x43, 0xf1, 0x22, 0x12, 0x22, 0x32, 0x10, 0x4 },
+{ 0x87, 0x8c, 0x10, 0x4, 0x22, 0x42, 0x22, 0x5a, 0x46, 0x49, 0x44, 0x41, 0x4c, 0x79, 0x49, 0xc1, 0x5c, 0x41, 0x54, 0x41, 0x44, 0x41, 0x44, 0x41, 0x44, 0x61, 0x44, 0x29, 0x24, 0x3a, 0x24, 0x12, 0x10, 0x4 },
+{ 0x87, 0x8d, 0x0, 0x4, 0x7, 0x44, 0x75, 0x64, 0x55, 0x28, 0x55, 0x9, 0x57, 0x5f, 0x75, 0x61, 0x55, 0x20, 0x55, 0xf, 0x57, 0x29, 0x55, 0x29, 0x75, 0x29, 0x5, 0x29, 0xd, 0x69, 0x9, 0x4f, 0x0, 0x0 },
+{ 0x87, 0x8e, 0x8, 0x0, 0x8, 0x7f, 0x8, 0x4, 0x8, 0x4, 0x7f, 0x4, 0x8, 0x4, 0x1c, 0x24, 0x14, 0x27, 0x14, 0x24, 0x36, 0x24, 0x22, 0x24, 0x22, 0x24, 0x63, 0x24, 0x41, 0x24, 0x41, 0x7f, 0x0, 0x0 },
+{ 0x87, 0x8f, 0x0, 0xc, 0xf, 0x18, 0x75, 0x70, 0x55, 0x17, 0x55, 0x15, 0x55, 0x7d, 0x5d, 0x15, 0x7b, 0x35, 0x50, 0x3d, 0x57, 0x55, 0x55, 0x55, 0x55, 0x95, 0x75, 0x15, 0x5, 0x15, 0x7, 0x17, 0x0, 0x10 },
+{ 0x87, 0x90, 0x0, 0x0, 0x0, 0x0, 0xc, 0x0, 0xc, 0x0, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x0, 0x0, 0x18, 0x0, 0x18, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x87, 0x91, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x87, 0x92, 0x1, 0xc0, 0x2, 0x40, 0x2, 0x0, 0x2, 0x0, 0x3, 0x0, 0x3, 0x0, 0x1, 0x0, 0x1, 0x80, 0x1, 0x80, 0x0, 0x80, 0x0, 0xc0, 0x0, 0xc0, 0x0, 0x40, 0x0, 0x40, 0x2, 0x40, 0x3, 0x80 },
+{ 0x87, 0x93, 0x1, 0xc0, 0x2, 0x40, 0x2, 0x0, 0x2, 0x0, 0x3, 0x0, 0x3, 0xe0, 0x5, 0x10, 0x9, 0x88, 0x9, 0x88, 0x4, 0x90, 0x3, 0xe0, 0x0, 0xc0, 0x0, 0x40, 0x0, 0x40, 0x2, 0x40, 0x3, 0x80 },
+{ 0x87, 0x94, 0x0, 0x0, 0xf, 0xfc, 0xc, 0x0, 0x6, 0x0, 0x3, 0x0, 0x1, 0x80, 0x0, 0xc0, 0x0, 0x60, 0x0, 0xc0, 0x1, 0x80, 0x3, 0x0, 0x6, 0x0, 0xc, 0x0, 0xf, 0xfc, 0x0, 0x0, 0x0, 0x0 },
+{ 0x87, 0x95, 0x0, 0xff, 0x0, 0x80, 0x0, 0x80, 0x1, 0x80, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x3, 0x0, 0x2, 0x0, 0x2, 0x0, 0x42, 0x0, 0x66, 0x0, 0x34, 0x0, 0x1c, 0x0, 0xc, 0x0, 0x4, 0x0 },
+{ 0x87, 0x96, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x0, 0x0, 0x0, 0x0 },
+{ 0x87, 0x97, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x0, 0x8, 0x0, 0x10, 0x0, 0x20, 0x0, 0x40, 0x0, 0x80, 0x1, 0x0, 0x2, 0x0, 0x4, 0x0, 0x8, 0x0, 0x10, 0x0, 0x3f, 0xfc, 0x0, 0x0, 0x0, 0x0 },
+{ 0x87, 0x98, 0x0, 0x0, 0x20, 0x0, 0x20, 0x0, 0x20, 0x0, 0x20, 0x0, 0x20, 0x0, 0x20, 0x0, 0x20, 0x0, 0x20, 0x0, 0x20, 0x0, 0x20, 0x0, 0x20, 0x0, 0x20, 0x0, 0x3f, 0xfe, 0x0, 0x0, 0x0, 0x0 },
+{ 0x87, 0x99, 0x0, 0x0, 0x0, 0x2, 0x0, 0x6, 0x0, 0xa, 0x0, 0x12, 0x0, 0x22, 0x0, 0x42, 0x0, 0x82, 0x1, 0x2, 0x2, 0x2, 0x4, 0x2, 0x8, 0x2, 0x10, 0x2, 0x3f, 0xfe, 0x0, 0x0, 0x0, 0x0 },
+{ 0x87, 0x9a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30, 0x6, 0x30, 0x6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0, 0x0, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x87, 0x9b, 0x0, 0x0, 0x1, 0xc0, 0x2, 0x20, 0x4, 0x10, 0x4, 0x10, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x0, 0x0, 0x0, 0x0 },
+{ 0x87, 0x9c, 0x0, 0x0, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x4, 0x10, 0x4, 0x10, 0x2, 0x20, 0x1, 0xc0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x88, 0x9f, 0x0, 0x0, 0x3f, 0xfe, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x1f, 0xfc, 0x12, 0x24, 0x12, 0x24, 0x12, 0x24, 0x12, 0x24, 0x1f, 0xfc, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x88, 0xa0, 0x0, 0x0, 0xf, 0xff, 0x70, 0x90, 0x50, 0x90, 0x50, 0x90, 0x57, 0xfe, 0x54, 0x92, 0x54, 0x92, 0x54, 0x92, 0x57, 0xfe, 0x50, 0x90, 0x70, 0x90, 0x0, 0x90, 0x0, 0x90, 0xf, 0xff, 0x0, 0x0 },
+{ 0x88, 0xa1, 0x10, 0x10, 0x10, 0x10, 0x10, 0xfe, 0x10, 0x10, 0x7e, 0x10, 0x12, 0x10, 0x13, 0xff, 0x32, 0x0, 0x22, 0x10, 0x26, 0x10, 0x74, 0xfe, 0xc, 0x10, 0xa, 0x10, 0x1a, 0x10, 0x30, 0x10, 0x61, 0xff },
+{ 0x88, 0xa2, 0x0, 0x0, 0x3e, 0xff, 0x22, 0x2, 0x26, 0x2, 0x2c, 0xf2, 0x28, 0x92, 0x24, 0x92, 0x22, 0x92, 0x22, 0x92, 0x22, 0x92, 0x22, 0xf2, 0x22, 0x2, 0x2e, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0xe },
+{ 0x88, 0xa3, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x3, 0x42, 0x6, 0x66, 0x1c, 0x2c, 0x74, 0x30, 0x4, 0x18, 0x7, 0xcc, 0x3c, 0x7 },
+{ 0x88, 0xa4, 0x0, 0x1c, 0x3f, 0xf0, 0x11, 0x4, 0x8, 0x88, 0x7f, 0xff, 0x40, 0x81, 0x4a, 0x4c, 0x1a, 0x16, 0x33, 0xf2, 0x4, 0x0, 0x7, 0xfc, 0x1e, 0x18, 0x73, 0x30, 0x1, 0xe0, 0xf, 0x38, 0x78, 0xf },
+{ 0x88, 0xa5, 0x10, 0x40, 0x10, 0x44, 0x10, 0xc4, 0x7c, 0x9e, 0x13, 0xf2, 0x10, 0x80, 0x10, 0x80, 0x11, 0xfe, 0x1b, 0x20, 0x70, 0x20, 0x13, 0xff, 0x10, 0x50, 0x10, 0xd8, 0x11, 0x8c, 0x13, 0x6, 0x36, 0x3 },
+{ 0x88, 0xa6, 0x10, 0x10, 0x10, 0x38, 0x10, 0x28, 0x10, 0x6c, 0x7e, 0xc6, 0x13, 0x83, 0x12, 0x0, 0x32, 0x7c, 0x26, 0x0, 0x24, 0x0, 0x74, 0xfe, 0xc, 0x82, 0xa, 0x82, 0x1a, 0x82, 0x30, 0x82, 0x60, 0xfe },
+{ 0x88, 0xa7, 0x0, 0x40, 0x30, 0x7c, 0x18, 0x84, 0xb, 0x48, 0x0, 0x30, 0x0, 0xcc, 0x3, 0x87, 0x78, 0x20, 0x9, 0xfc, 0x8, 0x20, 0x9, 0xfc, 0x8, 0x20, 0xb, 0xfe, 0x18, 0x20, 0x34, 0x0, 0x63, 0xff },
+{ 0x88, 0xa8, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x0, 0x0, 0x3f, 0x44, 0x2, 0x29, 0x24, 0x12, 0x1f, 0xfc, 0x70, 0x87, 0x0, 0x80, 0x3f, 0xfe, 0x1, 0x40, 0x3, 0x60, 0xe, 0x38, 0x38, 0xe },
+{ 0x88, 0xa9, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x0, 0x0, 0x7f, 0xff, 0x2, 0x20, 0x2, 0x20, 0x3f, 0xfe, 0x22, 0x22, 0x26, 0x22, 0x3c, 0x3e, 0x20, 0x2, 0x20, 0x2, 0x3f, 0xfe, 0x0, 0x0 },
+{ 0x88, 0xaa, 0x4, 0x40, 0x1c, 0xf8, 0x71, 0x10, 0x13, 0xfc, 0x11, 0x24, 0x7d, 0xfc, 0x11, 0x24, 0x19, 0xfc, 0x34, 0x20, 0x33, 0xfe, 0x32, 0x22, 0x53, 0xfe, 0x12, 0x22, 0x13, 0xfe, 0x10, 0x21, 0x10, 0x1f },
+{ 0x88, 0xab, 0x0, 0x0, 0x3f, 0xfe, 0x2, 0x20, 0x2, 0x20, 0x1f, 0xfc, 0x12, 0x24, 0x12, 0x24, 0x1f, 0xfc, 0x2, 0x20, 0x2, 0x20, 0x7f, 0xff, 0x0, 0x80, 0x12, 0xc6, 0x12, 0x4b, 0x33, 0x19, 0x61, 0xf0 },
+{ 0x88, 0xac, 0x10, 0x0, 0x13, 0xfe, 0x12, 0x2, 0x12, 0x2, 0x7b, 0xfe, 0x12, 0x0, 0x12, 0xfe, 0x12, 0x20, 0x12, 0x44, 0x1a, 0xfe, 0x72, 0x12, 0x12, 0x10, 0x16, 0xfe, 0x14, 0x10, 0x1c, 0x10, 0x31, 0xff },
+{ 0x88, 0xad, 0x0, 0x0, 0x33, 0xfe, 0x1a, 0x2, 0xa, 0x2, 0x3, 0xfe, 0x62, 0x0, 0x32, 0xfe, 0x12, 0x20, 0x2, 0x44, 0xa, 0xfe, 0xa, 0x12, 0x1a, 0x10, 0x16, 0xfe, 0x34, 0x10, 0x2c, 0x10, 0x61, 0xff },
+{ 0x88, 0xae, 0x10, 0x0, 0x10, 0x7e, 0x10, 0x42, 0x10, 0x42, 0x7e, 0x42, 0x12, 0x42, 0x12, 0x7e, 0x12, 0x42, 0x12, 0x42, 0x12, 0x42, 0x12, 0x42, 0x12, 0x7e, 0x12, 0x0, 0x32, 0x1, 0x23, 0x3, 0x61, 0xfe },
+{ 0x88, 0xaf, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x1, 0x0, 0x1f, 0xf8, 0x2, 0x8, 0x7f, 0xff, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x0, 0x20, 0x1f, 0xfc, 0x4, 0x20, 0x7f, 0xff, 0x0, 0x20 },
+{ 0x88, 0xb0, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x0, 0x0, 0x3f, 0xfe, 0x0, 0x0, 0xf, 0xfc, 0x8, 0x4, 0x8, 0x4, 0xf, 0xfc, 0x8, 0x0, 0x18, 0x0, 0x10, 0x0, 0x30, 0x0, 0x60, 0x0 },
+{ 0x88, 0xb1, 0x10, 0x20, 0x1e, 0x64, 0x32, 0x46, 0x24, 0xfa, 0x7e, 0x10, 0x2b, 0xfe, 0x2a, 0x28, 0x3e, 0x44, 0x2b, 0x93, 0x2a, 0x20, 0x3e, 0xc4, 0x0, 0x18, 0x55, 0x61, 0x55, 0x6, 0x54, 0x18, 0x40, 0xe0 },
+{ 0x88, 0xb2, 0x10, 0x20, 0x10, 0x20, 0x13, 0xfe, 0x7c, 0x0, 0x11, 0x4, 0x11, 0x8c, 0x38, 0x88, 0x37, 0xff, 0x54, 0x20, 0x50, 0x20, 0x10, 0x20, 0x13, 0xfe, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20 },
+{ 0x88, 0xb3, 0x0, 0x0, 0x1f, 0xfe, 0x10, 0x0, 0x10, 0x40, 0x10, 0x40, 0x10, 0x40, 0x10, 0x40, 0x17, 0xfe, 0x10, 0x40, 0x10, 0x40, 0x10, 0x40, 0x30, 0x40, 0x20, 0x40, 0x60, 0x40, 0xf, 0xff, 0x0, 0x0 },
+{ 0x88, 0xb4, 0x8, 0x10, 0x8, 0x38, 0x7f, 0x28, 0x8, 0x6c, 0x3e, 0xc6, 0x23, 0x83, 0x22, 0x64, 0x3e, 0x34, 0x22, 0x4, 0x22, 0xc4, 0x3e, 0x64, 0x8, 0x7, 0x7f, 0x3c, 0x8, 0xe4, 0x8, 0x4, 0x8, 0x4 },
+{ 0x88, 0xb5, 0x10, 0x0, 0x13, 0xf8, 0x11, 0x8, 0x11, 0x18, 0x7d, 0x10, 0x11, 0x10, 0x11, 0xbc, 0x11, 0x84, 0x11, 0xc4, 0x1d, 0x4c, 0x73, 0x68, 0x12, 0x38, 0x12, 0x10, 0x12, 0x38, 0x12, 0x6c, 0x36, 0xc7 },
+{ 0x88, 0xb6, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x2, 0x28, 0x2, 0x8, 0x0, 0xf, 0x7c, 0x19, 0x44, 0x11, 0x44, 0x3b, 0x44, 0x6a, 0x44, 0x6, 0x4c, 0x4, 0x40, 0xc, 0x41, 0x18, 0x63, 0x70, 0x3e },
+{ 0x88, 0xb7, 0x10, 0x0, 0x10, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x7e, 0x84, 0x12, 0xfc, 0x12, 0x84, 0x32, 0x84, 0x26, 0x84, 0x24, 0x84, 0x74, 0xfc, 0xc, 0x84, 0xa, 0x84, 0x1a, 0x84, 0x30, 0x84, 0x63, 0xff },
+{ 0x88, 0xb8, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10, 0x7f, 0x10, 0x49, 0xff, 0x49, 0x40, 0x49, 0x40, 0x49, 0x40, 0x7f, 0x40, 0x8, 0x40, 0x8, 0x40, 0xa, 0x40, 0xa, 0x40, 0xf, 0x60, 0x79, 0x3e, 0x0, 0x0 },
+{ 0x88, 0xb9, 0x8, 0x10, 0x1c, 0x10, 0x16, 0x34, 0x33, 0x26, 0x28, 0x62, 0x7e, 0x4f, 0x22, 0xf9, 0x3e, 0x0, 0x22, 0x0, 0x3e, 0x7e, 0x20, 0x42, 0x22, 0x42, 0x22, 0x42, 0x2f, 0x42, 0x39, 0x42, 0x60, 0x7e },
+{ 0x88, 0xba, 0x8, 0x40, 0x18, 0x40, 0x30, 0xff, 0x62, 0x81, 0x37, 0x81, 0xc, 0x79, 0x18, 0x49, 0x32, 0x49, 0x7f, 0x79, 0x9, 0x49, 0x8, 0x49, 0x2a, 0x79, 0x2b, 0x1, 0x69, 0x3, 0x48, 0x2, 0x8, 0xe },
+{ 0x88, 0xbb, 0x8, 0x20, 0x18, 0x20, 0x11, 0xfe, 0x64, 0x20, 0x2f, 0xff, 0x18, 0x48, 0x10, 0xc8, 0x25, 0x8f, 0x7e, 0x40, 0x12, 0x7c, 0x10, 0xc4, 0x55, 0x8c, 0x54, 0x58, 0x54, 0x30, 0x10, 0xcc, 0x13, 0x87 },
+{ 0x88, 0xbc, 0x10, 0x10, 0x1e, 0x10, 0x32, 0x10, 0x24, 0x10, 0x7f, 0x1f, 0x29, 0x10, 0x29, 0x10, 0x3f, 0x10, 0x29, 0x10, 0x29, 0x7e, 0x3f, 0x42, 0x0, 0x42, 0x55, 0x42, 0x55, 0x42, 0x54, 0x42, 0x40, 0x7e },
+{ 0x88, 0xbd, 0x0, 0x48, 0x0, 0x4c, 0x0, 0x44, 0x7f, 0xff, 0x0, 0x40, 0x0, 0x40, 0x3e, 0x42, 0x22, 0x66, 0x22, 0x24, 0x22, 0x2c, 0x3e, 0x38, 0x0, 0x10, 0x7, 0x39, 0x1c, 0x6d, 0x71, 0xc7, 0x7, 0x2 },
+{ 0x88, 0xbe, 0x0, 0x0, 0x7f, 0xff, 0x2, 0x20, 0x3f, 0xfe, 0x22, 0x22, 0x22, 0x22, 0x3f, 0xfe, 0x8, 0x88, 0xc, 0x98, 0x4, 0x90, 0x7f, 0xff, 0x2, 0xa0, 0x6, 0xb0, 0x1c, 0x9c, 0x70, 0x87, 0x0, 0x80 },
+{ 0x88, 0xbf, 0x10, 0x10, 0x10, 0x38, 0x10, 0x28, 0x7c, 0x6c, 0x4, 0xc6, 0xd, 0x83, 0x8, 0x0, 0x1a, 0x7c, 0x16, 0x0, 0x3c, 0x0, 0x76, 0xfe, 0x12, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0xfe },
+{ 0x88, 0xc0, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x2, 0x21, 0x2, 0x3, 0x0, 0x2, 0x0, 0x7f, 0xff, 0x4, 0x8, 0xc, 0x18, 0x8, 0x10, 0x1f, 0x30, 0x0, 0xe0, 0x3, 0xb8, 0xe, 0xc, 0x38, 0x6 },
+{ 0x88, 0xc1, 0x0, 0x40, 0x0, 0x40, 0x3f, 0xff, 0x20, 0x80, 0x2f, 0xfe, 0x21, 0x10, 0x22, 0x48, 0x27, 0xfc, 0x3c, 0x47, 0x24, 0x44, 0x27, 0xfc, 0x24, 0x44, 0x64, 0x44, 0x47, 0xfd, 0x40, 0x43, 0x0, 0x3e },
+{ 0x88, 0xc2, 0x10, 0x20, 0x10, 0x20, 0x13, 0xfe, 0x12, 0x2, 0x7e, 0x42, 0x10, 0x40, 0x10, 0x40, 0x17, 0xff, 0x1c, 0x84, 0x71, 0x8c, 0x11, 0x8, 0x13, 0xd8, 0x10, 0x30, 0x10, 0x6c, 0x10, 0xc6, 0x33, 0x83 },
+{ 0x88, 0xc3, 0x0, 0x20, 0x0, 0x20, 0x7b, 0xfe, 0x49, 0x4, 0x49, 0x8c, 0x48, 0x88, 0x4f, 0xff, 0x78, 0x0, 0x48, 0x0, 0x49, 0xfc, 0x49, 0x4, 0x49, 0x4, 0x79, 0xfc, 0x1, 0x4, 0x1, 0x4, 0x1, 0xfc },
+{ 0x88, 0xc4, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x2, 0x1, 0x0, 0x7f, 0xff, 0x4, 0x10, 0xf, 0x30, 0x1, 0xe0, 0x7, 0x38, 0x3c, 0xc, 0x0, 0x80, 0x7f, 0xff, 0x2, 0xa0, 0xe, 0xb8, 0x78, 0x8f, 0x0, 0x80 },
+{ 0x88, 0xc5, 0x0, 0x0, 0x3f, 0x7e, 0x21, 0x42, 0x3f, 0x7e, 0x21, 0x42, 0x3f, 0x7e, 0x20, 0x82, 0x27, 0xf2, 0x22, 0x22, 0x2f, 0xfa, 0x20, 0x2, 0x23, 0xe2, 0x22, 0x22, 0x23, 0xe2, 0x22, 0x22, 0x23, 0xee },
+{ 0x88, 0xc6, 0x22, 0x10, 0x22, 0x10, 0x7f, 0xfe, 0x22, 0x82, 0x22, 0xa2, 0x3e, 0x20, 0x8, 0x20, 0x7f, 0xff, 0x49, 0x24, 0x49, 0x64, 0x7f, 0x4c, 0x8, 0xe8, 0x7f, 0x38, 0x8, 0x2c, 0x8, 0x66, 0x8, 0xc2 },
+{ 0x88, 0xc7, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x2, 0xa0, 0x6, 0xb0, 0xc, 0x98, 0x18, 0x8c, 0x70, 0x87, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x1f, 0xfc },
+{ 0x88, 0xc8, 0x0, 0x0, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x13, 0x4, 0x11, 0x84, 0x10, 0xc4, 0x10, 0x44, 0x10, 0xc, 0x10, 0x8, 0x10, 0x8, 0x10, 0x1c, 0x17, 0x36, 0x1c, 0x62, 0x70, 0xc3, 0x3, 0x81 },
+{ 0x88, 0xc9, 0x4, 0x0, 0x5, 0xfe, 0xc, 0x22, 0x8, 0x22, 0x18, 0x22, 0x13, 0xff, 0x30, 0x22, 0x50, 0x22, 0x10, 0x22, 0x11, 0xfe, 0x10, 0x20, 0x10, 0x20, 0x10, 0x60, 0x10, 0x40, 0x10, 0xc0, 0x11, 0x80 },
+{ 0x88, 0xca, 0x4, 0x20, 0x4, 0x20, 0xc, 0x20, 0xb, 0xfe, 0x18, 0x0, 0x10, 0x0, 0x31, 0x4, 0x51, 0x4, 0x11, 0x8c, 0x10, 0x88, 0x10, 0x88, 0x10, 0x98, 0x10, 0x10, 0x10, 0x10, 0x17, 0xff, 0x10, 0x0 },
+{ 0x88, 0xcb, 0x8, 0x20, 0x8, 0x20, 0x18, 0x20, 0x17, 0xff, 0x10, 0x40, 0x30, 0x40, 0x30, 0xe2, 0x51, 0xa6, 0x13, 0x2c, 0x17, 0x38, 0x1d, 0x10, 0x11, 0x18, 0x11, 0x8, 0x11, 0x6c, 0x11, 0xc6, 0x17, 0x3 },
+{ 0x88, 0xcc, 0x4, 0x20, 0x5, 0xfc, 0xc, 0x44, 0x8, 0x44, 0x1b, 0xff, 0x10, 0x0, 0x31, 0xfc, 0x51, 0x4, 0x11, 0xfc, 0x10, 0x10, 0x13, 0xfe, 0x10, 0x90, 0x10, 0x90, 0x17, 0xff, 0x10, 0x10, 0x10, 0x10 },
+{ 0x88, 0xcd, 0x0, 0x0, 0x3f, 0xfe, 0x20, 0x2, 0x22, 0x22, 0x22, 0x22, 0x2f, 0xfa, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x2f, 0xfa, 0x22, 0x22, 0x26, 0x22, 0x2c, 0x22, 0x20, 0x2, 0x3f, 0xfe, 0x0, 0x0 },
+{ 0x88, 0xce, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x3f, 0xfc, 0x0, 0x84, 0x1f, 0xfc, 0x10, 0x80, 0x10, 0x80, 0x1f, 0xfe, 0x1, 0x42, 0x3, 0x62, 0x2, 0x2e, 0x6, 0x30, 0x1c, 0x1c, 0x70, 0x7 },
+{ 0x88, 0xcf, 0x0, 0x1c, 0x1f, 0xf0, 0x0, 0x80, 0x7f, 0xff, 0x2, 0xa0, 0x6, 0xb0, 0x1c, 0x9c, 0x70, 0x87, 0x0, 0x80, 0x1, 0x0, 0x7f, 0xff, 0x2, 0x10, 0x4, 0x30, 0xf, 0xe0, 0x1, 0xb8, 0x3e, 0xe },
+{ 0x88, 0xd0, 0x0, 0x24, 0x0, 0x26, 0x0, 0x22, 0x3f, 0xff, 0x20, 0x20, 0x2f, 0xa0, 0x20, 0x22, 0x22, 0x32, 0x2f, 0xd6, 0x24, 0x94, 0x24, 0x9c, 0x2f, 0x8, 0x21, 0x9d, 0x62, 0xb5, 0x4c, 0x67, 0x40, 0xc2 },
+{ 0x88, 0xd1, 0x0, 0x2, 0x3f, 0x82, 0x20, 0x82, 0x20, 0x82, 0x3f, 0x82, 0x20, 0x3f, 0x20, 0x2, 0x2f, 0x82, 0x20, 0x12, 0x2f, 0x9a, 0x22, 0xa, 0x2a, 0x82, 0x6a, 0x82, 0x4a, 0x82, 0x52, 0x82, 0x6, 0xe },
+{ 0x88, 0xd2, 0x10, 0x80, 0x10, 0x88, 0x11, 0x98, 0x19, 0x10, 0x55, 0xff, 0x53, 0x10, 0x55, 0x10, 0x51, 0xfe, 0x11, 0x10, 0x11, 0x10, 0x11, 0x10, 0x11, 0xfe, 0x11, 0x10, 0x11, 0x10, 0x11, 0x10, 0x11, 0xff },
+{ 0x88, 0xd3, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x4, 0x10, 0x2, 0x20, 0x7f, 0xff, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x0, 0x80, 0x12, 0x46, 0x32, 0xb, 0x61, 0xf9 },
+{ 0x88, 0xd4, 0x0, 0x4, 0x3f, 0x84, 0x20, 0x84, 0x3f, 0x84, 0x20, 0x7f, 0x2f, 0x84, 0x20, 0x24, 0x2f, 0x94, 0x22, 0x14, 0x6a, 0x84, 0x4a, 0x84, 0x16, 0x1c, 0x0, 0x80, 0x12, 0x46, 0x32, 0xb, 0x61, 0xf9 },
+{ 0x88, 0xd5, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x4, 0x0, 0xf, 0xfe, 0x19, 0x22, 0x73, 0x22, 0x6, 0x62, 0x1c, 0xc6, 0x3, 0x84, 0x0, 0x1c },
+{ 0x88, 0xd6, 0x10, 0x20, 0x10, 0x20, 0x13, 0xfe, 0x7c, 0x50, 0x10, 0xd8, 0x11, 0x8c, 0x18, 0x0, 0x37, 0xff, 0x34, 0x4, 0x51, 0xe4, 0x51, 0x24, 0x11, 0x24, 0x11, 0xe4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x1c },
+{ 0x88, 0xd7, 0x11, 0x0, 0x19, 0x0, 0x9, 0x0, 0x3f, 0xf8, 0x2, 0x8, 0x2, 0x10, 0x7, 0xfe, 0x4, 0x2, 0xc, 0x4, 0x1f, 0xff, 0x30, 0x1, 0x60, 0x11, 0x14, 0x89, 0x12, 0x4b, 0x22, 0x42, 0x0, 0xe },
+{ 0x88, 0xd8, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x0, 0x0, 0x7f, 0xff, 0x8, 0x84, 0x8, 0xcc, 0x8, 0x68, 0xb, 0x30, 0xe, 0x1c, 0x38, 0x7 },
+{ 0x88, 0xd9, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x2, 0x20, 0x3f, 0xfe, 0x2, 0x20, 0x2, 0x20, 0x7f, 0xff, 0x4, 0x10, 0x1c, 0x1c, 0x70, 0x7 },
+{ 0x88, 0xda, 0x2, 0x20, 0xe, 0x3e, 0x78, 0x62, 0x8, 0xc6, 0x9, 0xac, 0x7e, 0x18, 0x8, 0x30, 0x8, 0xe8, 0x1c, 0xf, 0x1a, 0x19, 0x2a, 0x33, 0x28, 0xea, 0x48, 0x6, 0x8, 0xc, 0x8, 0x38, 0x9, 0xe0 },
+{ 0x88, 0xdb, 0x8, 0x20, 0x18, 0x24, 0x30, 0x6c, 0x62, 0x48, 0x36, 0xff, 0xd, 0x48, 0x18, 0x48, 0x32, 0x7e, 0x7f, 0x48, 0x9, 0x48, 0x8, 0x48, 0x2a, 0x7e, 0x2b, 0x48, 0x69, 0x48, 0x48, 0x48, 0x8, 0x7f },
+{ 0x88, 0xdc, 0x8, 0x20, 0x18, 0xfc, 0x10, 0x44, 0x64, 0x44, 0x2d, 0xff, 0x18, 0x0, 0x10, 0xfe, 0x24, 0x82, 0x7e, 0xfe, 0x12, 0x8, 0x10, 0xfe, 0x54, 0x48, 0x54, 0x48, 0x55, 0xff, 0x10, 0x8, 0x10, 0x8 },
+{ 0x88, 0xdd, 0x3f, 0xfe, 0x20, 0x82, 0x20, 0x82, 0x3f, 0xfe, 0x20, 0x82, 0x20, 0x82, 0x3f, 0xfe, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x4, 0x1f, 0xfc, 0x10, 0x4, 0x1f, 0xfc, 0x10, 0x4, 0x10, 0x4, 0x10, 0x1c },
+{ 0x88, 0xde, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x0, 0x3c, 0x1f, 0xe0, 0x0, 0x80, 0x7f, 0xff, 0x2, 0xa0, 0x1c, 0x9c, 0x70, 0x87, 0x2, 0x0, 0x7f, 0xff, 0x4, 0x10, 0x1f, 0xa0, 0x0, 0xf8, 0x3f, 0xe },
+{ 0x88, 0xdf, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x1, 0x40, 0x3, 0x42, 0x6, 0x66, 0xc, 0x2c, 0x1c, 0x38, 0x74, 0x30, 0x4, 0x10, 0x4, 0x18, 0x4, 0x8, 0x5, 0xcc, 0xf, 0x6, 0x38, 0x3 },
+{ 0x88, 0xe0, 0x0, 0x0, 0x3e, 0xfe, 0x0, 0x92, 0x7f, 0xfe, 0x0, 0x92, 0x3e, 0x92, 0x0, 0xfe, 0x0, 0x0, 0x3e, 0xfe, 0x0, 0x82, 0x0, 0xfe, 0x3e, 0x82, 0x22, 0xfe, 0x22, 0x82, 0x22, 0x82, 0x3e, 0x86 },
+{ 0x88, 0xe1, 0x0, 0x20, 0x31, 0xfc, 0x18, 0x44, 0x8, 0x44, 0x3, 0xff, 0x0, 0x0, 0x0, 0xfc, 0x78, 0x84, 0x8, 0xfc, 0x8, 0x10, 0x9, 0xfe, 0x8, 0x90, 0xb, 0xff, 0x18, 0x10, 0x34, 0x10, 0x63, 0xff },
+{ 0x88, 0xe2, 0x0, 0x20, 0x31, 0xfc, 0x19, 0x24, 0x9, 0xfc, 0x0, 0x20, 0x7, 0xff, 0x0, 0x0, 0x79, 0xfc, 0x9, 0x4, 0x9, 0xfc, 0x9, 0x4, 0x9, 0xfc, 0x9, 0x4, 0x19, 0xfc, 0x36, 0x2, 0x63, 0xff },
+{ 0x88, 0xe3, 0x0, 0x0, 0x3f, 0xfe, 0x22, 0x0, 0x22, 0x0, 0x27, 0xfc, 0x2c, 0x40, 0x20, 0x40, 0x2f, 0xfe, 0x20, 0xa0, 0x21, 0xb0, 0x21, 0x10, 0x23, 0x18, 0x26, 0xc, 0x20, 0x0, 0x3f, 0xfe, 0x0, 0x0 },
+{ 0x88, 0xe4, 0x4, 0x20, 0x4, 0x20, 0x4, 0x20, 0x4, 0x20, 0x3f, 0xfe, 0x4, 0x20, 0x4, 0x20, 0x4, 0x20, 0x4, 0x20, 0x7f, 0xff, 0x4, 0x20, 0x4, 0x20, 0xc, 0x20, 0x8, 0x20, 0x18, 0x20, 0x30, 0x20 },
+{ 0x88, 0xe5, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x1, 0xa0, 0x1b, 0x60, 0xc, 0x48, 0x6, 0xd8, 0x1, 0x90, 0x7, 0x30, 0xc, 0x60, 0x38, 0xd0, 0x3, 0x98, 0xe, 0xc, 0x38, 0x6 },
+{ 0x88, 0xe6, 0x10, 0x14, 0x10, 0x12, 0x10, 0x12, 0x13, 0xff, 0x7c, 0x10, 0x10, 0x10, 0x13, 0xd2, 0x12, 0x52, 0x12, 0x5a, 0x12, 0x4e, 0x13, 0xcc, 0x1c, 0x8, 0x71, 0xdd, 0x7, 0x35, 0x0, 0x67, 0x1, 0x82 },
+{ 0x88, 0xe7, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x2, 0x0, 0x4, 0x4, 0xf, 0xfe, 0x38, 0x2, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x38 },
+{ 0x88, 0xe8, 0x4, 0x0, 0x4, 0x3e, 0x7f, 0xa2, 0x8, 0x26, 0x8, 0x24, 0x1f, 0x2c, 0x11, 0x28, 0x31, 0x24, 0x5f, 0x22, 0x11, 0x22, 0x11, 0x22, 0x1f, 0x22, 0x11, 0x22, 0x11, 0x2e, 0x11, 0x20, 0x17, 0x20 },
+{ 0x88, 0xe9, 0x0, 0x92, 0x7d, 0x14, 0x13, 0x5d, 0x10, 0x92, 0x11, 0x15, 0x11, 0x5f, 0x3b, 0xd4, 0x28, 0x12, 0x6b, 0xff, 0x2a, 0x10, 0x2b, 0x12, 0x2a, 0x94, 0x3a, 0x88, 0x6, 0x1d, 0x4, 0x27, 0xc, 0xc2 },
+{ 0x88, 0xea, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+{ 0x88, 0xeb, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x0, 0x7f, 0xff, 0x40, 0x1, 0x48, 0x31, 0x8, 0xe0, 0xf, 0x80, 0x8, 0x2, 0x8, 0x6, 0xc, 0x4, 0x7, 0xfc },
+{ 0x88, 0xec, 0x1, 0x4, 0x31, 0x8c, 0x18, 0x88, 0xb, 0xfe, 0x0, 0x88, 0x61, 0x8c, 0x31, 0x4, 0x13, 0x6, 0x6, 0x3, 0x0, 0x0, 0xb, 0xfe, 0x1a, 0x52, 0x12, 0x52, 0x32, 0x52, 0x22, 0x52, 0x67, 0xff },
+{ 0x88, 0xed, 0x0, 0x40, 0x30, 0x7c, 0x18, 0xc8, 0x9, 0x90, 0x3, 0xfe, 0x1, 0x22, 0x1, 0x22, 0x79, 0x22, 0x9, 0xfe, 0x8, 0x50, 0x8, 0xd0, 0x8, 0x91, 0x9, 0x91, 0x1b, 0xf, 0x34, 0x0, 0x63, 0xff },
+{ 0x88, 0xee, 0x6, 0x6, 0x1c, 0x3c, 0x71, 0xe0, 0x10, 0x0, 0x11, 0x22, 0x7d, 0xb6, 0x10, 0x94, 0x10, 0x0, 0x19, 0x3e, 0x35, 0x22, 0x31, 0x22, 0x51, 0x3e, 0x51, 0x22, 0x11, 0x22, 0x11, 0x22, 0x11, 0x3e },
+{ 0x88, 0xef, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x5, 0x10, 0x31, 0x0, 0x19, 0xfe, 0xb, 0x22, 0x2, 0x26, 0x6, 0x74, 0x8, 0x50, 0x18, 0xd8, 0x10, 0x88, 0x31, 0x8c, 0x63, 0x6, 0x6, 0x3 },
+{ 0x88, 0xf0, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x4, 0x10, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x3, 0x80 },
+{ 0x88, 0xf1, 0x21, 0xef, 0x3c, 0x21, 0x24, 0x21, 0x49, 0xef, 0x7d, 0x8, 0x55, 0x8, 0x55, 0xef, 0x7c, 0x21, 0x55, 0x29, 0x54, 0xa5, 0x7c, 0x21, 0x1, 0x63, 0x55, 0xa5, 0x55, 0x29, 0x54, 0x63, 0x40, 0xc6 },
+{ 0x88, 0xf2, 0x2, 0x0, 0x2, 0x0, 0x6, 0x10, 0x4, 0x18, 0xc, 0xc, 0x8, 0xfe, 0x3f, 0xa2, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x6, 0x20, 0x4, 0x21, 0xc, 0x21, 0x18, 0x33, 0x70, 0x1e },
+{ 0x88, 0xf3, 0x3, 0x0, 0xe, 0x0, 0x38, 0xfe, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x3e, 0x82, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x3e, 0x9e, 0x0, 0x80, 0x0, 0x80 },
+{ 0x88, 0xf4, 0x0, 0x0, 0x3, 0xfe, 0x7a, 0x2, 0x4a, 0x22, 0x4a, 0x22, 0x4a, 0xfa, 0x4a, 0x22, 0x4a, 0x22, 0x4a, 0x72, 0x4a, 0x52, 0x7a, 0x52, 0x2, 0x8a, 0x2, 0x2, 0x2, 0x2, 0x3, 0xfe, 0x0, 0x0 },
+{ 0x88, 0xf5, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x4, 0x1f, 0xfc, 0x10, 0x4, 0x1f, 0xfc, 0x10, 0x4, 0x1f, 0xfc, 0x0, 0x0, 0xc, 0x18, 0x38, 0xe },
+{ 0x88, 0xf6, 0x0, 0x0, 0x3f, 0xfe, 0x20, 0x2, 0x20, 0x82, 0x20, 0x82, 0x2f, 0xfa, 0x20, 0x82, 0x21, 0xc2, 0x21, 0x42, 0x23, 0x62, 0x26, 0x32, 0x2c, 0x1a, 0x20, 0x2, 0x20, 0x2, 0x3f, 0xfe, 0x0, 0x0 },
+{ 0x88, 0xf7, 0x20, 0x0, 0x23, 0xfe, 0x22, 0x2, 0x22, 0x22, 0x7a, 0x22, 0x2a, 0xfa, 0x2a, 0x22, 0x6a, 0x22, 0x4a, 0x72, 0x5a, 0x52, 0x52, 0x52, 0x52, 0x8a, 0x3a, 0x2, 0x2a, 0x2, 0x63, 0xfe, 0x40, 0x0 },
+{ 0x88, 0xf8, 0x0, 0x4, 0x7f, 0x4, 0x1, 0x4, 0x1, 0x4, 0x1, 0x4, 0x3f, 0x4, 0x20, 0x4, 0x20, 0x4, 0x20, 0x4, 0x3f, 0x4, 0x1, 0x4, 0x1, 0x4, 0x3, 0x4, 0x2, 0x4, 0x6, 0x4, 0x3c, 0x4 },
+{ 0x88, 0xf9, 0x8, 0x40, 0x1c, 0x40, 0x16, 0x40, 0x33, 0x7f, 0x28, 0x41, 0x7e, 0xd3, 0x22, 0x92, 0x3e, 0x10, 0x22, 0x10, 0x3e, 0x38, 0x20, 0x28, 0x24, 0x28, 0x24, 0x6c, 0x2e, 0x44, 0x3a, 0xc6, 0x61, 0x83 },
+{ 0x88, 0xfa, 0x30, 0xe, 0x1b, 0xf8, 0x8, 0x2, 0x2, 0x46, 0x63, 0x64, 0x31, 0x20, 0x10, 0x1c, 0x1, 0xf0, 0x0, 0x20, 0x8, 0x20, 0xf, 0xff, 0x18, 0x20, 0x10, 0x20, 0x30, 0x20, 0x23, 0xfe, 0x60, 0x0 },
+{ 0x88, 0xfb, 0x10, 0x84, 0x11, 0x4, 0x16, 0x24, 0x13, 0x44, 0x10, 0x84, 0x11, 0x24, 0x17, 0xf4, 0x10, 0x14, 0x13, 0xe4, 0x12, 0x24, 0x13, 0xe4, 0x12, 0x24, 0x13, 0xe4, 0x32, 0x25, 0x22, 0x25, 0x62, 0x63 },
+{ 0x88, 0xfc, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x0, 0x0, 0x3c, 0x30, 0x24, 0x48, 0x24, 0xb4, 0x2b, 0x3, 0x28, 0xfc, 0x24, 0x8, 0x25, 0xfe, 0x24, 0x0, 0x2b, 0xff, 0x20, 0x84, 0x21, 0x1e, 0x23, 0xf2 },
+{ 0x89, 0x40, 0x0, 0x20, 0x3c, 0x20, 0x25, 0xfe, 0x25, 0x2, 0x25, 0x2, 0x28, 0xfc, 0x28, 0x0, 0x24, 0x0, 0x27, 0xff, 0x24, 0x48, 0x24, 0x48, 0x24, 0x48, 0x2c, 0xc8, 0x20, 0x89, 0x21, 0x8b, 0x23, 0x6 },
+{ 0x89, 0x41, 0x0, 0x20, 0x3c, 0x70, 0x24, 0x58, 0x24, 0xcc, 0x25, 0xb6, 0x2b, 0x3, 0x28, 0xfc, 0x24, 0x8, 0x24, 0x10, 0x25, 0xfc, 0x24, 0x0, 0x27, 0xff, 0x2c, 0x80, 0x20, 0x84, 0x21, 0x1e, 0x23, 0xf2 },
+{ 0x89, 0x42, 0x0, 0x6, 0x3c, 0x3c, 0x27, 0xe2, 0x25, 0x26, 0x24, 0x94, 0x29, 0xfe, 0x28, 0x2, 0x25, 0xfe, 0x24, 0x2, 0x25, 0xfe, 0x24, 0x20, 0x24, 0x10, 0x2d, 0x52, 0x21, 0x43, 0x23, 0x45, 0x22, 0x3c },
+{ 0x89, 0x43, 0x8, 0x0, 0x8, 0x7e, 0x7f, 0x42, 0x22, 0x42, 0x36, 0x7e, 0x14, 0x0, 0x7f, 0x7e, 0x0, 0x42, 0x3e, 0x7e, 0x22, 0x42, 0x22, 0x7e, 0x3e, 0x42, 0x22, 0x7e, 0x22, 0x24, 0x3e, 0x66, 0x0, 0xc3 },
+{ 0x89, 0x44, 0x0, 0x4, 0x3e, 0x4, 0x22, 0x4, 0x22, 0x4, 0x23, 0xff, 0x22, 0x4, 0x22, 0x4, 0x22, 0xc4, 0x22, 0x64, 0x22, 0x24, 0x22, 0x4, 0x3e, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x1c },
+{ 0x89, 0x45, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x7f, 0xff, 0x2, 0x0, 0x2, 0x0, 0x6, 0x0, 0x4, 0x0, 0xf, 0xfc, 0x1c, 0x4, 0x34, 0x4, 0x64, 0x4, 0x4, 0x4, 0x4, 0x4, 0x7, 0xfc, 0x0, 0x0 },
+{ 0x89, 0x46, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x2, 0x20, 0x2, 0x2f, 0xfa, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x3, 0x80 },
+{ 0x89, 0x47, 0x0, 0x40, 0x0, 0x80, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x0, 0xf, 0xff, 0x8, 0x0, 0xf, 0xfe, 0x0, 0x22, 0x14, 0xb2, 0x36, 0xd6, 0x22, 0x44, 0x0, 0x1c },
+{ 0x89, 0x48, 0x0, 0x0, 0x7e, 0xfe, 0x2, 0x2, 0x2, 0x2, 0x32, 0x62, 0x1a, 0x32, 0xa, 0x12, 0x2, 0x2, 0xe, 0xe, 0xa, 0x1a, 0x1a, 0x32, 0x32, 0x62, 0x62, 0xc2, 0x2, 0x2, 0x2, 0x2, 0xe, 0xe },
+{ 0x89, 0x49, 0x0, 0x0, 0x33, 0xfe, 0x18, 0x20, 0x8, 0x20, 0x0, 0x20, 0x0, 0x20, 0x7, 0xff, 0x78, 0x20, 0x8, 0x20, 0x8, 0x20, 0x8, 0x20, 0x8, 0x20, 0x8, 0x20, 0x18, 0xe0, 0x34, 0x0, 0x63, 0xff },
+{ 0x89, 0x4a, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x82, 0x2c, 0xb2, 0x26, 0x9a, 0x22, 0x8a, 0x20, 0x82, 0x2c, 0xb2, 0x26, 0x9a, 0x22, 0x8a, 0x20, 0x82, 0x20, 0x82, 0x20, 0xe },
+{ 0x89, 0x4b, 0x3, 0x0, 0xe, 0x0, 0x38, 0x7e, 0x22, 0x42, 0x22, 0x42, 0x22, 0x42, 0x22, 0x42, 0x22, 0x42, 0x22, 0x42, 0x22, 0x42, 0x22, 0x42, 0x3e, 0x42, 0x64, 0x4e, 0xc, 0x40, 0x18, 0x40, 0x30, 0x40 },
+{ 0x89, 0x4c, 0x22, 0x8, 0x36, 0x10, 0x14, 0x7e, 0x7f, 0x42, 0x9, 0x7e, 0x3f, 0x42, 0x28, 0x7e, 0x28, 0x40, 0x3f, 0x7f, 0x9, 0x40, 0x9, 0x7f, 0x1b, 0x1, 0x28, 0xab, 0x48, 0xa9, 0x9, 0x3, 0x8, 0x6 },
+{ 0x89, 0x4d, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x22, 0x22, 0x2c, 0x3a, 0x0, 0x0, 0x8, 0x7c, 0x3e, 0x44, 0x8, 0x7c, 0x8, 0x44, 0x7f, 0x7c, 0x8, 0x44, 0x1c, 0x7c, 0x16, 0x29, 0x30, 0x69, 0x61, 0xc7 },
+{ 0x89, 0x4e, 0x0, 0x0, 0x3f, 0xf0, 0x2, 0x10, 0x2, 0x10, 0x2, 0x10, 0x2, 0x10, 0x2, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x89, 0x4f, 0x0, 0x24, 0x0, 0x6c, 0x7f, 0x48, 0x8, 0xff, 0x8, 0xc8, 0x19, 0x48, 0x10, 0x48, 0x3e, 0x7e, 0x32, 0x48, 0x52, 0x48, 0x12, 0x48, 0x12, 0x7e, 0x12, 0x48, 0x12, 0x48, 0x1e, 0x48, 0x0, 0x7f },
+{ 0x89, 0x50, 0x1, 0x80, 0x7, 0x0, 0x3c, 0x3e, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x3e, 0x3e, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x3f, 0xfe, 0x0, 0x0 },
+{ 0x89, 0x51, 0x0, 0x0, 0x33, 0xfc, 0x1a, 0x4, 0xa, 0x4, 0x2, 0x7c, 0x62, 0x44, 0x32, 0x44, 0x17, 0xfe, 0x4, 0x2, 0x4, 0xf2, 0x14, 0x92, 0x14, 0x92, 0x34, 0x92, 0x24, 0xf2, 0x64, 0x2, 0x44, 0xe },
+{ 0x89, 0x52, 0x0, 0x20, 0x0, 0x3e, 0x78, 0x20, 0x4b, 0xff, 0x4a, 0x21, 0x4a, 0x3a, 0x4a, 0xe0, 0x4a, 0x22, 0x4a, 0x1e, 0x4a, 0x0, 0x7a, 0x28, 0x6, 0xa9, 0x4, 0xaa, 0xc, 0xaa, 0x18, 0x28, 0x1, 0xff },
+{ 0x89, 0x53, 0x0, 0x0, 0x0, 0xfe, 0x7c, 0x82, 0x44, 0x82, 0x44, 0xfe, 0x44, 0x82, 0x44, 0x82, 0x44, 0x82, 0x44, 0xfe, 0x44, 0x82, 0x44, 0x82, 0x7c, 0x82, 0x0, 0xfe, 0x0, 0x44, 0x0, 0xc6, 0x1, 0x83 },
+{ 0x89, 0x54, 0x11, 0x44, 0x7c, 0x9f, 0x11, 0x44, 0x38, 0x8e, 0x55, 0x55, 0x1f, 0xfc, 0x12, 0x24, 0x1f, 0xfc, 0x0, 0x0, 0x3f, 0x4, 0x21, 0x7f, 0x3f, 0x4, 0x21, 0x24, 0x3f, 0x14, 0x22, 0x4, 0x7d, 0x1c },
+{ 0x89, 0x55, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x0, 0x2, 0x3f, 0x82, 0x20, 0x82, 0x3f, 0xbf, 0x20, 0x2, 0x2f, 0x92, 0x20, 0xa, 0x2f, 0x8a, 0x22, 0x2, 0x6a, 0x82, 0x52, 0x42, 0x6, 0xe },
+{ 0x89, 0x56, 0x10, 0x7c, 0x1e, 0x44, 0x32, 0x7c, 0x24, 0x44, 0x7e, 0x7c, 0x2a, 0x0, 0x2a, 0xfe, 0x3e, 0xaa, 0x2a, 0xfe, 0x2a, 0x0, 0x3e, 0xfc, 0x0, 0x44, 0x55, 0x6c, 0x55, 0x38, 0x54, 0x6c, 0x41, 0xc7 },
+{ 0x89, 0x57, 0x8, 0x22, 0x8, 0x22, 0x8, 0xfe, 0x8, 0x24, 0x7e, 0x2c, 0x12, 0x28, 0x13, 0xff, 0x12, 0x30, 0x36, 0x60, 0x25, 0xc6, 0x27, 0x5c, 0x7c, 0x70, 0xa, 0x40, 0x1a, 0x41, 0x30, 0x63, 0x60, 0x3e },
+{ 0x89, 0x58, 0x0, 0x0, 0x3f, 0xff, 0x20, 0x0, 0x2f, 0x7e, 0x29, 0x28, 0x29, 0x28, 0x2f, 0x28, 0x29, 0x28, 0x29, 0x7f, 0x2f, 0x8, 0x28, 0x18, 0x2a, 0x18, 0x6a, 0x38, 0x4f, 0x29, 0x59, 0x69, 0x0, 0xc7 },
+{ 0x89, 0x59, 0x0, 0x24, 0x30, 0x22, 0x1f, 0xff, 0x8, 0x20, 0x0, 0x20, 0x63, 0xfe, 0x32, 0x22, 0x12, 0x22, 0x3, 0xfe, 0xa, 0x22, 0xa, 0x22, 0x1b, 0xfe, 0x12, 0x22, 0x32, 0x22, 0x22, 0x22, 0x62, 0x26 },
+{ 0x89, 0x5a, 0x0, 0x6, 0x0, 0x3c, 0x1f, 0xe8, 0x10, 0x8, 0x11, 0x8, 0x11, 0x8, 0x11, 0x8, 0x11, 0x8, 0x11, 0x8, 0x11, 0xc, 0x11, 0x4, 0x11, 0x24, 0x11, 0x24, 0x31, 0xf6, 0x27, 0x12, 0x60, 0x3 },
+{ 0x89, 0x5b, 0x0, 0x0, 0x3f, 0x7e, 0x21, 0x42, 0x3f, 0x7e, 0x21, 0x42, 0x3f, 0x7e, 0x20, 0x2, 0x27, 0xf2, 0x20, 0x82, 0x20, 0x82, 0x23, 0xe2, 0x20, 0x82, 0x20, 0x82, 0x2f, 0xfa, 0x20, 0x2, 0x20, 0xe },
+{ 0x89, 0x5c, 0x1, 0x4, 0x0, 0x88, 0x7, 0xff, 0x78, 0x50, 0x4b, 0xfe, 0x4a, 0x52, 0x4b, 0x9e, 0x4a, 0x2, 0x4b, 0xfe, 0x4a, 0x2, 0x4b, 0xfe, 0x78, 0x4, 0x7, 0xff, 0x1, 0x4, 0x0, 0x84, 0x0, 0x1c },
+{ 0x89, 0x5d, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xff, 0x2, 0x0, 0x2, 0x0, 0x6, 0x8, 0x4, 0xc, 0x4, 0x4, 0xc, 0x3e, 0x9, 0xe2, 0x3f, 0x2, 0x0, 0x0 },
+{ 0x89, 0x5e, 0x0, 0x0, 0x33, 0xfe, 0x1a, 0x2, 0xa, 0x22, 0x1, 0xfc, 0x0, 0x20, 0x1, 0xfc, 0x79, 0x24, 0x9, 0xfc, 0x9, 0x24, 0x9, 0xfc, 0x8, 0x20, 0xb, 0xfe, 0x18, 0x20, 0x34, 0x0, 0x63, 0xff },
+{ 0x89, 0x5f, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x82, 0x2e, 0xba, 0x20, 0x82, 0xe, 0xb8, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x0, 0x7f, 0xff, 0x4, 0x8, 0xc, 0x8, 0x8, 0xfc, 0x1f, 0x84 },
+{ 0x89, 0x60, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x4, 0x10, 0x8, 0xc, 0x8, 0x38, 0x1b, 0xe0, 0x10, 0x20, 0x30, 0x20, 0x57, 0xff, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x13, 0xfe, 0x10, 0x0 },
+{ 0x89, 0x61, 0x8, 0x0, 0x1d, 0xff, 0x16, 0x44, 0x33, 0x44, 0x28, 0x44, 0x7e, 0x7c, 0x22, 0x44, 0x3e, 0x44, 0x22, 0x44, 0x3e, 0x7c, 0x20, 0x44, 0x22, 0x44, 0x22, 0x47, 0x2f, 0xfc, 0x39, 0x4, 0x60, 0x4 },
+{ 0x89, 0x62, 0x8, 0x0, 0xf, 0x7e, 0x8, 0x22, 0x7f, 0xa2, 0x40, 0xa2, 0xc, 0x36, 0x21, 0x14, 0x4c, 0x94, 0x12, 0x1c, 0x3f, 0x8, 0x61, 0x88, 0x3f, 0x1c, 0x21, 0x14, 0x3f, 0x36, 0x21, 0x22, 0x3f, 0x63 },
+{ 0x89, 0x63, 0x11, 0x4, 0x19, 0x8c, 0x8, 0x88, 0x7f, 0xff, 0x40, 0x1, 0x4f, 0xf9, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x0, 0x80, 0x1, 0x0, 0x1f, 0xfc, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x1f, 0xfc },
+{ 0x89, 0x64, 0x3f, 0x7e, 0x21, 0x42, 0x3f, 0x7e, 0x21, 0x42, 0x3f, 0x7e, 0x21, 0x42, 0x3f, 0x7e, 0x12, 0x24, 0x21, 0x42, 0x1, 0x0, 0x7f, 0xff, 0x2, 0x10, 0x4, 0x20, 0xf, 0xc0, 0x1, 0xf8, 0x3e, 0xe },
+{ 0x89, 0x65, 0x0, 0x2, 0x3f, 0x86, 0x20, 0x8c, 0x3f, 0x98, 0x20, 0xb0, 0x3f, 0x82, 0x4, 0x6, 0x7f, 0xcc, 0x0, 0x18, 0x3f, 0xb0, 0x20, 0x81, 0x3f, 0x83, 0x4, 0x6, 0x24, 0x8c, 0x44, 0x58, 0xc, 0x30 },
+{ 0x89, 0x66, 0x0, 0x20, 0x0, 0x20, 0x7c, 0x20, 0x45, 0xfe, 0x45, 0x22, 0x45, 0x22, 0x45, 0x22, 0x7d, 0x22, 0x45, 0x22, 0x47, 0xff, 0x44, 0x50, 0x44, 0xd8, 0x7c, 0x88, 0x1, 0x8c, 0x3, 0x6, 0x6, 0x3 },
+{ 0x89, 0x67, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x82, 0x20, 0x82, 0x3f, 0xfe, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x3f, 0xfe, 0x0, 0x84, 0x0, 0xcc, 0x0, 0x59, 0x0, 0xf1, 0x7, 0x99, 0x7c, 0xf },
+{ 0x89, 0x68, 0x3, 0x4, 0x31, 0x8c, 0x18, 0x98, 0x8, 0x10, 0x3f, 0xfe, 0x20, 0x2, 0x20, 0x82, 0x0, 0x80, 0x7f, 0xff, 0x2, 0xa0, 0x6, 0xb0, 0x4, 0x90, 0xc, 0x98, 0x18, 0x8c, 0x70, 0x87, 0x0, 0x80 },
+{ 0x89, 0x69, 0x3, 0x80, 0x0, 0xe0, 0x0, 0x20, 0x0, 0x0, 0x7, 0xc0, 0x0, 0x42, 0x0, 0x46, 0x3e, 0x6c, 0x2, 0x78, 0x6, 0x50, 0x4, 0x58, 0xc, 0x48, 0x18, 0x4c, 0x30, 0x46, 0x60, 0x43, 0x3, 0xc0 },
+{ 0x89, 0x6a, 0x1, 0xc0, 0x30, 0x70, 0x18, 0x10, 0x8, 0x0, 0x3, 0xe0, 0x60, 0x22, 0x30, 0x32, 0x17, 0xb6, 0x0, 0xbc, 0x0, 0xa8, 0x11, 0xa8, 0x11, 0x2c, 0x33, 0x24, 0x26, 0x26, 0x6c, 0x23, 0x40, 0xe0 },
+{ 0x89, 0x6b, 0x0, 0x20, 0x30, 0x20, 0x1b, 0xfe, 0xa, 0x22, 0x2, 0x22, 0x63, 0xfe, 0x32, 0x22, 0x12, 0x22, 0x3, 0xfe, 0x8, 0x20, 0x8, 0x32, 0x18, 0x16, 0x10, 0x1c, 0x30, 0x39, 0x20, 0xed, 0x67, 0x87 },
+{ 0x89, 0x6c, 0x0, 0x88, 0x7c, 0x88, 0x13, 0xff, 0x10, 0x88, 0x10, 0x88, 0x10, 0x20, 0x7d, 0xfe, 0x11, 0x22, 0x11, 0x22, 0x11, 0x22, 0x13, 0xff, 0x10, 0x50, 0x1c, 0xd8, 0x71, 0x8c, 0x3, 0x6, 0x6, 0x3 },
+{ 0x89, 0x6d, 0x0, 0x0, 0x7f, 0xf0, 0x8, 0x10, 0x8, 0x10, 0xf, 0xde, 0x8, 0x42, 0x1a, 0x82, 0x11, 0x2, 0x36, 0xce, 0x60, 0x0, 0x1f, 0xfc, 0x12, 0x24, 0x12, 0x24, 0x12, 0x24, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x89, 0x6e, 0x20, 0x0, 0x26, 0xff, 0x3c, 0x10, 0x20, 0x7e, 0x21, 0x42, 0x1f, 0x42, 0x0, 0x7e, 0x7, 0x42, 0x3c, 0x42, 0x4, 0x7e, 0x7f, 0xc2, 0x14, 0x42, 0x17, 0x7e, 0x35, 0xa4, 0x64, 0x66, 0x4, 0xc3 },
+{ 0x89, 0x6f, 0x20, 0x0, 0x26, 0xff, 0x3c, 0x10, 0x20, 0x7e, 0x21, 0x42, 0x1f, 0x42, 0x0, 0x7e, 0x3f, 0x42, 0x0, 0x42, 0x7f, 0xfe, 0x8, 0x42, 0x2a, 0x42, 0x2b, 0x7e, 0x69, 0x24, 0x48, 0x66, 0x18, 0xc3 },
+{ 0x89, 0x70, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x4, 0x90, 0x0, 0x80, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x7f, 0xff, 0x1, 0x40, 0x3, 0x60, 0x6, 0x30, 0x1c, 0x1c, 0x70, 0x7 },
+{ 0x89, 0x71, 0x8, 0x80, 0x1b, 0xef, 0x31, 0x20, 0x61, 0x20, 0x7, 0xf0, 0x8, 0x0, 0x1b, 0xef, 0x32, 0x22, 0x73, 0xe2, 0x10, 0x42, 0x17, 0xf2, 0x12, 0x42, 0x12, 0x42, 0x1f, 0xfa, 0x10, 0x42, 0x10, 0x46 },
+{ 0x89, 0x72, 0x0, 0x60, 0x3c, 0x38, 0x0, 0x8, 0x7e, 0x0, 0x0, 0xf0, 0x3c, 0x10, 0x0, 0x11, 0x1, 0xdb, 0x3c, 0x5a, 0x0, 0x5c, 0x0, 0x54, 0x3c, 0xd4, 0x24, 0x96, 0x25, 0x92, 0x27, 0x13, 0x3c, 0x70 },
+{ 0x89, 0x73, 0x8, 0x42, 0x1c, 0x66, 0x16, 0x24, 0x33, 0x7e, 0x21, 0x42, 0x7e, 0x42, 0x8, 0x42, 0x8, 0x42, 0x7f, 0x7e, 0x8, 0x28, 0x4a, 0x28, 0x6a, 0x28, 0x28, 0x68, 0xf, 0x48, 0x78, 0xc9, 0x1, 0x87 },
+{ 0x89, 0x74, 0x0, 0x20, 0x30, 0x20, 0x1b, 0xff, 0x8, 0x90, 0x0, 0x90, 0x61, 0x9e, 0x31, 0x12, 0x13, 0x32, 0x5, 0x2a, 0x1, 0x66, 0x9, 0x14, 0x19, 0x1c, 0x11, 0x8, 0x31, 0x1c, 0x21, 0x36, 0x61, 0x63 },
+{ 0x89, 0x75, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xff, 0x50, 0x0, 0x31, 0xf8, 0x11, 0x8, 0x13, 0x8, 0x16, 0xf, 0x10, 0x0, 0x37, 0xfc, 0x51, 0x4, 0x11, 0x8c, 0x30, 0xd8, 0x20, 0x70, 0x61, 0xd8, 0xf, 0xf },
+{ 0x89, 0x76, 0x8, 0x8, 0xc, 0x18, 0x6, 0x30, 0x2, 0x20, 0x7f, 0xff, 0x2, 0x20, 0x6, 0x30, 0xc, 0x18, 0x18, 0xc, 0x70, 0x7, 0x1f, 0xfc, 0x12, 0x44, 0x12, 0x44, 0x12, 0x44, 0x12, 0x44, 0x7f, 0xff },
+{ 0x89, 0x77, 0x0, 0x0, 0x3f, 0xbe, 0x24, 0x22, 0x24, 0x22, 0x3f, 0x22, 0x24, 0x22, 0x24, 0x22, 0x3f, 0x3e, 0x24, 0x28, 0x24, 0x28, 0x3f, 0xac, 0x0, 0xa4, 0x55, 0xa4, 0x54, 0xa6, 0x41, 0xa2, 0x3, 0x43 },
+{ 0x89, 0x78, 0x8, 0x82, 0x8, 0xc6, 0x8, 0x44, 0x8, 0xfe, 0x2c, 0x82, 0x2a, 0x82, 0x2a, 0x82, 0x68, 0x82, 0x48, 0xfe, 0x8, 0x28, 0x8, 0x28, 0x8, 0x28, 0x8, 0x68, 0x8, 0x49, 0x8, 0xc9, 0x9, 0x87 },
+{ 0x89, 0x79, 0x0, 0x0, 0x3c, 0xfe, 0x0, 0x82, 0x7e, 0xfe, 0x0, 0x82, 0x3c, 0xfe, 0x0, 0x40, 0x0, 0x7f, 0x3c, 0xc1, 0x1, 0x8d, 0x0, 0xf9, 0x3c, 0x81, 0x24, 0x85, 0x24, 0x7d, 0x24, 0x3, 0x3c, 0xe },
+{ 0x89, 0x7a, 0x8, 0x14, 0x8, 0x12, 0x3e, 0x10, 0x8, 0xff, 0x8, 0x90, 0x7f, 0x92, 0x8, 0x92, 0x8, 0x96, 0x28, 0x94, 0x2e, 0x9c, 0x28, 0xe8, 0x29, 0x9d, 0x28, 0x37, 0x38, 0x62, 0x6e, 0x0, 0x43, 0xff },
+{ 0x89, 0x7b, 0x0, 0x0, 0x3f, 0x7e, 0x21, 0x42, 0x3f, 0x7e, 0x21, 0x42, 0x3f, 0x7e, 0x22, 0x22, 0x21, 0x42, 0x27, 0xf2, 0x24, 0x12, 0x24, 0x12, 0x27, 0xf2, 0x21, 0x42, 0x23, 0x4a, 0x2e, 0x3a, 0x20, 0x6 },
+{ 0x89, 0x7c, 0x8, 0x0, 0x9, 0xff, 0x8, 0x20, 0x7e, 0xfe, 0x8, 0x82, 0x8, 0xfe, 0x1c, 0x82, 0x1a, 0xfe, 0x1a, 0x82, 0x28, 0xfe, 0x28, 0x20, 0x48, 0x7e, 0x9, 0xc6, 0x8, 0x6c, 0x8, 0x38, 0x9, 0xef },
+{ 0x89, 0x7d, 0x0, 0x0, 0x3f, 0xff, 0x20, 0x0, 0x2f, 0x8a, 0x28, 0x89, 0x2f, 0x88, 0x28, 0xbf, 0x2f, 0x88, 0x20, 0x8, 0x2f, 0x9c, 0x28, 0x94, 0x2f, 0x94, 0x68, 0x96, 0x4f, 0x92, 0x48, 0xb3, 0x9, 0xa1 },
+{ 0x89, 0x7e, 0x0, 0x0, 0x3f, 0xfe, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x3f, 0xfe, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0xe, 0x0, 0x0 },
+{ 0x89, 0x80, 0x0, 0x0, 0x3f, 0xfe, 0x20, 0x82, 0x27, 0xf2, 0x20, 0x82, 0x2f, 0xfa, 0x20, 0x2, 0x27, 0xf2, 0x24, 0x12, 0x27, 0xf2, 0x21, 0xaa, 0x22, 0xb2, 0x2c, 0x9a, 0x20, 0x82, 0x3f, 0xfe, 0x0, 0x0 },
+{ 0x89, 0x81, 0x10, 0x0, 0x13, 0xff, 0x12, 0x0, 0x12, 0xfc, 0x12, 0x84, 0x7e, 0xfc, 0x12, 0x84, 0x12, 0xfc, 0x12, 0x20, 0x13, 0xfe, 0x12, 0x48, 0x1e, 0xd8, 0x72, 0x30, 0x3, 0xce, 0x2, 0x0, 0x3, 0xff },
+{ 0x89, 0x82, 0x1, 0x0, 0x1, 0x0, 0x7f, 0xff, 0x2, 0x20, 0x4, 0x90, 0x8, 0x88, 0x1f, 0xfc, 0x70, 0x87, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x0, 0x81, 0x0, 0xc3, 0x0, 0x7e },
+{ 0x89, 0x83, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x2, 0x2f, 0xfa, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x1, 0x0, 0x7f, 0xff, 0x2, 0x10, 0x4, 0x30, 0xf, 0xe0, 0x1, 0xb8, 0x1e, 0xc },
+{ 0x89, 0x84, 0x0, 0x6, 0x7e, 0x1c, 0x5, 0xf0, 0x8, 0x10, 0x10, 0x10, 0x3c, 0x90, 0x4, 0x9e, 0x4, 0x90, 0x24, 0x90, 0x34, 0x90, 0x14, 0x90, 0x1c, 0x90, 0xb, 0xff, 0x1c, 0x0, 0x37, 0x0, 0x61, 0xff },
+{ 0x89, 0x85, 0x8, 0x0, 0xf, 0x7e, 0x19, 0x42, 0x11, 0x42, 0x3b, 0x4e, 0x6a, 0x40, 0x6, 0x41, 0xc, 0x63, 0x18, 0x3e, 0x70, 0x0, 0x1, 0x80, 0x14, 0xc4, 0x14, 0x46, 0x34, 0xb, 0x26, 0x19, 0x63, 0xf0 },
+{ 0x89, 0x86, 0x10, 0x40, 0x10, 0x40, 0x17, 0xff, 0x10, 0x88, 0x7c, 0xa8, 0x11, 0x24, 0x13, 0xfe, 0x15, 0x25, 0x11, 0x24, 0x1d, 0xfc, 0x71, 0x24, 0x11, 0x24, 0x11, 0xfc, 0x10, 0x21, 0x10, 0x33, 0x30, 0x1e },
+{ 0x89, 0x87, 0x10, 0xe, 0x13, 0xf8, 0x11, 0x22, 0x7d, 0xb6, 0x10, 0x94, 0x11, 0xfe, 0x10, 0x40, 0x13, 0xff, 0x1c, 0x40, 0x70, 0x7c, 0x10, 0xc4, 0x11, 0x8c, 0x13, 0x58, 0x10, 0x30, 0x10, 0xec, 0x33, 0x87 },
+{ 0x89, 0x88, 0x30, 0x88, 0x18, 0x88, 0x8, 0x88, 0x1, 0x8c, 0x1, 0x4, 0x63, 0x6, 0x36, 0x3, 0x10, 0x0, 0x1, 0xfc, 0x9, 0x4, 0x9, 0x4, 0x19, 0x4, 0x11, 0x4, 0x31, 0x4, 0x21, 0x4, 0x61, 0xfc },
+{ 0x89, 0x89, 0x0, 0x20, 0x30, 0x20, 0x1b, 0xff, 0xa, 0x1, 0x2, 0xfd, 0x60, 0x20, 0x31, 0xfe, 0x11, 0x22, 0x1, 0x22, 0x9, 0xfe, 0x9, 0x22, 0x19, 0x22, 0x11, 0xfe, 0x30, 0x84, 0x21, 0x86, 0x63, 0x3 },
+{ 0x89, 0x8a, 0x0, 0x80, 0x8, 0x84, 0x8, 0x8c, 0x19, 0xd8, 0x11, 0x40, 0x3, 0x60, 0xe, 0x38, 0x38, 0x8e, 0x0, 0x84, 0x8, 0x8c, 0x19, 0xd8, 0x31, 0x40, 0x3, 0x60, 0x6, 0x30, 0x1c, 0x1c, 0x70, 0x7 },
+{ 0x89, 0x8b, 0x8, 0x20, 0x8, 0x20, 0x8, 0x3e, 0xa, 0x62, 0x2a, 0x46, 0x2a, 0xcc, 0x28, 0x8, 0x68, 0xbf, 0x48, 0xa1, 0x8, 0xa1, 0x1c, 0xa1, 0x14, 0xbf, 0x16, 0xa1, 0x32, 0xa1, 0x20, 0xa1, 0x60, 0xbf },
+{ 0x89, 0x8c, 0x8, 0x0, 0x9, 0xff, 0x8, 0x28, 0xa, 0x28, 0x2a, 0xfe, 0x2a, 0xaa, 0x28, 0xaa, 0x68, 0xaa, 0x48, 0xfe, 0x8, 0x10, 0x1c, 0x10, 0x14, 0xfe, 0x16, 0x10, 0x32, 0x10, 0x21, 0xff, 0x60, 0x0 },
+{ 0x89, 0x8d, 0x4, 0x20, 0x4, 0x20, 0x7f, 0xff, 0x4, 0x20, 0x7, 0xe0, 0x10, 0x9, 0x73, 0xca, 0x12, 0x4c, 0x12, 0x48, 0x12, 0x49, 0x33, 0xc9, 0x50, 0xf, 0x0, 0x0, 0x12, 0x22, 0x33, 0x33, 0x61, 0x11 },
+{ 0x89, 0x8e, 0x4, 0x20, 0x44, 0x20, 0x29, 0xfc, 0x10, 0x20, 0x13, 0xfe, 0x28, 0x0, 0x49, 0xfc, 0x9, 0x4, 0x19, 0x4, 0x29, 0xfc, 0x48, 0x51, 0x8, 0xdb, 0xb, 0x8a, 0x8, 0x8c, 0x18, 0xe6, 0x73, 0x83 },
+{ 0x89, 0x8f, 0x8, 0x0, 0x19, 0xfc, 0x10, 0x4, 0x65, 0xfc, 0x2c, 0x4, 0x1b, 0xff, 0x10, 0x40, 0x24, 0xa2, 0x7d, 0x34, 0x14, 0x58, 0x10, 0x90, 0x55, 0x38, 0x54, 0x54, 0x54, 0x92, 0x11, 0x11, 0x10, 0x60 },
+{ 0x89, 0x90, 0xa, 0x10, 0x3f, 0x9e, 0x2a, 0x92, 0x3f, 0xb6, 0x2a, 0xe4, 0x3f, 0xbf, 0x0, 0x29, 0x7f, 0xe9, 0x0, 0x29, 0x3f, 0xbf, 0x20, 0xa0, 0x3f, 0xa0, 0x11, 0x20, 0x1b, 0x21, 0xa, 0x21, 0x7f, 0xdf },
+{ 0x89, 0x91, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x4, 0x10, 0x8, 0x0, 0xf, 0x7e, 0x19, 0x42, 0x11, 0x42, 0x3d, 0x42, 0x67, 0x42, 0x2, 0x4e, 0x6, 0x40, 0xc, 0x41, 0x18, 0x63, 0x70, 0x3e },
+{ 0x89, 0x92, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x3f, 0xfe, 0x20, 0x82, 0x27, 0xf2, 0x20, 0x82, 0x2f, 0xfa, 0x20, 0x2, 0x27, 0xf2, 0x24, 0x12, 0x27, 0xf2, 0x21, 0x9a, 0x2e, 0xe2, 0x20, 0x9a, 0x3f, 0xfe },
+{ 0x89, 0x93, 0x0, 0x20, 0x30, 0x20, 0x19, 0xfe, 0x8, 0x20, 0x3, 0xff, 0x0, 0x0, 0x1, 0xfe, 0x79, 0x2, 0x9, 0xfe, 0x8, 0x63, 0x8, 0xe6, 0x9, 0xb8, 0xb, 0x2e, 0x18, 0x23, 0x34, 0x20, 0x63, 0xff },
+{ 0x89, 0x94, 0x8, 0x24, 0x1c, 0x24, 0x16, 0x24, 0x33, 0x66, 0x21, 0x42, 0x7e, 0xc3, 0x8, 0x81, 0x8, 0x0, 0x7f, 0x7e, 0x8, 0x42, 0x4a, 0x42, 0x6a, 0x42, 0x28, 0x42, 0xf, 0x42, 0x38, 0x42, 0x60, 0x7e },
+{ 0x89, 0x95, 0x8, 0x3c, 0x1f, 0xa4, 0x71, 0x21, 0xa, 0x3f, 0xc, 0x80, 0x7f, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x0, 0xf, 0xff, 0x8, 0x0, 0x2f, 0xfe, 0x64, 0x92, 0x42, 0x4c },
+{ 0x89, 0x96, 0x1, 0x0, 0x11, 0x0, 0x13, 0xfe, 0x16, 0x0, 0x11, 0xfc, 0x7d, 0x4, 0x11, 0x4, 0x11, 0xfc, 0x10, 0x0, 0x13, 0xfe, 0x12, 0x52, 0x1e, 0x52, 0x72, 0x52, 0x2, 0x52, 0x2, 0x52, 0x7, 0xff },
+{ 0x89, 0x97, 0x8, 0x10, 0x8, 0x10, 0x8, 0x38, 0x7f, 0x28, 0x10, 0x6c, 0x10, 0x44, 0x1e, 0xc6, 0x13, 0xb3, 0x12, 0x18, 0x12, 0xc, 0x12, 0x4, 0x32, 0x60, 0x26, 0x30, 0x24, 0x18, 0x64, 0xc, 0x4c, 0x4 },
+{ 0x89, 0x98, 0x30, 0x0, 0x1b, 0xfe, 0x8, 0x40, 0x0, 0x40, 0x0, 0x40, 0x67, 0xff, 0x30, 0x80, 0x10, 0x80, 0x0, 0x80, 0x9, 0xfe, 0x8, 0x2, 0x18, 0x2, 0x10, 0x2, 0x30, 0x6, 0x20, 0x4, 0x60, 0x3c },
+{ 0x89, 0x99, 0x8, 0x0, 0x8, 0xfe, 0x28, 0x92, 0x28, 0x92, 0x3e, 0xfe, 0x68, 0x92, 0x48, 0x92, 0x8, 0xfe, 0x3e, 0x10, 0x9, 0xff, 0x8, 0x11, 0x8, 0x31, 0xe, 0x21, 0x38, 0x63, 0x60, 0xc2, 0x3, 0x8e },
+{ 0x89, 0x9a, 0x0, 0x0, 0x3e, 0x3e, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x23, 0xe2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x3f, 0xfe, 0x0, 0x0 },
+{ 0x89, 0x9b, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x7f, 0xff, 0x1, 0x40, 0x3, 0x60, 0x2, 0x20, 0x6, 0x30, 0x1c, 0x1c, 0x70, 0x7 },
+{ 0x89, 0x9c, 0x0, 0x80, 0x1, 0x0, 0x1f, 0xfc, 0x10, 0x4, 0x14, 0x94, 0x12, 0xa4, 0x17, 0xf4, 0x11, 0xc4, 0x12, 0xa4, 0x14, 0x94, 0x10, 0x84, 0x11, 0x4, 0x7f, 0xff, 0x3, 0x60, 0xe, 0x38, 0x38, 0xe },
+{ 0x89, 0x9d, 0x4, 0xc0, 0xc, 0x60, 0x18, 0x20, 0x33, 0xfe, 0x64, 0x20, 0xc, 0x20, 0x18, 0x20, 0x30, 0x20, 0x73, 0xfe, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x17, 0xff, 0x10, 0x0 },
+{ 0x89, 0x9e, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xff, 0x20, 0x0, 0x20, 0xc0, 0x20, 0x60, 0x21, 0x30, 0x21, 0x10, 0x25, 0x0, 0x25, 0x4, 0x25, 0x6, 0x2d, 0x3, 0x69, 0x1, 0x49, 0x4, 0x41, 0x8c, 0x0, 0xf8 },
+{ 0x89, 0x9f, 0x10, 0x0, 0x13, 0xfe, 0x12, 0x22, 0x12, 0x22, 0x7a, 0x22, 0x13, 0xfe, 0x12, 0x22, 0x12, 0x22, 0x12, 0x22, 0x1a, 0x22, 0x73, 0xfe, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x30, 0x20 },
+{ 0x89, 0xa0, 0x0, 0x0, 0x7d, 0xfe, 0x44, 0x20, 0x44, 0x20, 0x44, 0x20, 0x44, 0x20, 0x7c, 0x20, 0x45, 0xfe, 0x44, 0x20, 0x44, 0x20, 0x44, 0x20, 0x44, 0x20, 0x7c, 0x20, 0x0, 0x20, 0x3, 0xff, 0x0, 0x0 },
+{ 0x89, 0xa1, 0x8, 0x48, 0x9, 0xfe, 0x8, 0x48, 0x7e, 0x48, 0xb, 0xff, 0x8, 0x20, 0x1d, 0xfe, 0x1b, 0x22, 0x19, 0x22, 0x29, 0xfe, 0x29, 0x22, 0x49, 0x22, 0x9, 0xfe, 0x8, 0x84, 0x9, 0x86, 0xb, 0x3 },
+{ 0x89, 0xa2, 0x0, 0x40, 0x3f, 0x40, 0x20, 0x40, 0x20, 0x7f, 0x2a, 0xc1, 0x2a, 0x93, 0x25, 0x92, 0x24, 0x10, 0x24, 0x10, 0x24, 0x38, 0x2a, 0x28, 0x2a, 0x28, 0x20, 0x6c, 0x20, 0x44, 0x3e, 0xc6, 0x1, 0x83 },
+{ 0x89, 0xa3, 0x0, 0x0, 0x3f, 0x7c, 0x20, 0x44, 0x20, 0x44, 0x2a, 0x44, 0x2a, 0x87, 0x24, 0x0, 0x24, 0xfe, 0x24, 0x42, 0x2a, 0x66, 0x2a, 0x2c, 0x20, 0x38, 0x20, 0x10, 0x3f, 0x38, 0x0, 0x6c, 0x1, 0xc7 },
+{ 0x89, 0xa4, 0x0, 0x0, 0x3f, 0xfe, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x89, 0xa5, 0x2, 0x20, 0x6, 0x30, 0x1d, 0x1c, 0x73, 0x7, 0x2, 0x10, 0x7, 0xf8, 0x1c, 0xc, 0x0, 0x0, 0x7e, 0xfe, 0x22, 0x22, 0x12, 0x12, 0xe, 0xe, 0x1a, 0x3a, 0x72, 0xe2, 0x2, 0x2, 0xe, 0xe },
+{ 0x89, 0xa6, 0x10, 0x20, 0x10, 0x40, 0x11, 0xfe, 0x7d, 0x2, 0x5, 0xaa, 0xd, 0x22, 0x9, 0xfa, 0x19, 0x72, 0x35, 0xaa, 0x79, 0x22, 0x15, 0x42, 0x13, 0xff, 0x10, 0x50, 0x10, 0xd8, 0x11, 0x8c, 0x17, 0x7 },
+{ 0x89, 0xa7, 0x11, 0x4, 0x8, 0x88, 0x7f, 0xff, 0x40, 0x81, 0x4f, 0xf9, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x0, 0xf, 0xff, 0x8, 0x0, 0xf, 0xfe, 0x24, 0x92, 0x62, 0x4a, 0x40, 0x6 },
+{ 0x89, 0xa8, 0x0, 0x10, 0x7e, 0x20, 0x40, 0xfc, 0x40, 0x84, 0x54, 0xfc, 0x54, 0x84, 0x48, 0xfc, 0x48, 0x80, 0x48, 0xff, 0x54, 0x80, 0x54, 0xfe, 0x40, 0x2, 0x41, 0x56, 0x7d, 0x52, 0x2, 0x6, 0x0, 0xc },
+{ 0x89, 0xa9, 0x4, 0x10, 0x4, 0x10, 0x3f, 0xfe, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x0, 0x80, 0xf, 0xf8, 0x8, 0x88, 0x8, 0x88, 0xf, 0xf8, 0x8, 0x88, 0x8, 0x88, 0xf, 0xf8, 0x4, 0x10, 0x38, 0xe },
+{ 0x89, 0xaa, 0x0, 0x0, 0x3f, 0xfe, 0x24, 0x12, 0x22, 0x22, 0x22, 0x22, 0x2f, 0xfa, 0x20, 0x82, 0x20, 0x82, 0x24, 0x92, 0x24, 0x92, 0x24, 0x92, 0x24, 0x92, 0x27, 0xf2, 0x20, 0x2, 0x20, 0x2, 0x20, 0xe },
+{ 0x89, 0xab, 0x0, 0x20, 0x30, 0x20, 0x18, 0x20, 0x8, 0x20, 0x3, 0xff, 0x62, 0x21, 0x32, 0x21, 0x12, 0x21, 0x2, 0x21, 0xa, 0x21, 0xb, 0xff, 0x18, 0x20, 0x10, 0x20, 0x30, 0x20, 0x20, 0x20, 0x60, 0x20 },
+{ 0x89, 0xac, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x0, 0x0, 0x44, 0x20, 0x28, 0x21, 0x11, 0x23, 0x29, 0x26, 0x4b, 0x24, 0x1a, 0x70, 0x28, 0x50, 0x48, 0xd8, 0x9, 0x8c, 0x1b, 0x6, 0x36, 0x3 },
+{ 0x89, 0xad, 0x8, 0x20, 0x8, 0x20, 0x1b, 0xfe, 0x11, 0x4, 0x10, 0x88, 0x37, 0xff, 0x30, 0x0, 0x51, 0xfc, 0x11, 0x4, 0x11, 0xfc, 0x11, 0x4, 0x11, 0xfc, 0x10, 0x20, 0x12, 0x92, 0x12, 0x85, 0x14, 0x7c },
+{ 0x89, 0xae, 0x0, 0x0, 0x1f, 0xfe, 0x10, 0x2, 0x10, 0x2, 0x1f, 0xfe, 0x10, 0x0, 0x17, 0xfe, 0x11, 0x0, 0x11, 0x4, 0x12, 0x3e, 0x17, 0xe2, 0x10, 0x40, 0x33, 0xfc, 0x20, 0x40, 0x60, 0x40, 0xf, 0xff },
+{ 0x89, 0xaf, 0x10, 0x20, 0x10, 0x20, 0x13, 0xfe, 0x11, 0x4, 0x58, 0x88, 0x57, 0xff, 0x54, 0x0, 0x51, 0xfc, 0x11, 0x4, 0x11, 0xfc, 0x11, 0x4, 0x11, 0xfc, 0x10, 0x20, 0x12, 0x92, 0x12, 0x85, 0x14, 0x7c },
+{ 0x89, 0xb0, 0x0, 0x20, 0x3c, 0x20, 0x27, 0xfe, 0x25, 0x4, 0x24, 0x88, 0x3f, 0xff, 0x24, 0x0, 0x25, 0xfc, 0x25, 0x4, 0x3d, 0xfc, 0x25, 0x4, 0x25, 0xfc, 0x24, 0x22, 0x25, 0x51, 0x65, 0x42, 0x4d, 0x3e },
+{ 0x89, 0xb1, 0x8, 0x0, 0x9, 0xfe, 0x8, 0x4, 0x7e, 0x48, 0x8, 0x30, 0x9, 0xfe, 0x1d, 0x22, 0x1b, 0x22, 0x29, 0xfe, 0x29, 0x22, 0x49, 0x22, 0x9, 0xfe, 0x9, 0x22, 0x9, 0x22, 0x9, 0x22, 0x9, 0x26 },
+{ 0x89, 0xb2, 0x8, 0x20, 0x28, 0x20, 0x28, 0x20, 0x28, 0x20, 0x3e, 0x20, 0x69, 0xfe, 0x48, 0x20, 0x8, 0x20, 0x8, 0x20, 0xe, 0x20, 0x78, 0x20, 0x8, 0x20, 0x8, 0x20, 0x8, 0x20, 0xb, 0xff, 0x8, 0x0 },
+{ 0x89, 0xb3, 0x0, 0x0, 0x3f, 0xf8, 0x0, 0x30, 0x0, 0x60, 0x0, 0xc0, 0x1, 0x80, 0x3, 0x0, 0x6, 0x0, 0xc, 0x0, 0x18, 0x0, 0x10, 0x2, 0x30, 0x2, 0x20, 0x6, 0x30, 0x4, 0x1f, 0xfc, 0x0, 0x0 },
+{ 0x89, 0xb4, 0x8, 0x80, 0x8, 0x80, 0x1f, 0xff, 0x11, 0x10, 0x11, 0x50, 0x32, 0x48, 0x33, 0xfc, 0x56, 0x46, 0x1a, 0x45, 0x13, 0xfc, 0x12, 0x44, 0x12, 0x44, 0x13, 0xfc, 0x10, 0x41, 0x10, 0x63, 0x10, 0x3e },
+{ 0x89, 0xb5, 0x10, 0x0, 0x10, 0x3e, 0x3f, 0xa2, 0x24, 0x22, 0x44, 0x22, 0x4, 0x22, 0x7f, 0xa2, 0x4, 0x22, 0x24, 0x22, 0x27, 0xa2, 0x24, 0x22, 0x24, 0x22, 0x27, 0xae, 0x3c, 0x20, 0x60, 0x20, 0x0, 0x20 },
+{ 0x89, 0xb6, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x17, 0xf4, 0x11, 0x44, 0x12, 0x24, 0x14, 0x14, 0x10, 0x4, 0x1f, 0xfc, 0x0, 0x80, 0x14, 0xc6, 0x14, 0x43, 0x34, 0x9, 0x26, 0x18, 0x63, 0xf0 },
+{ 0x89, 0xb7, 0x0, 0x0, 0x31, 0xfc, 0x19, 0x4, 0x9, 0x4, 0x1, 0xfc, 0x61, 0x4, 0x31, 0x4, 0x11, 0xfc, 0x0, 0x0, 0xb, 0xfe, 0xa, 0x52, 0x1a, 0x52, 0x12, 0x52, 0x32, 0x52, 0x22, 0x52, 0x67, 0xff },
+{ 0x89, 0xb8, 0x6, 0x6, 0x1c, 0x1c, 0x73, 0xf2, 0x11, 0x26, 0x10, 0x94, 0x7d, 0xfe, 0x10, 0x2, 0x19, 0xfe, 0x14, 0x2, 0x35, 0xfe, 0x30, 0x0, 0x50, 0x10, 0x51, 0x5a, 0x11, 0x4b, 0x13, 0x45, 0x12, 0x3c },
+{ 0x89, 0xb9, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x4, 0x10, 0x6, 0x30, 0x2, 0x20, 0x7f, 0xff, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8 },
+{ 0x89, 0xba, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0xe0, 0x0, 0xb0, 0x0, 0x98, 0x0, 0x8c, 0x0, 0x84, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80 },
+{ 0x89, 0xbb, 0x2, 0x40, 0x2, 0x40, 0x6, 0x40, 0x4, 0x42, 0xc, 0x46, 0x8, 0x5c, 0x18, 0x70, 0x38, 0x40, 0x68, 0x40, 0x8, 0x40, 0x8, 0x40, 0x8, 0x41, 0x8, 0x41, 0x8, 0x43, 0x8, 0x62, 0x8, 0x3e },
+{ 0x89, 0xbc, 0x4, 0x0, 0x5, 0xfe, 0xd, 0x0, 0x9, 0x0, 0x19, 0x0, 0x11, 0xfc, 0x31, 0x44, 0x51, 0x44, 0x11, 0x6c, 0x11, 0x28, 0x11, 0x38, 0x13, 0x10, 0x12, 0x38, 0x16, 0x6c, 0x10, 0xc6, 0x11, 0x83 },
+{ 0x89, 0xbd, 0x4, 0x0, 0x4, 0x0, 0xf, 0xff, 0x8, 0x4, 0x18, 0x4, 0x13, 0xc4, 0x32, 0x44, 0x52, 0x44, 0x12, 0x44, 0x12, 0x44, 0x12, 0x44, 0x13, 0xc4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x1c },
+{ 0x89, 0xbe, 0x9, 0x0, 0x9, 0x0, 0x9, 0x1e, 0x19, 0x12, 0x17, 0xd2, 0x31, 0x52, 0x31, 0x52, 0x51, 0x52, 0x11, 0x52, 0x11, 0x52, 0x11, 0x52, 0x13, 0x52, 0x12, 0x52, 0x12, 0xd2, 0x16, 0x9e, 0x15, 0x80 },
+{ 0x89, 0xbf, 0x8, 0x0, 0x8, 0x0, 0xf, 0xff, 0x18, 0x90, 0x10, 0x90, 0x30, 0x90, 0x37, 0xfe, 0x54, 0x92, 0x14, 0x92, 0x14, 0x92, 0x14, 0x92, 0x14, 0x92, 0x14, 0x92, 0x14, 0x92, 0x17, 0xfe, 0x10, 0x0 },
+{ 0x89, 0xc0, 0x8, 0x20, 0x8, 0x20, 0xb, 0xfe, 0x18, 0x20, 0x10, 0x20, 0x30, 0x20, 0x37, 0xff, 0x50, 0x0, 0x10, 0x20, 0x10, 0x20, 0x13, 0xfe, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x17, 0xff, 0x10, 0x0 },
+{ 0x89, 0xc1, 0x8, 0x0, 0x8, 0x0, 0x8, 0x3e, 0x8, 0x22, 0x7f, 0x22, 0x9, 0x22, 0x9, 0x22, 0x9, 0x22, 0x9, 0x22, 0x9, 0x22, 0x19, 0x22, 0x11, 0x22, 0x13, 0x22, 0x32, 0x22, 0x22, 0x3e, 0x66, 0x0 },
+{ 0x89, 0xc2, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x4, 0x0, 0x4, 0xf, 0xc4, 0x8, 0x44, 0x8, 0x44, 0x8, 0x44, 0x8, 0x44, 0x8, 0x44, 0xf, 0xc4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x1c },
+{ 0x89, 0xc3, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x3f, 0xfe, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x2, 0x20, 0x7f, 0xff, 0x8, 0x0, 0x3f, 0x3e, 0x9, 0x22, 0x11, 0x22, 0x67, 0x3e },
+{ 0x89, 0xc4, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x80, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x2, 0x0, 0x7, 0xf8, 0xc, 0x10, 0x32, 0x20, 0x1, 0xc0, 0x7e, 0x3f },
+{ 0x89, 0xc5, 0x10, 0x20, 0x10, 0x20, 0x11, 0xfe, 0x7d, 0x2, 0x14, 0x0, 0x14, 0xfc, 0x14, 0x40, 0x34, 0xa2, 0x25, 0x26, 0x28, 0x54, 0x78, 0x90, 0x9, 0x38, 0x14, 0x54, 0x14, 0x96, 0x21, 0x13, 0x40, 0x60 },
+{ 0x89, 0xc6, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x2, 0x20, 0x2, 0xf, 0xf8, 0x1, 0x0, 0x6, 0x86, 0x38, 0xcc, 0x3, 0x58, 0xe, 0x60, 0x38, 0xf0, 0x3, 0x58, 0xe, 0x4c, 0x78, 0xc7, 0x3, 0x80 },
+{ 0x89, 0xc7, 0x0, 0x80, 0x7f, 0xff, 0x40, 0x1, 0x5f, 0xfd, 0x0, 0x80, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x7f, 0xff, 0x10, 0x4, 0x6f, 0xfb, 0x2, 0x8, 0x1c, 0x38 },
+{ 0x89, 0xc8, 0x6, 0x4, 0x1c, 0xc4, 0x68, 0x64, 0x8, 0x24, 0x8, 0x4, 0x7e, 0x4, 0x8, 0xc4, 0x8, 0x64, 0x1c, 0x24, 0x1a, 0x4, 0x28, 0x7, 0x28, 0x3c, 0x49, 0xe4, 0x8, 0x4, 0x8, 0x4, 0x8, 0x4 },
+{ 0x89, 0xc9, 0x0, 0x0, 0x3, 0xde, 0x7a, 0x42, 0x4a, 0x42, 0x4a, 0x42, 0x4b, 0xde, 0x4a, 0x0, 0x7a, 0x3e, 0x4b, 0xd2, 0x4a, 0x16, 0x4a, 0x14, 0x4a, 0x1c, 0x7b, 0xc8, 0x2, 0x1c, 0x2, 0x36, 0x2, 0x63 },
+{ 0x89, 0xca, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x0, 0x80, 0x7f, 0xff, 0x2, 0xa0, 0x6, 0xb0, 0xc, 0x98, 0x18, 0x8c, 0x70, 0x87, 0x0, 0x80 },
+{ 0x89, 0xcb, 0x8, 0x0, 0x8, 0x3e, 0x7f, 0x22, 0x9, 0x22, 0x9, 0x22, 0x19, 0x22, 0x11, 0x22, 0x37, 0x3e, 0x60, 0x0, 0x0, 0x80, 0x7f, 0xff, 0x2, 0xa0, 0x6, 0xb0, 0x1c, 0x9c, 0x70, 0x87, 0x0, 0x80 },
+{ 0x89, 0xcc, 0x0, 0x40, 0x7f, 0x40, 0x2, 0x40, 0x3a, 0x7f, 0x2a, 0xc1, 0x3a, 0x93, 0x2, 0x92, 0x6, 0x10, 0x0, 0x10, 0x7f, 0xb8, 0x2, 0x28, 0x3a, 0x28, 0x2a, 0x2c, 0x3a, 0x64, 0x2, 0x46, 0x6, 0xc3 },
+{ 0x89, 0xcd, 0x30, 0x0, 0x1b, 0xff, 0x8, 0x4, 0x0, 0x4, 0x1, 0xe4, 0x61, 0x24, 0x31, 0x24, 0x11, 0x24, 0x1, 0x24, 0x9, 0x24, 0x9, 0xe4, 0x18, 0x4, 0x10, 0x4, 0x30, 0x4, 0x20, 0x4, 0x60, 0x1c },
+{ 0x89, 0xce, 0x0, 0x80, 0x0, 0x80, 0x0, 0x82, 0x8, 0x86, 0x8, 0x84, 0x8, 0x8c, 0x18, 0x98, 0x10, 0x90, 0x31, 0xc0, 0x1, 0x40, 0x3, 0x60, 0x2, 0x20, 0x6, 0x30, 0xc, 0x18, 0x18, 0xc, 0x70, 0x7 },
+{ 0x89, 0xcf, 0x0, 0x0, 0x7d, 0xff, 0x10, 0x4, 0x10, 0x4, 0x11, 0xe4, 0x11, 0x24, 0x7d, 0x24, 0x11, 0x24, 0x11, 0x24, 0x11, 0x24, 0x11, 0xe4, 0x10, 0x4, 0x1c, 0x4, 0x70, 0x4, 0x0, 0x4, 0x0, 0x1c },
+{ 0x89, 0xd0, 0x8, 0x0, 0x8, 0xfc, 0x8, 0x84, 0x7e, 0xbc, 0x2, 0xa4, 0x6, 0xa4, 0x4, 0xa4, 0xd, 0xfe, 0x19, 0x2, 0x3d, 0x7a, 0x6b, 0x4a, 0x9, 0x4a, 0x9, 0x4a, 0x9, 0x7a, 0x9, 0x2, 0x9, 0x6 },
+{ 0x89, 0xd1, 0x0, 0x18, 0x0, 0xf0, 0x1f, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x2, 0xa0, 0x6, 0xb0, 0x4, 0x90, 0xc, 0x98, 0x18, 0x8c, 0x30, 0x86, 0x60, 0x83, 0x0, 0x80, 0x0, 0x80 },
+{ 0x89, 0xd2, 0x4, 0x20, 0x1c, 0x20, 0x73, 0xfe, 0x12, 0x2, 0x10, 0x0, 0x7d, 0xfc, 0x10, 0x40, 0x10, 0xa2, 0x39, 0x26, 0x34, 0x54, 0x30, 0x90, 0x53, 0x38, 0x50, 0x5c, 0x10, 0x96, 0x13, 0x13, 0x10, 0x60 },
+{ 0x89, 0xd3, 0x10, 0x20, 0x10, 0x20, 0x3f, 0x7f, 0x24, 0x90, 0x42, 0x8, 0x3f, 0xfe, 0x20, 0x82, 0x2f, 0xfa, 0x20, 0x82, 0x20, 0x82, 0x27, 0xf2, 0x24, 0x12, 0x24, 0x12, 0x27, 0xf2, 0x20, 0x2, 0x3f, 0xfe },
+{ 0x89, 0xd4, 0x2, 0x20, 0x2, 0x20, 0x7f, 0xff, 0x2, 0x20, 0x2, 0x20, 0x4, 0x40, 0x4, 0x40, 0x8, 0x46, 0x18, 0x5c, 0x28, 0x70, 0x48, 0x40, 0x8, 0x40, 0x8, 0x40, 0x8, 0x41, 0x8, 0x63, 0x8, 0x3e },
+{ 0x89, 0xd5, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x4, 0x10, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x8, 0xf, 0x88, 0x8, 0x88, 0x8, 0x88, 0x8, 0x88, 0xf, 0x88, 0x0, 0x8, 0x0, 0x8, 0x0, 0x38 },
+{ 0x89, 0xd6, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x4, 0x10, 0x8, 0x0, 0x8, 0x3e, 0x7f, 0x22, 0x9, 0x22, 0x9, 0x22, 0x19, 0x22, 0x11, 0x22, 0x13, 0x22, 0x32, 0x22, 0x22, 0x3e, 0x6e, 0x0 },
+{ 0x89, 0xd7, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x4, 0x10, 0x8, 0x0, 0xb, 0xff, 0x10, 0x4, 0x11, 0xe4, 0x31, 0x24, 0x51, 0x24, 0x11, 0x24, 0x11, 0xe4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x1c },
+{ 0x89, 0xd8, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x3f, 0xfe, 0x8, 0x88, 0x8, 0x88, 0x7f, 0xff, 0x8, 0x88, 0x8, 0x88, 0x3f, 0xfe, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x0, 0x80, 0x0, 0x80 },
+{ 0x89, 0xd9, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x1f, 0xfc, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x84, 0x1f, 0xfc, 0x0, 0x80, 0x7f, 0xff, 0x2, 0xa0, 0x6, 0xb0, 0x1c, 0x9c, 0x70, 0x87, 0x0, 0x80 },
+{ 0x89, 0xda, 0x0, 0x0, 0x11, 0xde, 0x11, 0x42, 0x11, 0x42, 0x7d, 0x42, 0x55, 0xde, 0x55, 0x0, 0x55, 0x3e, 0x55, 0xd2, 0x7d, 0x16, 0x11, 0x14, 0x15, 0xdc, 0x15, 0x8, 0x3d, 0x1c, 0x65, 0x36, 0x1, 0x63 },
+{ 0x89, 0xdb, 0x0, 0x0, 0x3c, 0xfe, 0x0, 0x92, 0x7e, 0x92, 0x0, 0xfe, 0x3c, 0x92, 0x0, 0x92, 0x0, 0xfe, 0x3c, 0x10, 0x1, 0xff, 0x0, 0x54, 0x3c, 0x54, 0x24, 0xd6, 0x24, 0x92, 0x25, 0x93, 0x3c, 0x10 },
+{ 0x89, 0xdc, 0x0, 0x88, 0x0, 0x88, 0x7b, 0xff, 0x48, 0x88, 0x4b, 0xfe, 0x49, 0x24, 0x49, 0x24, 0x4f, 0xff, 0x49, 0x24, 0x49, 0x24, 0x4b, 0xfe, 0x78, 0x20, 0x0, 0x20, 0x7, 0xff, 0x0, 0x20, 0x0, 0x20 },
+{ 0x89, 0xdd, 0x2, 0x40, 0x6, 0x46, 0x1c, 0x7c, 0x74, 0x40, 0x4, 0x42, 0x4, 0x3e, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x4, 0x10, 0x38, 0xe },
+{ 0x89, 0xde, 0x1, 0x0, 0x61, 0x0, 0x31, 0x1e, 0x17, 0xd2, 0x1, 0x52, 0x1, 0x52, 0x1, 0x52, 0x71, 0x52, 0x11, 0x52, 0x13, 0x52, 0x12, 0x52, 0x12, 0xd2, 0x16, 0x9e, 0x31, 0x80, 0x28, 0x0, 0x67, 0xff },
+{ 0x89, 0xdf, 0x1, 0xfc, 0x31, 0x4, 0x19, 0x3c, 0x9, 0x24, 0x1, 0x24, 0x1, 0x24, 0x3, 0xfe, 0x72, 0x2, 0x12, 0xfa, 0x12, 0x8a, 0x12, 0x8a, 0x12, 0xfa, 0x12, 0x2, 0x32, 0x6, 0x28, 0x0, 0x67, 0xff },
+{ 0x89, 0xe0, 0x3f, 0xfe, 0x0, 0x80, 0x7f, 0xff, 0x40, 0x81, 0x5e, 0xbd, 0x0, 0x80, 0x1e, 0xbc, 0x0, 0x0, 0x3f, 0x7e, 0x21, 0x2, 0x3f, 0x7e, 0x20, 0x0, 0x3e, 0x7e, 0x20, 0x24, 0x3e, 0x18, 0x20, 0xe7 },
+{ 0x89, 0xe1, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x7f, 0xff, 0x52, 0x44, 0x52, 0x44, 0x52, 0x44, 0x52, 0x6c, 0x52, 0x28, 0x7e, 0x38, 0x10, 0x10, 0x14, 0x38, 0x14, 0x28, 0x1e, 0x6c, 0x32, 0xc6, 0x61, 0x83 },
+{ 0x89, 0xe2, 0x8, 0xd4, 0x9, 0x96, 0xf, 0x12, 0x19, 0x10, 0x11, 0x10, 0x37, 0xff, 0x31, 0x10, 0x51, 0x12, 0x11, 0x12, 0x11, 0xd6, 0x17, 0x14, 0x11, 0x1c, 0x11, 0x9, 0x11, 0x1d, 0x11, 0x37, 0x17, 0x62 },
+{ 0x89, 0xe3, 0x10, 0x54, 0x10, 0xd6, 0x13, 0x92, 0x10, 0x90, 0x54, 0x90, 0x57, 0xff, 0x54, 0x90, 0x54, 0x92, 0x54, 0x92, 0x54, 0xd6, 0x57, 0x94, 0x54, 0x9c, 0x7c, 0x89, 0x0, 0x9d, 0x0, 0x97, 0x3, 0xb2 },
+{ 0x89, 0xe4, 0x1, 0xa0, 0x7, 0x2c, 0x3c, 0x26, 0x4, 0x22, 0x4, 0x20, 0x7f, 0xff, 0x4, 0x20, 0x4, 0x22, 0x4, 0x36, 0x7, 0x94, 0x7c, 0x1c, 0x4, 0x8, 0x4, 0x1d, 0x4, 0x35, 0x4, 0x67, 0x1d, 0xc2 },
+{ 0x89, 0xe5, 0x0, 0x0, 0x3f, 0xfe, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x0, 0x50, 0x0, 0xd0, 0x1, 0x90, 0x3, 0x10, 0x6, 0x10, 0x1c, 0x10, 0x70, 0x10, 0x0, 0x70 },
+{ 0x89, 0xe6, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x27, 0xf2, 0x24, 0x92, 0x24, 0x92, 0x24, 0x92, 0x27, 0xf2, 0x24, 0x92, 0x24, 0x92, 0x24, 0x92, 0x27, 0xf2, 0x20, 0x2, 0x3f, 0xfe, 0x0, 0x0 },
+{ 0x89, 0xe7, 0x0, 0x10, 0x3f, 0x90, 0x24, 0x10, 0x24, 0x10, 0x24, 0x10, 0x3f, 0x90, 0x20, 0x90, 0x20, 0xb8, 0x20, 0xa8, 0x3f, 0xa8, 0x24, 0x28, 0x24, 0x6c, 0x24, 0x44, 0x24, 0x44, 0x3f, 0xc6, 0x0, 0x83 },
+{ 0x89, 0xe8, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x0, 0x0, 0x3f, 0xfe, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x0, 0xd0, 0x1, 0x90, 0x3, 0x10, 0xe, 0x10, 0x78, 0x10, 0x0, 0x70 },
+{ 0x89, 0xe9, 0x10, 0x54, 0x10, 0x96, 0x13, 0x92, 0x7c, 0x90, 0x54, 0x90, 0x57, 0xff, 0x54, 0x90, 0x54, 0x92, 0x7c, 0x92, 0x10, 0xd4, 0x13, 0x94, 0x14, 0x98, 0x14, 0x89, 0x3c, 0x8d, 0x64, 0x97, 0x3, 0xa2 },
+{ 0x89, 0xea, 0x8, 0x0, 0x8, 0x7e, 0x7f, 0x42, 0x9, 0x42, 0x19, 0x42, 0x37, 0x7e, 0x60, 0x0, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x4, 0x10, 0x38, 0xe },
+{ 0x89, 0xeb, 0x0, 0x22, 0x3f, 0x26, 0x12, 0x24, 0x12, 0x7f, 0x12, 0xc8, 0x13, 0x48, 0x12, 0x48, 0x7f, 0x7e, 0xa, 0x48, 0xa, 0x48, 0xa, 0x48, 0x1a, 0x7e, 0x12, 0x48, 0x32, 0x48, 0x62, 0x48, 0xe, 0x7f },
+{ 0x89, 0xec, 0x8, 0x2a, 0x1c, 0x49, 0x15, 0xc9, 0x32, 0x48, 0x68, 0x48, 0x3d, 0xff, 0x24, 0x48, 0x3c, 0x49, 0x24, 0x49, 0x3c, 0x6a, 0x21, 0xca, 0x24, 0x4c, 0x24, 0x44, 0x2e, 0x45, 0x3a, 0x4b, 0x61, 0xd1 },
+{ 0x89, 0xed, 0x8, 0x0, 0x7f, 0xbf, 0x8, 0xa1, 0x18, 0xa1, 0x33, 0xbf, 0x60, 0x0, 0xf, 0xfc, 0x8, 0x80, 0xf, 0xf8, 0x8, 0x80, 0xf, 0xf8, 0x8, 0x80, 0xf, 0xfe, 0x24, 0x92, 0x62, 0x4a, 0x40, 0x6 },
+{ 0x89, 0xee, 0x0, 0x80, 0x1, 0xc0, 0x3, 0x60, 0x6, 0x30, 0xc, 0x18, 0x1c, 0x1c, 0x74, 0x17, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0xc, 0x10, 0x8, 0x10, 0x18, 0x10, 0x30, 0x10 },
+{ 0x89, 0xef, 0x0, 0x80, 0x1, 0xc0, 0x3, 0x60, 0x6, 0x30, 0x1c, 0x1c, 0x70, 0x7, 0xf, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xff, 0x2, 0x0, 0x2, 0x8, 0x6, 0x8, 0x4, 0x7c, 0xf, 0xc4, 0x38, 0x4 },
+{ 0x89, 0xf0, 0x10, 0x0, 0x1e, 0xfe, 0x32, 0x22, 0x24, 0x22, 0x7f, 0x62, 0x29, 0xce, 0x29, 0x0, 0x3f, 0x28, 0x29, 0x28, 0x29, 0x7e, 0x3f, 0x48, 0x21, 0x8, 0x21, 0xff, 0x21, 0x8, 0x61, 0x8, 0x47, 0x8 },
+{ 0x89, 0xf1, 0x0, 0x0, 0x3f, 0xfe, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x27, 0xf2, 0x24, 0x12, 0x24, 0x12, 0x24, 0x12, 0x24, 0x12, 0x27, 0xf2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x3f, 0xfe, 0x0, 0x0 },
+{ 0x89, 0xf2, 0x10, 0x20, 0x10, 0x40, 0x13, 0xfe, 0x12, 0x22, 0x7e, 0x22, 0x13, 0xfe, 0x12, 0x22, 0x12, 0x22, 0x13, 0xfe, 0x10, 0x90, 0x1c, 0x94, 0x70, 0x95, 0x1, 0x9f, 0x1, 0x10, 0x3, 0x11, 0xe, 0xf },
+{ 0x89, 0xf3, 0x10, 0x20, 0x10, 0x20, 0x13, 0xff, 0x10, 0x20, 0x7d, 0xfe, 0x11, 0x52, 0x11, 0x52, 0x11, 0xfe, 0x10, 0x20, 0x13, 0xff, 0x1c, 0x50, 0x70, 0xd9, 0x1, 0x8a, 0x6, 0x8c, 0x0, 0xe6, 0x3, 0x83 },
+{ 0x89, 0xf4, 0x0, 0x0, 0x7e, 0xfe, 0x4, 0x82, 0x8, 0x82, 0x10, 0xba, 0x3c, 0xaa, 0x4, 0xaa, 0x4, 0xaa, 0x24, 0xaa, 0x34, 0xba, 0x14, 0x82, 0x1c, 0x82, 0x8, 0xfe, 0x1c, 0x0, 0x37, 0x0, 0x61, 0xff },
+{ 0x89, 0xf5, 0x8, 0x20, 0x8, 0x20, 0x8, 0x20, 0x9, 0xfc, 0x2c, 0x24, 0x2a, 0x24, 0x2a, 0x24, 0x68, 0x24, 0x4b, 0xff, 0x8, 0x50, 0x8, 0x50, 0x8, 0x58, 0x8, 0xc8, 0x8, 0x8c, 0x9, 0x86, 0xb, 0x3 },
+{ 0x89, 0xf6, 0x8, 0x0, 0xb, 0xfc, 0x8, 0x84, 0x8, 0xcc, 0x2c, 0x58, 0x2a, 0x30, 0x2a, 0x78, 0x68, 0xcc, 0x4b, 0xa7, 0x8, 0x20, 0x9, 0xfe, 0x8, 0x20, 0x8, 0x20, 0x8, 0x20, 0xb, 0xff, 0x8, 0x0 },
+{ 0x89, 0xf7, 0x8, 0x80, 0x8, 0x80, 0x9, 0xfe, 0x9, 0x0, 0x2a, 0x0, 0x2c, 0xfc, 0x2a, 0xa4, 0x68, 0xa4, 0x48, 0xa4, 0xf, 0xff, 0x9, 0x44, 0x9, 0x44, 0x9, 0x44, 0x9, 0xff, 0x8, 0x8, 0x8, 0x38 },
+{ 0x89, 0xf8, 0x10, 0x0, 0x13, 0xff, 0x12, 0x0, 0x12, 0x10, 0x52, 0x12, 0x5a, 0x52, 0x56, 0x52, 0x52, 0xd6, 0x12, 0x94, 0x12, 0x10, 0x12, 0x38, 0x12, 0x28, 0x12, 0x6c, 0x14, 0x44, 0x10, 0xc6, 0x11, 0x83 },
+{ 0x89, 0xf9, 0x10, 0x20, 0x10, 0x20, 0x13, 0xff, 0x10, 0x20, 0x59, 0xfe, 0x55, 0x52, 0x55, 0x52, 0x51, 0xfe, 0x10, 0x20, 0x13, 0xff, 0x10, 0x50, 0x10, 0xd9, 0x11, 0x8a, 0x16, 0x8c, 0x10, 0xe6, 0x13, 0x83 },
+{ 0x89, 0xfa, 0x0, 0x2c, 0x0, 0x26, 0x0, 0x22, 0x7f, 0xff, 0x0, 0x20, 0x9, 0x20, 0x9, 0x32, 0x9, 0x12, 0x3f, 0xd6, 0x9, 0x14, 0x9, 0x1c, 0x19, 0x8, 0x11, 0x1d, 0x31, 0x35, 0x60, 0xe7, 0x3, 0x82 },
+{ 0x89, 0xfb, 0x10, 0x0, 0x10, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x7c, 0x84, 0x10, 0xfc, 0x10, 0x0, 0x10, 0x0, 0x1d, 0xfe, 0x70, 0x22, 0x10, 0x22, 0x10, 0x62, 0x10, 0x42, 0x10, 0xc6, 0x11, 0x84, 0x33, 0x1c },
+{ 0x89, 0xfc, 0x0, 0x40, 0x0, 0x40, 0x7e, 0x40, 0x2, 0x7f, 0x2, 0x44, 0x2, 0xc4, 0x3e, 0xa4, 0x21, 0xac, 0x20, 0x28, 0x20, 0x38, 0x20, 0x10, 0x22, 0x38, 0x32, 0x28, 0x1e, 0x6c, 0x0, 0xc6, 0x1, 0x83 },
+{ 0x8a, 0x40, 0x4, 0x4, 0x8, 0x24, 0x3f, 0xb4, 0x24, 0x94, 0x24, 0x84, 0x3f, 0xa4, 0x24, 0xb4, 0x24, 0x94, 0x3f, 0x87, 0x12, 0x3c, 0x12, 0x84, 0x12, 0xa4, 0x13, 0xe4, 0x32, 0x1, 0x23, 0x3, 0x41, 0xfe },
+{ 0x8a, 0x41, 0x0, 0x80, 0x0, 0x80, 0x3d, 0xff, 0x25, 0x0, 0x26, 0x0, 0x24, 0xfc, 0x24, 0xa4, 0x3c, 0xa4, 0x24, 0xa4, 0x27, 0xff, 0x25, 0x44, 0x25, 0x44, 0x3d, 0x44, 0x1, 0xff, 0x0, 0x8, 0x0, 0x38 },
+{ 0x8a, 0x42, 0x10, 0x14, 0x10, 0x12, 0x10, 0x10, 0x7d, 0xff, 0x10, 0x10, 0x11, 0x50, 0x39, 0x52, 0x35, 0x52, 0x33, 0xf6, 0x51, 0x54, 0x51, 0x5c, 0x11, 0x48, 0x11, 0x5d, 0x12, 0x35, 0x10, 0x67, 0x11, 0xc2 },
+{ 0x8a, 0x43, 0x1, 0x0, 0x31, 0x0, 0x1b, 0xfe, 0xa, 0x0, 0x6, 0x0, 0x61, 0xfc, 0x31, 0x24, 0x11, 0x24, 0x1, 0x24, 0x7, 0xff, 0xa, 0x44, 0xa, 0x44, 0x1a, 0x44, 0x13, 0xff, 0x30, 0x8, 0x60, 0x38 },
+{ 0x8a, 0x44, 0x0, 0x0, 0x1f, 0xff, 0x10, 0x0, 0x10, 0x40, 0x10, 0x42, 0x12, 0x46, 0x12, 0x4c, 0x16, 0x48, 0x14, 0x40, 0x10, 0xe0, 0x30, 0xa0, 0x21, 0xb0, 0x21, 0x10, 0x63, 0x18, 0x6, 0xc, 0x1c, 0x7 },
+{ 0x8a, 0x45, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x2, 0x20, 0x6, 0x30, 0x1c, 0x1c, 0x74, 0x17, 0x4, 0x10, 0x4, 0x10, 0xc, 0x10, 0x18, 0x10 },
+{ 0x8a, 0x46, 0x10, 0x40, 0x10, 0x46, 0x1f, 0x7c, 0x10, 0x40, 0x10, 0x41, 0x10, 0x43, 0x1f, 0x7e, 0x70, 0x80, 0x1, 0x0, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8 },
+{ 0x8a, 0x47, 0x8, 0x20, 0x18, 0x70, 0x10, 0x58, 0x64, 0xcc, 0x2d, 0x86, 0x1b, 0x3, 0x10, 0xfc, 0x24, 0x0, 0x7c, 0x0, 0x15, 0xfe, 0x10, 0x40, 0x54, 0x40, 0x54, 0xc4, 0x54, 0x84, 0x10, 0xbe, 0x11, 0xe2 },
+{ 0x8a, 0x48, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x4, 0x90, 0x1, 0xc0, 0x3, 0x60, 0x6, 0x30, 0x1c, 0x1c, 0x74, 0x17, 0x4, 0x10, 0x4, 0x10, 0xc, 0x10, 0x8, 0x10, 0x18, 0x10, 0x30, 0x10 },
+{ 0x8a, 0x49, 0x1c, 0x7e, 0x24, 0x12, 0x7f, 0x32, 0x29, 0x66, 0x3f, 0x28, 0x29, 0x3e, 0x3f, 0x48, 0x21, 0xff, 0x67, 0x8, 0x40, 0x88, 0x3f, 0xfe, 0x20, 0x82, 0x3f, 0xfe, 0x0, 0x84, 0x3, 0xfe, 0x7e, 0x2 },
+{ 0x8a, 0x4a, 0x0, 0x0, 0x3f, 0x7e, 0x21, 0x42, 0x3f, 0x7e, 0x21, 0x42, 0x3f, 0x7e, 0x20, 0x2, 0x2f, 0xf2, 0x22, 0x42, 0x22, 0x42, 0x2f, 0xfa, 0x22, 0x42, 0x22, 0x42, 0x26, 0x42, 0x2c, 0x42, 0x20, 0xe },
+{ 0x8a, 0x4b, 0x1, 0x10, 0x3d, 0x13, 0x25, 0xde, 0x25, 0x10, 0x25, 0x10, 0x29, 0x11, 0x29, 0xcf, 0x2b, 0x10, 0x24, 0x20, 0x25, 0xfe, 0x25, 0x2, 0x25, 0x2, 0x2d, 0xfe, 0x21, 0x2, 0x21, 0x2, 0x21, 0xfe },
+{ 0x8a, 0x4c, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x4, 0x10, 0xc, 0x18, 0x38, 0xe },
+{ 0x8a, 0x4d, 0x4, 0x0, 0x24, 0xbc, 0x24, 0xa4, 0x3f, 0xa4, 0x0, 0x24, 0x7f, 0xe4, 0x0, 0x24, 0x3f, 0xa4, 0x20, 0xa4, 0x20, 0xa4, 0x3f, 0xa4, 0x11, 0x24, 0x11, 0x24, 0xb, 0xa5, 0x1e, 0x65, 0x70, 0xc3 },
+{ 0x8a, 0x4e, 0x4, 0x8, 0x4, 0x8, 0x4, 0x8, 0x7f, 0xc8, 0x8, 0x3f, 0x18, 0x9, 0x31, 0x9, 0x1b, 0x9, 0x6, 0x9, 0xc, 0x89, 0x19, 0x99, 0x63, 0x11, 0x6, 0x13, 0xd, 0x32, 0x18, 0xa2, 0x60, 0x66 },
+{ 0x8a, 0x4f, 0x8, 0x20, 0x8, 0x20, 0xf, 0xa0, 0x8, 0xa0, 0x18, 0xa0, 0x10, 0xb8, 0x30, 0xac, 0x69, 0xa6, 0x5, 0x23, 0x3, 0x21, 0x2, 0x20, 0x6, 0x20, 0xc, 0x20, 0x18, 0x20, 0x30, 0x20, 0x60, 0x20 },
+{ 0x8a, 0x50, 0x0, 0x20, 0x0, 0x20, 0x7c, 0x20, 0x47, 0xff, 0x44, 0x40, 0x44, 0x48, 0x44, 0x88, 0x45, 0x9a, 0x44, 0xd2, 0x44, 0x36, 0x44, 0x64, 0x7c, 0xcc, 0x3, 0x98, 0x0, 0x34, 0x0, 0xe6, 0x7, 0x83 },
+{ 0x8a, 0x51, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x2, 0x20, 0x82, 0x1f, 0xfc, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8 },
+{ 0x8a, 0x52, 0x10, 0x82, 0x10, 0x82, 0x1f, 0xfe, 0x0, 0x0, 0x3f, 0xff, 0x20, 0x0, 0x20, 0x40, 0x27, 0xfc, 0x20, 0x40, 0x2f, 0xfe, 0x20, 0x0, 0x20, 0x40, 0x67, 0xfc, 0x40, 0x40, 0x5f, 0xff, 0x0, 0x0 },
+{ 0x8a, 0x53, 0x10, 0x0, 0x13, 0xbe, 0x12, 0x94, 0x12, 0x94, 0x53, 0x94, 0x5a, 0x94, 0x56, 0x94, 0x53, 0xbf, 0x12, 0x4, 0x12, 0x4, 0x12, 0x8c, 0x12, 0x8c, 0x12, 0xd4, 0x13, 0x55, 0x16, 0x25, 0x10, 0x43 },
+{ 0x8a, 0x54, 0x10, 0x0, 0x13, 0xbe, 0x12, 0x94, 0x12, 0x94, 0x7f, 0x94, 0x12, 0x94, 0x12, 0x94, 0x3b, 0xbf, 0x36, 0x4, 0x32, 0x4, 0x52, 0x8c, 0x12, 0x8c, 0x12, 0xd4, 0x13, 0x55, 0x16, 0x25, 0x10, 0x43 },
+{ 0x8a, 0x55, 0x0, 0x0, 0x33, 0xff, 0x1a, 0x0, 0xa, 0x10, 0x2, 0xfe, 0x62, 0x10, 0x32, 0x10, 0x13, 0xff, 0x2, 0x0, 0x2, 0x10, 0x12, 0xfe, 0x16, 0x10, 0x34, 0x10, 0x2c, 0x10, 0x61, 0xff, 0x0, 0x0 },
+{ 0x8a, 0x56, 0x0, 0xfc, 0x7e, 0x84, 0x8, 0x84, 0x8, 0xfc, 0x18, 0x84, 0x10, 0x84, 0x1e, 0xfc, 0x32, 0x0, 0x33, 0xff, 0x52, 0x4, 0x13, 0xff, 0x12, 0x44, 0x12, 0x24, 0x1e, 0x24, 0x0, 0x4, 0x0, 0x1c },
+{ 0x8a, 0x57, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x7f, 0xff, 0x4, 0x8, 0x8, 0x4, 0x3f, 0xfa, 0x0, 0x0, 0x1f, 0xfc, 0x12, 0x24, 0x12, 0x24, 0x7f, 0xff },
+{ 0x8a, 0x58, 0x9, 0x0, 0x19, 0x1e, 0x17, 0xe0, 0x31, 0x0, 0x61, 0x0, 0x7, 0xe0, 0x8, 0x1f, 0x19, 0x4, 0x31, 0x4, 0x77, 0xe4, 0x11, 0x4, 0x11, 0x4, 0x11, 0x4, 0x11, 0xe4, 0x17, 0x4, 0x10, 0x1c },
+{ 0x8a, 0x59, 0x0, 0x10, 0x3c, 0x10, 0x0, 0x10, 0x7e, 0xff, 0x0, 0x20, 0x3c, 0x60, 0x0, 0xc4, 0x0, 0x6c, 0x3c, 0x18, 0x0, 0x32, 0x0, 0x66, 0x3c, 0xcc, 0x24, 0x18, 0x24, 0x34, 0x24, 0x66, 0x3c, 0xc3 },
+{ 0x8a, 0x5a, 0x10, 0x10, 0x38, 0x92, 0x2c, 0x92, 0x66, 0xfe, 0x40, 0x0, 0x7d, 0xff, 0x10, 0x0, 0x10, 0xfe, 0x7c, 0x82, 0x10, 0x82, 0x54, 0xfe, 0x54, 0x44, 0x50, 0x6c, 0x1c, 0x28, 0x31, 0xff, 0x60, 0x0 },
+{ 0x8a, 0x5b, 0x0, 0x10, 0x3e, 0x10, 0x22, 0x10, 0x2e, 0xff, 0x2a, 0x10, 0x2a, 0x30, 0x7f, 0x64, 0x41, 0x2c, 0x3e, 0x18, 0x22, 0x32, 0x3e, 0x66, 0x22, 0xcc, 0x3e, 0x18, 0x22, 0x34, 0x22, 0x66, 0x26, 0xc3 },
+{ 0x8a, 0x5c, 0x0, 0x0, 0x33, 0xfe, 0x1a, 0x22, 0xa, 0x22, 0x3, 0xfe, 0x62, 0x22, 0x32, 0x22, 0x12, 0x22, 0x3, 0xfe, 0x8, 0x20, 0x18, 0x20, 0x13, 0xfe, 0x30, 0x20, 0x20, 0x20, 0x67, 0xff, 0x0, 0x0 },
+{ 0x8a, 0x5d, 0x8, 0x3c, 0x7f, 0xa4, 0x8, 0x47, 0x7f, 0xbc, 0x29, 0x24, 0x3f, 0x18, 0x20, 0x34, 0x4f, 0xe3, 0x0, 0x80, 0x7f, 0xff, 0x4, 0x90, 0x1f, 0xfc, 0x68, 0xb, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8 },
+{ 0x8a, 0x5e, 0x10, 0x10, 0x10, 0x10, 0x10, 0xfe, 0x7e, 0x10, 0x52, 0x10, 0x52, 0x10, 0x53, 0xff, 0x52, 0x0, 0x7e, 0x10, 0x10, 0x10, 0x14, 0xfe, 0x14, 0x10, 0x1e, 0x10, 0x32, 0x10, 0x61, 0xff, 0x0, 0x0 },
+{ 0x8a, 0x5f, 0x10, 0x0, 0x13, 0xfe, 0x10, 0x0, 0x10, 0x0, 0x7d, 0xfc, 0x11, 0x4, 0x11, 0x4, 0x11, 0xfc, 0x11, 0x4, 0x11, 0x4, 0x1d, 0x4, 0x71, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, 0x0, 0x0 },
+{ 0x8a, 0x60, 0x8, 0x20, 0x8, 0x20, 0x8, 0x20, 0x7f, 0xff, 0x8, 0x20, 0x8, 0x20, 0x19, 0xfe, 0x1d, 0x22, 0x1b, 0x22, 0x29, 0x22, 0x29, 0x22, 0x49, 0x22, 0x9, 0x2e, 0x8, 0x20, 0x8, 0x20, 0x8, 0x20 },
+{ 0x8a, 0x61, 0x10, 0x0, 0x11, 0xff, 0x11, 0x0, 0x7d, 0x0, 0x55, 0xff, 0x55, 0x20, 0x55, 0x20, 0x55, 0x3e, 0x7d, 0x22, 0x11, 0x22, 0x15, 0x22, 0x1d, 0x22, 0x37, 0x62, 0x62, 0x46, 0x6, 0xc4, 0x1, 0x9c },
+{ 0x8a, 0x62, 0x10, 0x40, 0x38, 0x40, 0x2c, 0x40, 0x64, 0xfe, 0x40, 0x82, 0x7d, 0x82, 0x10, 0x42, 0x10, 0x42, 0x7c, 0xd2, 0x10, 0x92, 0x54, 0xfa, 0x55, 0x8a, 0x50, 0x2, 0x1c, 0x6, 0x30, 0x4, 0x60, 0x1c },
+{ 0x8a, 0x63, 0x4, 0x2, 0x3f, 0x92, 0x4, 0x92, 0x7f, 0xd2, 0x4, 0x92, 0x3f, 0x92, 0x4, 0x12, 0x3f, 0x92, 0x4, 0x12, 0x7f, 0xd2, 0x24, 0x92, 0x3f, 0x82, 0x24, 0x82, 0x3f, 0x82, 0x0, 0x2, 0x7f, 0xce },
+{ 0x8a, 0x64, 0x1, 0x8, 0x1, 0x8, 0x77, 0xfe, 0x51, 0x8, 0x51, 0x8, 0x51, 0x8, 0x5f, 0xff, 0x52, 0x94, 0x52, 0xd4, 0x5a, 0xb6, 0x7a, 0xb5, 0xa, 0xd5, 0x12, 0x94, 0x4, 0xa4, 0x4, 0xa4, 0x9, 0xcc },
+{ 0x8a, 0x65, 0x2, 0x0, 0x2, 0x0, 0x7, 0xf0, 0xc, 0x10, 0x1e, 0x30, 0x73, 0x60, 0x1, 0xc0, 0x3, 0x60, 0xe, 0x38, 0x78, 0xf, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8 },
+{ 0x8a, 0x66, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xff, 0x22, 0x0, 0x3f, 0xde, 0x20, 0x12, 0x2f, 0x92, 0x28, 0x94, 0x2f, 0x94, 0x20, 0x12, 0x3f, 0x92, 0x21, 0x12, 0x63, 0xd2, 0x5e, 0x16, 0x42, 0x10, 0xe, 0x10 },
+{ 0x8a, 0x67, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x11, 0xff, 0x7d, 0x0, 0x11, 0x10, 0x11, 0x10, 0x11, 0x10, 0x1d, 0x30, 0x71, 0x24, 0x11, 0x24, 0x11, 0x26, 0x11, 0x62, 0x13, 0x42, 0x12, 0x4f, 0x36, 0xf9 },
+{ 0x8a, 0x68, 0x12, 0x42, 0x13, 0x66, 0x11, 0x24, 0x17, 0xff, 0x7c, 0x1, 0x15, 0xfd, 0x11, 0x4, 0x11, 0xfc, 0x19, 0x4, 0x71, 0xfc, 0x11, 0x4, 0x11, 0xfc, 0x10, 0x90, 0x10, 0x91, 0x11, 0x93, 0x37, 0xe },
+{ 0x8a, 0x69, 0x10, 0x40, 0x10, 0x40, 0x10, 0xfc, 0x7c, 0x84, 0x11, 0xcc, 0x13, 0x58, 0x38, 0x30, 0x34, 0x78, 0x30, 0xcc, 0x53, 0x87, 0x50, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0xfc },
+{ 0x8a, 0x6a, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10, 0x7f, 0xff, 0x8, 0x20, 0x8, 0x60, 0x18, 0xc4, 0x1c, 0x6c, 0x1a, 0x18, 0x28, 0x32, 0x28, 0x66, 0x49, 0xcc, 0x8, 0x18, 0x8, 0x34, 0x8, 0x66, 0x9, 0xc3 },
+{ 0x8a, 0x6b, 0x8, 0x0, 0x8, 0x3c, 0x7f, 0x24, 0x8, 0x24, 0x8, 0x24, 0x3e, 0x47, 0x0, 0x0, 0x7f, 0x7e, 0x41, 0x22, 0x5d, 0x26, 0x14, 0x24, 0x14, 0x2c, 0x35, 0x18, 0x26, 0x3c, 0x6c, 0x66, 0x40, 0xc3 },
+{ 0x8a, 0x6c, 0x4, 0x48, 0x47, 0xff, 0x28, 0x48, 0x10, 0x90, 0x11, 0xff, 0x2b, 0x10, 0x4d, 0xfe, 0x9, 0x10, 0x19, 0xfe, 0x29, 0x10, 0x49, 0xff, 0x8, 0x0, 0xb, 0xfe, 0x8, 0x4c, 0x18, 0x30, 0x73, 0xcf },
+{ 0x8a, 0x6d, 0x0, 0x10, 0x0, 0x10, 0x7e, 0xff, 0x8, 0x91, 0x8, 0xb5, 0x18, 0x28, 0x10, 0x7f, 0x1e, 0xc8, 0x33, 0x48, 0x32, 0x7e, 0x52, 0x48, 0x12, 0x48, 0x12, 0x7e, 0x12, 0x48, 0x1e, 0x48, 0x0, 0x7f },
+{ 0x8a, 0x6e, 0x4, 0x44, 0x1b, 0xff, 0x70, 0x44, 0x10, 0x90, 0x11, 0xff, 0x7f, 0x10, 0x11, 0xfe, 0x39, 0x10, 0x35, 0xfe, 0x35, 0x10, 0x51, 0xff, 0x50, 0x0, 0x13, 0xfe, 0x10, 0x84, 0x10, 0x78, 0x13, 0x87 },
+{ 0x8a, 0x6f, 0x11, 0x4, 0x19, 0x8c, 0x8, 0x88, 0x3f, 0xfe, 0x20, 0x2, 0x2f, 0xfa, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x2, 0x20, 0x6, 0x21, 0x1c, 0x33, 0x70, 0x1e },
+{ 0x8a, 0x70, 0x2, 0x0, 0x7, 0xf0, 0xc, 0x20, 0x18, 0x40, 0x6f, 0xfc, 0x8, 0x84, 0x8, 0x84, 0xf, 0xfc, 0x8, 0x84, 0x8, 0x84, 0xf, 0xfc, 0x8, 0x4, 0x18, 0x4, 0x10, 0x4, 0x30, 0x4, 0x60, 0x1c },
+{ 0x8a, 0x71, 0x4, 0x10, 0x4, 0x10, 0x3f, 0x7e, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0xa, 0x28, 0x2b, 0x6a, 0x2a, 0xaa, 0x6a, 0xab, 0x4a, 0x29, 0xa, 0x28, 0x1a, 0x68, 0x12, 0x48, 0x36, 0xd8 },
+{ 0x8a, 0x72, 0x8, 0x10, 0x8, 0x10, 0x7e, 0x10, 0x9, 0xff, 0x3e, 0x44, 0x2a, 0xc6, 0x2b, 0x83, 0x3e, 0x44, 0x2a, 0x6c, 0x2a, 0x28, 0x3e, 0x38, 0x8, 0x10, 0x7f, 0x38, 0x8, 0x6c, 0x8, 0xc6, 0x9, 0x83 },
+{ 0x8a, 0x73, 0x4, 0x0, 0x4, 0x1e, 0x7f, 0xd2, 0x0, 0x12, 0x3f, 0x92, 0x20, 0x94, 0x3f, 0x94, 0x0, 0x12, 0x7f, 0x92, 0x3, 0x12, 0xc, 0x12, 0x7, 0xd2, 0x7c, 0x12, 0x4, 0x16, 0x4, 0x10, 0x1c, 0x10 },
+{ 0x8a, 0x74, 0x0, 0x0, 0x3f, 0x7e, 0x21, 0x42, 0x3f, 0x7e, 0x21, 0x42, 0x3f, 0x7e, 0x21, 0x2, 0x23, 0xe2, 0x26, 0x42, 0x21, 0x82, 0x23, 0x62, 0x2c, 0x1a, 0x23, 0xe2, 0x22, 0x22, 0x23, 0xe2, 0x20, 0xe },
+{ 0x8a, 0x75, 0x0, 0x0, 0x3d, 0xfe, 0x24, 0x0, 0x24, 0xfc, 0x24, 0x84, 0x28, 0xfc, 0x28, 0x0, 0x25, 0xfe, 0x25, 0x52, 0x25, 0x52, 0x25, 0x8e, 0x25, 0x2, 0x2d, 0x7a, 0x21, 0x22, 0x21, 0x22, 0x21, 0x26 },
+{ 0x8a, 0x76, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x4, 0x10, 0x7, 0xf0, 0x0, 0x80, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80 },
+{ 0x8a, 0x77, 0x11, 0x4, 0x19, 0x8c, 0x8, 0x88, 0x3f, 0xfe, 0x20, 0x2, 0x20, 0x2, 0xf, 0xf8, 0x0, 0x30, 0x0, 0x40, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x3, 0x80 },
+{ 0x8a, 0x78, 0x0, 0x18, 0x0, 0xf0, 0xf, 0x80, 0x8, 0x0, 0xf, 0xfe, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x0, 0x0 },
+{ 0x8a, 0x79, 0x0, 0x80, 0x31, 0x6, 0x1b, 0xec, 0x2, 0x20, 0x2, 0x20, 0x3, 0xe0, 0x2, 0x20, 0x1a, 0x2c, 0x33, 0xe6, 0x0, 0x80, 0x7f, 0xff, 0x2, 0xa0, 0x6, 0xb0, 0x1c, 0x9c, 0x70, 0x87, 0x0, 0x80 },
+{ 0x8a, 0x7a, 0x8, 0x0, 0x8, 0xff, 0x7f, 0x10, 0x41, 0x7e, 0x51, 0x42, 0x1e, 0x42, 0x22, 0x7e, 0x54, 0x42, 0x8, 0x42, 0x14, 0x7e, 0x63, 0x42, 0x3e, 0x42, 0x22, 0x7e, 0x22, 0x24, 0x3e, 0x66, 0x0, 0xc3 },
+{ 0x8a, 0x7b, 0x0, 0x0, 0x77, 0x7f, 0x55, 0x8, 0x55, 0x3e, 0x77, 0x22, 0x0, 0x22, 0x3e, 0x3e, 0x0, 0x22, 0x7f, 0x22, 0x8, 0x3e, 0x10, 0x22, 0x3e, 0x22, 0x2, 0x3e, 0x2, 0x14, 0x6, 0x36, 0x1c, 0x63 },
+{ 0x8a, 0x7c, 0x10, 0x84, 0x10, 0x84, 0x13, 0xe4, 0x10, 0x84, 0x78, 0x84, 0x17, 0xf4, 0x10, 0x6, 0x10, 0x85, 0x18, 0x85, 0x73, 0xe4, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0xf4, 0x17, 0x84, 0x30, 0x4 },
+{ 0x8a, 0x7d, 0x8, 0x10, 0x8, 0x10, 0x1f, 0xbf, 0x24, 0x28, 0x42, 0x44, 0x2, 0x84, 0x0, 0x80, 0x3f, 0xfe, 0x0, 0x0, 0x8, 0x8, 0xc, 0x18, 0x4, 0x10, 0x4, 0x30, 0x0, 0x20, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x8a, 0x7e, 0x10, 0x0, 0x13, 0xc0, 0x12, 0xbe, 0x7e, 0x92, 0x13, 0xd6, 0x12, 0x5c, 0x1b, 0xc8, 0x36, 0x9c, 0x32, 0xb6, 0x33, 0xc3, 0x50, 0x20, 0x11, 0xfe, 0x10, 0x20, 0x10, 0x20, 0x13, 0xff, 0x10, 0x0 },
+{ 0x8a, 0x80, 0x10, 0x0, 0x13, 0xff, 0x10, 0x0, 0x7d, 0xfc, 0x11, 0x24, 0x11, 0xfc, 0x31, 0x24, 0x3b, 0xff, 0x34, 0x0, 0x51, 0xfc, 0x51, 0x24, 0x11, 0xfc, 0x11, 0x24, 0x11, 0xfc, 0x10, 0x0, 0x13, 0xff },
+{ 0x8a, 0x81, 0x10, 0x0, 0x13, 0xfe, 0x12, 0x2, 0x7e, 0x2, 0x13, 0xfe, 0x12, 0x0, 0x3a, 0x1c, 0x36, 0xf0, 0x32, 0x20, 0x53, 0xfe, 0x52, 0x20, 0x13, 0xff, 0x12, 0x20, 0x12, 0x21, 0x14, 0x33, 0x10, 0x1e },
+{ 0x8a, 0x82, 0x20, 0x28, 0x3c, 0xe8, 0x27, 0x89, 0x48, 0xa9, 0x7c, 0xab, 0x57, 0xea, 0x54, 0xaa, 0x7c, 0x88, 0x55, 0xc8, 0x56, 0xa8, 0x7c, 0x9c, 0x0, 0x94, 0x0, 0x94, 0x54, 0x96, 0x54, 0xb2, 0x40, 0xa3 },
+{ 0x8a, 0x83, 0x0, 0x60, 0x31, 0xce, 0x19, 0x2, 0x9, 0x2, 0x1, 0xce, 0x61, 0x2, 0x31, 0x2, 0x11, 0xfe, 0x0, 0x80, 0x9, 0xff, 0xb, 0x1, 0x1e, 0x5, 0x11, 0x55, 0x31, 0x53, 0x22, 0x2, 0x60, 0xe },
+{ 0x8a, 0x84, 0x4, 0x2, 0x4, 0x12, 0x7f, 0xd2, 0x40, 0x52, 0x44, 0x52, 0x3f, 0x92, 0x4, 0x12, 0x3f, 0x92, 0x4, 0x12, 0x7f, 0xd2, 0x0, 0x12, 0x3f, 0x82, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x3f, 0x8e },
+{ 0x8a, 0x85, 0x1, 0xfc, 0x1, 0x4, 0x79, 0x4, 0x49, 0xfc, 0x49, 0x4, 0x49, 0x4, 0x49, 0xfc, 0x48, 0x80, 0x48, 0xff, 0x49, 0x81, 0x7b, 0x19, 0x7, 0xf1, 0x1, 0x1, 0x1, 0xb, 0x0, 0xfa, 0x0, 0x6 },
+{ 0x8a, 0x86, 0x10, 0x20, 0x10, 0x70, 0x10, 0x50, 0x18, 0xd8, 0x55, 0x8c, 0x53, 0x6, 0x56, 0x3, 0x51, 0xfc, 0x10, 0x0, 0x10, 0x0, 0x11, 0xfc, 0x11, 0x4, 0x11, 0x4, 0x11, 0x4, 0x11, 0x4, 0x11, 0xfc },
+{ 0x8a, 0x87, 0x8, 0x6, 0x8, 0x1c, 0x9, 0xf0, 0x8, 0x10, 0x7e, 0x10, 0x8, 0x10, 0x9, 0xff, 0x8, 0x10, 0xe, 0x10, 0x78, 0x10, 0x8, 0xfe, 0x8, 0x82, 0x8, 0x82, 0x8, 0x82, 0x8, 0x82, 0x38, 0xfe },
+{ 0x8a, 0x88, 0x0, 0x6, 0x30, 0x3c, 0x1b, 0xe0, 0x8, 0x20, 0x0, 0x20, 0x60, 0x20, 0x37, 0xff, 0x10, 0x20, 0x0, 0x20, 0x8, 0x20, 0xb, 0xfe, 0x1a, 0x2, 0x12, 0x2, 0x32, 0x2, 0x22, 0x2, 0x63, 0xfe },
+{ 0x8a, 0x89, 0x31, 0xfc, 0x19, 0x4, 0x9, 0x4, 0x1, 0xfc, 0x1, 0x4, 0x61, 0x4, 0x31, 0xfc, 0x10, 0x80, 0x0, 0xff, 0x9, 0x81, 0xb, 0x19, 0x1f, 0xf1, 0x11, 0x1, 0x31, 0xb, 0x20, 0xfa, 0x60, 0x6 },
+{ 0x8a, 0x8a, 0x31, 0xfc, 0x19, 0x4, 0x9, 0x3c, 0x1, 0x24, 0x1, 0x24, 0x67, 0xff, 0x34, 0x1, 0x14, 0x1, 0x1, 0xfc, 0x9, 0x4, 0x9, 0xfc, 0x19, 0x4, 0x11, 0xfc, 0x31, 0x4, 0x21, 0x4, 0x61, 0x1c },
+{ 0x8a, 0x8b, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x4, 0x0, 0xf, 0xfe, 0x18, 0x2, 0x6f, 0x82, 0x8, 0x26, 0x7, 0xe4, 0x0, 0x1c },
+{ 0x8a, 0x8c, 0x10, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x7c, 0xfc, 0x4, 0x84, 0xc, 0x84, 0x8, 0xfc, 0x1a, 0x40, 0x34, 0x7f, 0x58, 0xc1, 0x15, 0x99, 0x12, 0xf1, 0x10, 0x81, 0x10, 0x8b, 0x10, 0x7a, 0x10, 0x6 },
+{ 0x8a, 0x8d, 0x8, 0x10, 0x8, 0x10, 0x7f, 0xff, 0x8, 0x81, 0x3e, 0x91, 0x2a, 0x7e, 0x2a, 0x10, 0x3e, 0x7e, 0x2a, 0x10, 0x2a, 0xff, 0x3e, 0x0, 0x8, 0x7e, 0x7f, 0x42, 0x8, 0x42, 0x8, 0x42, 0x8, 0x7e },
+{ 0x8a, 0x8e, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x8a, 0x8f, 0x20, 0x0, 0x3d, 0xe0, 0x25, 0x5e, 0x49, 0x4a, 0x7d, 0xea, 0x55, 0x2e, 0x55, 0xe4, 0x7d, 0x4e, 0x55, 0x5a, 0x55, 0xe3, 0x7c, 0x10, 0x0, 0xfe, 0x55, 0x10, 0x54, 0x10, 0x41, 0xff, 0x0, 0x0 },
+{ 0x8a, 0x90, 0x0, 0x20, 0x0, 0x20, 0x78, 0x20, 0x48, 0x20, 0x48, 0x20, 0x48, 0x20, 0x4b, 0xff, 0x48, 0x20, 0x48, 0x20, 0x48, 0x20, 0x48, 0x20, 0x78, 0x20, 0x0, 0x20, 0x0, 0x20, 0x0, 0x20, 0x0, 0x20 },
+{ 0x8a, 0x91, 0x10, 0x88, 0x10, 0x88, 0x13, 0xff, 0x7c, 0x88, 0x10, 0x88, 0x10, 0x50, 0x38, 0xd0, 0x34, 0x93, 0x31, 0x96, 0x53, 0x9c, 0x56, 0x90, 0x10, 0x90, 0x10, 0x90, 0x10, 0x91, 0x10, 0x93, 0x10, 0x8e },
+{ 0x8a, 0x92, 0x10, 0x88, 0x10, 0x88, 0x17, 0xff, 0x78, 0x88, 0x13, 0xfe, 0x11, 0x24, 0x39, 0x24, 0x37, 0xff, 0x31, 0x24, 0x51, 0x24, 0x53, 0xfe, 0x10, 0x20, 0x17, 0xff, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20 },
+{ 0x8a, 0x93, 0x22, 0x20, 0x22, 0x20, 0x7f, 0x20, 0x22, 0x7e, 0x22, 0x42, 0x3e, 0xfa, 0x8, 0xa, 0x7f, 0xa, 0x49, 0x7a, 0x49, 0x46, 0x7f, 0x44, 0x8, 0x5c, 0x7f, 0x40, 0x8, 0x41, 0x8, 0x63, 0x8, 0x3e },
+{ 0x8a, 0x94, 0x10, 0x20, 0x11, 0x20, 0x11, 0x20, 0x7d, 0x20, 0x13, 0xfe, 0x1a, 0x20, 0x34, 0x20, 0x30, 0x20, 0x37, 0xff, 0x50, 0xa8, 0x50, 0xa8, 0x11, 0xac, 0x11, 0x24, 0x13, 0x26, 0x16, 0x23, 0x10, 0x20 },
+{ 0x8a, 0x95, 0x4, 0x80, 0xd, 0xe, 0x3b, 0xe2, 0x22, 0x22, 0x22, 0x22, 0x23, 0xe2, 0x22, 0x22, 0x22, 0x22, 0x3b, 0xee, 0x0, 0x0, 0x2, 0x40, 0x2, 0x40, 0x6, 0x40, 0xc, 0x41, 0x18, 0x63, 0x70, 0x3e },
+{ 0x8a, 0x96, 0x0, 0x80, 0x3f, 0xfe, 0x24, 0x8a, 0x7b, 0xef, 0x0, 0x80, 0x7f, 0xff, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x84, 0x3f, 0xfe, 0x20, 0x82, 0x3f, 0xfe, 0x20, 0x82, 0x3f, 0xfe, 0x0, 0x81, 0x0, 0x7f },
+{ 0x8a, 0x97, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x14, 0x20, 0x22, 0x37, 0xff, 0x10, 0x20, 0x43, 0xfe, 0x62, 0x22, 0x23, 0xfe, 0x2, 0x22, 0x13, 0xfe, 0x12, 0x22, 0x32, 0x22, 0x22, 0x22, 0x62, 0x26 },
+{ 0x8a, 0x98, 0x2, 0x40, 0x6, 0x60, 0xc, 0x38, 0x3b, 0x6e, 0x1, 0xc0, 0x3, 0x60, 0xe, 0x38, 0x7b, 0xef, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x8, 0x88, 0xc, 0x98, 0x4, 0x90, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x8a, 0x99, 0x10, 0x84, 0x38, 0x48, 0x2f, 0xff, 0x64, 0x50, 0x41, 0xfe, 0x7c, 0x52, 0x10, 0x52, 0x13, 0xff, 0x7c, 0x52, 0x10, 0x52, 0x55, 0xfe, 0x54, 0x58, 0x50, 0xd4, 0x1d, 0x56, 0x72, 0x53, 0x0, 0x50 },
+{ 0x8a, 0x9a, 0x0, 0x20, 0x1, 0x20, 0x79, 0x3e, 0x49, 0x20, 0x49, 0x20, 0x4f, 0xff, 0x4a, 0x2, 0x4a, 0xaa, 0x4a, 0x22, 0x4a, 0xfa, 0x4a, 0x22, 0x7a, 0x72, 0x2, 0xaa, 0x2, 0x22, 0x2, 0x2, 0x3, 0xfe },
+{ 0x8a, 0x9b, 0x0, 0x10, 0x7e, 0x20, 0x52, 0xfe, 0x52, 0x82, 0x52, 0xfe, 0x7e, 0x82, 0x52, 0xfe, 0x52, 0x80, 0x52, 0xff, 0x7e, 0x80, 0x10, 0xff, 0x10, 0x1, 0x11, 0x55, 0x13, 0x55, 0x12, 0x3, 0x10, 0x6 },
+{ 0x8a, 0x9c, 0x8, 0x0, 0x9, 0xff, 0x8, 0x10, 0x7e, 0x30, 0x8, 0x20, 0x8, 0xfe, 0x1c, 0x82, 0x1a, 0x82, 0x1a, 0x82, 0x28, 0x82, 0x28, 0xfe, 0x48, 0x82, 0x8, 0x82, 0x8, 0x82, 0x8, 0x82, 0x8, 0xfe },
+{ 0x8a, 0x9d, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x1f, 0xfc, 0x0, 0x18, 0x2, 0x20, 0x1, 0x40, 0x7f, 0xff, 0x1, 0x42, 0x3, 0x44, 0x6, 0x40, 0xc, 0x40, 0x18, 0x40, 0x70, 0x40, 0x1, 0xc0 },
+{ 0x8a, 0x9e, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x2, 0x2f, 0xfa, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x0, 0x0, 0x7f, 0xff },
+{ 0x8a, 0x9f, 0x0, 0x0, 0x78, 0x9e, 0xa, 0xa2, 0xa, 0xa2, 0xa, 0xa2, 0x38, 0x8e, 0x27, 0xf8, 0x20, 0x88, 0x39, 0xce, 0x9, 0xc2, 0xa, 0xa2, 0xa, 0xa2, 0xc, 0x92, 0x18, 0x86, 0x10, 0x84, 0x70, 0x1c },
+{ 0x8a, 0xa0, 0x0, 0x82, 0x0, 0x92, 0x0, 0x92, 0x0, 0x92, 0x31, 0x92, 0x19, 0x12, 0xd, 0x12, 0x7, 0x12, 0x2, 0x12, 0x7, 0x12, 0x5, 0x92, 0xc, 0x82, 0x8, 0xc2, 0x18, 0x42, 0x30, 0x2, 0x60, 0xe },
+{ 0x8a, 0xa1, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x4, 0x10, 0x0, 0x82, 0x30, 0x92, 0x19, 0x92, 0xd, 0x12, 0x7, 0x12, 0x2, 0x12, 0x7, 0x12, 0xd, 0x82, 0x18, 0xc2, 0x30, 0x42, 0x60, 0xe },
+{ 0x8a, 0xa2, 0x0, 0x0, 0x7f, 0xff, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x7, 0xf0, 0x4, 0x10, 0x4, 0x10, 0x5, 0x10, 0x5, 0x90, 0xc, 0x90, 0x8, 0x10, 0x8, 0x10, 0x9, 0xd1, 0x1f, 0x1b, 0x70, 0xe },
+{ 0x8a, 0xa3, 0x8, 0x40, 0x8, 0x40, 0x7f, 0x40, 0x8, 0xff, 0x3e, 0x80, 0x23, 0x80, 0x22, 0x7e, 0x3e, 0xc, 0x22, 0x18, 0x22, 0x10, 0x3e, 0x30, 0x8, 0x20, 0x7f, 0x60, 0x8, 0x41, 0x8, 0x63, 0x8, 0x3e },
+{ 0x8a, 0xa4, 0x8, 0x0, 0xb, 0xfe, 0xa, 0x2, 0x1a, 0x2, 0x12, 0x2, 0x33, 0xfe, 0x30, 0x0, 0x51, 0x24, 0x11, 0x24, 0x11, 0x24, 0x11, 0x24, 0x11, 0x24, 0x11, 0x24, 0x13, 0x25, 0x12, 0x25, 0x16, 0x3 },
+{ 0x8a, 0xa5, 0x0, 0x0, 0x3f, 0xfe, 0x20, 0x2, 0x20, 0x2, 0x3f, 0x4, 0x0, 0x4, 0x0, 0x7f, 0x7f, 0x84, 0x12, 0x24, 0x12, 0x34, 0x12, 0x14, 0x12, 0x4, 0x12, 0x4, 0x32, 0x1d, 0x23, 0x3, 0x61, 0xfe },
+{ 0x8a, 0xa6, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x2, 0x22, 0x22, 0x1f, 0xfc, 0x2, 0x20, 0x1f, 0xfc, 0x2, 0x20, 0x7f, 0xff, 0x4, 0x10, 0x1d, 0xdc, 0x70, 0x67, 0x7, 0x0, 0x1, 0xe0, 0x0, 0x30 },
+{ 0x8a, 0xa7, 0x0, 0x2, 0x3f, 0x92, 0x4, 0x12, 0x4, 0x12, 0x4, 0x12, 0x4, 0x12, 0x7f, 0xd2, 0x4, 0x12, 0x4, 0x12, 0x4, 0x12, 0x4, 0x12, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0xe },
+{ 0x8a, 0xa8, 0x11, 0x8, 0x11, 0x8, 0x7f, 0xc8, 0x11, 0x8, 0x1f, 0x3f, 0x11, 0x9, 0x1f, 0x9, 0x11, 0x9, 0x7f, 0xc9, 0x2a, 0x9, 0x2a, 0x19, 0x2b, 0x91, 0x30, 0x13, 0x20, 0x32, 0x3f, 0xa2, 0x0, 0x6e },
+{ 0x8a, 0xa9, 0x10, 0x8, 0x10, 0x8, 0x3f, 0xc8, 0x24, 0x8, 0x44, 0x3f, 0x3f, 0xc9, 0x9, 0x9, 0x12, 0x9, 0x3f, 0xc9, 0x52, 0x19, 0x1f, 0x91, 0x12, 0x11, 0x1f, 0xb3, 0x12, 0x22, 0x1f, 0xe2, 0x0, 0x4e },
+{ 0x8a, 0xaa, 0x8, 0x88, 0xc, 0x98, 0x4, 0x90, 0x1f, 0xfc, 0x1, 0x40, 0x2, 0x20, 0x7f, 0xff, 0x4, 0x10, 0xf, 0xf8, 0x18, 0x2c, 0x70, 0x27, 0x7, 0xe0, 0x4, 0x0, 0x4, 0x4, 0x6, 0xc, 0x3, 0xf8 },
+{ 0x8a, 0xab, 0x0, 0x80, 0x0, 0xf8, 0x79, 0x88, 0x49, 0x10, 0x4b, 0xfe, 0x49, 0x52, 0x49, 0x52, 0x49, 0x52, 0x49, 0x5e, 0x49, 0x82, 0x49, 0x22, 0x7b, 0xff, 0x0, 0x50, 0x0, 0xd8, 0x1, 0x8c, 0x7, 0x7 },
+{ 0x8a, 0xac, 0x10, 0x84, 0x10, 0x84, 0x13, 0xff, 0x10, 0x84, 0x7c, 0xfc, 0x10, 0x84, 0x10, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x13, 0xff, 0x11, 0x28, 0x1d, 0x28, 0x71, 0x4f, 0x1, 0x80, 0x1, 0x0, 0x1, 0xff },
+{ 0x8a, 0xad, 0x1, 0x0, 0x1, 0x0, 0x3f, 0xfe, 0x2, 0x10, 0x4, 0x20, 0xf, 0xe0, 0x1, 0x3c, 0x3e, 0x6, 0x8, 0x10, 0x7f, 0xff, 0x11, 0x22, 0x23, 0x46, 0x3a, 0x74, 0xe, 0x1c, 0x1b, 0x36, 0x71, 0x63 },
+{ 0x8a, 0xae, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x2, 0x20, 0x2, 0xf, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xff, 0x2, 0x20, 0x2, 0x20, 0x6, 0x20, 0x4, 0x20, 0xc, 0x21, 0x18, 0x33, 0x70, 0x1e },
+{ 0x8a, 0xaf, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x40, 0x1, 0x40, 0x1, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x0, 0x8, 0x0, 0xf, 0xfc, 0x8, 0x4, 0x8, 0x4, 0x8, 0x4, 0xf, 0xfc },
+{ 0x8a, 0xb0, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x42, 0x21, 0x5f, 0xfd, 0x2, 0x20, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x2, 0x21, 0xe, 0x23, 0x78, 0x1e },
+{ 0x8a, 0xb1, 0x0, 0x0, 0x3f, 0xfe, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80 },
+{ 0x8a, 0xb2, 0x8, 0x10, 0x8, 0x38, 0x7f, 0x28, 0x8, 0x6c, 0x3e, 0xc6, 0x23, 0x83, 0x22, 0x7c, 0x3e, 0x10, 0x22, 0x10, 0x22, 0x10, 0x3e, 0xff, 0x8, 0x10, 0x7f, 0x10, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10 },
+{ 0x8a, 0xb3, 0x0, 0x80, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x0, 0x80, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x40, 0x12, 0x66, 0x12, 0x2b, 0x33, 0x19, 0x61, 0xf0 },
+{ 0x8a, 0xb4, 0x0, 0x28, 0x0, 0x24, 0x3f, 0xff, 0x20, 0x20, 0x2f, 0xa4, 0x20, 0x2c, 0x2f, 0xb8, 0x28, 0x90, 0x2f, 0xb9, 0x60, 0x6d, 0x40, 0x7, 0x1, 0x80, 0x14, 0xc6, 0x14, 0x4b, 0x36, 0x19, 0x63, 0xf0 },
+{ 0x8a, 0xb5, 0x10, 0x0, 0x11, 0xfe, 0x11, 0x22, 0x13, 0xff, 0x59, 0x22, 0x55, 0xfe, 0x50, 0x0, 0x51, 0xfe, 0x11, 0x2, 0x11, 0xfe, 0x11, 0x2, 0x11, 0xfe, 0x11, 0x2, 0x11, 0xfe, 0x10, 0x84, 0x13, 0x3 },
+{ 0x8a, 0xb6, 0x10, 0x14, 0x10, 0x12, 0x13, 0xff, 0x12, 0x10, 0x52, 0xfa, 0x5a, 0xa, 0x56, 0xee, 0x52, 0xa4, 0x12, 0xed, 0x12, 0x17, 0x14, 0x2, 0x10, 0x20, 0x12, 0xb6, 0x12, 0x93, 0x16, 0x85, 0x14, 0x7c },
+{ 0x8a, 0xb7, 0x11, 0x0, 0x11, 0xf8, 0x13, 0x8, 0x7a, 0x10, 0x17, 0xfe, 0x12, 0x52, 0x12, 0x52, 0x12, 0x52, 0x1a, 0x9e, 0x73, 0x2, 0x12, 0x22, 0x17, 0xff, 0x10, 0x50, 0x10, 0xd8, 0x11, 0x8c, 0x37, 0x7 },
+{ 0x8a, 0xb8, 0x0, 0x10, 0x3f, 0x90, 0x4, 0x10, 0x4, 0x3f, 0x7f, 0xe2, 0x11, 0x22, 0x11, 0x72, 0x1f, 0x16, 0x11, 0x14, 0x11, 0x1c, 0x1f, 0x8, 0x11, 0x1c, 0x11, 0x14, 0x1f, 0x36, 0x71, 0x22, 0x1, 0x63 },
+{ 0x8a, 0xb9, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x7c, 0x84, 0x13, 0xff, 0x10, 0x84, 0x38, 0x84, 0x34, 0x84, 0x34, 0x84, 0x50, 0xfc, 0x50, 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0xfc },
+{ 0x8a, 0xba, 0x10, 0x0, 0x13, 0xfe, 0x10, 0x0, 0x7c, 0x0, 0x11, 0xfc, 0x11, 0x4, 0x39, 0x4, 0x35, 0xfc, 0x35, 0x4, 0x51, 0x4, 0x51, 0x4, 0x11, 0xfc, 0x10, 0x0, 0x10, 0x0, 0x17, 0xff, 0x10, 0x0 },
+{ 0x8a, 0xbb, 0x10, 0x20, 0x10, 0x20, 0x13, 0xff, 0x7e, 0x1, 0x12, 0x1, 0x10, 0xfc, 0x38, 0x84, 0x34, 0x84, 0x34, 0xfc, 0x50, 0x80, 0x50, 0x80, 0x10, 0xfe, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0xfe },
+{ 0x8a, 0xbc, 0x8, 0x20, 0x8, 0x20, 0x7f, 0x20, 0x8, 0x7f, 0x8, 0x41, 0x3e, 0x53, 0x0, 0xd2, 0x3e, 0x10, 0x0, 0x10, 0x7f, 0x38, 0x8, 0x28, 0x2a, 0x28, 0x29, 0x6c, 0x49, 0x44, 0x8, 0xc6, 0x19, 0x83 },
+{ 0x8a, 0xbd, 0x10, 0x20, 0x10, 0x20, 0x3f, 0x20, 0x68, 0x7f, 0x8, 0x41, 0x7f, 0x53, 0x12, 0xd2, 0x14, 0x10, 0x3f, 0x90, 0x64, 0x38, 0x3f, 0x28, 0x24, 0x28, 0x3f, 0x6c, 0x24, 0x44, 0x3f, 0xc6, 0x0, 0x83 },
+{ 0x8a, 0xbe, 0x0, 0x0, 0x33, 0xfe, 0x18, 0x20, 0x8, 0x20, 0x0, 0x20, 0x60, 0x20, 0x30, 0x20, 0x17, 0xff, 0x0, 0x20, 0x8, 0x20, 0x18, 0x20, 0x10, 0x20, 0x30, 0x20, 0x20, 0x20, 0x60, 0x20, 0x0, 0x20 },
+{ 0x8a, 0xbf, 0x0, 0x88, 0x33, 0xff, 0x18, 0x88, 0x8, 0x0, 0x1, 0xfe, 0x61, 0x22, 0x31, 0x22, 0x11, 0xfe, 0x0, 0x20, 0x9, 0xfe, 0x8, 0x20, 0x1b, 0xff, 0x10, 0x50, 0x30, 0xd8, 0x21, 0x8c, 0x67, 0x7 },
+{ 0x8a, 0xc0, 0x0, 0x0, 0x27, 0xdf, 0x34, 0x51, 0x17, 0xdf, 0x4, 0x51, 0x47, 0xdf, 0x64, 0x1, 0x24, 0xf9, 0x4, 0x89, 0x14, 0x89, 0x14, 0xf9, 0x14, 0x89, 0x34, 0x89, 0x24, 0xf9, 0x64, 0x1, 0x44, 0x7 },
+{ 0x8a, 0xc1, 0x0, 0x80, 0x30, 0x80, 0x19, 0xfe, 0x9, 0x20, 0x7, 0xff, 0x60, 0x44, 0x30, 0x88, 0x11, 0xfe, 0x3, 0x10, 0x9, 0xfe, 0x9, 0x10, 0x19, 0x10, 0x11, 0xfe, 0x31, 0x10, 0x21, 0x10, 0x61, 0xff },
+{ 0x8a, 0xc2, 0x0, 0x0, 0x1, 0xfe, 0x7d, 0x52, 0x11, 0x52, 0x11, 0xfe, 0x10, 0x0, 0x13, 0xff, 0x7c, 0x0, 0x11, 0xfe, 0x11, 0x2, 0x11, 0xfe, 0x10, 0x61, 0x1c, 0xb2, 0x71, 0x2c, 0x6, 0x23, 0x0, 0x20 },
+{ 0x8a, 0xc3, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x7, 0xf0, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x7, 0xf0 },
+{ 0x8a, 0xc4, 0x0, 0x20, 0x3f, 0x20, 0x24, 0x20, 0x3f, 0x7f, 0x21, 0x40, 0x21, 0xc0, 0x3f, 0x3e, 0x24, 0x0, 0x3f, 0x0, 0x0, 0x0, 0x1f, 0xfc, 0x12, 0x44, 0x12, 0x44, 0x12, 0x44, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x8a, 0xc5, 0x0, 0x18, 0x0, 0xf0, 0x1f, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x1, 0x0, 0x7f, 0xff, 0x2, 0x0, 0x7, 0xfc, 0xc, 0x4, 0x17, 0xfc, 0x64, 0x4, 0x7, 0xfc, 0x4, 0x4, 0x4, 0x4, 0x7, 0xfc },
+{ 0x8a, 0xc6, 0x8, 0x20, 0x8, 0x20, 0x1f, 0x7f, 0x24, 0x90, 0x42, 0x8, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80 },
+{ 0x8a, 0xc7, 0x8, 0x20, 0x8, 0x20, 0x1f, 0x7f, 0x24, 0x90, 0x42, 0x8, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x2, 0x27, 0xf2, 0x4, 0x10, 0x7, 0xf0, 0x4, 0x0, 0x7, 0xf8, 0x4, 0x8, 0x4, 0x8, 0x7, 0xf8 },
+{ 0x8a, 0xc8, 0x10, 0x40, 0x1f, 0x7f, 0x24, 0x90, 0x42, 0x8, 0x3f, 0x7e, 0x21, 0x42, 0x3f, 0x7e, 0x21, 0x42, 0x3f, 0x7e, 0x20, 0x2, 0x23, 0xe2, 0x22, 0x22, 0x23, 0xe2, 0x22, 0x22, 0x23, 0xe2, 0x20, 0xe },
+{ 0x8a, 0xc9, 0x8, 0x6, 0x18, 0x3c, 0x13, 0xe2, 0x65, 0x26, 0x2c, 0x94, 0x1b, 0xfe, 0x10, 0x40, 0x2b, 0xff, 0x7c, 0x40, 0x14, 0x7c, 0x10, 0x44, 0x54, 0xec, 0x55, 0xa8, 0x50, 0x38, 0x10, 0x6c, 0x11, 0xc7 },
+{ 0x8a, 0xca, 0x4, 0x0, 0x4, 0x0, 0xf, 0xfc, 0x18, 0x80, 0x30, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc },
+{ 0x8a, 0xcb, 0x10, 0x20, 0x10, 0x70, 0x7c, 0xd8, 0x11, 0x8c, 0x7f, 0x7, 0x44, 0x0, 0x47, 0xde, 0x7c, 0x42, 0x46, 0x52, 0x45, 0x4a, 0x7c, 0x42, 0x10, 0xc6, 0x7d, 0x4a, 0x12, 0x52, 0x10, 0x42, 0x11, 0xce },
+{ 0x8a, 0xcc, 0x0, 0x0, 0x3e, 0xfe, 0x22, 0x10, 0x22, 0x10, 0x22, 0x10, 0x3e, 0x10, 0x22, 0x10, 0x23, 0xff, 0x22, 0x10, 0x3e, 0x10, 0x22, 0x10, 0x22, 0x10, 0x22, 0x10, 0x22, 0x10, 0x62, 0x10, 0x4e, 0x10 },
+{ 0x8a, 0xcd, 0x8, 0x4, 0x11, 0xf4, 0x3d, 0x44, 0x25, 0x4f, 0x35, 0xf8, 0x35, 0x10, 0x25, 0xf0, 0x7f, 0x4f, 0x25, 0x40, 0x35, 0xf0, 0x34, 0x0, 0x34, 0xfe, 0x24, 0xaa, 0x24, 0xaa, 0x64, 0xaa, 0x4d, 0xff },
+{ 0x8a, 0xce, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x2, 0x2f, 0xfa, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xff, 0x2, 0x40, 0x6, 0x40, 0xc, 0x41, 0x18, 0x63, 0x70, 0x3e },
+{ 0x8a, 0xcf, 0x10, 0x0, 0x10, 0x7e, 0x3f, 0x42, 0x68, 0x42, 0x8, 0x7e, 0x7f, 0xc2, 0x12, 0x42, 0x14, 0x7e, 0x3f, 0x42, 0x64, 0x42, 0x3f, 0x7e, 0x24, 0x28, 0x3f, 0x28, 0x24, 0x69, 0x3f, 0x49, 0x0, 0xc7 },
+{ 0x8a, 0xd0, 0x0, 0x10, 0x3c, 0x10, 0x1, 0xff, 0x7e, 0x10, 0x0, 0xfe, 0x3c, 0x92, 0x0, 0x92, 0x0, 0xfe, 0x3c, 0x92, 0x0, 0x92, 0x0, 0xfe, 0x3c, 0x54, 0x24, 0x54, 0x24, 0xd6, 0x25, 0x93, 0x3c, 0x10 },
+{ 0x8a, 0xd1, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x88, 0x7f, 0xff, 0x8, 0x88, 0xf, 0xf8, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x4, 0x10, 0x38, 0xe },
+{ 0x8a, 0xd2, 0x0, 0x0, 0x33, 0xfe, 0x1a, 0x52, 0xb, 0xfe, 0x0, 0x0, 0x7, 0xff, 0x0, 0x0, 0x79, 0xfc, 0x9, 0x4, 0x9, 0xfc, 0x8, 0x62, 0x8, 0xb4, 0xb, 0x28, 0x18, 0x26, 0x34, 0x20, 0x63, 0xff },
+{ 0x8a, 0xd3, 0x10, 0x4, 0x39, 0xf4, 0x2d, 0x44, 0x65, 0x4f, 0x41, 0xf8, 0x7d, 0x10, 0x11, 0xf0, 0x11, 0x4f, 0x7d, 0x40, 0x11, 0xf0, 0x54, 0x0, 0x54, 0xfe, 0x54, 0xaa, 0x10, 0xaa, 0x1c, 0xaa, 0x71, 0xff },
+{ 0x8a, 0xd4, 0x0, 0x0, 0x3f, 0x7e, 0x21, 0x42, 0x3f, 0x7e, 0x21, 0x42, 0x3f, 0x7e, 0x20, 0x2, 0x23, 0xe2, 0x22, 0x22, 0x22, 0x22, 0x23, 0xe2, 0x22, 0x22, 0x22, 0x22, 0x23, 0xe2, 0x20, 0x2, 0x20, 0xe },
+{ 0x8a, 0xd5, 0x0, 0x0, 0x3f, 0x7e, 0x21, 0x42, 0x3f, 0x7e, 0x21, 0x42, 0x3f, 0x7e, 0x20, 0x82, 0x20, 0x82, 0x27, 0xf2, 0x20, 0x82, 0x21, 0xc2, 0x21, 0xc2, 0x22, 0xa2, 0x24, 0x92, 0x20, 0x82, 0x20, 0xe },
+{ 0x8a, 0xd6, 0x0, 0x0, 0x3f, 0x7e, 0x21, 0x42, 0x3f, 0x7e, 0x21, 0x42, 0x3f, 0x7e, 0x22, 0x22, 0x21, 0x42, 0x27, 0xf2, 0x20, 0x82, 0x20, 0x82, 0x2f, 0xfa, 0x21, 0x42, 0x23, 0x62, 0x26, 0x32, 0x20, 0xe },
+{ 0x8a, 0xd7, 0x0, 0x20, 0x3e, 0x20, 0x22, 0x7e, 0x26, 0x42, 0x24, 0xc6, 0x2d, 0x8c, 0x28, 0x8, 0x24, 0xbe, 0x22, 0xa2, 0x22, 0xa2, 0x22, 0xa2, 0x22, 0xbe, 0x2e, 0xa2, 0x20, 0xa2, 0x20, 0xa2, 0x20, 0xbe },
+{ 0x8a, 0xd8, 0x8, 0x10, 0x8, 0x7c, 0x7f, 0x24, 0x8, 0x24, 0x3e, 0xff, 0x22, 0x0, 0x22, 0x7e, 0x3e, 0x42, 0x22, 0x7e, 0x22, 0x4, 0x3e, 0x7e, 0x8, 0x24, 0x7f, 0x24, 0x8, 0xff, 0x8, 0x4, 0x8, 0x4 },
+{ 0x8a, 0xd9, 0x8, 0x10, 0x1c, 0x10, 0x16, 0xff, 0x32, 0x81, 0x28, 0x81, 0x7e, 0x7c, 0x22, 0x44, 0x3e, 0x44, 0x22, 0x7c, 0x3e, 0x40, 0x20, 0x40, 0x22, 0x7e, 0x22, 0x42, 0x2f, 0x42, 0x39, 0x42, 0x60, 0x7e },
+{ 0x8a, 0xda, 0x8, 0x10, 0x1c, 0x10, 0x16, 0xff, 0x33, 0x81, 0x20, 0x81, 0x7e, 0x7c, 0x8, 0x44, 0x8, 0x44, 0x7f, 0x7c, 0x8, 0x40, 0x8, 0x40, 0x3e, 0x7e, 0x22, 0x42, 0x22, 0x42, 0x22, 0x42, 0x3e, 0x7e },
+{ 0x8a, 0xdb, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x3f, 0xf0, 0x2, 0x10, 0x2, 0x10, 0x32, 0x10, 0x1a, 0x10, 0xe, 0x10, 0x4, 0x10, 0xe, 0x10, 0xb, 0x10, 0x19, 0x11, 0x30, 0x13, 0x60, 0xe },
+{ 0x8a, 0xdc, 0x0, 0x80, 0x1, 0xc0, 0x3, 0x60, 0x6, 0x30, 0x1c, 0x1c, 0x73, 0xe7, 0x0, 0x0, 0xf, 0xf8, 0x0, 0x10, 0x0, 0x20, 0x0, 0x40, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8 },
+{ 0x8a, 0xdd, 0x0, 0x80, 0x10, 0x82, 0x10, 0x82, 0x1f, 0xfe, 0x0, 0x0, 0x1f, 0xff, 0x10, 0x0, 0x17, 0xfc, 0x10, 0x40, 0x10, 0x40, 0x1f, 0xff, 0x10, 0x40, 0x30, 0x40, 0x20, 0x40, 0x60, 0x40, 0x0, 0x40 },
+{ 0x8a, 0xde, 0x10, 0x82, 0x10, 0x82, 0x1f, 0xfe, 0x9, 0x4, 0x3f, 0xff, 0x20, 0x10, 0x2f, 0x10, 0x24, 0x3f, 0x3f, 0xa4, 0x29, 0x64, 0x2f, 0x14, 0x29, 0x1c, 0x2f, 0x8, 0x69, 0x1c, 0x4f, 0x36, 0x19, 0x63 },
+{ 0x8a, 0xdf, 0x0, 0x0, 0x7c, 0xfe, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x7d, 0xff, 0x10, 0x48, 0x10, 0x48, 0x10, 0x48, 0x10, 0x48, 0x1c, 0x48, 0x70, 0xc8, 0x0, 0x89, 0x1, 0x89, 0x3, 0x7 },
+{ 0x8a, 0xe0, 0x0, 0x40, 0x0, 0x40, 0x1f, 0xff, 0x10, 0x0, 0x51, 0xf8, 0x31, 0x8, 0x11, 0xf8, 0x10, 0x0, 0x37, 0x9e, 0x54, 0x92, 0x17, 0x9e, 0x10, 0x0, 0x30, 0x40, 0x24, 0x42, 0x64, 0x42, 0x7, 0xfe },
+{ 0x8a, 0xe1, 0x0, 0x0, 0x3c, 0xfe, 0x24, 0x82, 0x24, 0x82, 0x24, 0xfe, 0x3c, 0x82, 0x24, 0x82, 0x24, 0xfe, 0x24, 0xa1, 0x3c, 0xb3, 0x24, 0x96, 0x24, 0x9c, 0x24, 0x88, 0x3c, 0x8c, 0x0, 0xe6, 0x3, 0x83 },
+{ 0x8a, 0xe2, 0x0, 0x80, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xff, 0x2, 0x0, 0x4, 0x0, 0xf, 0xfc, 0x14, 0x4, 0x64, 0x4, 0x4, 0x4, 0x4, 0x4, 0x7, 0xfc },
+{ 0x8a, 0xe3, 0x0, 0x0, 0x77, 0xbe, 0x10, 0x80, 0x54, 0x80, 0x32, 0x80, 0x10, 0x80, 0x32, 0xff, 0x54, 0x94, 0x8, 0x14, 0x3f, 0x14, 0x21, 0x14, 0x21, 0x14, 0x3f, 0x14, 0x21, 0x35, 0x21, 0x25, 0x3f, 0x63 },
+{ 0x8a, 0xe4, 0x3f, 0xff, 0x22, 0x44, 0x24, 0xff, 0x2d, 0x90, 0x36, 0xfe, 0x24, 0x90, 0x24, 0xfe, 0x24, 0x90, 0x23, 0xff, 0x22, 0x4, 0x23, 0xfc, 0x22, 0x4, 0x23, 0xfc, 0x62, 0x4, 0x43, 0xfc, 0xe, 0x7 },
+{ 0x8a, 0xe5, 0x0, 0x0, 0x1f, 0xff, 0x10, 0x0, 0x11, 0x22, 0x11, 0x24, 0x12, 0x7f, 0x12, 0xc8, 0x17, 0x48, 0x1a, 0x7e, 0x12, 0x48, 0x12, 0x48, 0x12, 0x7e, 0x32, 0x48, 0x22, 0x48, 0x62, 0x7f, 0x2, 0x0 },
+{ 0x8a, 0xe6, 0x0, 0x0, 0x3e, 0xff, 0x0, 0x10, 0x0, 0x7e, 0x0, 0x42, 0x7f, 0x42, 0x14, 0x7e, 0x14, 0x42, 0x14, 0x42, 0x14, 0x7e, 0x15, 0x42, 0x15, 0x42, 0x33, 0x7e, 0x20, 0x24, 0x60, 0x66, 0x0, 0xc3 },
+{ 0x8a, 0xe7, 0x4, 0x0, 0x4, 0x7f, 0x3f, 0x88, 0x11, 0x3e, 0xa, 0x22, 0x3f, 0xa2, 0x22, 0x3e, 0x26, 0x22, 0x2d, 0x22, 0x23, 0x3e, 0x26, 0x22, 0x2c, 0xa2, 0x21, 0xbe, 0x63, 0x14, 0x46, 0x36, 0x1c, 0x63 },
+{ 0x8a, 0xe8, 0x0, 0x0, 0x3f, 0xbf, 0x22, 0x8, 0x2f, 0xbe, 0x28, 0xa2, 0x28, 0xa2, 0x2f, 0xbe, 0x28, 0xa2, 0x28, 0xa2, 0x2f, 0xbe, 0x22, 0x22, 0x2a, 0xa2, 0x6a, 0xbe, 0x5a, 0x94, 0x52, 0x36, 0x6, 0x63 },
+{ 0x8a, 0xe9, 0x0, 0x80, 0x1, 0xc0, 0x1, 0x60, 0x3, 0x30, 0x6, 0x18, 0xc, 0x8c, 0x18, 0x87, 0x74, 0x80, 0x4, 0xf8, 0x4, 0x80, 0x4, 0x80, 0x4, 0x80, 0x4, 0x80, 0x4, 0x80, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x8a, 0xea, 0x8, 0x20, 0x8, 0x20, 0x18, 0x20, 0x17, 0xff, 0x10, 0x20, 0x30, 0x20, 0x33, 0xfc, 0x51, 0x4, 0x11, 0x8c, 0x10, 0x88, 0x10, 0xd8, 0x10, 0x70, 0x10, 0x70, 0x10, 0xd8, 0x11, 0x8c, 0x17, 0x7 },
+{ 0x8a, 0xeb, 0x4, 0x0, 0x7, 0xf0, 0xc, 0x20, 0x10, 0x40, 0x7f, 0xff, 0x10, 0x0, 0x10, 0x0, 0x13, 0xf8, 0x12, 0x8, 0x12, 0x8, 0x12, 0x8, 0x12, 0x38, 0x32, 0x0, 0x22, 0x2, 0x63, 0x6, 0x1, 0xfc },
+{ 0x8a, 0xec, 0x0, 0x80, 0x3f, 0xfe, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x4, 0x10, 0x2, 0x20, 0x7f, 0xff, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8 },
+{ 0x8a, 0xed, 0x0, 0x0, 0x3f, 0x7e, 0x21, 0x42, 0x21, 0x42, 0x21, 0x42, 0x3f, 0x7e, 0x0, 0x80, 0x7f, 0xff, 0x2, 0x20, 0xc, 0x18, 0x70, 0x7, 0x3f, 0x7e, 0x21, 0x42, 0x21, 0x42, 0x21, 0x42, 0x3f, 0x7e },
+{ 0x8a, 0xee, 0x4, 0x10, 0x4, 0x10, 0x3f, 0xfe, 0x4, 0x10, 0x7, 0xf0, 0x4, 0x10, 0x7, 0xf0, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x8, 0x88, 0x17, 0xf4, 0x60, 0x83, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x8a, 0xef, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x1, 0x40, 0x2, 0x20, 0xc, 0x18, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x8, 0xf, 0xc8, 0x8, 0x48, 0x8, 0x48, 0x8, 0x48, 0xf, 0xc8, 0x0, 0x8, 0x0, 0x38 },
+{ 0x8a, 0xf0, 0x10, 0x10, 0x11, 0xff, 0x10, 0x10, 0x7e, 0xfe, 0x12, 0x0, 0x12, 0xfe, 0x12, 0x82, 0x32, 0xfe, 0x26, 0x44, 0x24, 0x28, 0x75, 0xff, 0xc, 0x0, 0xa, 0xfe, 0x1a, 0x82, 0x30, 0x82, 0x60, 0xfe },
+{ 0x8a, 0xf1, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x2, 0x20, 0x82, 0x1f, 0xfc, 0x1, 0x40, 0x6, 0x30, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x8, 0xf, 0xc8, 0x8, 0x48, 0x8, 0x48, 0xf, 0xc8, 0x0, 0x38 },
+{ 0x8a, 0xf2, 0x0, 0x20, 0x10, 0x20, 0x13, 0xff, 0x54, 0x20, 0x54, 0x20, 0x55, 0xfc, 0x54, 0x84, 0x54, 0x8c, 0x54, 0xc8, 0x54, 0x58, 0x54, 0x70, 0x7c, 0x20, 0x0, 0x70, 0x0, 0xd8, 0x1, 0x8c, 0x3, 0x7 },
+{ 0x8a, 0xf3, 0xe, 0xc, 0x3, 0xb8, 0x0, 0xe0, 0x7, 0xb8, 0x3d, 0xc, 0x1, 0x0, 0x7f, 0xff, 0x2, 0x40, 0x4, 0x40, 0xf, 0xfe, 0x14, 0x42, 0x64, 0x42, 0x4, 0x42, 0x4, 0x42, 0x4, 0x4e, 0x0, 0x40 },
+{ 0x8a, 0xf4, 0x8, 0x88, 0x18, 0x98, 0x32, 0xb2, 0x14, 0x94, 0x8, 0x88, 0xa, 0x92, 0x1e, 0xbe, 0x32, 0x8a, 0x0, 0x84, 0x1f, 0xff, 0x10, 0x40, 0x1c, 0x64, 0x16, 0x28, 0x32, 0x31, 0x20, 0xdb, 0x63, 0xe },
+{ 0x8a, 0xf5, 0x0, 0x0, 0x1f, 0xf8, 0x0, 0x8, 0x0, 0x8, 0x1f, 0xf8, 0x10, 0x0, 0x10, 0x2, 0x18, 0x6, 0xf, 0xfc, 0x0, 0x0, 0x1, 0x80, 0x14, 0xc6, 0x14, 0x43, 0x34, 0x9, 0x26, 0x18, 0x63, 0xf0 },
+{ 0x8a, 0xf6, 0x10, 0x0, 0x17, 0xff, 0x14, 0x1, 0x14, 0x21, 0x7b, 0xfe, 0x10, 0x20, 0x13, 0xfe, 0x12, 0x22, 0x1b, 0xfe, 0x72, 0x22, 0x12, 0x22, 0x13, 0xfe, 0x10, 0x20, 0x17, 0xff, 0x10, 0x20, 0x30, 0x20 },
+{ 0x8a, 0xf7, 0x10, 0x0, 0x10, 0xf8, 0x10, 0x88, 0x7e, 0x88, 0x10, 0x88, 0x10, 0x88, 0x38, 0x88, 0x34, 0x88, 0x34, 0x88, 0x50, 0x88, 0x50, 0x88, 0x10, 0x88, 0x11, 0x88, 0x11, 0x9, 0x13, 0x9, 0x16, 0x7 },
+{ 0x8a, 0xf8, 0x8, 0x40, 0x8, 0x40, 0x8, 0xff, 0x7e, 0x80, 0x11, 0x24, 0x10, 0xff, 0x1e, 0x24, 0x12, 0x3c, 0x12, 0x24, 0x12, 0x3c, 0x12, 0x24, 0x12, 0xff, 0x32, 0x0, 0x26, 0x24, 0x24, 0x66, 0x6c, 0xc3 },
+{ 0x8a, 0xf9, 0x0, 0x0, 0x3e, 0xfe, 0x22, 0x48, 0x22, 0x48, 0x3e, 0x48, 0x22, 0x48, 0x22, 0x48, 0x3f, 0xff, 0x20, 0x8, 0x20, 0x18, 0x22, 0x18, 0x22, 0x38, 0x2f, 0x28, 0x39, 0x69, 0x60, 0xc9, 0x1, 0x87 },
+{ 0x8a, 0xfa, 0x22, 0x0, 0x22, 0x3e, 0x7f, 0xa2, 0x22, 0x22, 0x22, 0x22, 0x3e, 0x3e, 0x22, 0x22, 0x22, 0x22, 0x3e, 0x22, 0x22, 0x3e, 0x22, 0x22, 0x7f, 0xa2, 0x0, 0x22, 0x26, 0x22, 0x63, 0x62, 0x40, 0xce },
+{ 0x8a, 0xfb, 0x8, 0x44, 0x8, 0x44, 0x9, 0xff, 0x7e, 0x44, 0x8, 0x44, 0x8, 0x7c, 0x1c, 0x44, 0x1a, 0x44, 0x1a, 0x7c, 0x28, 0x44, 0x28, 0x44, 0x49, 0xff, 0x8, 0x0, 0x8, 0x44, 0x8, 0xc6, 0x9, 0x83 },
+{ 0x8a, 0xfc, 0x0, 0x80, 0x7f, 0xff, 0x2, 0x10, 0x4, 0x8, 0x1f, 0xf4, 0x0, 0x0, 0x8, 0x88, 0x7f, 0xff, 0x8, 0x88, 0xf, 0xf8, 0x0, 0x80, 0x7f, 0xff, 0x2, 0xa0, 0xe, 0xb8, 0x78, 0x8f, 0x0, 0x80 },
+{ 0x8b, 0x40, 0x10, 0xa2, 0x11, 0x24, 0x13, 0x6d, 0x7c, 0xa2, 0x11, 0x25, 0x11, 0x6f, 0x33, 0xe4, 0x38, 0x22, 0x35, 0xff, 0x55, 0x20, 0x51, 0x12, 0x11, 0x94, 0x11, 0x48, 0x13, 0x55, 0x12, 0x27, 0x16, 0xc2 },
+{ 0x8b, 0x41, 0x8, 0x0, 0x9, 0xfc, 0x28, 0x4, 0x29, 0xfc, 0x28, 0x4, 0x29, 0xfc, 0x28, 0x0, 0x2f, 0xff, 0x2c, 0x21, 0x2c, 0x21, 0xb, 0xfe, 0xa, 0x22, 0x1a, 0x22, 0x12, 0x22, 0x32, 0x26, 0x60, 0x20 },
+{ 0x8b, 0x42, 0x4, 0x0, 0x4, 0x3c, 0x3f, 0xa4, 0x11, 0x24, 0xa, 0x24, 0x7f, 0xe4, 0x8, 0x47, 0x14, 0x80, 0x65, 0x7e, 0xa, 0x22, 0x13, 0x36, 0x66, 0x9c, 0xa, 0x48, 0x12, 0x1c, 0x62, 0x36, 0xc, 0xe3 },
+{ 0x8b, 0x43, 0x8, 0x0, 0x8, 0x0, 0x1f, 0xfe, 0x10, 0x0, 0x37, 0xf8, 0x60, 0x0, 0x1f, 0xf8, 0x0, 0x8, 0x0, 0x48, 0x18, 0xc8, 0xd, 0x88, 0x7, 0x8, 0x7, 0x8d, 0xc, 0xc5, 0x18, 0x47, 0x70, 0x2 },
+{ 0x8b, 0x44, 0x2, 0x0, 0x22, 0x0, 0x37, 0xfe, 0x14, 0x0, 0xd, 0xf8, 0x40, 0x0, 0x67, 0xf8, 0x20, 0x8, 0x0, 0x8, 0x8, 0x8, 0x8, 0x8, 0x18, 0x8, 0x10, 0xd, 0x30, 0x5, 0x20, 0x7, 0x60, 0x2 },
+{ 0x8b, 0x45, 0x8, 0x88, 0x18, 0x98, 0x32, 0xb2, 0x14, 0x94, 0x8, 0x88, 0x14, 0x94, 0x3e, 0xbe, 0x2, 0x8a, 0x7f, 0xff, 0x0, 0x40, 0x3f, 0xe2, 0x24, 0xa4, 0x3f, 0xa8, 0x24, 0x91, 0x3f, 0xad, 0x0, 0xc7 },
+{ 0x8b, 0x46, 0x8, 0x6, 0x8, 0x1c, 0x8, 0x70, 0x7e, 0x40, 0x2, 0x40, 0x6, 0x7f, 0x4, 0x44, 0xc, 0x44, 0x18, 0x44, 0x3e, 0x44, 0x6b, 0x44, 0x8, 0x44, 0x8, 0xc4, 0x8, 0x84, 0x9, 0x84, 0x8, 0x4 },
+{ 0x8b, 0x47, 0x0, 0xc, 0x0, 0x78, 0x1f, 0xc0, 0x0, 0x80, 0x7f, 0xff, 0x2, 0xa0, 0x6, 0xb0, 0x1c, 0x9c, 0x70, 0x7, 0xf, 0xf8, 0x0, 0x30, 0x0, 0xc0, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x3, 0x80 },
+{ 0x8b, 0x48, 0x2, 0xc4, 0xe, 0x6c, 0x78, 0x38, 0x8, 0x6c, 0x9, 0xc6, 0x7e, 0x20, 0x9, 0xff, 0x1c, 0x40, 0x1a, 0x90, 0x19, 0xfe, 0x2a, 0x92, 0x2c, 0x92, 0x48, 0x92, 0x8, 0x92, 0x8, 0x96, 0x8, 0x10 },
+{ 0x8b, 0x49, 0x8, 0x0, 0x18, 0x7e, 0x30, 0x2, 0x62, 0x2, 0x36, 0x2, 0xc, 0x2, 0x18, 0x7e, 0x32, 0x40, 0x7f, 0x40, 0x9, 0x40, 0x8, 0x40, 0x2a, 0x40, 0x2b, 0x41, 0x69, 0x63, 0x48, 0x3e, 0x8, 0x0 },
+{ 0x8b, 0x4a, 0x8, 0x88, 0x1a, 0xa8, 0x12, 0xa8, 0x32, 0xaf, 0x63, 0xea, 0x8, 0x92, 0x19, 0xa, 0x13, 0x4a, 0x30, 0x8e, 0x71, 0x24, 0x13, 0xe4, 0x10, 0x84, 0x12, 0xae, 0x12, 0xaa, 0x14, 0xbb, 0x10, 0x91 },
+{ 0x8b, 0x4b, 0x8, 0x0, 0x8, 0x7e, 0x8, 0x42, 0x3f, 0x42, 0x8, 0x7e, 0x8, 0x42, 0x8, 0x42, 0x3f, 0x7e, 0x8, 0x42, 0x8, 0x42, 0x1c, 0x7e, 0x16, 0x28, 0x33, 0x28, 0x20, 0x69, 0x60, 0xc9, 0x1, 0x87 },
+{ 0x8b, 0x4c, 0x0, 0x0, 0x3e, 0x7e, 0x0, 0x2, 0x7f, 0x2, 0x0, 0x2, 0x3e, 0x2, 0x0, 0x2, 0x0, 0x7e, 0x3e, 0x40, 0x0, 0x40, 0x0, 0x40, 0x3e, 0x40, 0x22, 0x40, 0x22, 0x41, 0x22, 0x63, 0x3e, 0x3e },
+{ 0x8b, 0x4d, 0x0, 0x80, 0xf, 0xf8, 0x8, 0x88, 0xf, 0xf8, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x4, 0x10, 0x38, 0xe },
+{ 0x8b, 0x4e, 0x4, 0x0, 0x4, 0x3e, 0x3f, 0x82, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x7f, 0xbe, 0x4, 0x20, 0x24, 0x20, 0x27, 0xa0, 0x24, 0x21, 0x24, 0x33, 0x34, 0x1e, 0x2c, 0x0, 0x67, 0x0, 0x41, 0xff },
+{ 0x8b, 0x4f, 0x8, 0x20, 0x8, 0x20, 0x7f, 0x20, 0x8, 0x20, 0x3f, 0xfc, 0x29, 0x24, 0x29, 0x24, 0x3f, 0x24, 0x29, 0x24, 0x29, 0x24, 0x3f, 0x24, 0x8, 0x24, 0x7f, 0xa4, 0x8, 0x65, 0x8, 0x45, 0x8, 0xc3 },
+{ 0x8b, 0x50, 0x10, 0x0, 0x11, 0xff, 0x55, 0x1, 0x75, 0x11, 0x34, 0xfe, 0x10, 0x10, 0x10, 0xfe, 0x7e, 0x92, 0x28, 0xfe, 0x28, 0x92, 0x28, 0x92, 0x2a, 0xfe, 0x6c, 0x10, 0x49, 0xff, 0x40, 0x10, 0x0, 0x10 },
+{ 0x8b, 0x51, 0x4, 0x0, 0xe, 0x3c, 0xb, 0x24, 0x19, 0xa4, 0x14, 0x24, 0x3f, 0x24, 0x51, 0x24, 0x1f, 0x24, 0x11, 0x24, 0x1f, 0x24, 0x10, 0x24, 0x12, 0x24, 0x12, 0x24, 0x13, 0x65, 0x1d, 0x45, 0x30, 0xc3 },
+{ 0x8b, 0x52, 0x0, 0x8, 0x3f, 0x88, 0x24, 0x7f, 0x24, 0x8, 0x3f, 0x14, 0x24, 0x22, 0x24, 0x0, 0x3f, 0x7f, 0x24, 0x2, 0x24, 0x3a, 0x3f, 0xaa, 0x0, 0xaa, 0x55, 0xba, 0x54, 0x82, 0x41, 0x82, 0x3, 0xe },
+{ 0x8b, 0x53, 0x0, 0x80, 0x1, 0x0, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x2, 0x50, 0x2, 0x54, 0x6, 0x66, 0x4, 0x7a, 0xc, 0x41, 0x18, 0x63, 0x70, 0x3e },
+{ 0x8b, 0x54, 0x2, 0x0, 0x7, 0xe0, 0x8, 0x40, 0x1f, 0xf8, 0x68, 0x88, 0xf, 0xf8, 0x8, 0x88, 0xf, 0xf8, 0x0, 0x80, 0x1f, 0xfc, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x84, 0x1f, 0xfd, 0x0, 0x81, 0x0, 0x7f },
+{ 0x8b, 0x55, 0x5, 0x20, 0x4, 0xa0, 0xc, 0x20, 0xb, 0xfc, 0x18, 0x44, 0x10, 0x48, 0x30, 0xfe, 0x51, 0x82, 0x11, 0x4, 0x13, 0xff, 0x16, 0x1, 0x1c, 0x9, 0x12, 0xa5, 0x12, 0xa3, 0x14, 0x2, 0x10, 0xe },
+{ 0x8b, 0x56, 0x9, 0x4, 0x8, 0x88, 0x1b, 0xfe, 0x10, 0x20, 0x11, 0xfc, 0x30, 0x20, 0x37, 0xff, 0x50, 0x4, 0x13, 0xd2, 0x10, 0x90, 0x17, 0xff, 0x10, 0x92, 0x10, 0xd4, 0x17, 0x89, 0x10, 0x95, 0x13, 0xa3 },
+{ 0x8b, 0x57, 0x10, 0x10, 0x10, 0x10, 0x11, 0xff, 0x10, 0x10, 0x7e, 0x10, 0x12, 0xfe, 0x12, 0x42, 0x32, 0x46, 0x22, 0x64, 0x26, 0x2c, 0x74, 0x38, 0xc, 0x10, 0xa, 0x38, 0x19, 0x6c, 0x30, 0xc6, 0x61, 0x83 },
+{ 0x8b, 0x58, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x2, 0x20, 0x2, 0x7, 0xf0, 0x4, 0x10, 0x4, 0x10, 0x7, 0xf0, 0x4, 0x10, 0x4, 0x10, 0x7, 0xf0, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x8b, 0x59, 0x4, 0x14, 0x7, 0x92, 0x4, 0x10, 0x3f, 0x93, 0x24, 0x9e, 0x27, 0x70, 0x3c, 0x92, 0x27, 0x92, 0x20, 0x16, 0x25, 0x14, 0x35, 0x5c, 0x2d, 0x88, 0x25, 0x1c, 0x25, 0x15, 0x47, 0xb7, 0x1c, 0x62 },
+{ 0x8b, 0x5a, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x13, 0xff, 0x7c, 0x10, 0x10, 0x10, 0x11, 0xfe, 0x10, 0x82, 0x1c, 0xc6, 0x70, 0x6c, 0x10, 0x38, 0x10, 0x10, 0x10, 0x38, 0x10, 0x6c, 0x10, 0xc6, 0x33, 0x83 },
+{ 0x8b, 0x5b, 0x12, 0x0, 0x12, 0xbf, 0x13, 0x2, 0x12, 0x14, 0x7a, 0x48, 0x11, 0xff, 0x12, 0x9, 0x13, 0xca, 0x15, 0x28, 0x79, 0x2e, 0x17, 0xe8, 0x11, 0x28, 0x11, 0xa8, 0x11, 0x78, 0x12, 0x2c, 0x34, 0x47 },
+{ 0x8b, 0x5c, 0x11, 0x10, 0x11, 0x10, 0x7f, 0xd0, 0x11, 0x1f, 0x11, 0x31, 0x1f, 0x2b, 0x11, 0x6a, 0x11, 0x8, 0x1f, 0x8, 0x11, 0x8, 0x11, 0x1c, 0x7f, 0xd4, 0x0, 0x14, 0x13, 0x36, 0x31, 0xa2, 0x60, 0x63 },
+{ 0x8b, 0x5d, 0x9, 0x4, 0x28, 0x88, 0x29, 0xfe, 0x28, 0x20, 0x3e, 0xfc, 0x68, 0x20, 0x4b, 0xff, 0x8, 0x4, 0x9, 0xd2, 0xc, 0x90, 0x3b, 0xff, 0x68, 0x92, 0x8, 0xd4, 0xb, 0x89, 0x8, 0x95, 0x9, 0xa3 },
+{ 0x8b, 0x5e, 0x20, 0x0, 0x27, 0x7e, 0x3c, 0x4, 0x20, 0x28, 0x21, 0x10, 0x1f, 0x7f, 0x10, 0x12, 0x1f, 0x14, 0x24, 0x50, 0x44, 0x5e, 0x3f, 0x50, 0x4, 0x50, 0xe, 0x50, 0x1b, 0x70, 0x30, 0xdc, 0x61, 0x87 },
+{ 0x8b, 0x5f, 0x10, 0x6, 0x10, 0x1c, 0x11, 0xf0, 0x7d, 0x10, 0x5, 0x10, 0xd, 0x10, 0x9, 0x10, 0x19, 0xff, 0x11, 0x10, 0x3d, 0x18, 0x57, 0x8, 0x11, 0x8, 0x11, 0xc, 0x11, 0x5, 0x11, 0xe7, 0x17, 0x2 },
+{ 0x8b, 0x60, 0x4, 0x10, 0x2, 0x20, 0x3f, 0xfe, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x8, 0x3f, 0x44, 0x4, 0x40, 0x7f, 0xff, 0x4, 0x44, 0x7, 0xa8, 0x7c, 0x11, 0x4, 0x6d, 0x1d, 0x87 },
+{ 0x8b, 0x61, 0x10, 0x82, 0x10, 0x44, 0x11, 0xff, 0x7c, 0x10, 0x54, 0xfe, 0x54, 0x10, 0x55, 0xff, 0x54, 0x2, 0x7d, 0xe9, 0x10, 0x48, 0x11, 0xff, 0x14, 0x48, 0x14, 0x6a, 0x1d, 0xc5, 0x74, 0x4d, 0x0, 0xd3 },
+{ 0x8b, 0x62, 0x0, 0x10, 0x3c, 0x10, 0x0, 0xfe, 0x7e, 0x82, 0x0, 0x82, 0x3c, 0x7c, 0x0, 0x44, 0x0, 0x44, 0x3c, 0x7c, 0x0, 0x44, 0x0, 0x44, 0x3c, 0x7c, 0x24, 0x44, 0x24, 0x44, 0x24, 0x44, 0x3d, 0xff },
+{ 0x8b, 0x63, 0x0, 0x82, 0x3c, 0x44, 0x1, 0xff, 0x7e, 0x10, 0x0, 0xfe, 0x3c, 0x10, 0x1, 0xff, 0x0, 0x2, 0x3d, 0xe9, 0x0, 0x48, 0x1, 0xff, 0x3c, 0x48, 0x24, 0x6a, 0x25, 0xc5, 0x24, 0x4d, 0x3c, 0xd3 },
+{ 0x8b, 0x64, 0x10, 0x80, 0x10, 0x80, 0x10, 0x80, 0x11, 0xff, 0x7d, 0x1, 0x12, 0x21, 0x11, 0x25, 0x10, 0xa9, 0x1d, 0xfd, 0x70, 0x61, 0x10, 0xf9, 0x10, 0xad, 0x11, 0xa5, 0x13, 0x23, 0x10, 0x22, 0x30, 0xe },
+{ 0x8b, 0x65, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x8, 0x0, 0xf, 0xfe, 0x18, 0x2, 0x34, 0x92, 0x62, 0xa2, 0xf, 0xfa, 0x1, 0x82, 0x3, 0xe2, 0x6, 0xb2, 0xc, 0x96, 0x30, 0x84, 0x0, 0x1c },
+{ 0x8b, 0x66, 0x14, 0x40, 0x14, 0x40, 0x7f, 0x7f, 0x14, 0x81, 0x15, 0x11, 0x1c, 0x55, 0x8, 0x55, 0x3e, 0xff, 0x2a, 0x11, 0x2a, 0x39, 0x3e, 0x35, 0x8, 0x55, 0x7f, 0x51, 0x8, 0x93, 0x8, 0x12, 0x8, 0xe },
+{ 0x8b, 0x67, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8 },
+{ 0x8b, 0x68, 0x0, 0x80, 0x0, 0x80, 0x78, 0x80, 0x49, 0xff, 0x49, 0x0, 0x4b, 0x0, 0x4e, 0xfe, 0x48, 0xc, 0x48, 0x18, 0x48, 0x30, 0x48, 0x60, 0x48, 0xc0, 0x79, 0x80, 0x1, 0x1, 0x1, 0x83, 0x0, 0xfe },
+{ 0x8b, 0x69, 0x1, 0x0, 0x7, 0xde, 0x71, 0xa, 0x51, 0xa, 0x57, 0xca, 0x51, 0xa, 0x51, 0x1a, 0x51, 0xd2, 0x57, 0x36, 0x50, 0x0, 0x70, 0x40, 0xf, 0xff, 0x0, 0x90, 0x1, 0x98, 0x3, 0xc, 0xe, 0x7 },
+{ 0x8b, 0x6a, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x7d, 0xff, 0x10, 0x10, 0x10, 0x10, 0x38, 0x10, 0x34, 0xfe, 0x34, 0x0, 0x50, 0x0, 0x50, 0xfe, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0xfe },
+{ 0x8b, 0x6b, 0x10, 0x0, 0x11, 0xfe, 0x10, 0x44, 0x7c, 0x28, 0x13, 0xff, 0x18, 0x52, 0x34, 0x94, 0x31, 0x30, 0x33, 0xff, 0x52, 0x51, 0x52, 0x91, 0x13, 0x7f, 0x12, 0x49, 0x12, 0x49, 0x12, 0x79, 0x12, 0x7 },
+{ 0x8b, 0x6c, 0x0, 0x10, 0x3c, 0x10, 0x0, 0x10, 0x7e, 0xff, 0x0, 0x10, 0x3c, 0x10, 0x0, 0x10, 0x0, 0x7e, 0x3c, 0x0, 0x0, 0x0, 0x0, 0x7e, 0x3c, 0x42, 0x24, 0x42, 0x24, 0x42, 0x24, 0x42, 0x3c, 0x7e },
+{ 0x8b, 0x6d, 0x0, 0x10, 0x7f, 0x10, 0x8, 0x10, 0x8, 0x10, 0x8, 0x1f, 0x18, 0x10, 0x10, 0x10, 0x1e, 0x10, 0x32, 0x10, 0x32, 0xfe, 0x52, 0x82, 0x12, 0x82, 0x12, 0x82, 0x12, 0x82, 0x1e, 0x82, 0x0, 0xfe },
+{ 0x8b, 0x6e, 0x10, 0x40, 0x10, 0x40, 0x10, 0x40, 0x7c, 0xfe, 0x10, 0x90, 0x11, 0x90, 0x38, 0x10, 0x34, 0x10, 0x35, 0xff, 0x50, 0x10, 0x50, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 },
+{ 0x8b, 0x6f, 0x0, 0xc, 0x0, 0x78, 0x1f, 0xc0, 0x0, 0x80, 0x7f, 0xff, 0x2, 0xa0, 0xc, 0x98, 0x71, 0xc7, 0x7, 0x70, 0x1c, 0x1c, 0x70, 0x87, 0xc, 0x98, 0x3, 0xe0, 0xc, 0x98, 0x70, 0x87, 0x3, 0x80 },
+{ 0x8b, 0x70, 0x8, 0x0, 0x8, 0x3e, 0x3f, 0x22, 0x8, 0x22, 0x8, 0x22, 0x8, 0x22, 0x8, 0x22, 0x7f, 0xa2, 0x8, 0x22, 0x1a, 0x22, 0x13, 0x22, 0x31, 0x22, 0x27, 0xae, 0x7c, 0xa0, 0x0, 0x20, 0x0, 0x20 },
+{ 0x8b, 0x71, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x22, 0x2, 0x23, 0xfa, 0x4, 0x10, 0xa, 0x20, 0x31, 0xc0, 0x3, 0x70, 0xe, 0x1c, 0x78, 0x7, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8 },
+{ 0x8b, 0x72, 0x0, 0x80, 0x3c, 0x8f, 0x24, 0x89, 0x27, 0xe9, 0x24, 0x89, 0x3c, 0x89, 0x24, 0x89, 0x27, 0xf9, 0x24, 0x89, 0x3c, 0x89, 0x25, 0xa9, 0x25, 0x29, 0x25, 0x79, 0x27, 0xdb, 0x64, 0x8, 0x4c, 0x8 },
+{ 0x8b, 0x73, 0x0, 0x80, 0x0, 0xfe, 0x0, 0x80, 0x1f, 0xff, 0x10, 0x1, 0x11, 0x2, 0x11, 0xf8, 0x17, 0x0, 0x11, 0x2, 0x10, 0xfe, 0x10, 0x0, 0x17, 0xfe, 0x34, 0x0, 0x27, 0xfe, 0x64, 0x0, 0x7, 0xfe },
+{ 0x8b, 0x74, 0x0, 0x84, 0x30, 0xcc, 0x18, 0x48, 0xb, 0xff, 0x0, 0x20, 0x1, 0x22, 0x1, 0x22, 0x79, 0x22, 0x9, 0x22, 0x9, 0xfe, 0x8, 0x20, 0x8, 0x60, 0x8, 0xc0, 0x19, 0x80, 0x34, 0x0, 0x63, 0xff },
+{ 0x8b, 0x75, 0x0, 0x18, 0x0, 0xf0, 0xf, 0x80, 0x8, 0x0, 0x8, 0x0, 0x8, 0x0, 0xf, 0xfe, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x8b, 0x76, 0x1, 0x0, 0x1, 0x0, 0x3, 0xf0, 0x2, 0x10, 0x6, 0x10, 0xc, 0x30, 0x18, 0x20, 0x30, 0x60, 0x0, 0x40, 0x0, 0xe0, 0x1, 0xa0, 0x3, 0x30, 0x6, 0x10, 0xc, 0x18, 0x18, 0xc, 0x70, 0x7 },
+{ 0x8b, 0x77, 0x4, 0x80, 0x4, 0x80, 0xc, 0x80, 0x8, 0x80, 0x1b, 0xf8, 0x10, 0x88, 0x30, 0x88, 0x50, 0x88, 0x10, 0x88, 0x10, 0x88, 0x10, 0x88, 0x10, 0x88, 0x11, 0x88, 0x11, 0x9, 0x13, 0x9, 0x16, 0x7 },
+{ 0x8b, 0x78, 0x4, 0x40, 0x4, 0x40, 0xc, 0x40, 0x8, 0x40, 0x1f, 0xff, 0x11, 0x50, 0x31, 0x50, 0x51, 0x50, 0x11, 0x58, 0x13, 0x48, 0x12, 0x4c, 0x16, 0x46, 0x1c, 0x43, 0x10, 0x40, 0x10, 0x40, 0x10, 0x40 },
+{ 0x8b, 0x79, 0x0, 0x0, 0x3f, 0xf0, 0x2, 0x10, 0x2, 0x30, 0x2, 0x20, 0x7, 0x7c, 0x5, 0x4, 0x5, 0x8c, 0x4, 0x88, 0xc, 0xd8, 0x8, 0x70, 0x8, 0x60, 0x18, 0xf0, 0x11, 0x98, 0x33, 0xc, 0x6e, 0x7 },
+{ 0x8b, 0x7a, 0x0, 0x0, 0x3, 0xfc, 0x78, 0x84, 0x48, 0x8c, 0x48, 0x88, 0x48, 0x9e, 0x48, 0x82, 0x49, 0xc6, 0x49, 0x44, 0x49, 0x6c, 0x4b, 0x38, 0x7a, 0x10, 0x6, 0x38, 0xc, 0x6c, 0x18, 0xc6, 0x3, 0x83 },
+{ 0x8b, 0x7b, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x2, 0x20, 0x2, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x0, 0x80, 0x1, 0x0, 0x1f, 0xfc, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x1f, 0xfc },
+{ 0x8b, 0x7c, 0x0, 0x0, 0x3f, 0xfc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x1f, 0xfc, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x1f, 0xfe, 0x0, 0x2, 0x0, 0x2, 0x0, 0x6, 0x0, 0x4, 0x0, 0xc, 0x0, 0x78 },
+{ 0x8b, 0x7d, 0x2, 0x0, 0x7, 0xf0, 0xc, 0x20, 0x18, 0x40, 0x7f, 0xfc, 0x0, 0x4, 0x0, 0x4, 0x1f, 0xfc, 0x0, 0x4, 0x0, 0x4, 0x1f, 0xfc, 0x0, 0x80, 0x14, 0xc6, 0x14, 0x4b, 0x36, 0x19, 0x63, 0xf0 },
+{ 0x8b, 0x7e, 0x5, 0x10, 0x4, 0x90, 0x4, 0x10, 0x7f, 0x9f, 0x4, 0x12, 0x24, 0xb2, 0x35, 0xa2, 0x15, 0x76, 0x4, 0x14, 0x4, 0x1c, 0xf, 0x8, 0x1d, 0x88, 0x34, 0x9c, 0x64, 0x34, 0x4, 0x66, 0x1c, 0xc3 },
+{ 0x8b, 0x80, 0x8, 0x0, 0x9, 0xff, 0x8, 0x20, 0x7e, 0x20, 0x8, 0x60, 0x8, 0x40, 0x1c, 0xfe, 0x1a, 0x2, 0x1a, 0x2, 0x28, 0x2, 0x28, 0x2, 0x48, 0x6, 0x8, 0x4, 0x8, 0x4, 0x8, 0xc, 0x8, 0x38 },
+{ 0x8b, 0x81, 0x0, 0x98, 0x0, 0x8c, 0x0, 0x84, 0x7f, 0xff, 0x0, 0x80, 0x10, 0x82, 0x18, 0x86, 0xc, 0x8c, 0x4, 0x98, 0x0, 0xc0, 0x2, 0xe0, 0x6, 0xb0, 0xc, 0x98, 0x38, 0x8c, 0x60, 0x87, 0x3, 0x80 },
+{ 0x8b, 0x82, 0x0, 0x0, 0x37, 0xfc, 0x18, 0x84, 0x8, 0x8c, 0x0, 0x88, 0x60, 0x9e, 0x30, 0x82, 0x11, 0xc6, 0x1, 0x44, 0x9, 0x6c, 0x9, 0x38, 0x1b, 0x10, 0x12, 0x38, 0x36, 0x6c, 0x2c, 0xc6, 0x61, 0x83 },
+{ 0x8b, 0x83, 0x0, 0x20, 0x30, 0x20, 0x18, 0x20, 0xb, 0xfe, 0x0, 0x0, 0x61, 0x4, 0x31, 0x4, 0x11, 0x4, 0x1, 0x8c, 0x8, 0x88, 0x8, 0x88, 0x18, 0x98, 0x10, 0x10, 0x30, 0x10, 0x27, 0xff, 0x60, 0x0 },
+{ 0x8b, 0x84, 0x2, 0x0, 0x7, 0xf0, 0xc, 0x30, 0x38, 0x60, 0x0, 0xf0, 0x3, 0x98, 0xe, 0xc, 0x78, 0x7, 0x0, 0x80, 0x8, 0x82, 0x18, 0x86, 0x31, 0xcc, 0x3, 0x60, 0x6, 0x30, 0x1c, 0x1c, 0x70, 0x7 },
+{ 0x8b, 0x85, 0x0, 0x24, 0x0, 0x26, 0x7c, 0x22, 0x13, 0xff, 0x10, 0x20, 0x11, 0x22, 0x11, 0xa6, 0x7c, 0xac, 0x10, 0x20, 0x10, 0x30, 0x10, 0xb8, 0x1d, 0xac, 0x73, 0x26, 0x6, 0x23, 0x0, 0x20, 0x0, 0x60 },
+{ 0x8b, 0x86, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x22, 0x22, 0x26, 0x22, 0xc, 0x20, 0x38, 0x3e, 0x1, 0x0, 0x1, 0x0, 0x3f, 0xf0, 0x1, 0x10, 0x3, 0x10, 0x2, 0x10, 0x6, 0x11, 0xc, 0x13, 0x38, 0xe },
+{ 0x8b, 0x87, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x22, 0x22, 0xc, 0x3c, 0x32, 0x0, 0x1f, 0x7e, 0x11, 0x2, 0x1f, 0x3e, 0x11, 0x20, 0x1f, 0x20, 0x11, 0xbe, 0x7f, 0x2, 0x5, 0x2, 0x19, 0x6, 0x67, 0x1c },
+{ 0x8b, 0x88, 0x8, 0x10, 0x8, 0x10, 0x1f, 0xbf, 0x34, 0x48, 0x62, 0x4, 0x0, 0x0, 0x3f, 0xf8, 0x2, 0x10, 0x2, 0x3e, 0x7, 0xc, 0x5, 0x98, 0xc, 0xf0, 0x18, 0x60, 0x30, 0xf0, 0x63, 0x9c, 0xe, 0x7 },
+{ 0x8b, 0x89, 0x8, 0x0, 0x19, 0xfc, 0x30, 0x44, 0x62, 0x4c, 0x36, 0x48, 0xc, 0x5e, 0x18, 0x42, 0x34, 0xe2, 0x7e, 0xa6, 0xa, 0xb4, 0x8, 0x9c, 0x2d, 0x88, 0x2b, 0x1c, 0x69, 0x34, 0x4b, 0x66, 0x8, 0xc3 },
+{ 0x8b, 0x8a, 0x8, 0x4, 0x18, 0x24, 0x30, 0x24, 0x62, 0x24, 0x36, 0x24, 0xc, 0x24, 0x18, 0x24, 0x32, 0x24, 0x7f, 0x24, 0x9, 0x27, 0x8, 0x3c, 0x2a, 0xe4, 0x2b, 0x4, 0x69, 0x4, 0x48, 0x4, 0x8, 0x4 },
+{ 0x8b, 0x8b, 0x8, 0x10, 0x18, 0x38, 0x10, 0x28, 0x64, 0x6c, 0x2c, 0xc6, 0x19, 0x83, 0x10, 0x0, 0x24, 0x7c, 0x7e, 0x0, 0xa, 0x0, 0x8, 0xfe, 0x2a, 0x82, 0x2a, 0x82, 0x6a, 0x82, 0x48, 0x82, 0x8, 0xfe },
+{ 0x8b, 0x8c, 0x0, 0x0, 0x21, 0xfe, 0x21, 0x2, 0x21, 0x2, 0x21, 0x2, 0x21, 0x2, 0x21, 0x2, 0x21, 0xfe, 0x21, 0x2, 0x21, 0x2, 0x21, 0x2, 0x21, 0x2, 0x21, 0x2, 0x21, 0x2, 0x21, 0xfe, 0x0, 0x0 },
+{ 0x8b, 0x8d, 0x0, 0x80, 0x8, 0x80, 0x8, 0x80, 0x8, 0x80, 0x1f, 0xfc, 0x30, 0x80, 0x60, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80 },
+{ 0x8b, 0x8e, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x1, 0x0, 0x3, 0x10, 0x2, 0x18, 0x6, 0x8, 0xc, 0x1c, 0x9, 0xf6, 0x3f, 0x2 },
+{ 0x8b, 0x8f, 0x0, 0x0, 0x1f, 0xfe, 0x10, 0x2, 0x10, 0x2, 0x1f, 0xfe, 0x10, 0x40, 0x10, 0x40, 0x1f, 0xff, 0x10, 0x40, 0x10, 0x40, 0x17, 0xfe, 0x14, 0x2, 0x34, 0x2, 0x24, 0x2, 0x64, 0x2, 0x7, 0xfe },
+{ 0x8b, 0x90, 0x0, 0x0, 0x1f, 0xfe, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x1f, 0xfc, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x1f, 0xfc, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x1f, 0xfe, 0x0, 0x0 },
+{ 0x8b, 0x91, 0x8, 0x0, 0x8, 0xff, 0x8, 0x80, 0x8, 0x80, 0x7e, 0x80, 0x8, 0xfe, 0x8, 0x82, 0x8, 0x82, 0xe, 0x82, 0x78, 0xfe, 0x8, 0x80, 0x8, 0x80, 0x8, 0x80, 0x8, 0x80, 0x8, 0xff, 0x38, 0x0 },
+{ 0x8b, 0x92, 0x12, 0x0, 0x12, 0x3c, 0x13, 0xa4, 0x12, 0xa4, 0x7a, 0xa4, 0x16, 0xa4, 0x14, 0xa4, 0x12, 0xa4, 0x12, 0xa4, 0x1b, 0xa4, 0x71, 0x25, 0x11, 0x45, 0x13, 0x83, 0x12, 0xc0, 0x16, 0x70, 0x34, 0x1f },
+{ 0x8b, 0x93, 0x11, 0x4, 0x19, 0x8c, 0x8, 0x88, 0x7f, 0xff, 0x2, 0x20, 0x6, 0x30, 0x1c, 0x1c, 0x70, 0xe7, 0x7, 0x80, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x3, 0x80 },
+{ 0x8b, 0x94, 0x0, 0x0, 0x19, 0xfe, 0xd, 0x0, 0x61, 0xfc, 0x31, 0x4, 0x1, 0x4, 0xd, 0xfc, 0x39, 0x0, 0x61, 0xff, 0x0, 0x80, 0x7f, 0xff, 0x2, 0xa0, 0x6, 0xb0, 0x1c, 0x9c, 0x70, 0x87, 0x0, 0x80 },
+{ 0x8b, 0x95, 0x0, 0x40, 0x0, 0x7e, 0x0, 0x40, 0x1f, 0xff, 0x10, 0x81, 0x10, 0xfa, 0x17, 0x80, 0x10, 0x82, 0x10, 0x7e, 0x10, 0x0, 0x10, 0x90, 0x14, 0x92, 0x36, 0x96, 0x22, 0x94, 0x60, 0x90, 0xf, 0xff },
+{ 0x8b, 0x96, 0x0, 0x20, 0x3e, 0x20, 0x0, 0x20, 0x7f, 0x7e, 0x0, 0x50, 0x3e, 0x90, 0x0, 0x10, 0x0, 0x10, 0x3e, 0xff, 0x0, 0x10, 0x0, 0x10, 0x3e, 0x10, 0x22, 0x10, 0x22, 0x10, 0x22, 0x10, 0x3e, 0x10 },
+{ 0x8b, 0x97, 0x0, 0x0, 0x3e, 0xff, 0x22, 0x80, 0x22, 0x80, 0x22, 0x80, 0x22, 0xfe, 0x3e, 0x82, 0x8, 0x82, 0x28, 0x82, 0x2e, 0xfe, 0x28, 0x80, 0x28, 0x80, 0x28, 0x80, 0x2e, 0x80, 0x38, 0xff, 0x60, 0x0 },
+{ 0x8b, 0x98, 0x8, 0x0, 0x1c, 0xfe, 0x16, 0x82, 0x32, 0x82, 0x20, 0xfe, 0x7e, 0x88, 0x8, 0x88, 0x8, 0xff, 0x7e, 0x88, 0x8, 0x88, 0x4a, 0xbe, 0x6a, 0xa2, 0x29, 0xa2, 0xd, 0x22, 0x3b, 0x22, 0x60, 0x3e },
+{ 0x8b, 0x99, 0x0, 0x80, 0x30, 0x80, 0x19, 0xfc, 0xb, 0x8, 0x6, 0x10, 0x63, 0xfe, 0x32, 0x22, 0x12, 0x22, 0x3, 0xfe, 0xa, 0x22, 0xa, 0x22, 0x1b, 0xfe, 0x10, 0x0, 0x32, 0x92, 0x26, 0xdb, 0x6c, 0x49 },
+{ 0x8b, 0x9a, 0xa, 0x0, 0x13, 0xde, 0x24, 0x92, 0x4b, 0xd2, 0x10, 0x92, 0x32, 0xd2, 0x52, 0x92, 0x13, 0xd6, 0x16, 0x10, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x80, 0x18, 0x8c, 0x73, 0x87 },
+{ 0x8b, 0x9b, 0x2, 0x0, 0x2, 0x0, 0x7, 0xf8, 0xc, 0x10, 0x18, 0x20, 0x7f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x0, 0x0, 0x12, 0x22, 0x33, 0x33, 0x61, 0x11 },
+{ 0x8b, 0x9c, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x0, 0x0, 0x3f, 0xfe, 0x0, 0xc, 0x0, 0x30, 0x0, 0xc0, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x3, 0x80 },
+{ 0x8b, 0x9d, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x18, 0x0, 0x60, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x3, 0x80 },
+{ 0x8b, 0x9e, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x0, 0x80, 0x4, 0x90, 0xc, 0x98, 0x18, 0x8c, 0x70, 0x87, 0x3, 0x80 },
+{ 0x8b, 0x9f, 0x8, 0x88, 0x8, 0x88, 0x18, 0x88, 0x10, 0x88, 0x13, 0xfe, 0x30, 0x88, 0x30, 0x88, 0x50, 0x88, 0x10, 0x88, 0x10, 0x88, 0x17, 0xff, 0x10, 0x0, 0x10, 0x88, 0x11, 0x8c, 0x13, 0x6, 0x16, 0x3 },
+{ 0x8b, 0xa0, 0x8, 0x20, 0x8, 0x20, 0x1b, 0xfe, 0x10, 0x20, 0x12, 0x22, 0x33, 0x26, 0x31, 0x24, 0x51, 0x24, 0x10, 0x20, 0x17, 0xff, 0x10, 0x50, 0x10, 0xd8, 0x10, 0x88, 0x11, 0x8c, 0x13, 0x6, 0x16, 0x3 },
+{ 0x8b, 0xa1, 0x8, 0x1c, 0x9, 0xf0, 0x18, 0x40, 0x17, 0xff, 0x10, 0x88, 0x31, 0xfc, 0x36, 0x8b, 0x50, 0xf8, 0x10, 0x0, 0x13, 0xfe, 0x12, 0x2, 0x12, 0xfa, 0x12, 0x8a, 0x12, 0xfa, 0x12, 0x2, 0x12, 0xe },
+{ 0x8b, 0xa2, 0x0, 0x10, 0x16, 0x34, 0x13, 0x64, 0x11, 0xc4, 0x10, 0xc4, 0x11, 0xe4, 0x13, 0x34, 0x16, 0x14, 0x10, 0x4, 0x1f, 0xfc, 0x2, 0x20, 0x2, 0x20, 0x6, 0x20, 0xc, 0x21, 0x18, 0x33, 0x70, 0x1e },
+{ 0x8b, 0xa3, 0x8, 0x10, 0x8, 0x10, 0x7f, 0xff, 0x21, 0x42, 0x12, 0x24, 0x7f, 0xff, 0x0, 0x0, 0x3f, 0x7e, 0x21, 0x42, 0x21, 0x42, 0x3f, 0x7e, 0x14, 0x28, 0x14, 0x28, 0x35, 0x69, 0x26, 0x49, 0x64, 0xc7 },
+{ 0x8b, 0xa4, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x3f, 0xfe, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x0, 0x0, 0x4, 0x10, 0xc, 0x18, 0x18, 0xc, 0x70, 0x7 },
+{ 0x8b, 0xa5, 0x0, 0x0, 0x0, 0x8, 0x2c, 0x1a, 0x26, 0x12, 0x23, 0x32, 0x21, 0xa2, 0x20, 0xe2, 0x20, 0xc2, 0x21, 0xe2, 0x23, 0x32, 0x26, 0x1a, 0x2c, 0xa, 0x20, 0x2, 0x20, 0x2, 0x3f, 0xfe, 0x0, 0x0 },
+{ 0x8b, 0xa6, 0x10, 0x40, 0x10, 0x40, 0x13, 0xfc, 0x10, 0x44, 0x10, 0xc4, 0x7d, 0x8c, 0x13, 0x18, 0x10, 0x0, 0x11, 0x8, 0x17, 0xff, 0x11, 0x49, 0x11, 0x49, 0x13, 0x49, 0x12, 0x59, 0x16, 0xd3, 0x15, 0xb6 },
+{ 0x8b, 0xa7, 0x0, 0x0, 0x3f, 0xfe, 0x20, 0x0, 0x20, 0x0, 0x27, 0xf8, 0x20, 0x80, 0x20, 0x80, 0x23, 0xf0, 0x20, 0x80, 0x20, 0x80, 0x20, 0x80, 0x2f, 0xfc, 0x20, 0x0, 0x20, 0x0, 0x3f, 0xfe, 0x0, 0x0 },
+{ 0x8b, 0xa8, 0xc, 0x0, 0x39, 0xef, 0x21, 0x29, 0x25, 0x29, 0x25, 0xe9, 0x25, 0x29, 0x25, 0x29, 0x25, 0xe9, 0x25, 0x9, 0x25, 0x9, 0x3d, 0x9, 0x65, 0x49, 0xd, 0x49, 0x19, 0xeb, 0x33, 0x28, 0x60, 0x8 },
+{ 0x8b, 0xa9, 0x0, 0x4, 0x0, 0x4, 0x3e, 0x44, 0x22, 0x44, 0x22, 0x44, 0x22, 0x44, 0x22, 0x44, 0x22, 0x44, 0x22, 0x44, 0x22, 0x44, 0x22, 0x47, 0x3e, 0x7c, 0x1, 0xc4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4 },
+{ 0x8b, 0xaa, 0x0, 0x78, 0x1f, 0xc0, 0x1, 0x0, 0x7f, 0xff, 0x2, 0x20, 0x7, 0xf0, 0x1a, 0x2c, 0x63, 0xe3, 0x0, 0x0, 0x3f, 0xfe, 0x20, 0x2, 0x27, 0xf2, 0x24, 0x12, 0x27, 0xf2, 0x20, 0x2, 0x20, 0xe },
+{ 0x8b, 0xab, 0x10, 0x20, 0x10, 0x20, 0x13, 0xff, 0x10, 0x84, 0x7c, 0x48, 0x13, 0xff, 0x10, 0x0, 0x11, 0xfe, 0x11, 0x2, 0x11, 0xfe, 0x11, 0x2, 0x1d, 0xfe, 0x70, 0x48, 0x0, 0xc9, 0x1, 0x89, 0x7, 0x7 },
+{ 0x8b, 0xac, 0x0, 0x20, 0x10, 0x20, 0x11, 0xfe, 0x54, 0x20, 0x55, 0x22, 0x55, 0xa6, 0x54, 0xa4, 0x54, 0xa4, 0x54, 0x20, 0x57, 0xff, 0x54, 0x50, 0x7c, 0xd8, 0x0, 0x88, 0x1, 0x8c, 0x3, 0x6, 0x6, 0x3 },
+{ 0x8b, 0xad, 0x0, 0x40, 0x7c, 0x44, 0x4, 0xc4, 0x4, 0x9e, 0x5, 0xf2, 0x3c, 0x20, 0x21, 0xfe, 0x21, 0x22, 0x21, 0x22, 0x3d, 0x22, 0x5, 0xfe, 0x4, 0x20, 0x4, 0x22, 0xc, 0x22, 0x8, 0x3f, 0x3b, 0xe1 },
+{ 0x8b, 0xae, 0x0, 0x0, 0x7b, 0xff, 0x8, 0x0, 0x9, 0xfe, 0x9, 0x22, 0x39, 0xfe, 0x21, 0x22, 0x23, 0xff, 0x20, 0x0, 0x39, 0xfe, 0x9, 0x22, 0x9, 0xfe, 0x9, 0x22, 0x19, 0xfe, 0x10, 0x0, 0x73, 0xff },
+{ 0x8b, 0xaf, 0x8, 0x20, 0x8, 0x20, 0x8, 0x20, 0x9, 0xfe, 0x2c, 0x20, 0x2a, 0x20, 0x6a, 0x20, 0x48, 0x20, 0xb, 0xff, 0x8, 0x40, 0x8, 0x40, 0x8, 0xc4, 0x8, 0x84, 0x8, 0x9e, 0x9, 0xf2, 0xb, 0x2 },
+{ 0x8b, 0xb0, 0x1, 0xf8, 0x7d, 0x8, 0x11, 0x8, 0x11, 0xc8, 0x11, 0x68, 0x11, 0x28, 0x1d, 0x9, 0x73, 0x9, 0x6, 0x7, 0x0, 0x0, 0x1, 0x80, 0x14, 0xc4, 0x14, 0x46, 0x34, 0xb, 0x26, 0x19, 0x63, 0xf0 },
+{ 0x8b, 0xb1, 0x2, 0x20, 0x2, 0x20, 0x3f, 0xfe, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x7f, 0xff, 0x4, 0x10, 0x8, 0x88, 0x10, 0x84, 0x60, 0x83, 0x8, 0x8c, 0x8, 0xa6, 0x18, 0xb2, 0x30, 0x90, 0x3, 0x80 },
+{ 0x8b, 0xb2, 0x10, 0x20, 0x10, 0x20, 0x13, 0xfe, 0x10, 0x20, 0x7a, 0x22, 0x13, 0x26, 0x11, 0x24, 0x11, 0x24, 0x18, 0x20, 0x77, 0xff, 0x10, 0x50, 0x10, 0xd8, 0x10, 0x88, 0x11, 0x8c, 0x13, 0x6, 0x36, 0x3 },
+{ 0x8b, 0xb3, 0x4, 0x50, 0x4, 0x50, 0x3f, 0x90, 0x4, 0xbf, 0x5, 0x24, 0x7f, 0xc4, 0x2, 0x24, 0x3f, 0x2c, 0x9, 0x28, 0x12, 0x38, 0x64, 0x10, 0x7, 0xb8, 0x7c, 0x28, 0x4, 0x6c, 0x4, 0xc6, 0x1d, 0x83 },
+{ 0x8b, 0xb4, 0x10, 0x1c, 0x11, 0xf0, 0x10, 0x20, 0x13, 0xff, 0x7c, 0x48, 0x10, 0xfc, 0x13, 0x4b, 0x38, 0x78, 0x34, 0x0, 0x55, 0xfe, 0x51, 0x2, 0x11, 0x7a, 0x11, 0x4a, 0x11, 0x7a, 0x11, 0x2, 0x11, 0x6 },
+{ 0x8b, 0xb5, 0x0, 0x0, 0x33, 0xfc, 0x1a, 0x4, 0xa, 0x4, 0x2, 0x4, 0x62, 0x4, 0x32, 0x4, 0x13, 0xfc, 0x0, 0x90, 0x0, 0x90, 0x8, 0x90, 0x18, 0x90, 0x11, 0x90, 0x31, 0x11, 0x23, 0x13, 0x6e, 0xe },
+{ 0x8b, 0xb6, 0x0, 0x0, 0x4b, 0xfe, 0x28, 0x20, 0x10, 0x20, 0x10, 0x20, 0x28, 0x20, 0x48, 0x20, 0x9, 0xfc, 0x18, 0x20, 0x18, 0x20, 0x28, 0x20, 0x48, 0x20, 0x8, 0x20, 0x18, 0x20, 0x17, 0xff, 0x70, 0x0 },
+{ 0x8b, 0xb7, 0x4, 0x20, 0x44, 0x20, 0x2b, 0xfe, 0x10, 0x20, 0x12, 0x22, 0x2b, 0x26, 0x49, 0x24, 0x9, 0x24, 0x18, 0x20, 0x1f, 0xff, 0x28, 0x50, 0x48, 0xd8, 0x8, 0x88, 0x9, 0x8c, 0x1b, 0x6, 0x76, 0x3 },
+{ 0x8b, 0xb8, 0x20, 0x1c, 0x21, 0xf0, 0x3c, 0x20, 0x53, 0xff, 0x50, 0x48, 0x10, 0xfc, 0x13, 0x4b, 0x7c, 0x78, 0x10, 0x0, 0x11, 0xfe, 0x39, 0x2, 0x29, 0x7a, 0x2d, 0x4a, 0x65, 0x7a, 0x41, 0x2, 0x1, 0x6 },
+{ 0x8b, 0xb9, 0x3c, 0x80, 0x24, 0x80, 0x25, 0xff, 0x25, 0x1, 0x3f, 0x1, 0x24, 0x51, 0x25, 0x55, 0x25, 0x25, 0x25, 0x25, 0x3d, 0x55, 0x25, 0x55, 0x25, 0x5, 0x25, 0xfd, 0x24, 0x3, 0x64, 0x2, 0x4c, 0xe },
+{ 0x8b, 0xba, 0x0, 0x40, 0x1f, 0xfc, 0x1, 0x84, 0x1e, 0x38, 0x8, 0x8, 0x7f, 0x7f, 0x11, 0x11, 0x66, 0x66, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x4, 0x1f, 0xfc, 0x10, 0x4, 0x1f, 0xfc, 0x10, 0x4, 0x10, 0x1c },
+{ 0x8b, 0xbb, 0x4, 0x0, 0xf, 0xf0, 0x34, 0x1e, 0x24, 0x12, 0x25, 0xd2, 0x3c, 0x1e, 0x25, 0xd2, 0x25, 0x52, 0x3d, 0x5e, 0x25, 0xd2, 0x24, 0x12, 0x24, 0x12, 0x7f, 0xff, 0x4, 0x10, 0x1c, 0x1c, 0x70, 0x7 },
+{ 0x8b, 0xbc, 0x2, 0x20, 0x7f, 0xff, 0x2, 0x20, 0xf, 0xf8, 0x1, 0x0, 0x7f, 0xff, 0x2, 0x20, 0x7, 0xf0, 0x1a, 0x2c, 0x63, 0xe3, 0x0, 0x0, 0x3f, 0xfe, 0x20, 0x2, 0x23, 0xe2, 0x22, 0x22, 0x23, 0xe6 },
+{ 0x8b, 0xbd, 0x10, 0x0, 0x33, 0xdf, 0x22, 0x51, 0x62, 0x53, 0x4b, 0xd2, 0x2a, 0x56, 0x1a, 0x54, 0x13, 0xd2, 0x32, 0x11, 0x22, 0x11, 0x7a, 0x11, 0xa, 0x91, 0x1a, 0xd1, 0x13, 0x57, 0x36, 0x10, 0x60, 0x10 },
+{ 0x8b, 0xbe, 0x10, 0x10, 0x38, 0x10, 0x2d, 0xff, 0x64, 0x82, 0x40, 0x44, 0x7d, 0xff, 0x10, 0x0, 0x10, 0xfe, 0x7c, 0x82, 0x10, 0xfe, 0x54, 0x82, 0x54, 0xfe, 0x50, 0x48, 0x1c, 0x49, 0x30, 0xc9, 0x63, 0x87 },
+{ 0x8b, 0xbf, 0x13, 0xef, 0x62, 0x29, 0x2b, 0xea, 0x12, 0x2a, 0x7b, 0xe9, 0x12, 0x49, 0x23, 0xeb, 0x46, 0x28, 0x0, 0x80, 0x3f, 0xfe, 0x2, 0x20, 0x7f, 0xff, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8 },
+{ 0x8b, 0xc0, 0x13, 0xef, 0x62, 0x29, 0x2b, 0xea, 0x12, 0x2a, 0x7b, 0xe9, 0x12, 0x49, 0x23, 0xeb, 0x46, 0x28, 0x0, 0xc0, 0x7, 0xf0, 0x7c, 0x1f, 0x7, 0xf0, 0x4, 0x10, 0x7, 0xf4, 0x4, 0xc8, 0x3f, 0x3f },
+{ 0x8b, 0xc1, 0x12, 0x20, 0x7f, 0xbe, 0x12, 0x24, 0x3f, 0x54, 0x21, 0x8, 0x5d, 0x14, 0x15, 0x23, 0x1f, 0xf8, 0x8, 0x80, 0xf, 0xf8, 0x8, 0x80, 0xf, 0xf8, 0x8, 0x80, 0x2f, 0xfe, 0x64, 0x92, 0x42, 0x4e },
+{ 0x8b, 0xc2, 0x8, 0x60, 0x8, 0xc0, 0x1b, 0x9f, 0x12, 0x11, 0x12, 0x11, 0x32, 0x11, 0x32, 0x11, 0x52, 0x11, 0x12, 0x11, 0x12, 0x11, 0x12, 0x11, 0x12, 0xd1, 0x13, 0x97, 0x16, 0x10, 0x10, 0x10, 0x10, 0x10 },
+{ 0x8b, 0xc3, 0x4, 0x0, 0x4, 0xbe, 0x67, 0x2, 0x34, 0x24, 0x14, 0x58, 0x3, 0xc8, 0x4, 0x3f, 0x7, 0x89, 0x15, 0xa, 0x19, 0x28, 0x17, 0xae, 0x31, 0x28, 0x22, 0xa8, 0x22, 0x38, 0x64, 0x6c, 0x8, 0xc7 },
+{ 0x8b, 0xc4, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x0, 0x80, 0x8, 0x88, 0x8, 0x8, 0x7f, 0xff, 0x8, 0x8, 0x8, 0x8, 0x0, 0x0, 0x3f, 0xff, 0x2, 0x20, 0x2, 0x20, 0x6, 0x21, 0xc, 0x33, 0x78, 0x1e },
+{ 0x8b, 0xc5, 0x0, 0x20, 0x0, 0x20, 0x7b, 0xfe, 0x48, 0x20, 0x49, 0x24, 0x49, 0x4, 0x4f, 0xff, 0x79, 0x4, 0x49, 0x4, 0x48, 0x0, 0x4b, 0xfe, 0x48, 0x88, 0x78, 0x88, 0x1, 0x89, 0x3, 0x9, 0xe, 0x7 },
+{ 0x8b, 0xc6, 0x11, 0x44, 0x19, 0x4c, 0x9, 0x48, 0x7f, 0xff, 0x4, 0x10, 0x2, 0x20, 0x3f, 0xfe, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x7f, 0xff, 0x2, 0xa0, 0x6, 0xb0, 0x1c, 0x9c, 0x70, 0x87, 0x0, 0x80 },
+{ 0x8b, 0xc7, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x4, 0x10, 0x4, 0x1f, 0xfc, 0x10, 0x0, 0x10, 0x0, 0x1f, 0xfe, 0x10, 0x2, 0x13, 0xf2, 0x12, 0x12, 0x32, 0x12, 0x23, 0xf2, 0x60, 0x6, 0x0, 0x4, 0x0, 0x1c },
+{ 0x8b, 0xc8, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x3f, 0xfe, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x3f, 0xfe, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x3f, 0xfe, 0x0, 0x0 },
+{ 0x8b, 0xc9, 0x10, 0x0, 0x13, 0xfe, 0x10, 0x40, 0x7c, 0x40, 0x10, 0xe0, 0x10, 0x20, 0x1b, 0xbe, 0x36, 0xa2, 0x32, 0xaa, 0x52, 0xa4, 0x53, 0xaa, 0x10, 0x51, 0x11, 0xc0, 0x10, 0x0, 0x17, 0xff, 0x10, 0x0 },
+{ 0x8b, 0xca, 0x0, 0x0, 0x3f, 0xfe, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x80, 0x0, 0x98, 0x0, 0x8c, 0x0, 0x84, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x8b, 0xcb, 0x8, 0x0, 0x9, 0xfe, 0x9, 0x2, 0x7f, 0x2, 0x9, 0x7a, 0x9, 0x2, 0x1d, 0x2, 0x1b, 0x7a, 0x19, 0x4a, 0x29, 0x4a, 0x29, 0x4a, 0x49, 0x7a, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0xe },
+{ 0x8b, 0xcc, 0x8, 0x6, 0x49, 0x1c, 0x6b, 0x70, 0x2a, 0x10, 0x8, 0x10, 0x7e, 0x10, 0x8, 0x10, 0x9, 0xff, 0x1c, 0x10, 0x1a, 0x10, 0x29, 0x10, 0x28, 0x10, 0x48, 0x10, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10 },
+{ 0x8b, 0xcd, 0x8, 0x88, 0x8, 0x88, 0xf, 0xff, 0x18, 0x88, 0x10, 0x0, 0x33, 0xfe, 0x32, 0x22, 0x52, 0x22, 0x13, 0xfe, 0x10, 0x20, 0x13, 0xfe, 0x10, 0x20, 0x13, 0xfe, 0x10, 0x20, 0x10, 0x20, 0x17, 0xff },
+{ 0x8b, 0xce, 0x11, 0x8, 0x11, 0x8, 0x7f, 0xc8, 0x11, 0x8, 0x0, 0x7f, 0x3f, 0x89, 0x24, 0x89, 0x24, 0x89, 0x3f, 0x89, 0x4, 0x9, 0x3f, 0x99, 0x4, 0x11, 0x3f, 0x93, 0x4, 0x32, 0x7, 0xa2, 0x7c, 0x6e },
+{ 0x8b, 0xcf, 0x0, 0x80, 0x10, 0x80, 0x10, 0x80, 0x11, 0xfe, 0x7d, 0x2, 0x13, 0x2, 0x10, 0xe2, 0x10, 0x32, 0x10, 0x2, 0x10, 0x1a, 0x1c, 0x72, 0x71, 0xc2, 0x0, 0x6, 0x0, 0x4, 0x0, 0xc, 0x0, 0x38 },
+{ 0x8b, 0xd0, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x20, 0x8e, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80 },
+{ 0x8b, 0xd1, 0x8, 0x8, 0x1c, 0x10, 0x16, 0x7e, 0x33, 0x42, 0x20, 0x7e, 0x7e, 0x42, 0x8, 0x42, 0x8, 0x7e, 0x7f, 0x10, 0x8, 0xff, 0x4a, 0x91, 0x6a, 0x91, 0x28, 0x91, 0xe, 0x97, 0x38, 0x10, 0x60, 0x10 },
+{ 0x8b, 0xd2, 0x0, 0xc, 0x0, 0x78, 0x1f, 0xc0, 0x10, 0x0, 0x10, 0x0, 0x1f, 0xff, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x30, 0x20, 0x20, 0x20, 0x60, 0x20, 0x0, 0x20 },
+{ 0x8b, 0xd3, 0x3, 0x40, 0xe, 0x40, 0x38, 0x40, 0x20, 0x7f, 0x20, 0xc1, 0x3e, 0x93, 0x25, 0x92, 0x24, 0x10, 0x24, 0x10, 0x24, 0x38, 0x24, 0x28, 0x24, 0x28, 0x24, 0x6c, 0x64, 0x44, 0x44, 0xc6, 0x5, 0x83 },
+{ 0x8b, 0xd4, 0x8, 0x20, 0x1c, 0x20, 0x16, 0x20, 0x33, 0x7f, 0x20, 0x41, 0x7e, 0xd3, 0x8, 0x92, 0x8, 0x10, 0x7f, 0x10, 0x8, 0x38, 0x4a, 0x28, 0x6a, 0x28, 0x28, 0x6c, 0xf, 0x44, 0x38, 0xc6, 0x61, 0x83 },
+{ 0x8b, 0xd5, 0x0, 0x0, 0x7f, 0x3f, 0x8, 0x8, 0x3e, 0x1e, 0x8, 0x8, 0xf, 0x8, 0x78, 0xbf, 0x1, 0xc0, 0x7, 0x70, 0x1c, 0x1c, 0x73, 0xe7, 0x0, 0x0, 0xf, 0xfc, 0x0, 0x18, 0x0, 0x30, 0x0, 0x60 },
+{ 0x8b, 0xd6, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xfe, 0x14, 0x54, 0x16, 0x54, 0x35, 0x56, 0x64, 0x93, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x80, 0x8, 0x88, 0x18, 0x8c, 0x70, 0x87, 0x3, 0x80 },
+{ 0x8b, 0xd7, 0x0, 0x80, 0x1, 0xc0, 0x7, 0x70, 0x1c, 0x9c, 0x73, 0xe7, 0x9, 0x48, 0x8, 0x88, 0x9, 0x48, 0xf, 0xf8, 0x1, 0x0, 0x3f, 0xfe, 0x22, 0x2, 0x26, 0x22, 0x24, 0xf2, 0x2f, 0x92, 0x20, 0xe },
+{ 0x8b, 0xd8, 0x10, 0x20, 0x10, 0x20, 0x3f, 0x7f, 0x24, 0x48, 0x42, 0x84, 0x0, 0x10, 0x1f, 0x10, 0x11, 0x7e, 0x11, 0x12, 0x1f, 0x12, 0x11, 0x12, 0x11, 0x12, 0x1f, 0x12, 0x11, 0x32, 0x31, 0x22, 0x63, 0x6e },
+{ 0x8b, 0xd9, 0x0, 0x0, 0x3f, 0x7e, 0x24, 0x2, 0x3f, 0x26, 0x21, 0x14, 0x3f, 0x8, 0x24, 0x14, 0x3f, 0x63, 0x0, 0x80, 0x5, 0x20, 0x2, 0x44, 0x3f, 0xfe, 0x0, 0x82, 0x4, 0x90, 0x1c, 0x9c, 0x70, 0x87 },
+{ 0x8b, 0xda, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x0, 0xe, 0x1f, 0xf8, 0x10, 0x0, 0x10, 0x0, 0x1f, 0xff, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x30, 0x20, 0x20, 0x20, 0x60, 0x20, 0x0, 0x20 },
+{ 0x8b, 0xdb, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x0, 0x0, 0x3f, 0xfe, 0x20, 0x2, 0x27, 0xf2, 0x20, 0x82, 0x2f, 0xfa, 0x22, 0xa2, 0x22, 0xa2, 0x24, 0x92, 0x20, 0x82, 0x20, 0x2, 0x3f, 0xfe },
+{ 0x8b, 0xdc, 0x8, 0x10, 0x8, 0x38, 0x8, 0x28, 0x7e, 0x6c, 0x2, 0x44, 0x6, 0xc6, 0xd, 0xbb, 0x8, 0x0, 0x1a, 0x0, 0x3c, 0x7c, 0x6a, 0x4, 0x8, 0x4, 0x8, 0xc, 0x8, 0x8, 0x8, 0x18, 0x8, 0x10 },
+{ 0x8b, 0xdd, 0x10, 0x88, 0x10, 0x88, 0x13, 0xff, 0x7c, 0x88, 0x5, 0xdc, 0xd, 0xaa, 0xa, 0x89, 0x10, 0x0, 0x34, 0xfc, 0x58, 0x0, 0x15, 0xfe, 0x10, 0x20, 0x11, 0x24, 0x13, 0x26, 0x16, 0x23, 0x10, 0x60 },
+{ 0x8b, 0xde, 0x0, 0x44, 0x3c, 0x44, 0x1, 0xff, 0x7e, 0x44, 0x0, 0x0, 0x3c, 0xfe, 0x0, 0x92, 0x0, 0x92, 0x3c, 0xfe, 0x0, 0x10, 0x0, 0xfe, 0x3c, 0x10, 0x24, 0xfe, 0x24, 0x10, 0x24, 0x10, 0x3d, 0xff },
+{ 0x8b, 0xdf, 0x0, 0xc, 0x30, 0x38, 0x18, 0xe0, 0x8, 0x80, 0x0, 0x80, 0x0, 0xff, 0x0, 0x88, 0x78, 0x88, 0x8, 0x88, 0x8, 0x88, 0x9, 0x88, 0x9, 0x8, 0xb, 0x8, 0x18, 0x8, 0x34, 0x0, 0x63, 0xff },
+{ 0x8b, 0xe0, 0x0, 0x80, 0x1, 0xc0, 0x3, 0x60, 0x6, 0x30, 0xc, 0x18, 0x18, 0xc, 0x77, 0xf7, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x0, 0x80, 0x10, 0x84, 0x18, 0x8c, 0xc, 0x98, 0x4, 0x90, 0x7f, 0xff },
+{ 0x8b, 0xe1, 0x0, 0x20, 0x0, 0x70, 0x78, 0x50, 0x48, 0xd8, 0x49, 0x8c, 0x4b, 0x6, 0x4e, 0xfb, 0x48, 0x0, 0x48, 0x0, 0x49, 0xfc, 0x48, 0x4, 0x78, 0xc, 0x0, 0x8, 0x0, 0x18, 0x0, 0x10, 0x0, 0x30 },
+{ 0x8b, 0xe2, 0x8, 0x0, 0x1c, 0x7e, 0x16, 0x42, 0x33, 0x42, 0x21, 0x7e, 0x7e, 0x42, 0x8, 0x42, 0x8, 0x7e, 0x7f, 0x49, 0x8, 0x4b, 0x4a, 0x4a, 0x6a, 0x4c, 0x28, 0x44, 0xf, 0x46, 0x38, 0x7a, 0x61, 0xc3 },
+{ 0x8b, 0xe3, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x7f, 0xf0, 0x2, 0x10, 0x2, 0x10, 0x2, 0x10, 0x2, 0x10, 0x2, 0x10, 0x2, 0x10, 0x6, 0x10, 0x4, 0x10, 0xc, 0x11, 0x18, 0x1b, 0x70, 0xe },
+{ 0x8b, 0xe4, 0x4, 0x0, 0x5, 0xfc, 0xd, 0x4, 0x9, 0x4, 0x19, 0xfc, 0x11, 0x4, 0x31, 0x4, 0x51, 0xfc, 0x11, 0x4, 0x11, 0x4, 0x11, 0xfc, 0x10, 0x0, 0x17, 0xff, 0x10, 0x88, 0x11, 0x8c, 0x13, 0x6 },
+{ 0x8b, 0xe5, 0x2, 0x0, 0x6, 0x0, 0x4, 0x0, 0xf, 0xfe, 0x18, 0x2, 0x30, 0x2, 0x67, 0xe2, 0x4, 0x22, 0x4, 0x22, 0x4, 0x22, 0x4, 0x22, 0x7, 0xe2, 0x0, 0x2, 0x0, 0x6, 0x0, 0x4, 0x0, 0x1c },
+{ 0x8b, 0xe6, 0x0, 0x0, 0x3f, 0xfe, 0x20, 0x0, 0x20, 0x10, 0x2c, 0x10, 0x26, 0x30, 0x23, 0x20, 0x21, 0xe0, 0x20, 0xc0, 0x21, 0xe0, 0x23, 0x30, 0x26, 0x18, 0x2c, 0x8, 0x20, 0x0, 0x3f, 0xfe, 0x0, 0x0 },
+{ 0x8b, 0xe7, 0x5, 0x0, 0x45, 0x0, 0x29, 0x0, 0x13, 0xfe, 0x12, 0x2, 0x2a, 0x2, 0x4d, 0xf2, 0x9, 0x12, 0x19, 0x12, 0x19, 0x12, 0x29, 0x12, 0x49, 0xf2, 0x8, 0x2, 0x8, 0x2, 0x18, 0x6, 0x70, 0x1c },
+{ 0x8b, 0xe8, 0x0, 0x80, 0x0, 0x80, 0x7c, 0xf8, 0x10, 0x88, 0x11, 0x88, 0x11, 0x8, 0x13, 0x18, 0x7c, 0x10, 0x10, 0x30, 0x10, 0x20, 0x10, 0x70, 0x10, 0x50, 0x1c, 0xd8, 0x71, 0x8c, 0x3, 0x6, 0x6, 0x3 },
+{ 0x8b, 0xe9, 0x10, 0x0, 0x10, 0x7f, 0x10, 0x40, 0x3f, 0x40, 0x28, 0x40, 0x68, 0x7e, 0x8, 0x42, 0x7f, 0xc2, 0x8, 0x42, 0x8, 0x7e, 0x1c, 0x40, 0x16, 0x40, 0x33, 0x40, 0x21, 0x40, 0x60, 0x7f, 0x0, 0x0 },
+{ 0x8b, 0xea, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x4, 0x10, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8 },
+{ 0x8b, 0xeb, 0x4, 0x0, 0x8, 0xff, 0x3e, 0x80, 0x22, 0x82, 0x22, 0xa2, 0x3e, 0xb6, 0x22, 0x94, 0x22, 0x9c, 0x3e, 0x88, 0x23, 0x8c, 0x22, 0x9c, 0x7e, 0x96, 0x6, 0xb2, 0xa, 0xa2, 0x12, 0x80, 0x6e, 0xff },
+{ 0x8b, 0xec, 0x0, 0x0, 0x3f, 0xbf, 0x24, 0x20, 0x24, 0x20, 0x3f, 0x2a, 0x24, 0x2a, 0x24, 0x2a, 0x3f, 0x24, 0x24, 0x24, 0x24, 0x24, 0x3f, 0xaa, 0x0, 0xaa, 0x55, 0xaa, 0x54, 0xa0, 0x41, 0xa0, 0x7, 0x3e },
+{ 0x8b, 0xed, 0x0, 0x6, 0x3f, 0x8c, 0x24, 0x38, 0x24, 0x20, 0x3f, 0x20, 0x24, 0x3f, 0x24, 0x24, 0x3f, 0x24, 0x24, 0x24, 0x24, 0x24, 0x3f, 0xa4, 0x0, 0xa4, 0x55, 0xa4, 0x54, 0xa4, 0x41, 0xa4, 0x7, 0x7f },
+{ 0x8b, 0xee, 0x0, 0x20, 0x3f, 0x20, 0x24, 0x3f, 0x24, 0x61, 0x3f, 0x41, 0x24, 0xfd, 0x24, 0x25, 0x3f, 0x25, 0x24, 0x25, 0x24, 0x25, 0x3f, 0xbd, 0x0, 0x81, 0x55, 0x81, 0x54, 0x83, 0x41, 0x82, 0x7, 0xe },
+{ 0x8b, 0xef, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x0, 0x0, 0x7f, 0xff, 0x4, 0x10, 0xc, 0x18, 0x38, 0xe },
+{ 0x8b, 0xf0, 0x1f, 0xfc, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x84, 0x1f, 0xfc, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x92, 0x20, 0xfa, 0x2f, 0x8a, 0x20, 0x6, 0x1, 0x80, 0x14, 0xc6, 0x14, 0x4b, 0x36, 0x19, 0x63, 0xf0 },
+{ 0x8b, 0xf1, 0x0, 0x80, 0x0, 0xfc, 0x0, 0x80, 0x1f, 0xfe, 0x11, 0x2, 0x17, 0xf8, 0x11, 0x2, 0x10, 0xfe, 0x10, 0x0, 0x15, 0xf8, 0x15, 0x8, 0x17, 0xfc, 0x30, 0x4, 0x2f, 0xff, 0x61, 0x8, 0x6, 0x6 },
+{ 0x8b, 0xf2, 0x0, 0x20, 0x0, 0x70, 0x78, 0xd8, 0x49, 0x8c, 0x4f, 0x27, 0x49, 0xfc, 0x49, 0x4, 0x49, 0xfc, 0x49, 0x4, 0x49, 0xfd, 0x49, 0x23, 0x79, 0x36, 0x1, 0x18, 0x1, 0xc, 0x1, 0xe6, 0x7, 0x3 },
+{ 0x8b, 0xf3, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x2, 0x22, 0x22, 0x2, 0x20, 0x6, 0x20, 0xc, 0x3e, 0x38, 0x0, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x8b, 0xf4, 0x4, 0x0, 0x5, 0xfe, 0xd, 0x22, 0x9, 0x22, 0x19, 0xfe, 0x11, 0x22, 0x31, 0x22, 0x51, 0xfe, 0x10, 0x20, 0x13, 0xff, 0x12, 0x21, 0x12, 0x29, 0x12, 0x3d, 0x12, 0xe5, 0x12, 0x1, 0x12, 0x7 },
+{ 0x8b, 0xf5, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x2, 0x2f, 0xfa, 0x8, 0x88, 0xf, 0xf8, 0x8, 0x88, 0xf, 0xf8, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x82, 0x20, 0x92, 0x21, 0xfa, 0x2f, 0xa, 0x20, 0x6 },
+{ 0x8b, 0xf6, 0x0, 0x0, 0x31, 0xfc, 0x19, 0x24, 0x9, 0xfc, 0x1, 0x24, 0x1, 0x24, 0x1, 0xfc, 0x70, 0x20, 0x13, 0xfe, 0x12, 0x22, 0x12, 0x2a, 0x12, 0x3a, 0x12, 0xea, 0x32, 0x6, 0x28, 0x0, 0x67, 0xff },
+{ 0x8b, 0xf7, 0x0, 0x0, 0x3e, 0xfe, 0x22, 0x92, 0x26, 0x92, 0x2c, 0xfe, 0x28, 0x92, 0x28, 0x92, 0x24, 0xfe, 0x24, 0x10, 0x25, 0xff, 0x25, 0x11, 0x25, 0x15, 0x2d, 0x1d, 0x21, 0x75, 0x21, 0x1, 0x21, 0x7 },
+{ 0x8b, 0xf8, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x3f, 0xfe, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80 },
+{ 0x8b, 0xf9, 0x11, 0x8, 0x11, 0x8, 0x13, 0xef, 0x7a, 0x94, 0x14, 0x42, 0x10, 0x0, 0x33, 0xef, 0x3a, 0x29, 0x37, 0xe9, 0x52, 0x29, 0x53, 0xe9, 0x12, 0x9, 0x12, 0x49, 0x13, 0xeb, 0x16, 0x28, 0x10, 0x8 },
+{ 0x8b, 0xfa, 0x8, 0x2, 0x1c, 0x92, 0x16, 0x92, 0x32, 0x92, 0x21, 0x92, 0x7e, 0x92, 0x8, 0x92, 0x8, 0x92, 0x7e, 0x92, 0x8, 0x92, 0x4a, 0x92, 0x6a, 0x92, 0x28, 0x92, 0xf, 0x82, 0x79, 0x2, 0x3, 0x2 },
+{ 0x8b, 0xfb, 0x0, 0x0, 0x1f, 0xfe, 0x10, 0x2, 0x10, 0x2, 0x1f, 0xfe, 0x10, 0x0, 0x12, 0x22, 0x11, 0x24, 0x13, 0xfe, 0x12, 0x2, 0x13, 0xfe, 0x12, 0x2, 0x33, 0xfe, 0x22, 0x2, 0x62, 0x2, 0x2, 0xe },
+{ 0x8b, 0xfc, 0x0, 0x0, 0x1f, 0xfe, 0x10, 0x2, 0x10, 0x2, 0x1f, 0xfe, 0x10, 0x0, 0x10, 0x40, 0x14, 0x44, 0x14, 0x44, 0x14, 0x44, 0x17, 0xfc, 0x30, 0x40, 0x28, 0x42, 0x28, 0x42, 0x68, 0x42, 0xf, 0xfe },
+{ 0x8c, 0x40, 0x10, 0x0, 0x13, 0xfe, 0x12, 0x2, 0x12, 0x2, 0x7b, 0xfe, 0x12, 0x0, 0x12, 0x10, 0x12, 0x92, 0x1a, 0x92, 0x72, 0xfe, 0x12, 0x10, 0x12, 0x10, 0x16, 0x92, 0x14, 0x92, 0x1c, 0x92, 0x30, 0xfe },
+{ 0x8c, 0x41, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x22, 0x22, 0x2c, 0x3f, 0x70, 0x0, 0x1f, 0xfe, 0x10, 0x2, 0x1f, 0xfe, 0x10, 0x0, 0x14, 0x44, 0x14, 0x44, 0x37, 0xfc, 0x28, 0x42, 0x68, 0x42, 0xf, 0xfe },
+{ 0x8c, 0x42, 0x0, 0x80, 0x0, 0x82, 0x7e, 0xc6, 0x2, 0xec, 0x6, 0xb0, 0xc, 0x98, 0x18, 0x8c, 0x73, 0x87, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x4, 0x10, 0x4, 0x1f, 0xfc, 0x10, 0x4, 0x10, 0x4, 0x1f, 0xfc },
+{ 0x8c, 0x43, 0x12, 0x28, 0x12, 0x28, 0x7f, 0xa8, 0x12, 0x68, 0x12, 0x49, 0x1e, 0x4b, 0x8, 0xce, 0x3f, 0x48, 0x29, 0x48, 0x29, 0x48, 0x3f, 0x48, 0x8, 0x48, 0x7f, 0xc8, 0x8, 0x49, 0x8, 0x49, 0x8, 0x47 },
+{ 0x8c, 0x44, 0x10, 0x84, 0x23, 0xe8, 0x48, 0x92, 0x33, 0xec, 0x2a, 0xa9, 0x7b, 0xff, 0x12, 0xa4, 0x5b, 0xed, 0x54, 0x95, 0x53, 0xe5, 0x10, 0x84, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x4, 0x10, 0x4, 0x1f, 0xfc },
+{ 0x8c, 0x45, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x22, 0x42, 0x26, 0x42, 0x7c, 0x7f, 0x0, 0x0, 0x30, 0x20, 0x19, 0xfe, 0x60, 0x20, 0x33, 0xff, 0x0, 0x0, 0x8, 0x20, 0x19, 0xfe, 0x30, 0x20, 0x63, 0xff },
+{ 0x8c, 0x46, 0x10, 0x20, 0x21, 0x26, 0x7f, 0xbc, 0x0, 0xa0, 0x3f, 0x21, 0x21, 0x1f, 0x3f, 0x0, 0x21, 0x26, 0x3f, 0x3c, 0x21, 0x20, 0x21, 0x21, 0x23, 0x1f, 0x0, 0x0, 0x12, 0x24, 0x33, 0x36, 0x61, 0x13 },
+{ 0x8c, 0x47, 0x0, 0x0, 0x3d, 0xfc, 0x25, 0x24, 0x25, 0x24, 0x2d, 0xfc, 0x29, 0x24, 0x29, 0x24, 0x25, 0xfc, 0x24, 0x0, 0x27, 0xff, 0x25, 0x20, 0x25, 0x32, 0x2d, 0x14, 0x21, 0x18, 0x21, 0xcc, 0x27, 0x7 },
+{ 0x8c, 0x48, 0x1, 0x0, 0x3, 0xf0, 0xe, 0x20, 0x38, 0x60, 0x1, 0xb0, 0x7, 0x18, 0x1c, 0xc, 0x70, 0x87, 0x8, 0x88, 0x4, 0x90, 0x7f, 0xff, 0x2, 0xa0, 0x6, 0xb0, 0x1c, 0x9c, 0x70, 0x87, 0x0, 0x80 },
+{ 0x8c, 0x49, 0x0, 0x0, 0x7f, 0xff, 0x2, 0x20, 0x2, 0x20, 0x3f, 0xfe, 0x22, 0x22, 0x22, 0x22, 0x3f, 0xfe, 0x0, 0x80, 0x7f, 0xff, 0x2, 0xa0, 0x6, 0xb0, 0xc, 0x98, 0x18, 0x8c, 0x70, 0x87, 0x0, 0x80 },
+{ 0x8c, 0x4a, 0x8, 0x7c, 0x18, 0x44, 0x10, 0x44, 0x64, 0x7c, 0x2c, 0x0, 0x19, 0xef, 0x11, 0x29, 0x25, 0x29, 0x7d, 0xef, 0x14, 0x10, 0x11, 0xff, 0x54, 0x54, 0x54, 0x54, 0x54, 0xd6, 0x11, 0x93, 0x10, 0x10 },
+{ 0x8c, 0x4b, 0xf, 0xf8, 0x2, 0x30, 0x1, 0xc0, 0xe, 0x3c, 0x0, 0x0, 0x3f, 0x7e, 0x12, 0x24, 0xc, 0x18, 0x73, 0x67, 0x0, 0x80, 0x7f, 0xff, 0x2, 0xa0, 0x6, 0xb0, 0x1c, 0x9c, 0x70, 0x87, 0x0, 0x80 },
+{ 0x8c, 0x4c, 0x10, 0x24, 0x38, 0xe4, 0x2f, 0x84, 0x64, 0x95, 0x40, 0x95, 0x7f, 0xf5, 0x10, 0x95, 0x11, 0xc4, 0x7d, 0xa4, 0x12, 0xa4, 0x54, 0x8e, 0x54, 0x8a, 0x50, 0x8a, 0x1c, 0x8a, 0x30, 0x9b, 0x60, 0x91 },
+{ 0x8c, 0x4d, 0x1, 0x88, 0x3f, 0x8, 0x4, 0x8, 0x7f, 0xc8, 0x4, 0x3f, 0x3f, 0x89, 0x24, 0x89, 0x3f, 0x89, 0x24, 0x89, 0x3f, 0x99, 0x4, 0x13, 0x3f, 0x92, 0x4, 0x36, 0x7f, 0xc0, 0x22, 0x22, 0x41, 0x11 },
+{ 0x8c, 0x4e, 0x0, 0x0, 0x1f, 0xfc, 0x1, 0x4, 0x1, 0x4, 0x7f, 0xff, 0x1, 0x4, 0x1, 0x4, 0x1f, 0xfc, 0x2, 0x0, 0x4, 0x0, 0xf, 0xfe, 0x14, 0x2, 0x64, 0x2, 0x4, 0x2, 0x4, 0x2, 0x7, 0xfe },
+{ 0x8c, 0x4f, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x1f, 0xfc, 0x0, 0x80, 0x7f, 0xff, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x84, 0x1f, 0xfc, 0x0, 0x80, 0x3f, 0xfe, 0x0, 0x80, 0x7f, 0xff, 0x24, 0x22, 0x42, 0x11 },
+{ 0x8c, 0x50, 0x0, 0x2, 0x3c, 0x82, 0x0, 0x92, 0x7e, 0x92, 0x0, 0x92, 0x3c, 0x92, 0x0, 0x92, 0x0, 0x92, 0x3c, 0x92, 0x0, 0x92, 0x0, 0x92, 0x3c, 0x92, 0x24, 0x92, 0x24, 0x82, 0x24, 0x82, 0x3d, 0x2 },
+{ 0x8c, 0x51, 0x0, 0x41, 0x3f, 0x63, 0x9, 0x22, 0x9, 0x7f, 0x7f, 0x88, 0x9, 0x8, 0x9, 0x8, 0x3f, 0x3e, 0x10, 0x8, 0x10, 0x8, 0x3f, 0x8, 0x51, 0x7f, 0x11, 0x8, 0x11, 0x8, 0x11, 0x8, 0x1f, 0x8 },
+{ 0x8c, 0x52, 0x0, 0x0, 0x3f, 0xfe, 0x20, 0x2, 0x20, 0x82, 0x1f, 0xfc, 0x0, 0x80, 0x1f, 0xfc, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80 },
+{ 0x8c, 0x53, 0x0, 0x0, 0x3f, 0xbf, 0x8, 0xa1, 0x8, 0xa3, 0x7f, 0xe2, 0x8, 0xa6, 0x8, 0xa4, 0x3f, 0xa2, 0x10, 0x21, 0x10, 0x21, 0x3f, 0xa1, 0x50, 0xa1, 0x10, 0xa7, 0x10, 0xa0, 0x10, 0xa0, 0x1f, 0xa0 },
+{ 0x8c, 0x54, 0x4, 0x10, 0x4, 0x10, 0x3f, 0x90, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xdc, 0x0, 0x16, 0x4, 0x13, 0x4, 0x11, 0x3f, 0x90, 0x4, 0x10, 0x4, 0x10, 0x5, 0xd0, 0x1f, 0x10, 0x70, 0x10 },
+{ 0x8c, 0x55, 0x8, 0x0, 0x8, 0x3e, 0x7f, 0x22, 0x9, 0x22, 0x9, 0x22, 0x19, 0x22, 0x37, 0x3e, 0x60, 0x0, 0x0, 0x80, 0x7f, 0xff, 0x2, 0x44, 0xc, 0x68, 0x74, 0x30, 0x4, 0x18, 0x7, 0x8c, 0x3c, 0x7 },
+{ 0x8c, 0x56, 0x8, 0x0, 0x8, 0x7e, 0x8, 0x42, 0x7f, 0x46, 0x1, 0x44, 0x3, 0x4c, 0x6, 0x48, 0xc, 0x44, 0x18, 0x42, 0x3e, 0x42, 0x6b, 0x42, 0x9, 0x42, 0x8, 0x42, 0x8, 0x4e, 0x8, 0x40, 0x8, 0x40 },
+{ 0x8c, 0x57, 0x4, 0x6, 0x4, 0x3c, 0xf, 0xe0, 0x8, 0x40, 0x18, 0xc4, 0x11, 0x8c, 0x30, 0xd8, 0x50, 0x32, 0x10, 0x62, 0x17, 0xff, 0x10, 0x21, 0x11, 0x24, 0x11, 0x24, 0x13, 0x26, 0x16, 0x23, 0x10, 0x20 },
+{ 0x8c, 0x58, 0x8, 0x0, 0x8, 0xff, 0x18, 0x8, 0x14, 0x10, 0x14, 0x7e, 0x35, 0x42, 0x36, 0x42, 0x54, 0x7e, 0x14, 0x42, 0x14, 0x42, 0x15, 0x7e, 0x15, 0x42, 0x13, 0x42, 0x10, 0x7e, 0x10, 0x24, 0x10, 0xc3 },
+{ 0x8c, 0x59, 0x0, 0x2, 0x7f, 0xa2, 0x12, 0x22, 0x12, 0x22, 0x12, 0x22, 0x12, 0x22, 0x7f, 0xa2, 0x12, 0x22, 0x12, 0x22, 0x12, 0x22, 0x12, 0x22, 0x12, 0x2, 0x12, 0x2, 0x32, 0x2, 0x22, 0x2, 0x62, 0xe },
+{ 0x8c, 0x5a, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x1f, 0xfc, 0x2, 0x20, 0x2, 0x20, 0x6, 0x20, 0x4, 0x20, 0xc, 0x21, 0x18, 0x33, 0x70, 0x1e },
+{ 0x8c, 0x5b, 0x0, 0x20, 0x7f, 0xa0, 0x0, 0x7f, 0x3f, 0x44, 0x21, 0xcc, 0x21, 0x28, 0x3f, 0x38, 0x20, 0x6c, 0x20, 0xc6, 0x60, 0x3, 0x4f, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8 },
+{ 0x8c, 0x5c, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x0, 0x0, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x8c, 0x5d, 0x0, 0x20, 0x7c, 0x20, 0x11, 0xfe, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x7d, 0xff, 0x10, 0x0, 0x10, 0x20, 0x10, 0x20, 0x11, 0xfe, 0x10, 0x20, 0x1c, 0x20, 0x70, 0x20, 0x3, 0xff, 0x0, 0x0 },
+{ 0x8c, 0x5e, 0x0, 0x2, 0x7f, 0xa2, 0x12, 0x22, 0x12, 0x22, 0x12, 0x22, 0x7f, 0xa2, 0x12, 0x22, 0x12, 0x2, 0x32, 0x2, 0x60, 0xe, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x8c, 0x5f, 0x8, 0x0, 0x8, 0x0, 0x7f, 0x7e, 0x8, 0x12, 0x3f, 0x12, 0x8, 0x32, 0x8, 0x22, 0x1f, 0x66, 0x70, 0x4c, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x1, 0x40, 0x3, 0x60, 0xe, 0x38, 0x78, 0xf },
+{ 0x8c, 0x60, 0x0, 0x2, 0x7f, 0x86, 0x12, 0xc, 0x12, 0x18, 0x12, 0x30, 0x12, 0x2, 0x7f, 0x86, 0x12, 0xc, 0x12, 0x18, 0x12, 0x30, 0x12, 0x0, 0x12, 0x2, 0x32, 0x6, 0x22, 0xc, 0x22, 0x18, 0x62, 0x70 },
+{ 0x8c, 0x61, 0x8, 0x0, 0x1b, 0xfc, 0x31, 0x4, 0x61, 0x8c, 0x0, 0xd8, 0x8, 0x70, 0x19, 0xdc, 0x37, 0x7, 0x70, 0x20, 0x10, 0x20, 0x13, 0xfe, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x17, 0xff, 0x10, 0x0 },
+{ 0x8c, 0x62, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x0, 0x40, 0x12, 0x66, 0x12, 0x2b, 0x33, 0x19, 0x61, 0xf0 },
+{ 0x8c, 0x63, 0x0, 0x80, 0x3f, 0xff, 0x22, 0x20, 0x3f, 0xfe, 0x22, 0x22, 0x3f, 0xfe, 0x20, 0x0, 0x3f, 0xff, 0x20, 0x41, 0x25, 0x2a, 0x29, 0xf9, 0x20, 0x80, 0x21, 0xfc, 0x6f, 0x18, 0x40, 0xe0, 0x1f, 0x1f },
+{ 0x8c, 0x64, 0x8, 0x8, 0x7f, 0x7f, 0x8, 0x8, 0x7f, 0x7f, 0x8, 0x8, 0x7f, 0x7f, 0x8, 0x8, 0x3f, 0xfe, 0x0, 0x2, 0x3f, 0xfe, 0x0, 0x2, 0x3f, 0xfe, 0x0, 0x80, 0x12, 0x46, 0x32, 0xb, 0x61, 0xf9 },
+{ 0x8c, 0x65, 0x2, 0x8, 0xe, 0x10, 0x38, 0x7e, 0x8, 0x42, 0x7f, 0x7e, 0x8, 0x42, 0x8, 0x42, 0x3f, 0x7e, 0x21, 0x42, 0x21, 0x42, 0x3f, 0x7e, 0x0, 0x80, 0x14, 0xc6, 0x14, 0x4b, 0x36, 0x19, 0x63, 0xf0 },
+{ 0x8c, 0x66, 0x11, 0xfc, 0x11, 0x4, 0x11, 0x4, 0x11, 0xfc, 0x7d, 0x4, 0x11, 0x4, 0x11, 0xfc, 0x10, 0x80, 0x1d, 0xff, 0x73, 0x1, 0x16, 0x31, 0x13, 0xe1, 0x12, 0x1, 0x12, 0x13, 0x11, 0xf2, 0x30, 0xe },
+{ 0x8c, 0x67, 0x10, 0x48, 0x10, 0x90, 0x11, 0xff, 0x13, 0x10, 0x7d, 0xfe, 0x11, 0x10, 0x11, 0xfe, 0x11, 0x10, 0x1d, 0xff, 0x70, 0x0, 0x13, 0xfc, 0x10, 0x44, 0x10, 0x4f, 0x10, 0xc1, 0x11, 0x83, 0x37, 0xe },
+{ 0x8c, 0x68, 0x12, 0x20, 0x12, 0x20, 0x7f, 0xa0, 0x12, 0x7f, 0x12, 0x44, 0x20, 0xc4, 0x3f, 0x24, 0x21, 0x2c, 0x7d, 0x28, 0x25, 0x38, 0x25, 0x10, 0x25, 0x38, 0x3d, 0x28, 0x3, 0x6c, 0x2, 0x46, 0xe, 0xc3 },
+{ 0x8c, 0x69, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x0, 0x80, 0x4, 0x90, 0xc, 0x98, 0x3b, 0x8e },
+{ 0x8c, 0x6a, 0x8, 0x10, 0x8, 0x10, 0x8, 0xfe, 0x7e, 0x10, 0x8, 0x10, 0x8, 0x10, 0x1d, 0xff, 0x1a, 0x0, 0x1a, 0x10, 0x28, 0x10, 0x28, 0xfe, 0x48, 0x10, 0x8, 0x10, 0x8, 0x10, 0x9, 0xff, 0x8, 0x0 },
+{ 0x8c, 0x6b, 0x0, 0x6, 0x30, 0x3c, 0x1b, 0xe0, 0x8, 0x42, 0x2, 0x66, 0x63, 0x2c, 0x31, 0x8, 0x10, 0x20, 0x1, 0xfe, 0x8, 0x20, 0x8, 0x20, 0x1b, 0xff, 0x10, 0x50, 0x30, 0xd8, 0x21, 0x8c, 0x67, 0x7 },
+{ 0x8c, 0x6c, 0x0, 0x10, 0x0, 0x10, 0x7c, 0xfe, 0x54, 0x10, 0x54, 0x10, 0x54, 0x10, 0x7d, 0xff, 0x54, 0x0, 0x54, 0x10, 0x54, 0x10, 0x54, 0xfe, 0x7c, 0x10, 0x0, 0x10, 0x0, 0x10, 0x1, 0xff, 0x0, 0x0 },
+{ 0x8c, 0x6d, 0x4, 0x24, 0x1c, 0x22, 0x71, 0xff, 0x10, 0x48, 0x10, 0x48, 0x7c, 0x8f, 0x11, 0x40, 0x10, 0x7c, 0x38, 0x40, 0x34, 0x7e, 0x54, 0x0, 0x50, 0xfe, 0x10, 0x82, 0x10, 0xfe, 0x10, 0x82, 0x10, 0xfe },
+{ 0x8c, 0x6e, 0x0, 0xc, 0x0, 0x78, 0x3f, 0xc0, 0x1, 0x0, 0x3, 0x10, 0x6, 0x30, 0xc, 0x60, 0x6, 0xcc, 0x1, 0x86, 0x7f, 0xff, 0x0, 0x81, 0x4, 0x90, 0xc, 0x98, 0x18, 0x8c, 0x70, 0x87, 0x0, 0x80 },
+{ 0x8c, 0x6f, 0x8, 0x0, 0x19, 0xfe, 0x10, 0x82, 0x64, 0xc6, 0x2c, 0x6c, 0x18, 0x38, 0x10, 0x6c, 0x25, 0xc7, 0x7e, 0x10, 0xa, 0x10, 0x8, 0xfe, 0x2a, 0x10, 0x2a, 0x10, 0x6a, 0x10, 0x49, 0xff, 0x8, 0x0 },
+{ 0x8c, 0x70, 0x8, 0x88, 0x18, 0xc9, 0x30, 0xaa, 0x62, 0xaa, 0x36, 0x88, 0xc, 0xff, 0x18, 0x88, 0x32, 0x9c, 0x7e, 0x9c, 0xa, 0xaa, 0x8, 0xaa, 0x2a, 0xc9, 0x2a, 0x88, 0x6a, 0x80, 0x48, 0xff, 0x8, 0x0 },
+{ 0x8c, 0x71, 0x8, 0x3c, 0x7f, 0xa4, 0x8, 0x24, 0x3f, 0x47, 0x29, 0x80, 0x3f, 0x7e, 0x29, 0x22, 0x3f, 0x14, 0x8, 0x8, 0x7f, 0xb7, 0x8, 0x80, 0x3, 0x10, 0x1, 0xa2, 0x7f, 0xff, 0x4, 0x91, 0x38, 0x8c },
+{ 0x8c, 0x72, 0x3f, 0xfe, 0x22, 0x22, 0x22, 0x22, 0x3f, 0xfe, 0x0, 0x0, 0x4, 0x8, 0x3f, 0xc8, 0x4, 0x8, 0x4, 0x8, 0x7f, 0xee, 0x0, 0xb, 0x4, 0x9, 0x3f, 0xc8, 0x4, 0x8, 0x7, 0xe8, 0x7c, 0x8 },
+{ 0x8c, 0x73, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x0, 0x0, 0x3f, 0xfc, 0x4, 0x8, 0x3, 0x30, 0x1, 0xe0, 0xf, 0x38, 0x78, 0x8f, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff },
+{ 0x8c, 0x74, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x0, 0x0, 0x7f, 0x82, 0x12, 0x22, 0x12, 0x22, 0x12, 0x22, 0x7f, 0xa2, 0x12, 0x22, 0x12, 0x22, 0x12, 0x22, 0x32, 0x2, 0x22, 0x2, 0x62, 0xe },
+{ 0x8c, 0x75, 0x3, 0x2, 0x31, 0x86, 0x18, 0x8c, 0x8, 0x8, 0x7f, 0xff, 0x40, 0x81, 0x40, 0x81, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x84, 0x7, 0xfe, 0x7c, 0x2 },
+{ 0x8c, 0x76, 0x0, 0x10, 0x3e, 0x10, 0x0, 0x10, 0x7f, 0x10, 0x0, 0x10, 0x3e, 0x10, 0x0, 0xff, 0x0, 0x10, 0x3e, 0x10, 0x0, 0x10, 0x0, 0x10, 0x3e, 0x10, 0x22, 0x10, 0x22, 0x10, 0x22, 0x10, 0x3e, 0x10 },
+{ 0x8c, 0x77, 0x0, 0x40, 0x3e, 0x46, 0x0, 0x7c, 0x7f, 0x40, 0x0, 0x41, 0x3e, 0x63, 0x0, 0x3e, 0x0, 0x0, 0x3e, 0x0, 0x0, 0x7e, 0x0, 0x42, 0x3e, 0x42, 0x22, 0x7e, 0x22, 0x42, 0x22, 0x42, 0x3e, 0x7e },
+{ 0x8c, 0x78, 0x12, 0x20, 0x7f, 0xa0, 0x12, 0x7f, 0x3f, 0x44, 0x61, 0x2c, 0x3d, 0x18, 0x25, 0x24, 0x3e, 0xc3, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x0, 0xf, 0xf8, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x4, 0x1f, 0xfc },
+{ 0x8c, 0x79, 0x8, 0x0, 0x8, 0xfe, 0x7f, 0x42, 0x8, 0x66, 0x3e, 0x2c, 0x2a, 0x38, 0x2a, 0x6c, 0x3e, 0xc7, 0x2a, 0x10, 0x2a, 0x10, 0x3e, 0xfe, 0x8, 0x10, 0x7f, 0x10, 0x8, 0x10, 0x9, 0xff, 0x8, 0x0 },
+{ 0x8c, 0x7a, 0x0, 0x0, 0x7e, 0xff, 0x22, 0x10, 0x36, 0x7e, 0x1c, 0x42, 0x8, 0x42, 0x1c, 0x7e, 0x36, 0x42, 0x63, 0x42, 0x8, 0x7e, 0x3e, 0x42, 0x8, 0x42, 0x8, 0x7e, 0xf, 0x24, 0x78, 0x66, 0x0, 0xc3 },
+{ 0x8c, 0x7b, 0x7, 0x8, 0x7c, 0x10, 0x1, 0x7e, 0x4b, 0x42, 0x6a, 0x7e, 0x20, 0x42, 0x8, 0x7e, 0x3e, 0x40, 0x8, 0x7f, 0x8, 0x40, 0x7f, 0x7f, 0x8, 0x1, 0x1c, 0xab, 0x16, 0xa9, 0x32, 0x83, 0x60, 0x6 },
+{ 0x8c, 0x7c, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x4, 0x10, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xff, 0x2, 0x0, 0x6, 0x8, 0x4, 0xc, 0xc, 0x4, 0x9, 0xfe, 0x3f, 0x2 },
+{ 0x8c, 0x7d, 0x0, 0x20, 0x30, 0x60, 0x19, 0xde, 0x9, 0x12, 0x1, 0x12, 0x1, 0x12, 0x1, 0x12, 0x79, 0x12, 0x9, 0x12, 0x9, 0x12, 0x9, 0xd2, 0xb, 0x16, 0x8, 0x10, 0x18, 0x10, 0x34, 0x0, 0x63, 0xff },
+{ 0x8c, 0x7e, 0x10, 0x10, 0x1e, 0x10, 0x32, 0xff, 0x24, 0x0, 0x7e, 0x7e, 0x2a, 0x42, 0x2a, 0x42, 0x3e, 0x42, 0x2a, 0x7e, 0x2a, 0x10, 0x3e, 0x10, 0x0, 0x54, 0x1, 0x56, 0x55, 0x52, 0x54, 0x93, 0x40, 0x30 },
+{ 0x8c, 0x80, 0x4, 0x2, 0x7, 0xd2, 0x4, 0x12, 0x3f, 0xd2, 0x24, 0x52, 0x27, 0x12, 0x3c, 0x52, 0x27, 0xd2, 0x20, 0x12, 0x3f, 0xd2, 0x24, 0x12, 0x2a, 0x42, 0x35, 0x82, 0x6b, 0x42, 0x45, 0x22, 0x1b, 0xe },
+{ 0x8c, 0x81, 0x4, 0x14, 0x4, 0x16, 0x7f, 0xd2, 0x4, 0x10, 0x3f, 0x9f, 0x20, 0xf0, 0x20, 0x90, 0x3f, 0x92, 0x20, 0x92, 0x20, 0x96, 0x3f, 0x9c, 0x4, 0x8, 0x7f, 0xdd, 0x4, 0x35, 0x4, 0x67, 0x4, 0xc2 },
+{ 0x8c, 0x82, 0x8, 0x3c, 0x7f, 0xa4, 0x29, 0x47, 0x3f, 0x0, 0x29, 0x7e, 0x3f, 0x24, 0x8, 0x18, 0x7f, 0xa7, 0x8, 0x0, 0x7, 0xf0, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x3, 0x80 },
+{ 0x8c, 0x83, 0x1, 0x8, 0x22, 0x8, 0x37, 0xc8, 0x14, 0x5f, 0x7, 0xd2, 0x44, 0x72, 0x67, 0xd2, 0x21, 0x1a, 0xf, 0xea, 0x12, 0xe, 0x13, 0xc4, 0x32, 0x44, 0x26, 0x4e, 0x24, 0xca, 0x6c, 0x9b, 0x59, 0x91 },
+{ 0x8c, 0x84, 0x0, 0x20, 0x3c, 0xa4, 0x25, 0xa6, 0x27, 0x23, 0x2c, 0x20, 0x29, 0xfc, 0x29, 0x4, 0x25, 0xfc, 0x25, 0x4, 0x25, 0xfc, 0x24, 0x20, 0x25, 0x24, 0x29, 0x24, 0x23, 0x26, 0x26, 0x23, 0x20, 0xe0 },
+{ 0x8c, 0x85, 0x10, 0x80, 0x10, 0x9e, 0x11, 0x80, 0x7d, 0x0, 0x13, 0x0, 0x12, 0x80, 0x38, 0xbf, 0x35, 0x84, 0x31, 0x4, 0x53, 0x4, 0x51, 0x4, 0x11, 0x4, 0x11, 0x4, 0x11, 0x4, 0x11, 0x4, 0x11, 0x1c },
+{ 0x8c, 0x86, 0xa, 0x4, 0xb, 0xc4, 0x1a, 0x7f, 0x17, 0x54, 0x15, 0xd4, 0x30, 0x94, 0x31, 0xbf, 0x53, 0x4, 0x16, 0x4, 0x10, 0x20, 0x17, 0xff, 0x10, 0xa8, 0x11, 0xac, 0x13, 0x26, 0x16, 0x23, 0x10, 0x20 },
+{ 0x8c, 0x87, 0x4, 0x0, 0x4, 0x0, 0xf, 0xfe, 0x8, 0x2, 0x18, 0x86, 0x30, 0x8c, 0x60, 0x88, 0x0, 0x80, 0x1, 0xc0, 0x1, 0x40, 0x3, 0x60, 0x2, 0x20, 0x6, 0x30, 0xc, 0x18, 0x18, 0xc, 0x70, 0x7 },
+{ 0x8c, 0x88, 0x0, 0x40, 0x30, 0x40, 0x18, 0x40, 0xb, 0xfc, 0x0, 0x44, 0x60, 0x44, 0x30, 0x44, 0x10, 0x44, 0x7, 0xff, 0x8, 0xa0, 0x8, 0xb0, 0x19, 0x90, 0x11, 0x18, 0x33, 0xc, 0x26, 0x6, 0x6c, 0x3 },
+{ 0x8c, 0x89, 0x1, 0x0, 0x27, 0xdf, 0x31, 0x9, 0x17, 0xc9, 0x1, 0x19, 0x41, 0xd3, 0x67, 0x36, 0x20, 0x0, 0x0, 0x88, 0x11, 0x10, 0x10, 0xa2, 0x17, 0xff, 0x30, 0x21, 0x21, 0x24, 0x23, 0x26, 0x66, 0x23 },
+{ 0x8c, 0x8a, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x2, 0x20, 0x2, 0x20, 0x6, 0x30, 0x4, 0x10, 0xc, 0x18, 0x8, 0x8, 0x18, 0xc, 0x30, 0x6, 0x60, 0x3 },
+{ 0x8c, 0x8b, 0x8, 0x10, 0x18, 0x10, 0x30, 0x10, 0x61, 0xff, 0x34, 0x10, 0xc, 0x10, 0x18, 0x10, 0x34, 0xfe, 0x7e, 0x0, 0xa, 0x0, 0x8, 0xfe, 0x2a, 0x82, 0x2a, 0x82, 0x6a, 0x82, 0x48, 0x82, 0x8, 0xfe },
+{ 0x8c, 0x8c, 0x0, 0x80, 0x1, 0x80, 0x1, 0x0, 0x1f, 0xfc, 0x12, 0x44, 0x12, 0x44, 0x12, 0x44, 0x12, 0x44, 0x12, 0x44, 0x12, 0x44, 0x12, 0x44, 0x12, 0x44, 0x12, 0x44, 0x12, 0x44, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x8c, 0x8d, 0x0, 0x20, 0x3c, 0x20, 0x0, 0x20, 0x7e, 0xfc, 0x0, 0x24, 0x3c, 0x24, 0x0, 0x24, 0x0, 0x24, 0x3d, 0xff, 0x0, 0x50, 0x0, 0x50, 0x3c, 0x58, 0x24, 0xc8, 0x24, 0x8c, 0x25, 0x86, 0x3d, 0x3 },
+{ 0x8c, 0x8e, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x18, 0x8, 0x10, 0x8, 0x30, 0x8, 0x60, 0x38 },
+{ 0x8c, 0x8f, 0x8, 0x20, 0x9, 0x20, 0x19, 0x20, 0x11, 0x20, 0x13, 0xfe, 0x32, 0x20, 0x36, 0x20, 0x50, 0x20, 0x10, 0x20, 0x17, 0xff, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20 },
+{ 0x8c, 0x90, 0x8, 0x20, 0x8, 0x70, 0x18, 0xd8, 0x11, 0x8c, 0x17, 0x7, 0x31, 0xfc, 0x30, 0x20, 0x53, 0xfe, 0x12, 0x22, 0x12, 0x22, 0x12, 0x22, 0x13, 0xfe, 0x10, 0x50, 0x10, 0xd8, 0x11, 0x8c, 0x17, 0x7 },
+{ 0x8c, 0x91, 0xa, 0x44, 0xb, 0x4c, 0x19, 0x48, 0x17, 0xfe, 0x10, 0x90, 0x30, 0x90, 0x3f, 0xff, 0x51, 0x8, 0x12, 0xc, 0x17, 0xf6, 0x1c, 0x13, 0x10, 0x10, 0x13, 0xf0, 0x12, 0x2, 0x12, 0x6, 0x11, 0xfc },
+{ 0x8c, 0x92, 0x8, 0x10, 0xf, 0x7e, 0x9, 0x12, 0x19, 0x12, 0x12, 0x7f, 0x37, 0x12, 0x31, 0x12, 0x51, 0x7e, 0x15, 0x10, 0x15, 0x7e, 0x17, 0x10, 0x12, 0xff, 0x12, 0x10, 0x16, 0x10, 0x15, 0x0, 0x14, 0xff },
+{ 0x8c, 0x93, 0x8, 0x8, 0x4, 0x10, 0x3f, 0xfe, 0x2, 0x40, 0x1f, 0xfc, 0x2, 0x44, 0x2, 0x44, 0x7f, 0xff, 0x2, 0x44, 0x2, 0x44, 0x1f, 0xfc, 0xa, 0x50, 0x1a, 0x58, 0x32, 0x4c, 0x62, 0x47, 0x2, 0x40 },
+{ 0x8c, 0x94, 0x8, 0x88, 0xc, 0x98, 0x4, 0x90, 0x1f, 0xfc, 0x1, 0x40, 0x2, 0x20, 0x7f, 0xff, 0x6, 0x30, 0xc, 0x18, 0x1f, 0xfc, 0x71, 0x17, 0x3, 0x10, 0x2, 0x10, 0x6, 0x30, 0xc, 0x20, 0x38, 0xe0 },
+{ 0x8c, 0x95, 0x4, 0x2, 0xe, 0x12, 0x1b, 0x12, 0x11, 0x92, 0x30, 0xd2, 0x6f, 0x12, 0x4, 0x12, 0x3f, 0xd2, 0x24, 0x52, 0x24, 0x52, 0x3f, 0xd2, 0x4, 0x2, 0xe, 0x2, 0x1b, 0x2, 0x31, 0x82, 0x60, 0xce },
+{ 0x8c, 0x96, 0x0, 0x20, 0x0, 0x20, 0x7b, 0xfe, 0x4a, 0x2, 0x4a, 0x2, 0x49, 0xfc, 0x48, 0x0, 0x49, 0xfc, 0x49, 0x4, 0x49, 0x4, 0x49, 0xfc, 0x79, 0x4, 0x1, 0x4, 0x1, 0xfc, 0x0, 0x0, 0x7, 0xff },
+{ 0x8c, 0x97, 0x0, 0x0, 0x3f, 0xfe, 0x24, 0x92, 0x22, 0xa2, 0x2f, 0xfa, 0x21, 0x42, 0x2f, 0xfa, 0x22, 0x22, 0x27, 0xf2, 0x38, 0x2e, 0x23, 0xe2, 0x22, 0x12, 0x23, 0xf2, 0x20, 0x2, 0x3f, 0xfe, 0x0, 0x0 },
+{ 0x8c, 0x98, 0x0, 0x0, 0x3f, 0x7e, 0x24, 0x22, 0x24, 0x26, 0x3f, 0x34, 0x21, 0x1c, 0x3f, 0x8, 0x24, 0x1c, 0x24, 0x36, 0x3f, 0x63, 0x0, 0x0, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x8c, 0x99, 0x11, 0x4, 0x10, 0x88, 0x13, 0xfe, 0x10, 0x50, 0x7d, 0xfe, 0x14, 0x52, 0x14, 0x52, 0x37, 0xff, 0x24, 0x52, 0x24, 0x52, 0x7d, 0xfe, 0x8, 0x58, 0x14, 0xd4, 0x15, 0x56, 0x22, 0x53, 0x40, 0x50 },
+{ 0x8c, 0x9a, 0x0, 0x10, 0x7e, 0xfe, 0x4, 0x12, 0x8, 0x12, 0x11, 0xff, 0x3c, 0x12, 0x4, 0x12, 0x4, 0xfe, 0x2c, 0x10, 0x28, 0xfe, 0x28, 0x10, 0x39, 0xff, 0x10, 0x10, 0x38, 0x10, 0x2e, 0x0, 0x63, 0xff },
+{ 0x8c, 0x9b, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x82, 0x2f, 0xfa, 0x0, 0x80, 0xf, 0xf8, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x0, 0x1f, 0xfc, 0x12, 0x24, 0x1f, 0xfc, 0x0, 0x80, 0x12, 0x46, 0x32, 0xb, 0x61, 0xf9 },
+{ 0x8c, 0x9c, 0xf, 0x7, 0x29, 0x7c, 0x2f, 0x10, 0x29, 0x24, 0x2f, 0x68, 0x29, 0x12, 0x2f, 0x7f, 0x20, 0x9, 0x3f, 0xaa, 0x4, 0x2a, 0x25, 0x49, 0x44, 0x88, 0x0, 0x0, 0x14, 0x86, 0x34, 0x53, 0x63, 0xf1 },
+{ 0x8c, 0x9d, 0x8, 0x88, 0xc, 0x98, 0x4, 0x90, 0x3f, 0xfe, 0x1, 0x40, 0x7f, 0xff, 0x2, 0x20, 0x4, 0xf0, 0x1f, 0x9c, 0x70, 0x87, 0xf, 0xf8, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x3, 0x80 },
+{ 0x8c, 0x9e, 0x12, 0x22, 0x13, 0x26, 0x11, 0x24, 0x13, 0xfe, 0x78, 0x50, 0x10, 0x50, 0x17, 0xff, 0x10, 0x88, 0x19, 0x4, 0x73, 0xfe, 0x16, 0xb, 0x10, 0x8, 0x11, 0xf8, 0x11, 0x2, 0x11, 0x6, 0x30, 0xfc },
+{ 0x8c, 0x9f, 0x10, 0x20, 0x10, 0x70, 0x10, 0xd8, 0x79, 0x8c, 0x17, 0x7, 0x11, 0xfc, 0x30, 0x20, 0x3b, 0xfe, 0x36, 0x22, 0x52, 0x22, 0x52, 0x22, 0x13, 0xfe, 0x10, 0x50, 0x10, 0xd8, 0x11, 0x8c, 0x17, 0x7 },
+{ 0x8c, 0xa0, 0x8, 0x80, 0x8, 0x80, 0x8, 0xfe, 0x7f, 0xa0, 0x9, 0x20, 0xb, 0xff, 0x18, 0x48, 0x1c, 0x50, 0x1a, 0xfe, 0x28, 0x90, 0x29, 0xfe, 0x4a, 0x90, 0x8, 0xfe, 0x8, 0x90, 0x8, 0x90, 0x8, 0xff },
+{ 0x8c, 0xa1, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x9, 0x10, 0x6, 0x20, 0x3f, 0xfe, 0x22, 0x2, 0x24, 0x12, 0xf, 0xf8, 0x0, 0x8, 0x4, 0x80, 0xf, 0xf8, 0x10, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80 },
+{ 0x8c, 0xa2, 0x0, 0x80, 0x0, 0x98, 0x0, 0x8c, 0x0, 0x84, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x1, 0xc0, 0x1, 0x40, 0x1, 0x40, 0x3, 0x60, 0x2, 0x20, 0x6, 0x30, 0xc, 0x18, 0x18, 0xc, 0x70, 0x7 },
+{ 0x8c, 0xa3, 0x8, 0x8, 0x8, 0xa, 0x7f, 0x8a, 0x8, 0x8, 0x8, 0x8, 0x7f, 0xbf, 0x40, 0x88, 0x62, 0x88, 0x54, 0x88, 0x7e, 0x9c, 0x48, 0x94, 0x7e, 0x94, 0x48, 0x94, 0x48, 0x96, 0x48, 0xb2, 0x41, 0xa3 },
+{ 0x8c, 0xa4, 0x0, 0x0, 0x7e, 0xff, 0x8, 0x24, 0x8, 0x24, 0x8, 0x24, 0x18, 0x24, 0x10, 0x24, 0x1e, 0xff, 0x32, 0x24, 0x32, 0x24, 0x52, 0x24, 0x12, 0x24, 0x12, 0x64, 0x1e, 0x44, 0x0, 0xc4, 0x1, 0x84 },
+{ 0x8c, 0xa5, 0x0, 0x0, 0x7f, 0x7e, 0x8, 0x42, 0x8, 0x42, 0x18, 0x7e, 0x10, 0x42, 0x1e, 0x42, 0x32, 0x7e, 0x32, 0x42, 0x52, 0x42, 0x12, 0x7e, 0x12, 0x28, 0x12, 0x28, 0x1e, 0x69, 0x0, 0xc9, 0x1, 0x87 },
+{ 0x8c, 0xa6, 0x8, 0x0, 0x18, 0xfe, 0x30, 0x82, 0x62, 0x82, 0x36, 0xfe, 0xc, 0x0, 0x18, 0xfe, 0x34, 0x82, 0x7e, 0x82, 0xa, 0xfe, 0x8, 0x82, 0x2a, 0x82, 0x2a, 0xfe, 0x6a, 0x82, 0x48, 0x82, 0x8, 0x8e },
+{ 0x8c, 0xa7, 0x3, 0xf8, 0x12, 0x8, 0x12, 0x8, 0x13, 0xf8, 0x12, 0x8, 0x12, 0x8, 0x13, 0xf8, 0x12, 0x8, 0x12, 0x8, 0x13, 0xf8, 0x10, 0x0, 0x1f, 0xff, 0x2, 0x48, 0x6, 0x4c, 0x1c, 0x47, 0x0, 0x40 },
+{ 0x8c, 0xa8, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x4, 0x10, 0x4, 0x1f, 0xfc, 0x10, 0x0, 0x17, 0xfc, 0x14, 0x4, 0x17, 0xfc, 0x14, 0x4, 0x37, 0xfc, 0x24, 0x4, 0x64, 0x4, 0x4, 0x1c },
+{ 0x8c, 0xa9, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x2, 0x20, 0x2, 0x20, 0x6, 0x21, 0xc, 0x33, 0x78, 0x1e },
+{ 0x8c, 0xaa, 0x0, 0x82, 0x3c, 0x44, 0x1, 0xff, 0x7e, 0x28, 0x0, 0xfe, 0x3c, 0x2a, 0x0, 0x2a, 0x1, 0xff, 0x3c, 0x2a, 0x0, 0x2a, 0x0, 0xfe, 0x3c, 0x28, 0x24, 0x6c, 0x24, 0xaa, 0x25, 0x29, 0x3c, 0x28 },
+{ 0x8c, 0xab, 0x3f, 0x7e, 0x24, 0x22, 0x3f, 0x36, 0x21, 0x14, 0x3f, 0x1c, 0x24, 0x36, 0x3f, 0x63, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x38, 0xe },
+{ 0x8c, 0xac, 0x8, 0x0, 0x8, 0x7f, 0x7f, 0x88, 0x8, 0x8, 0x3f, 0x8, 0x29, 0x8, 0x29, 0x8, 0x3f, 0x7f, 0x29, 0x8, 0x29, 0x8, 0x3f, 0x8, 0x8, 0x8, 0x7f, 0x88, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8 },
+{ 0x8c, 0xad, 0x0, 0x20, 0x33, 0xfe, 0x1a, 0x22, 0xb, 0xfe, 0x0, 0x20, 0x7, 0xff, 0x0, 0x0, 0x79, 0xfc, 0x9, 0x4, 0x9, 0xfc, 0x9, 0x0, 0x9, 0xfe, 0x9, 0x2, 0x19, 0xfe, 0x34, 0x0, 0x63, 0xff },
+{ 0x8c, 0xae, 0x10, 0x8, 0x39, 0xde, 0x2c, 0x4a, 0x64, 0x8a, 0x40, 0xbf, 0x39, 0xa, 0x11, 0xca, 0x10, 0x5e, 0x7c, 0x48, 0x11, 0x5e, 0x55, 0x48, 0x54, 0xbf, 0x50, 0x88, 0x1d, 0x88, 0x31, 0x40, 0x63, 0x3f },
+{ 0x8c, 0xaf, 0x0, 0x20, 0x3c, 0x70, 0x24, 0xd8, 0x25, 0x8c, 0x27, 0x7, 0x28, 0xfc, 0x28, 0x20, 0x25, 0xfe, 0x25, 0x22, 0x25, 0x22, 0x25, 0x22, 0x25, 0xfe, 0x2c, 0x50, 0x20, 0xd8, 0x21, 0x8c, 0x27, 0x7 },
+{ 0x8c, 0xb0, 0x0, 0x0, 0x3e, 0xff, 0x22, 0x10, 0x22, 0x7e, 0x3e, 0x42, 0x22, 0x42, 0x22, 0x7e, 0x3e, 0x42, 0x0, 0x42, 0x14, 0x7e, 0x15, 0x42, 0x56, 0x42, 0x34, 0x7e, 0x17, 0x24, 0x1c, 0x66, 0x70, 0xc3 },
+{ 0x8c, 0xb1, 0x0, 0x8, 0x3f, 0x9c, 0x24, 0x36, 0x24, 0x63, 0x3f, 0x3e, 0x24, 0x8, 0x24, 0x7f, 0x3f, 0x49, 0x24, 0x49, 0x24, 0x49, 0x3f, 0xff, 0x0, 0x88, 0x55, 0x9c, 0x54, 0x94, 0x41, 0xb6, 0x3, 0x63 },
+{ 0x8c, 0xb2, 0x8, 0x8, 0x8, 0x1c, 0xf, 0x36, 0x8, 0x63, 0x8, 0x3e, 0x7f, 0x8, 0x49, 0x7f, 0x41, 0x49, 0x55, 0x49, 0x49, 0x49, 0x6b, 0x7f, 0x49, 0x8, 0x55, 0x1c, 0x41, 0x14, 0x49, 0x36, 0x7f, 0x63 },
+{ 0x8c, 0xb3, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xff, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x6, 0x20, 0x4, 0x20, 0xc, 0x21, 0x18, 0x33, 0x70, 0x1e },
+{ 0x8c, 0xb4, 0x0, 0x0, 0x1f, 0xff, 0x10, 0x20, 0x10, 0x40, 0x13, 0xfe, 0x12, 0x2, 0x12, 0x2, 0x13, 0xfe, 0x12, 0x2, 0x12, 0x2, 0x13, 0xfe, 0x10, 0x20, 0x31, 0x24, 0x23, 0x26, 0x66, 0x23, 0x0, 0xe0 },
+{ 0x8c, 0xb5, 0x10, 0x82, 0x8, 0x44, 0x3f, 0xff, 0x20, 0x0, 0x2f, 0x90, 0x22, 0x10, 0x3f, 0xde, 0x28, 0xb4, 0x2f, 0xa4, 0x28, 0x94, 0x2f, 0x9c, 0x28, 0x88, 0x68, 0x9c, 0x4f, 0x94, 0x58, 0xb6, 0x0, 0xe3 },
+{ 0x8c, 0xb6, 0x4, 0x0, 0xc, 0xfe, 0x18, 0x2, 0x10, 0x2, 0x30, 0x2, 0x61, 0x2, 0x33, 0x2, 0x1a, 0x2, 0x6, 0x2, 0xc, 0x2, 0x8, 0x2, 0x19, 0x2, 0x11, 0x6, 0x3f, 0x84, 0x60, 0x84, 0x0, 0x1c },
+{ 0x8c, 0xb7, 0x0, 0x20, 0x7c, 0x20, 0x4, 0x20, 0x7, 0xff, 0x4, 0x20, 0x3c, 0x60, 0x20, 0xc4, 0x21, 0x8c, 0x20, 0xc8, 0x3c, 0x58, 0x4, 0x30, 0x4, 0x64, 0x4, 0x46, 0xc, 0xc2, 0x9, 0x9f, 0x3b, 0xf1 },
+{ 0x8c, 0xb8, 0x0, 0x14, 0x20, 0x12, 0x30, 0x12, 0x17, 0xff, 0x4, 0x10, 0x45, 0xd2, 0x64, 0x12, 0x25, 0xd6, 0x5, 0x54, 0x15, 0x5c, 0x15, 0x48, 0x15, 0xc8, 0x34, 0x1d, 0x2c, 0x35, 0x28, 0x67, 0x68, 0xc2 },
+{ 0x8c, 0xb9, 0x0, 0x0, 0x23, 0xff, 0x32, 0x8, 0x12, 0x10, 0x2, 0xfe, 0x42, 0x82, 0x62, 0x82, 0x22, 0xfe, 0x2, 0x82, 0x12, 0x82, 0x12, 0xfe, 0x12, 0x10, 0x36, 0x54, 0x24, 0xd6, 0x2d, 0x93, 0x60, 0x30 },
+{ 0x8c, 0xba, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x1, 0x80, 0x3, 0x8, 0x6, 0x18, 0xc, 0x30, 0x6, 0x60, 0x3, 0xc0, 0x1, 0x90, 0x3, 0x18, 0x6, 0xc, 0xf, 0xfe, 0x38, 0x2 },
+{ 0x8c, 0xbb, 0x0, 0x0, 0x1, 0xfc, 0x7d, 0x4, 0x11, 0x4, 0x11, 0xfc, 0x11, 0x4, 0x7d, 0x4, 0x11, 0xfc, 0x11, 0x4, 0x11, 0x4, 0x11, 0xfc, 0x1c, 0x50, 0x70, 0x50, 0x0, 0xd1, 0x1, 0x93, 0x7, 0xe },
+{ 0x8c, 0xbc, 0x8, 0x10, 0x18, 0x10, 0x30, 0x10, 0x65, 0xff, 0x34, 0x10, 0xc, 0x30, 0x18, 0x60, 0x34, 0xc4, 0x7e, 0x6c, 0xa, 0x38, 0x8, 0x10, 0x2a, 0x30, 0x2a, 0x62, 0x6a, 0x42, 0x48, 0xdf, 0x9, 0xf1 },
+{ 0x8c, 0xbd, 0x4, 0x10, 0x8, 0x10, 0x3e, 0x10, 0x22, 0xff, 0x2a, 0x10, 0x2a, 0x10, 0x22, 0x30, 0x7f, 0x24, 0x22, 0x6c, 0x2a, 0x28, 0x2a, 0x18, 0x2a, 0x10, 0x2a, 0x32, 0x22, 0x62, 0x62, 0x4f, 0x46, 0xf9 },
+{ 0x8c, 0xbe, 0x0, 0x0, 0xf, 0xf8, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x0, 0xf, 0xf8, 0x0, 0x0, 0x0, 0x0, 0xf, 0xf8, 0x0, 0x0, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8 },
+{ 0x8c, 0xbf, 0x0, 0x10, 0x3c, 0x10, 0x1, 0xff, 0x7e, 0x44, 0x0, 0x28, 0x3d, 0xff, 0x1, 0x4, 0x1, 0x1c, 0x3d, 0x72, 0x1, 0x6, 0x1, 0x1c, 0x3d, 0x71, 0x25, 0x3, 0x25, 0x6, 0x26, 0x1c, 0x3c, 0x70 },
+{ 0x8c, 0xc0, 0x0, 0x0, 0x3d, 0xfc, 0x25, 0x4, 0x25, 0x4, 0x25, 0xfc, 0x2d, 0x4, 0x29, 0x4, 0x25, 0xfc, 0x25, 0x21, 0x25, 0x33, 0x25, 0x16, 0x25, 0x1c, 0x2d, 0x8, 0x21, 0xc, 0x21, 0xe6, 0x27, 0x3 },
+{ 0x8c, 0xc1, 0x0, 0x18, 0x0, 0xf0, 0x3f, 0x80, 0x0, 0x84, 0x10, 0x8c, 0x18, 0x98, 0x8, 0x90, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x3, 0x80 },
+{ 0x8c, 0xc2, 0x8, 0x0, 0xb, 0xfe, 0x1a, 0x2, 0x12, 0x22, 0x12, 0x22, 0x32, 0xfa, 0x32, 0x22, 0x52, 0x22, 0x12, 0xfa, 0x12, 0x8a, 0x12, 0x8a, 0x12, 0x8a, 0x12, 0xfa, 0x12, 0x2, 0x13, 0xfe, 0x10, 0x0 },
+{ 0x8c, 0xc3, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x0, 0x0 },
+{ 0x8c, 0xc4, 0x0, 0x6, 0x0, 0x3c, 0x7b, 0xe0, 0x48, 0x22, 0x4a, 0x26, 0x4b, 0x24, 0x49, 0x24, 0x48, 0x20, 0x4f, 0xff, 0x48, 0x20, 0x48, 0x20, 0x78, 0x20, 0x0, 0x20, 0x0, 0x20, 0x0, 0x20, 0x0, 0xe0 },
+{ 0x8c, 0xc5, 0x0, 0x0, 0x3f, 0xfe, 0x20, 0x2, 0x20, 0x82, 0x20, 0x82, 0x2f, 0xfa, 0x20, 0x82, 0x20, 0x82, 0x27, 0xf2, 0x24, 0x12, 0x24, 0x12, 0x24, 0x12, 0x27, 0xf2, 0x20, 0x2, 0x3f, 0xfe, 0x0, 0x0 },
+{ 0x8c, 0xc6, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10, 0x7d, 0xff, 0x14, 0x10, 0x14, 0x10, 0x34, 0x10, 0x24, 0x10, 0x2c, 0xfe, 0x28, 0x82, 0x78, 0x82, 0x14, 0x82, 0x12, 0x82, 0x22, 0x82, 0x40, 0xfe },
+{ 0x8c, 0xc7, 0x0, 0x6, 0x7c, 0x3c, 0x5, 0xe4, 0x9, 0x4, 0x11, 0x24, 0x11, 0x24, 0x11, 0x24, 0x1d, 0x24, 0x71, 0x24, 0x11, 0x24, 0x11, 0x24, 0x11, 0x26, 0x11, 0x2a, 0x13, 0x3a, 0x12, 0xea, 0x76, 0x3 },
+{ 0x8c, 0xc8, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x1f, 0xfc, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x10, 0x2, 0x18, 0x6, 0xf, 0xfc, 0x0, 0x0 },
+{ 0x8c, 0xc9, 0x0, 0x40, 0x0, 0x40, 0x1f, 0xff, 0x10, 0x0, 0x10, 0x40, 0x17, 0xfe, 0x10, 0x40, 0x13, 0xfc, 0x12, 0x44, 0x13, 0xfc, 0x12, 0x44, 0x13, 0xfc, 0x30, 0x40, 0x2f, 0xff, 0x60, 0x40, 0x0, 0x40 },
+{ 0x8c, 0xca, 0x0, 0x6, 0x78, 0x3c, 0x9, 0xe4, 0x9, 0x4, 0x9, 0x24, 0x79, 0x24, 0x41, 0x24, 0x41, 0x24, 0x41, 0x24, 0x79, 0x24, 0x9, 0x24, 0x9, 0x26, 0x9, 0x2a, 0xb, 0x3a, 0x1a, 0xea, 0x76, 0x3 },
+{ 0x8c, 0xcb, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x1f, 0xfc, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x30, 0x0, 0x20, 0x0, 0x60, 0x0 },
+{ 0x8c, 0xcc, 0x8, 0x40, 0x8, 0x40, 0x8, 0x40, 0x7f, 0x7f, 0x8, 0xc4, 0x8, 0x84, 0x9, 0xc4, 0x8, 0x4c, 0x3e, 0x68, 0x22, 0x38, 0x22, 0x10, 0x22, 0x38, 0x22, 0x28, 0x22, 0x6c, 0x3e, 0xc6, 0x1, 0x83 },
+{ 0x8c, 0xcd, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10, 0x7e, 0x10, 0x9, 0xff, 0x8, 0x10, 0x1c, 0x10, 0x1a, 0x10, 0x1a, 0xfe, 0x28, 0x82, 0x28, 0x82, 0x48, 0x82, 0x8, 0x82, 0x8, 0x82, 0x8, 0xfe, 0x8, 0x0 },
+{ 0x8c, 0xce, 0x1, 0x0, 0x21, 0x1f, 0x31, 0x11, 0x11, 0x11, 0xf, 0xf1, 0x41, 0x1f, 0x61, 0x11, 0x21, 0x11, 0x7, 0xd1, 0x14, 0x5f, 0x14, 0x51, 0x14, 0x51, 0x34, 0x51, 0x24, 0x51, 0x27, 0xd1, 0x60, 0x27 },
+{ 0x8c, 0xcf, 0x4, 0x6, 0x44, 0x3c, 0x29, 0xe4, 0x11, 0x4, 0x11, 0x24, 0x29, 0x24, 0x49, 0x24, 0x9, 0x24, 0x19, 0x24, 0x29, 0x24, 0x49, 0x24, 0x9, 0x26, 0x9, 0x2a, 0xb, 0x3a, 0x1a, 0xea, 0x76, 0x3 },
+{ 0x8c, 0xd0, 0x10, 0x80, 0x54, 0x8f, 0x54, 0x89, 0x54, 0x89, 0x13, 0xe9, 0x10, 0x8f, 0x7c, 0x89, 0x10, 0x89, 0x13, 0xe9, 0x3a, 0x2f, 0x36, 0x29, 0x52, 0x29, 0x52, 0x29, 0x12, 0x29, 0x13, 0xe9, 0x10, 0x13 },
+{ 0x8c, 0xd1, 0x8, 0x10, 0x8, 0x10, 0x9, 0xff, 0x7e, 0x28, 0x2, 0x44, 0x7, 0x83, 0xc, 0x7c, 0x9, 0x0, 0x1a, 0xff, 0x3c, 0x10, 0x6a, 0x20, 0x9, 0x7e, 0x8, 0x2, 0x8, 0x2, 0x8, 0x6, 0x8, 0x1c },
+{ 0x8c, 0xd2, 0x0, 0x0, 0x3c, 0xf8, 0x24, 0x88, 0x24, 0x88, 0x24, 0x88, 0x3d, 0xf, 0x24, 0x0, 0x25, 0xfc, 0x24, 0x84, 0x3c, 0x8c, 0x24, 0xd8, 0x24, 0x70, 0x24, 0x20, 0x24, 0x70, 0x64, 0xdc, 0x4d, 0x87 },
+{ 0x8c, 0xd3, 0x8, 0x0, 0x8, 0x7e, 0x8, 0x42, 0x7f, 0x42, 0x8, 0x42, 0x8, 0x7e, 0x8, 0x42, 0x8, 0x42, 0x3e, 0x42, 0x22, 0x7e, 0x22, 0x42, 0x22, 0x42, 0x22, 0x42, 0x22, 0xc2, 0x3e, 0x82, 0x1, 0x8e },
+{ 0x8c, 0xd4, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x0, 0x2, 0x7c, 0x1e, 0x5, 0xf4, 0x9, 0x4, 0x11, 0x24, 0x11, 0x24, 0x1d, 0x24, 0x71, 0x26, 0x11, 0x2a, 0x13, 0x7a, 0x12, 0xca, 0x36, 0x3 },
+{ 0x8c, 0xd5, 0x0, 0x80, 0x0, 0xfc, 0x0, 0x80, 0x1f, 0xff, 0x10, 0x1, 0x11, 0x2, 0x11, 0xf8, 0x17, 0x0, 0x11, 0x2, 0x10, 0xfe, 0x10, 0x0, 0x11, 0x20, 0x31, 0x20, 0x21, 0x21, 0x63, 0x33, 0xe, 0x1e },
+{ 0x8c, 0xd6, 0x0, 0x10, 0x3c, 0x10, 0x1, 0xff, 0x7e, 0x28, 0x0, 0x44, 0x3d, 0x83, 0x0, 0x7c, 0x0, 0x0, 0x3d, 0xff, 0x0, 0x20, 0x0, 0x40, 0x3c, 0xfe, 0x24, 0x2, 0x24, 0x2, 0x24, 0x6, 0x3c, 0x1c },
+{ 0x8c, 0xd7, 0x0, 0x10, 0x3e, 0x10, 0x23, 0xff, 0x22, 0x28, 0x22, 0x44, 0x23, 0x83, 0x3e, 0x7c, 0x8, 0x0, 0x29, 0xff, 0x2e, 0x20, 0x28, 0x40, 0x28, 0xfe, 0x28, 0x2, 0x2e, 0x2, 0x38, 0x6, 0x60, 0x1c },
+{ 0x8c, 0xd8, 0x8, 0x10, 0x1c, 0x10, 0x16, 0x10, 0x32, 0x10, 0x21, 0xff, 0x7e, 0x10, 0x8, 0x10, 0x8, 0x10, 0x7e, 0x10, 0x8, 0xfe, 0x4a, 0x82, 0x6a, 0x82, 0x28, 0x82, 0xe, 0x82, 0x38, 0x82, 0x60, 0xfe },
+{ 0x8c, 0xd9, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x0, 0x1f, 0xfe, 0x10, 0x2, 0x1f, 0xfe, 0x11, 0x10, 0x11, 0x20, 0x13, 0xfe, 0x16, 0x20, 0x1b, 0xfc, 0x12, 0x20, 0x33, 0xfc, 0x22, 0x20, 0x62, 0x20, 0x3, 0xff },
+{ 0x8c, 0xda, 0x0, 0x0, 0x7f, 0xbf, 0x0, 0x8, 0x3f, 0xbe, 0x20, 0xa2, 0x3f, 0xa2, 0x20, 0x3e, 0x25, 0x22, 0x2f, 0xa2, 0x3a, 0x3e, 0x2f, 0xa2, 0x2a, 0x22, 0x6f, 0xbe, 0x4a, 0x14, 0xf, 0xb6, 0x0, 0x63 },
+{ 0x8c, 0xdb, 0x8, 0x8, 0x8, 0x8, 0x7f, 0x7f, 0x8, 0x8, 0x3e, 0x8, 0x0, 0x7e, 0x3e, 0x22, 0x22, 0x22, 0x22, 0x36, 0x3e, 0x14, 0x0, 0x1c, 0x22, 0x8, 0x32, 0x1c, 0x17, 0x34, 0x1c, 0x66, 0x70, 0xc3 },
+{ 0x8c, 0xdc, 0x0, 0x0, 0x3f, 0xfe, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1f, 0xf0, 0x2, 0x10, 0x2, 0x10, 0x2, 0x10, 0x2, 0x10, 0x6, 0x10, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x8c, 0xdd, 0x0, 0x0, 0x3f, 0xfe, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x7, 0xf0, 0x4, 0x10, 0x4, 0x10, 0xc, 0x10, 0x8, 0x10, 0xf, 0xf0, 0x0, 0x20, 0x0, 0x20, 0x0, 0x20, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x8c, 0xde, 0x8, 0x0, 0xb, 0xfe, 0x18, 0x20, 0x10, 0x20, 0x10, 0x20, 0x30, 0x20, 0x31, 0xfc, 0x50, 0x44, 0x10, 0x44, 0x10, 0x44, 0x10, 0x44, 0x10, 0xc4, 0x10, 0x84, 0x10, 0x84, 0x17, 0xff, 0x10, 0x0 },
+{ 0x8c, 0xdf, 0x4, 0x0, 0x4, 0x0, 0xf, 0xfc, 0x8, 0x80, 0x18, 0x80, 0x30, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80 },
+{ 0x8c, 0xe0, 0x0, 0x0, 0x3, 0xf0, 0x12, 0x10, 0x12, 0x10, 0x12, 0x10, 0x13, 0xf0, 0x10, 0x0, 0x10, 0x0, 0x1f, 0xf8, 0x0, 0x8, 0x0, 0x8, 0x7f, 0xff, 0x0, 0x0, 0x4, 0x10, 0xc, 0x18, 0x38, 0xe },
+{ 0x8c, 0xe1, 0x0, 0x0, 0x3f, 0xfe, 0x1, 0x0, 0x1, 0x0, 0x1f, 0xf8, 0x2, 0x8, 0x6, 0x8, 0x4, 0x8, 0x7f, 0xff, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8 },
+{ 0x8c, 0xe2, 0x8, 0x0, 0x8, 0xbc, 0x8, 0xa4, 0x8, 0xa4, 0x7e, 0xa4, 0x12, 0xbc, 0x12, 0x80, 0x12, 0x80, 0x36, 0xfe, 0x24, 0x2, 0x24, 0x2, 0x7d, 0xff, 0xa, 0x0, 0x1a, 0x44, 0x30, 0xc6, 0x61, 0x83 },
+{ 0x8c, 0xe3, 0x4, 0x40, 0xc, 0xc0, 0x19, 0x88, 0x33, 0x18, 0x65, 0xb0, 0xc, 0x64, 0x18, 0xc2, 0x37, 0xff, 0x70, 0x81, 0x11, 0xf8, 0x13, 0x8, 0x16, 0x98, 0x10, 0xd0, 0x10, 0x70, 0x11, 0xdc, 0x17, 0x7 },
+{ 0x8c, 0xe4, 0x9, 0x0, 0x19, 0xf, 0x13, 0xe9, 0x32, 0x89, 0x60, 0x89, 0x8, 0x89, 0x1b, 0xe9, 0x10, 0x89, 0x30, 0x89, 0x72, 0xe9, 0x12, 0x89, 0x12, 0x89, 0x12, 0xeb, 0x13, 0x88, 0x16, 0x8, 0x10, 0x8 },
+{ 0x8c, 0xe5, 0x10, 0x0, 0x13, 0xff, 0x10, 0x20, 0x10, 0x20, 0x59, 0xfc, 0x54, 0x44, 0x54, 0x44, 0x50, 0x44, 0x13, 0xff, 0x10, 0x0, 0x11, 0xfe, 0x11, 0x2, 0x11, 0x2, 0x11, 0x2, 0x11, 0x2, 0x11, 0xfe },
+{ 0x8c, 0xe6, 0x10, 0x0, 0x13, 0xff, 0x10, 0x20, 0x7c, 0x20, 0x11, 0xfc, 0x10, 0x44, 0x38, 0x44, 0x34, 0x44, 0x33, 0xff, 0x50, 0x0, 0x51, 0xfe, 0x11, 0x2, 0x11, 0x2, 0x11, 0x2, 0x11, 0x2, 0x11, 0xfe },
+{ 0x8c, 0xe7, 0x10, 0x20, 0x10, 0x50, 0x10, 0x88, 0x79, 0x24, 0x16, 0xfb, 0x11, 0x54, 0x19, 0x24, 0x35, 0x54, 0x31, 0xfc, 0x50, 0x20, 0x53, 0xfe, 0x12, 0x42, 0x12, 0x92, 0x12, 0xea, 0x12, 0x2, 0x12, 0xe },
+{ 0x8c, 0xe8, 0x0, 0x80, 0x0, 0x8f, 0x7c, 0x89, 0x10, 0x89, 0x17, 0xf9, 0x10, 0x8f, 0x10, 0x89, 0x7c, 0x89, 0x10, 0x89, 0x13, 0xef, 0x12, 0x29, 0x12, 0x29, 0x1e, 0x29, 0x72, 0x29, 0x3, 0xe9, 0x0, 0x17 },
+{ 0x8c, 0xe9, 0x4, 0x10, 0x4, 0x10, 0x3f, 0xfe, 0x4, 0x10, 0x7, 0xf0, 0x4, 0x10, 0x7, 0xf0, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0xf, 0xf8, 0x12, 0x4, 0x67, 0xfb, 0xc, 0x8, 0x34, 0x8, 0x7, 0xf8 },
+{ 0x8c, 0xea, 0x0, 0x0, 0x3d, 0xfe, 0x0, 0x20, 0x7e, 0x20, 0x0, 0xfc, 0x3c, 0x44, 0x0, 0x44, 0x0, 0x44, 0x3d, 0xff, 0x0, 0x0, 0x0, 0xfe, 0x3c, 0x82, 0x24, 0x82, 0x24, 0x82, 0x24, 0x82, 0x3c, 0xfe },
+{ 0x8c, 0xeb, 0x0, 0x0, 0x3c, 0xbc, 0x0, 0xa4, 0x7e, 0xa4, 0x0, 0xa4, 0x3c, 0xbc, 0x0, 0x80, 0x0, 0x80, 0x3c, 0xfe, 0x0, 0x2, 0x0, 0x2, 0x3d, 0xff, 0x24, 0x0, 0x24, 0x44, 0x24, 0xc6, 0x3d, 0x83 },
+{ 0x8c, 0xec, 0x0, 0x44, 0x3d, 0xff, 0x0, 0x44, 0x7e, 0x90, 0x0, 0xff, 0x3d, 0x90, 0x2, 0xfe, 0x0, 0x90, 0x3c, 0xfe, 0x0, 0x90, 0x0, 0xff, 0x3c, 0x0, 0x25, 0xfe, 0x24, 0x44, 0x24, 0x38, 0x3d, 0xc7 },
+{ 0x8c, 0xed, 0x0, 0x20, 0x7f, 0x27, 0x14, 0x25, 0x14, 0x25, 0x7f, 0xfd, 0x55, 0x27, 0x55, 0x25, 0x55, 0x25, 0x67, 0x75, 0x41, 0x57, 0x41, 0x55, 0x7f, 0x55, 0x41, 0x55, 0x41, 0x55, 0x7f, 0x75, 0x0, 0xb },
+{ 0x8c, 0xee, 0x2, 0x0, 0x6, 0x0, 0x4, 0x0, 0xf, 0xfe, 0x18, 0x0, 0x30, 0x0, 0x6f, 0xf8, 0x0, 0x30, 0x0, 0xc0, 0x3, 0x80, 0x6, 0x0, 0xc, 0x0, 0x18, 0x0, 0x10, 0x2, 0x18, 0x6, 0xf, 0xfc },
+{ 0x8c, 0xef, 0x10, 0x0, 0x1e, 0xfe, 0x32, 0x92, 0x24, 0x92, 0x7e, 0xfe, 0x2a, 0x92, 0x2a, 0x92, 0x3e, 0x92, 0x2a, 0xfe, 0x2a, 0x10, 0x3e, 0x10, 0x0, 0xfe, 0x2a, 0x10, 0x2a, 0x10, 0x6a, 0x10, 0x41, 0xff },
+{ 0x8c, 0xf0, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x4, 0x10, 0xc, 0x18, 0x18, 0xc, 0x34, 0x16, 0x6, 0x30, 0x3, 0x60, 0x1, 0xc0, 0x1, 0xc0, 0x3, 0x60, 0x6, 0x30, 0x1c, 0x1c, 0x70, 0x7 },
+{ 0x8c, 0xf1, 0x8, 0x20, 0x8, 0x20, 0x18, 0x20, 0x17, 0xff, 0x10, 0x88, 0x31, 0x8c, 0x33, 0x6, 0x56, 0x8b, 0x10, 0x88, 0x10, 0xd8, 0x10, 0x70, 0x10, 0x20, 0x10, 0x70, 0x10, 0xd8, 0x11, 0x8c, 0x17, 0x7 },
+{ 0x8c, 0xf2, 0x8, 0x0, 0x9, 0xfc, 0x8, 0x4, 0x18, 0x4, 0x13, 0xff, 0x30, 0x80, 0x30, 0x80, 0x51, 0xfe, 0x13, 0x20, 0x10, 0x20, 0x17, 0xff, 0x10, 0x50, 0x10, 0x58, 0x10, 0xcc, 0x11, 0x86, 0x17, 0x3 },
+{ 0x8c, 0xf3, 0x8, 0x0, 0x8, 0xfc, 0x18, 0x4, 0x14, 0x4, 0x15, 0xff, 0x34, 0x40, 0x34, 0x40, 0x54, 0xfe, 0x15, 0x90, 0x14, 0x10, 0x15, 0xff, 0x14, 0x28, 0x14, 0x28, 0x14, 0x6c, 0x10, 0xc6, 0x11, 0x83 },
+{ 0x8c, 0xf4, 0x8, 0x20, 0x8, 0x20, 0xb, 0xfe, 0x18, 0x20, 0x10, 0x20, 0x37, 0xff, 0x31, 0x4, 0x51, 0x8c, 0x10, 0x88, 0x17, 0xff, 0x10, 0x20, 0x10, 0x20, 0x13, 0xfe, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20 },
+{ 0x8c, 0xf5, 0x0, 0x80, 0x20, 0x82, 0x30, 0x86, 0x18, 0x8c, 0xc, 0x98, 0x4, 0x90, 0x0, 0x80, 0x7f, 0xff, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x6, 0x20, 0x4, 0x20, 0xc, 0x21, 0x18, 0x33, 0x70, 0x1e },
+{ 0x8c, 0xf6, 0x2, 0x20, 0x2, 0x20, 0x6, 0x30, 0x4, 0x10, 0xc, 0x18, 0x8, 0xc, 0x19, 0x6, 0x31, 0x3, 0x61, 0x0, 0x3, 0x20, 0x2, 0x30, 0x2, 0x18, 0x6, 0x8, 0x4, 0x7c, 0xf, 0xc6, 0x38, 0x2 },
+{ 0x8c, 0xf7, 0x0, 0x20, 0x0, 0x20, 0x0, 0x20, 0x7e, 0x20, 0x9, 0xfe, 0x8, 0x22, 0x8, 0x22, 0x8, 0x22, 0x8, 0x22, 0x8, 0x62, 0xe, 0x42, 0x38, 0x42, 0x60, 0xc6, 0x0, 0x84, 0x1, 0x84, 0x3, 0x1c },
+{ 0x8c, 0xf8, 0x4, 0x8, 0x4, 0x8, 0x4, 0x8, 0x7f, 0xc8, 0x11, 0x3f, 0x31, 0x89, 0x60, 0xc9, 0x11, 0x9, 0x1b, 0x9, 0xa, 0x9, 0xe, 0x19, 0x4, 0x11, 0xe, 0x13, 0x1b, 0x32, 0x31, 0x22, 0x60, 0x6e },
+{ 0x8c, 0xf9, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0xf, 0xfe, 0x8, 0x2, 0x19, 0x2, 0x31, 0x2, 0x63, 0x2, 0x2, 0x42, 0x2, 0x62, 0x6, 0x22, 0x4, 0xf2, 0xf, 0x96, 0x0, 0x4, 0x0, 0xc, 0x0, 0x38 },
+{ 0x8c, 0xfa, 0x0, 0x0, 0x1f, 0xff, 0x10, 0x0, 0x13, 0xfe, 0x12, 0x2, 0x13, 0xfe, 0x12, 0x2, 0x13, 0xfe, 0x10, 0x0, 0x13, 0xfe, 0x10, 0xc, 0x10, 0x30, 0x37, 0xff, 0x20, 0x20, 0x60, 0x20, 0x0, 0xe0 },
+{ 0x8c, 0xfb, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x1f, 0xfc, 0x0, 0x0, 0x0, 0x0 },
+{ 0x8c, 0xfc, 0x1, 0x0, 0x3, 0x0, 0x2, 0x0, 0x3f, 0xfe, 0x20, 0x2, 0x20, 0x2, 0x23, 0xe2, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x23, 0xe2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0xe },
+{ 0x8d, 0x40, 0x0, 0xc, 0x0, 0xf8, 0x1f, 0x80, 0x10, 0x0, 0x10, 0x0, 0x1f, 0xff, 0x10, 0x0, 0x10, 0x0, 0x13, 0xfc, 0x12, 0x4, 0x12, 0x4, 0x12, 0x4, 0x32, 0x4, 0x22, 0x4, 0x62, 0x4, 0x3, 0xfc },
+{ 0x8d, 0x41, 0x2, 0x0, 0x2, 0xfc, 0x72, 0x4, 0x52, 0x4, 0x55, 0xff, 0x54, 0x0, 0x5c, 0x80, 0x54, 0xfe, 0x55, 0x10, 0x54, 0x10, 0x55, 0xff, 0x74, 0x28, 0x4, 0x6c, 0x4, 0x44, 0x4, 0xc6, 0x5, 0x83 },
+{ 0x8d, 0x42, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x13, 0xff, 0x7c, 0x0, 0x10, 0x0, 0x10, 0xf8, 0x10, 0x88, 0x10, 0x88, 0x10, 0x88, 0x1c, 0x88, 0x70, 0x88, 0x1, 0x88, 0x1, 0x9, 0x3, 0x9, 0x6, 0x7 },
+{ 0x8d, 0x43, 0x0, 0x6, 0x10, 0x3c, 0x11, 0xe0, 0x11, 0x0, 0x11, 0x0, 0x7d, 0xff, 0x11, 0x0, 0x11, 0x0, 0x11, 0x7e, 0x11, 0x42, 0x11, 0x42, 0x1d, 0x42, 0x73, 0x42, 0x2, 0x42, 0x6, 0x42, 0x0, 0x7e },
+{ 0x8d, 0x44, 0x8, 0x0, 0x8, 0xfe, 0x8, 0x6, 0x8, 0xc, 0x7f, 0x18, 0x11, 0x10, 0x11, 0x10, 0x11, 0xff, 0x33, 0x10, 0x22, 0x10, 0x26, 0x10, 0x7c, 0x10, 0xa, 0x10, 0x19, 0x10, 0x31, 0x10, 0x60, 0x70 },
+{ 0x8d, 0x45, 0x0, 0x20, 0x7f, 0xa0, 0x3, 0x20, 0x6, 0x20, 0xc, 0x20, 0x8, 0x20, 0x8, 0x20, 0xb, 0x20, 0xe, 0x20, 0x38, 0x20, 0x68, 0x20, 0x8, 0x20, 0x8, 0x20, 0x8, 0x21, 0x8, 0x33, 0x38, 0x1e },
+{ 0x8d, 0x46, 0x1, 0x2, 0x1, 0x6, 0x1f, 0xfc, 0x1, 0x18, 0x1, 0x20, 0x7f, 0xff, 0x1, 0x80, 0x6, 0x0, 0x1f, 0xf8, 0x60, 0x20, 0x0, 0x40, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x3, 0x80 },
+{ 0x8d, 0x47, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x2, 0x21, 0x2, 0x1, 0x0, 0x7f, 0xff, 0x2, 0x0, 0x2, 0x20, 0x6, 0x60, 0x4, 0x40, 0xc, 0xc8, 0x18, 0x8c, 0x31, 0x84, 0x61, 0x3e, 0x3, 0xe2 },
+{ 0x8d, 0x48, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xfe, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x0, 0x0, 0x0 },
+{ 0x8d, 0x49, 0x0, 0x0, 0x3, 0xff, 0x7c, 0x20, 0x10, 0x20, 0x10, 0x60, 0x10, 0x40, 0x10, 0xfe, 0x10, 0x2, 0x10, 0x2, 0x1c, 0x2, 0x70, 0x2, 0x0, 0x6, 0x0, 0x4, 0x0, 0x4, 0x0, 0xc, 0x0, 0x78 },
+{ 0x8d, 0x4a, 0x4, 0x10, 0x4, 0x10, 0x3f, 0xfe, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x8, 0x8, 0x1f, 0xfc, 0x70, 0x17, 0x0, 0x10, 0xf, 0xf0, 0x8, 0x0, 0x8, 0x4, 0xc, 0xc, 0x7, 0xf8 },
+{ 0x8d, 0x4b, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x4, 0x10, 0x6, 0x30, 0x2, 0x20, 0x3f, 0xfe, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80 },
+{ 0x8d, 0x4c, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x1f, 0xff, 0x10, 0x0, 0x10, 0x0, 0x10, 0x80, 0x10, 0x80, 0x11, 0x90, 0x11, 0x18, 0x11, 0x8, 0x13, 0xc, 0x32, 0x4, 0x22, 0x3e, 0x67, 0xe2, 0xc, 0x2 },
+{ 0x8d, 0x4d, 0x0, 0x40, 0x0, 0x40, 0x1f, 0xff, 0x10, 0x40, 0x17, 0xfc, 0x10, 0x44, 0x10, 0x44, 0x1f, 0xff, 0x10, 0x44, 0x10, 0x44, 0x17, 0xfc, 0x10, 0xa0, 0x31, 0xb0, 0x23, 0x18, 0x66, 0xc, 0x1c, 0x7 },
+{ 0x8d, 0x4e, 0x0, 0x40, 0x0, 0x40, 0x1f, 0xff, 0x10, 0x40, 0x17, 0xfc, 0x10, 0x44, 0x1f, 0xff, 0x10, 0x44, 0x17, 0xfc, 0x10, 0x40, 0x16, 0x46, 0x13, 0x6c, 0x30, 0xd8, 0x23, 0x4c, 0x6c, 0x47, 0x1, 0xc0 },
+{ 0x8d, 0x4f, 0x0, 0x10, 0x7e, 0x10, 0x2, 0x10, 0x2, 0x10, 0x2, 0x30, 0x3e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x60, 0x3e, 0x44, 0x2, 0x44, 0x2, 0x46, 0x2, 0xc2, 0x6, 0x82, 0x4, 0x9f, 0x3d, 0xf1 },
+{ 0x8d, 0x50, 0x8, 0x0, 0x9, 0xfe, 0x8, 0x0, 0x8, 0x0, 0x2c, 0xfc, 0x2a, 0x84, 0x6a, 0x84, 0x48, 0xfc, 0x8, 0x84, 0x8, 0x84, 0x8, 0x84, 0x8, 0xfc, 0x8, 0x0, 0x8, 0x0, 0xb, 0xff, 0x8, 0x0 },
+{ 0x8d, 0x51, 0x10, 0x84, 0x10, 0x84, 0x13, 0xff, 0x10, 0x84, 0x50, 0x20, 0x5b, 0xff, 0x54, 0x80, 0x54, 0x80, 0x10, 0x7e, 0x10, 0x0, 0x11, 0x24, 0x11, 0x24, 0x11, 0x24, 0x11, 0x25, 0x13, 0x25, 0x16, 0x3 },
+{ 0x8d, 0x52, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x13, 0xfe, 0x7c, 0x0, 0x10, 0x0, 0x10, 0xf8, 0x10, 0x88, 0x1c, 0x88, 0x70, 0x88, 0x10, 0x88, 0x10, 0x88, 0x11, 0x88, 0x11, 0x9, 0x13, 0x9, 0x76, 0x7 },
+{ 0x8d, 0x53, 0x10, 0x80, 0x10, 0x80, 0x10, 0x80, 0x11, 0xfe, 0x7d, 0x2, 0x13, 0x2, 0x10, 0xf2, 0x10, 0x92, 0x10, 0x92, 0x1c, 0x92, 0x70, 0x92, 0x10, 0xf2, 0x10, 0x2, 0x10, 0x6, 0x10, 0x4, 0x30, 0x1c },
+{ 0x8d, 0x54, 0x10, 0x20, 0x10, 0x20, 0x13, 0xfe, 0x12, 0x92, 0x7a, 0x92, 0x11, 0x90, 0x13, 0x1e, 0x10, 0x0, 0x18, 0x0, 0x73, 0xfe, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x17, 0xff, 0x30, 0x0 },
+{ 0x8d, 0x55, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7d, 0xff, 0x11, 0x4, 0x13, 0x84, 0x16, 0x8c, 0x10, 0xc8, 0x10, 0x58, 0x10, 0x70, 0x1c, 0x20, 0x70, 0x70, 0x0, 0xd8, 0x1, 0x8c, 0x3, 0x6, 0xe, 0x3 },
+{ 0x8d, 0x56, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x4, 0x1f, 0xfc, 0x10, 0x4, 0x1f, 0xfc, 0x0, 0x0, 0x7, 0x0, 0x3c, 0x7e, 0x20, 0x42, 0x20, 0x42, 0x20, 0x42, 0x3e, 0x42, 0x60, 0x4e, 0x0, 0x40, 0x0, 0x40 },
+{ 0x8d, 0x57, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x4, 0x1f, 0xfc, 0x10, 0x4, 0x1f, 0xfc, 0x8, 0x88, 0xc, 0x98, 0x4, 0x90, 0x7f, 0xff, 0x2, 0x20, 0x2, 0x20, 0x6, 0x20, 0xc, 0x21, 0x18, 0x33, 0x70, 0x1e },
+{ 0x8d, 0x58, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x80, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x8, 0x80, 0x5, 0x80, 0x3, 0x0, 0x6, 0xc0, 0x1c, 0x78, 0x70, 0xf },
+{ 0x8d, 0x59, 0x8, 0x20, 0x8, 0x20, 0x8, 0x20, 0x7f, 0xff, 0x8, 0x0, 0x8, 0x0, 0x1c, 0xf8, 0x1a, 0x88, 0x1a, 0x88, 0x28, 0x88, 0x28, 0x88, 0x48, 0x88, 0x8, 0x88, 0x9, 0x89, 0x9, 0x9, 0xb, 0x7 },
+{ 0x8d, 0x5a, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x7d, 0xff, 0x10, 0x44, 0x10, 0xc6, 0x39, 0x83, 0x34, 0x44, 0x34, 0x44, 0x50, 0x6c, 0x50, 0x38, 0x10, 0x10, 0x10, 0x38, 0x10, 0x6c, 0x10, 0xc6, 0x11, 0x83 },
+{ 0x8d, 0x5b, 0x10, 0x0, 0x13, 0xfe, 0x10, 0x20, 0x7d, 0xfc, 0x11, 0x24, 0x11, 0x24, 0x39, 0xfc, 0x35, 0x24, 0x35, 0x24, 0x51, 0xfc, 0x50, 0x20, 0x11, 0xa0, 0x10, 0xe0, 0x10, 0x70, 0x10, 0xdc, 0x13, 0x87 },
+{ 0x8d, 0x5c, 0x10, 0x48, 0x10, 0x48, 0x13, 0xff, 0x7c, 0x48, 0x11, 0xfe, 0x10, 0x48, 0x33, 0xff, 0x38, 0x20, 0x35, 0xfe, 0x51, 0x22, 0x51, 0xfe, 0x11, 0x22, 0x13, 0xff, 0x11, 0x2, 0x11, 0x2, 0x11, 0xe },
+{ 0x8d, 0x5d, 0x0, 0x0, 0x30, 0x0, 0x1b, 0xfe, 0x8, 0x20, 0x0, 0x20, 0x60, 0x20, 0x30, 0x20, 0x10, 0x20, 0x0, 0x20, 0x8, 0x20, 0x8, 0x20, 0x18, 0x20, 0x10, 0x20, 0x30, 0x20, 0x27, 0xff, 0x60, 0x0 },
+{ 0x8d, 0x5e, 0x0, 0x88, 0x30, 0x88, 0x18, 0x88, 0xb, 0xfe, 0x0, 0x88, 0x60, 0x88, 0x30, 0x88, 0x10, 0x88, 0x0, 0x88, 0x7, 0xff, 0x8, 0x0, 0x18, 0x0, 0x10, 0x88, 0x31, 0x8c, 0x23, 0x6, 0x66, 0x3 },
+{ 0x8d, 0x5f, 0x0, 0x20, 0x31, 0x20, 0x19, 0x20, 0xb, 0xfe, 0x2, 0x20, 0x64, 0x20, 0x30, 0x20, 0x17, 0xff, 0x0, 0x0, 0x8, 0x0, 0xb, 0xfe, 0x1a, 0x2, 0x12, 0x2, 0x32, 0x2, 0x22, 0x2, 0x63, 0xfe },
+{ 0x8d, 0x60, 0x0, 0x88, 0x30, 0x88, 0x1b, 0xfe, 0x8, 0x88, 0x0, 0x88, 0x67, 0xff, 0x30, 0x88, 0x11, 0x4, 0x3, 0xfe, 0x6, 0xb, 0x10, 0x8, 0x11, 0xf8, 0x11, 0x0, 0x31, 0x2, 0x21, 0x86, 0x60, 0xfc },
+{ 0x8d, 0x61, 0x0, 0x88, 0x20, 0x88, 0x37, 0xff, 0x10, 0x88, 0x3, 0xfe, 0x40, 0x88, 0x67, 0xff, 0x20, 0x20, 0x3, 0xfe, 0x12, 0x22, 0x13, 0xfe, 0x12, 0x22, 0x37, 0xff, 0x22, 0x2, 0x22, 0x2, 0x62, 0xe },
+{ 0x8d, 0x62, 0x0, 0x0, 0x3f, 0xfe, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x3f, 0xfe, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x3f, 0xfe, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80 },
+{ 0x8d, 0x63, 0x0, 0x80, 0x1, 0x0, 0x1f, 0xfc, 0x10, 0x4, 0x1f, 0xfc, 0x10, 0x4, 0x1f, 0xfc, 0x0, 0x0, 0x3f, 0xfe, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x8d, 0x64, 0x0, 0x0, 0x7d, 0xff, 0x10, 0x10, 0x10, 0xfe, 0x10, 0x92, 0x3c, 0x92, 0x24, 0xfe, 0x64, 0x92, 0x24, 0x92, 0x24, 0xfe, 0x24, 0x10, 0x24, 0xd0, 0x3c, 0x70, 0x0, 0x38, 0x0, 0x6c, 0x1, 0xc7 },
+{ 0x8d, 0x65, 0x4, 0x20, 0x1c, 0x20, 0x73, 0xff, 0x10, 0x0, 0x10, 0xfc, 0x7c, 0x84, 0x10, 0xfc, 0x10, 0x0, 0x39, 0xfe, 0x35, 0x2, 0x55, 0x7a, 0x51, 0x4a, 0x11, 0x4a, 0x11, 0x7a, 0x11, 0x2, 0x11, 0x6 },
+{ 0x8d, 0x66, 0x10, 0x10, 0x10, 0x10, 0x55, 0xff, 0x55, 0x10, 0x55, 0xfe, 0x11, 0x12, 0x7d, 0xff, 0x11, 0x12, 0x11, 0xfe, 0x39, 0x10, 0x35, 0x92, 0x51, 0x54, 0x53, 0x38, 0x12, 0x54, 0x16, 0x93, 0x10, 0x30 },
+{ 0x8d, 0x67, 0x8, 0x0, 0x18, 0x0, 0x30, 0xfe, 0x62, 0x10, 0x36, 0x10, 0xc, 0x10, 0x18, 0x10, 0x32, 0x10, 0x7f, 0x10, 0x9, 0x10, 0x8, 0x10, 0x2a, 0x10, 0x2a, 0x10, 0x6a, 0x10, 0x49, 0xff, 0x8, 0x0 },
+{ 0x8d, 0x68, 0x8, 0x20, 0x18, 0x20, 0x10, 0x20, 0x65, 0xff, 0x2c, 0x20, 0x18, 0x20, 0x10, 0x20, 0x24, 0x68, 0x7e, 0x48, 0xa, 0x58, 0x8, 0xd0, 0x2a, 0x92, 0x2b, 0xb2, 0x6a, 0x22, 0x48, 0x7f, 0x8, 0xc1 },
+{ 0x8d, 0x69, 0x8, 0x10, 0x18, 0x10, 0x10, 0x10, 0x65, 0xff, 0x2c, 0x44, 0x18, 0xc6, 0x11, 0x83, 0x24, 0x44, 0x7e, 0x44, 0xa, 0x6c, 0x8, 0x38, 0x2a, 0x10, 0x2a, 0x38, 0x6a, 0x6c, 0x48, 0xc6, 0x9, 0x83 },
+{ 0x8d, 0x6a, 0x8, 0x0, 0x19, 0xff, 0x11, 0x1, 0x65, 0x45, 0x2d, 0x29, 0x19, 0x1, 0x11, 0x7d, 0x25, 0x11, 0x7d, 0x11, 0x15, 0x55, 0x11, 0x55, 0x55, 0x55, 0x55, 0x7d, 0x55, 0x1, 0x11, 0x1, 0x11, 0x7 },
+{ 0x8d, 0x6b, 0x8, 0x24, 0x8, 0x24, 0x7f, 0x24, 0x8, 0xff, 0x8, 0x24, 0x7f, 0x24, 0x8, 0x24, 0x8, 0x24, 0x7f, 0x24, 0x8, 0xff, 0x1c, 0x24, 0x1a, 0x24, 0x29, 0x24, 0x48, 0x64, 0x8, 0x44, 0x8, 0xc4 },
+{ 0x8d, 0x6c, 0x1, 0x2, 0x1, 0x6, 0x1f, 0xfc, 0x1, 0x18, 0x1, 0x20, 0x7f, 0xff, 0x0, 0xc0, 0x1, 0x1c, 0x7, 0xf0, 0x1c, 0x0, 0x74, 0x0, 0x7, 0xfc, 0x0, 0x4, 0x0, 0x4, 0x0, 0xc, 0x0, 0x78 },
+{ 0x8d, 0x6d, 0x0, 0x80, 0x8, 0xfc, 0x8, 0x80, 0x8, 0x80, 0x7f, 0xff, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x38 },
+{ 0x8d, 0x6e, 0x0, 0x20, 0x3c, 0x20, 0x24, 0x20, 0x25, 0xff, 0x24, 0x20, 0x3c, 0x20, 0x24, 0x60, 0x24, 0x48, 0x24, 0x48, 0x3c, 0xd8, 0x24, 0x90, 0x25, 0x92, 0x27, 0x32, 0x24, 0x22, 0x64, 0x3f, 0x4c, 0xe1 },
+{ 0x8d, 0x6f, 0x0, 0x10, 0x3c, 0x10, 0x25, 0xff, 0x25, 0x49, 0x25, 0x49, 0x3c, 0xc8, 0x25, 0x8f, 0x24, 0x0, 0x24, 0x0, 0x3c, 0xfe, 0x24, 0x10, 0x24, 0x10, 0x24, 0x10, 0x24, 0x10, 0x65, 0xff, 0x4c, 0x0 },
+{ 0x8d, 0x70, 0x0, 0x80, 0x7f, 0xff, 0x8, 0x8, 0xf, 0xf8, 0x0, 0x0, 0x7f, 0xff, 0x48, 0x9, 0x4f, 0xf9, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x4, 0x1f, 0xfc, 0x10, 0x4, 0x1f, 0xfc, 0x10, 0x4, 0x10, 0x1c },
+{ 0x8d, 0x71, 0x4, 0x10, 0x8, 0x10, 0x3e, 0x10, 0x23, 0xff, 0x2a, 0x0, 0x2a, 0x7c, 0x22, 0x44, 0x7f, 0x44, 0x22, 0x44, 0x2a, 0x44, 0x2a, 0x44, 0x2a, 0x44, 0x2a, 0x44, 0x22, 0x45, 0x62, 0xc5, 0x46, 0x83 },
+{ 0x8d, 0x72, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x0, 0x80, 0x7f, 0xff, 0x8, 0x0, 0x8, 0x0, 0x7, 0xfc, 0x0, 0x0, 0x8, 0x88, 0x8, 0x88, 0x8, 0x88, 0x18, 0x89, 0x30, 0x8b, 0x60, 0x6 },
+{ 0x8d, 0x73, 0x4, 0x0, 0xc, 0xfe, 0x18, 0x0, 0x30, 0x0, 0x60, 0x0, 0x4, 0x0, 0xd, 0xff, 0x18, 0x8, 0x38, 0x8, 0x68, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x38 },
+{ 0x8d, 0x74, 0x9, 0x0, 0x19, 0xef, 0x13, 0x20, 0x36, 0x40, 0x63, 0xe0, 0xa, 0xaf, 0x1a, 0xa2, 0x13, 0xe2, 0x32, 0xa2, 0x72, 0xa2, 0x13, 0xe2, 0x10, 0x82, 0x17, 0xf2, 0x11, 0x42, 0x13, 0x62, 0x16, 0x36 },
+{ 0x8d, 0x75, 0x0, 0x24, 0x3c, 0x24, 0x1, 0xff, 0x7e, 0x24, 0x0, 0xfe, 0x3c, 0x24, 0x1, 0xff, 0x0, 0x10, 0x3c, 0xfe, 0x0, 0x92, 0x0, 0xfe, 0x3c, 0x92, 0x25, 0xff, 0x24, 0x82, 0x24, 0x82, 0x3c, 0x8e },
+{ 0x8d, 0x76, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x4, 0x10, 0xc, 0x18, 0x38, 0xe },
+{ 0x8d, 0x77, 0x0, 0x24, 0x3c, 0x24, 0x25, 0xff, 0x24, 0x24, 0x3c, 0xfe, 0x24, 0x24, 0x25, 0xff, 0x24, 0x10, 0x3c, 0xfe, 0x24, 0x92, 0x24, 0xfe, 0x24, 0x92, 0x3d, 0xff, 0x14, 0x82, 0x36, 0x82, 0x62, 0x8e },
+{ 0x8d, 0x78, 0x4, 0x0, 0x4, 0x1f, 0x4, 0x11, 0x7f, 0xd3, 0x11, 0x12, 0x31, 0x96, 0x60, 0xd4, 0x11, 0x12, 0x1b, 0x11, 0xe, 0x11, 0x6, 0x11, 0x7, 0x11, 0xd, 0x11, 0x19, 0x97, 0x30, 0x90, 0x60, 0x10 },
+{ 0x8d, 0x79, 0x0, 0x11, 0x7f, 0x11, 0x14, 0x7e, 0x14, 0x12, 0x7f, 0x14, 0x55, 0xff, 0x55, 0x8, 0x55, 0x10, 0x57, 0x3e, 0x61, 0xc4, 0x41, 0x8, 0x41, 0xff, 0x7f, 0x8, 0x41, 0x8, 0x41, 0x8, 0x7f, 0x38 },
+{ 0x8d, 0x7a, 0x8, 0x10, 0x1c, 0x10, 0x16, 0x10, 0x32, 0xff, 0x20, 0x80, 0x7e, 0x80, 0x8, 0x88, 0x8, 0x88, 0x7e, 0x88, 0x8, 0x98, 0x4a, 0x90, 0x6a, 0x90, 0x28, 0xb2, 0xf, 0xa2, 0x39, 0x2f, 0x63, 0x79 },
+{ 0x8d, 0x7b, 0x0, 0x10, 0x7e, 0x10, 0x10, 0x10, 0x10, 0xff, 0x10, 0x80, 0x10, 0x80, 0x3c, 0x88, 0x24, 0x88, 0x64, 0x88, 0x24, 0x98, 0x24, 0x90, 0x24, 0x90, 0x24, 0xb2, 0x3d, 0xa2, 0x1, 0x2f, 0x3, 0x79 },
+{ 0x8d, 0x7c, 0x10, 0x0, 0x39, 0xff, 0x2d, 0x1, 0x65, 0x45, 0x41, 0x29, 0x7d, 0x1, 0x11, 0x7d, 0x11, 0x11, 0x7d, 0x11, 0x11, 0x55, 0x55, 0x55, 0x55, 0x55, 0x51, 0x7d, 0x1d, 0x1, 0x31, 0x1, 0x61, 0x7 },
+{ 0x8d, 0x7d, 0x0, 0x0, 0x3f, 0x7e, 0x21, 0x42, 0x3f, 0x7e, 0x21, 0x42, 0x3f, 0x7e, 0x20, 0x82, 0x21, 0x42, 0x22, 0x22, 0x2d, 0xda, 0x20, 0x2, 0x23, 0xe2, 0x22, 0x22, 0x22, 0x22, 0x23, 0xe2, 0x20, 0xe },
+{ 0x8d, 0x7e, 0x0, 0x20, 0x3e, 0x20, 0x22, 0x7e, 0x26, 0xc2, 0x25, 0xa4, 0x2c, 0x18, 0x28, 0x6c, 0x29, 0xc7, 0x24, 0x8, 0x24, 0xfe, 0x24, 0x48, 0x24, 0x48, 0x2d, 0xff, 0x20, 0x8, 0x20, 0x8, 0x20, 0x8 },
+{ 0x8d, 0x80, 0x0, 0x0, 0x1, 0xff, 0x7c, 0x10, 0x10, 0xfe, 0x10, 0x82, 0x10, 0x82, 0x10, 0xfe, 0x10, 0x82, 0x10, 0x82, 0x10, 0xfe, 0x1c, 0x82, 0x70, 0x82, 0x0, 0xfe, 0x0, 0x44, 0x0, 0xc6, 0x1, 0x83 },
+{ 0x8d, 0x81, 0x0, 0xc, 0x0, 0x78, 0x1f, 0xc0, 0x0, 0x80, 0x7f, 0xff, 0x2, 0xa0, 0x6, 0xb0, 0xc, 0x98, 0x18, 0x8c, 0x6f, 0xfb, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8 },
+{ 0x8d, 0x82, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x0, 0x7, 0xf0, 0x4, 0x10, 0x7, 0xf0, 0x0, 0x0, 0x3f, 0xfe, 0x20, 0x2, 0x27, 0xf2, 0x24, 0x12, 0x24, 0x12, 0x27, 0xf2, 0x20, 0x2, 0x20, 0xe },
+{ 0x8d, 0x83, 0x0, 0x10, 0x20, 0x20, 0x37, 0x7e, 0x12, 0x42, 0x2, 0x7e, 0x42, 0x42, 0x62, 0x7e, 0x22, 0x40, 0x2, 0x7f, 0x12, 0x40, 0x13, 0x7f, 0x16, 0x1, 0x30, 0xab, 0x20, 0xa9, 0x20, 0x83, 0x60, 0x6 },
+{ 0x8d, 0x84, 0x0, 0x2, 0x7f, 0xd2, 0x40, 0x52, 0x51, 0x52, 0x4a, 0x52, 0x40, 0x52, 0x5f, 0x52, 0x44, 0x52, 0x44, 0x52, 0x55, 0x52, 0x55, 0x52, 0x55, 0x42, 0x5f, 0x42, 0x40, 0x42, 0x40, 0x42, 0x41, 0xce },
+{ 0x8d, 0x85, 0x4, 0x8, 0x4, 0x8, 0x4, 0x8, 0x3f, 0x88, 0x4, 0x3f, 0x4, 0x9, 0x4, 0x9, 0x4, 0x9, 0x7f, 0xc9, 0x8, 0x9, 0x8, 0x19, 0x19, 0x11, 0x11, 0x13, 0x17, 0xb2, 0x3c, 0xa2, 0x60, 0x6e },
+{ 0x8d, 0x86, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x0, 0x0, 0x7f, 0xff, 0x2, 0x0, 0x4, 0x0, 0xf, 0xf8, 0x0, 0x8, 0x0, 0x8, 0x0, 0x18, 0x0, 0x10, 0x0, 0xf0 },
+{ 0x8d, 0x87, 0x0, 0x80, 0x1, 0xc0, 0x3, 0x60, 0x6, 0x30, 0x1c, 0x1c, 0x70, 0x7, 0x7, 0xf0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8 },
+{ 0x8d, 0x88, 0x10, 0x20, 0x13, 0xff, 0x10, 0x0, 0x10, 0xfc, 0x7c, 0x84, 0x10, 0xfc, 0x10, 0x0, 0x13, 0xff, 0x12, 0x1, 0x12, 0xfd, 0x10, 0x40, 0x1d, 0xa2, 0x70, 0x54, 0x1, 0xb8, 0x0, 0x54, 0x3, 0xb3 },
+{ 0x8d, 0x89, 0x10, 0x42, 0x10, 0x42, 0x13, 0xfc, 0x10, 0x44, 0x78, 0x48, 0x17, 0xff, 0x10, 0x20, 0x10, 0x4e, 0x19, 0xf8, 0x76, 0x80, 0x10, 0x80, 0x10, 0xfe, 0x10, 0x2, 0x10, 0x2, 0x10, 0x6, 0x30, 0x3c },
+{ 0x8d, 0x8a, 0x0, 0x20, 0x27, 0xff, 0x30, 0x0, 0x11, 0xfc, 0x1, 0x4, 0x41, 0xfc, 0x60, 0x0, 0x27, 0xff, 0x4, 0x1, 0x15, 0xfd, 0x10, 0xc0, 0x13, 0x22, 0x30, 0xd4, 0x23, 0x38, 0x20, 0xd4, 0x67, 0x33 },
+{ 0x8d, 0x8b, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x0, 0x0, 0x3f, 0xfe, 0x20, 0x2, 0x2f, 0xfa, 0x3, 0x0, 0x1c, 0xc6, 0x3, 0x6c, 0x1c, 0xf0, 0x3, 0x5c, 0x3c, 0xc7 },
+{ 0x8d, 0x8c, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x7, 0xf0, 0x4, 0x90, 0x7, 0xf0, 0x4, 0x90, 0x3f, 0xfe, 0x0, 0x80, 0x8, 0x8, 0x7f, 0x7f, 0x2a, 0x2a, 0x3e, 0x3e, 0x2a, 0x2a, 0x7f, 0x7f, 0x8, 0x8 },
+{ 0x8d, 0x8d, 0x8, 0x80, 0x8, 0x80, 0x7f, 0xfe, 0x9, 0x2, 0x3e, 0xaa, 0x8, 0xaa, 0x7f, 0x22, 0x10, 0xfa, 0x1e, 0x22, 0x32, 0x72, 0x66, 0xaa, 0x15, 0x26, 0x8, 0x4, 0x16, 0x1c, 0x33, 0x80, 0x60, 0xff },
+{ 0x8d, 0x8e, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xfc, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x1f, 0xfc, 0x2, 0x20, 0x2, 0x20, 0x6, 0x20, 0xc, 0x21, 0x18, 0x33, 0x70, 0x1e },
+{ 0x8d, 0x8f, 0x4, 0x2, 0x4, 0x2, 0x4, 0x12, 0x7f, 0xd2, 0x8, 0x12, 0x18, 0x12, 0x31, 0x12, 0x63, 0x12, 0x36, 0x12, 0xc, 0x92, 0x19, 0x92, 0x33, 0x2, 0x66, 0x2, 0xd, 0x82, 0x18, 0xc2, 0x70, 0x4e },
+{ 0x8d, 0x90, 0x0, 0x80, 0x8, 0x80, 0x8, 0x80, 0x1f, 0xfc, 0x10, 0x80, 0x30, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x0, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8 },
+{ 0x8d, 0x91, 0x0, 0x0, 0x3f, 0xfe, 0x20, 0x2, 0x27, 0xf2, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x27, 0xf2, 0x20, 0x82, 0x20, 0xa2, 0x20, 0x92, 0x20, 0x92, 0x2f, 0xfa, 0x20, 0x2, 0x3f, 0xfe, 0x0, 0x0 },
+{ 0x8d, 0x92, 0x8, 0x0, 0x8, 0x3c, 0x7f, 0x24, 0x8, 0x24, 0x3e, 0x24, 0x0, 0x47, 0x7f, 0x0, 0x41, 0x7e, 0x4d, 0x22, 0x38, 0x22, 0x8, 0x36, 0x7f, 0x1c, 0x2a, 0x8, 0x2b, 0x1c, 0x69, 0xb6, 0x48, 0x63 },
+{ 0x8d, 0x93, 0x0, 0x8, 0x7f, 0x28, 0x14, 0x28, 0x14, 0x7e, 0x7f, 0x48, 0x55, 0x8, 0x55, 0x8, 0x55, 0xff, 0x55, 0x0, 0x67, 0x0, 0x41, 0x3e, 0x41, 0x22, 0x7f, 0x22, 0x41, 0x22, 0x41, 0x22, 0x7f, 0x3e },
+{ 0x8d, 0x94, 0x8, 0x8, 0x28, 0x10, 0x28, 0x7e, 0x7e, 0x42, 0x48, 0x7e, 0x8, 0x42, 0x8, 0x7e, 0x7f, 0x40, 0x0, 0x7f, 0x3e, 0x40, 0x22, 0x7f, 0x22, 0x1, 0x22, 0xab, 0x22, 0xa9, 0x3e, 0x83, 0x0, 0x6 },
+{ 0x8d, 0x95, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x0, 0x12, 0x22, 0x33, 0x33, 0x61, 0x11 },
+{ 0x8d, 0x96, 0x8, 0xa, 0x4b, 0x89, 0x28, 0x9, 0x17, 0xc8, 0x10, 0x3e, 0x2b, 0x88, 0x48, 0x8, 0xb, 0x88, 0x18, 0x8, 0x18, 0x1c, 0x2b, 0x94, 0x4a, 0x94, 0xa, 0x94, 0xa, 0xb6, 0x1b, 0xa2, 0x70, 0x63 },
+{ 0x8d, 0x97, 0x0, 0x20, 0x20, 0x20, 0x37, 0xff, 0x14, 0x90, 0x4, 0x90, 0x47, 0xfe, 0x64, 0x92, 0x24, 0x92, 0x7, 0xfe, 0x14, 0x0, 0x15, 0x10, 0x15, 0xd6, 0x35, 0x1c, 0x2d, 0x10, 0x29, 0xd1, 0x63, 0xf },
+{ 0x8d, 0x98, 0x0, 0x0, 0x3d, 0xff, 0x24, 0x28, 0x25, 0xff, 0x25, 0x29, 0x3d, 0x29, 0x25, 0xff, 0x24, 0x20, 0x24, 0x20, 0x3d, 0xff, 0x24, 0x44, 0x24, 0x4c, 0x24, 0xe8, 0x24, 0x38, 0x64, 0x6e, 0x4d, 0xc3 },
+{ 0x8d, 0x99, 0x22, 0x0, 0x14, 0xff, 0x7f, 0x20, 0x49, 0x20, 0x49, 0x20, 0x7f, 0x3c, 0x49, 0x24, 0x49, 0x24, 0x7f, 0x34, 0x0, 0x2c, 0x3e, 0x24, 0x22, 0x24, 0x3e, 0x24, 0x22, 0x25, 0x22, 0x35, 0x3e, 0xe3 },
+{ 0x8d, 0x9a, 0x2, 0x0, 0x2, 0x0, 0x7, 0xfe, 0xc, 0x92, 0x39, 0x92, 0x3, 0x32, 0xe, 0x62, 0x38, 0xc6, 0x3, 0x84, 0x1e, 0x1c, 0x0, 0xc0, 0x0, 0x66, 0x12, 0x23, 0x12, 0x5, 0x33, 0xc, 0x61, 0xf8 },
+{ 0x8d, 0x9b, 0x10, 0x80, 0x10, 0x80, 0x11, 0xfe, 0x11, 0x2a, 0x5a, 0x4a, 0x54, 0x92, 0x51, 0x26, 0x50, 0x44, 0x10, 0x9c, 0x10, 0x0, 0x10, 0x60, 0x10, 0xb0, 0x12, 0x86, 0x12, 0x8b, 0x16, 0x99, 0x14, 0x70 },
+{ 0x8d, 0x9c, 0xf, 0xf8, 0x8, 0x8, 0x8, 0xf8, 0x8, 0x88, 0x8, 0x88, 0x7f, 0xff, 0x40, 0x1, 0x4f, 0xf9, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x38 },
+{ 0x8d, 0x9d, 0x4, 0x10, 0x44, 0x10, 0x28, 0x30, 0x10, 0x20, 0x11, 0xfe, 0x29, 0x2, 0x49, 0x2, 0x9, 0x2, 0x19, 0x2, 0x19, 0xfe, 0x29, 0x2, 0x49, 0x2, 0x9, 0x2, 0x9, 0x2, 0x19, 0x2, 0x71, 0xfe },
+{ 0x8d, 0x9e, 0x0, 0x0, 0x31, 0xe0, 0x18, 0x20, 0x8, 0x20, 0x0, 0x20, 0x0, 0x20, 0x0, 0x70, 0x78, 0x50, 0x8, 0x58, 0x8, 0xc8, 0x8, 0x8c, 0x9, 0x86, 0xb, 0x3, 0x18, 0x0, 0x34, 0x0, 0x63, 0xff },
+{ 0x8d, 0x9f, 0x4, 0x20, 0x4, 0x20, 0x4, 0x20, 0x24, 0x23, 0x24, 0x26, 0x24, 0x2c, 0x27, 0xb8, 0x24, 0x20, 0x24, 0x20, 0x24, 0x20, 0x24, 0x20, 0x24, 0x20, 0x24, 0x20, 0x27, 0xa1, 0x3c, 0x33, 0x60, 0x1e },
+{ 0x8d, 0xa0, 0x0, 0x0, 0x21, 0xff, 0x20, 0x10, 0x20, 0xfe, 0x26, 0x82, 0x3c, 0x82, 0x20, 0xfe, 0x20, 0x82, 0x20, 0x82, 0x20, 0xfe, 0x22, 0x82, 0x22, 0x82, 0x1e, 0xfe, 0x0, 0x44, 0x0, 0xc6, 0x1, 0x83 },
+{ 0x8d, 0xa1, 0x0, 0x80, 0x1, 0xc0, 0x1, 0x40, 0x3, 0x60, 0x6, 0x30, 0xc, 0x18, 0x1b, 0xec, 0x70, 0x7, 0x0, 0x0, 0xf, 0xf8, 0x0, 0x8, 0x0, 0x18, 0x0, 0x10, 0x0, 0x30, 0x0, 0x60, 0x0, 0x40 },
+{ 0x8d, 0xa2, 0x0, 0x0, 0x3f, 0xfe, 0x20, 0x2, 0x20, 0x82, 0x20, 0x82, 0x2f, 0xfa, 0x22, 0xa2, 0x22, 0xa2, 0x26, 0xb2, 0x24, 0x92, 0x2c, 0x9a, 0x20, 0x82, 0x20, 0x82, 0x20, 0x2, 0x3f, 0xfe, 0x0, 0x0 },
+{ 0x8d, 0xa3, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x11, 0xff, 0x7d, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0xff, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x1d, 0xff, 0x70, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x10 },
+{ 0x8d, 0xa4, 0x6, 0x0, 0x18, 0x7e, 0x65, 0x42, 0x12, 0x7e, 0x4, 0x42, 0x1a, 0x7e, 0x65, 0x51, 0x1b, 0x5b, 0x65, 0x4a, 0x19, 0x7c, 0x63, 0xc6, 0xe, 0x3, 0x0, 0x80, 0x3f, 0xfe, 0x0, 0x80, 0x7f, 0xff },
+{ 0x8d, 0xa5, 0x8, 0xe, 0x8, 0xf8, 0x8, 0x88, 0x8, 0x88, 0x7e, 0xff, 0x12, 0x88, 0x12, 0x88, 0x12, 0xe5, 0x33, 0x83, 0x26, 0xfe, 0x24, 0x82, 0x7c, 0x82, 0xa, 0xfe, 0x19, 0x82, 0x30, 0x82, 0x60, 0xfe },
+{ 0x8d, 0xa6, 0x8, 0x0, 0x8, 0xfe, 0x8, 0x82, 0x8, 0x82, 0x2c, 0xfe, 0x2a, 0x82, 0x6a, 0x82, 0x48, 0xfe, 0x8, 0xa1, 0x8, 0xb3, 0x8, 0x96, 0x8, 0x98, 0x8, 0x88, 0x8, 0x8c, 0x8, 0xf6, 0xb, 0x83 },
+{ 0x8d, 0xa7, 0x6, 0x0, 0x18, 0x7e, 0x65, 0x42, 0x12, 0x7e, 0x4, 0x42, 0x1a, 0x7e, 0x65, 0x51, 0x1b, 0x5b, 0x65, 0x4a, 0x19, 0x7c, 0x63, 0xc6, 0xe, 0x3, 0x0, 0xc0, 0x12, 0x66, 0x32, 0xb, 0x61, 0xf9 },
+{ 0x8d, 0xa8, 0x0, 0x18, 0x0, 0xf0, 0x1f, 0x80, 0x10, 0x80, 0x1f, 0xfe, 0x10, 0x40, 0x10, 0x61, 0x1e, 0x33, 0x70, 0xe, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8 },
+{ 0x8d, 0xa9, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x4, 0x10, 0x4, 0x1f, 0xfc, 0x10, 0x4, 0x10, 0x4, 0x1f, 0xfc, 0x0, 0x0, 0x10, 0x40, 0x10, 0x46, 0x1f, 0x7c, 0x10, 0x40, 0x10, 0x41, 0x1f, 0x63, 0x70, 0x3e },
+{ 0x8d, 0xaa, 0x8, 0x0, 0x8, 0xfe, 0x8, 0x82, 0x7e, 0x82, 0x8, 0xfe, 0x8, 0x82, 0x1c, 0x82, 0x1a, 0xfe, 0x1a, 0xa1, 0x28, 0xb3, 0x28, 0x96, 0x48, 0x98, 0x8, 0x88, 0x8, 0x8c, 0x8, 0xf6, 0xb, 0x83 },
+{ 0x8d, 0xab, 0x10, 0x0, 0x13, 0xfe, 0x12, 0x2, 0x7e, 0x22, 0x12, 0x22, 0x12, 0xfa, 0x3a, 0x22, 0x36, 0x72, 0x32, 0x72, 0x52, 0xaa, 0x52, 0xaa, 0x12, 0x22, 0x12, 0x22, 0x12, 0x2, 0x13, 0xfe, 0x10, 0x0 },
+{ 0x8d, 0xac, 0x0, 0x0, 0x33, 0xfc, 0x1a, 0x4, 0xa, 0x4, 0x3, 0xfc, 0x62, 0x4, 0x32, 0x4, 0x13, 0xfc, 0x0, 0x0, 0xa, 0x10, 0xa, 0x16, 0x1b, 0xdc, 0x12, 0x10, 0x32, 0x11, 0x23, 0xd3, 0x6e, 0xe },
+{ 0x8d, 0xad, 0x0, 0x40, 0x0, 0x40, 0x1f, 0xff, 0x10, 0x0, 0x53, 0xfc, 0x32, 0x4, 0x12, 0x4, 0x13, 0xfc, 0x32, 0x4, 0x52, 0x4, 0x13, 0xfd, 0x12, 0x43, 0x32, 0x66, 0x22, 0x30, 0x63, 0xdc, 0xe, 0x7 },
+{ 0x8d, 0xae, 0x8, 0x44, 0x18, 0x44, 0x30, 0x44, 0x63, 0xff, 0x36, 0x44, 0xc, 0x44, 0x18, 0x44, 0x32, 0x44, 0x7f, 0x44, 0x9, 0x7c, 0x8, 0x44, 0x2a, 0x44, 0x2b, 0x44, 0x69, 0x44, 0x48, 0x44, 0x8, 0x7c },
+{ 0x8d, 0xaf, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xfa, 0x8, 0x86, 0x8, 0xcc, 0x8, 0x58, 0x8, 0x60, 0xb, 0x30, 0xe, 0x1c, 0x38, 0x7 },
+{ 0x8d, 0xb0, 0x0, 0x20, 0x0, 0x40, 0x3d, 0xfe, 0x1, 0x22, 0x1, 0x22, 0x1, 0xfe, 0x7f, 0x22, 0x11, 0x22, 0x11, 0xfe, 0x30, 0x50, 0x24, 0x54, 0x24, 0x55, 0x3e, 0xdf, 0x62, 0x90, 0x1, 0x91, 0x7, 0xf },
+{ 0x8d, 0xb1, 0x4, 0x20, 0x4, 0x20, 0x24, 0x26, 0x27, 0xbc, 0x24, 0x20, 0x24, 0x20, 0x24, 0x21, 0x27, 0xb3, 0x3c, 0x1e, 0x60, 0x0, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x8d, 0xb2, 0x4, 0x40, 0x4, 0x40, 0xc, 0x40, 0xb, 0xff, 0x18, 0x80, 0x10, 0x80, 0x31, 0x80, 0x51, 0x0, 0x13, 0xfe, 0x16, 0x20, 0x1c, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x17, 0xff, 0x10, 0x0 },
+{ 0x8d, 0xb3, 0x0, 0x0, 0x3f, 0xfc, 0x8, 0x4, 0x9, 0x8c, 0xc, 0xc8, 0x4, 0x58, 0x6, 0x10, 0x2, 0x30, 0x3, 0x20, 0x1, 0xe0, 0x0, 0xc0, 0x1, 0xe0, 0x3, 0x30, 0x6, 0x18, 0x1c, 0xc, 0x70, 0x7 },
+{ 0x8d, 0xb4, 0x0, 0x80, 0x1, 0x84, 0x79, 0x4, 0x4b, 0xfe, 0x48, 0x92, 0x49, 0x90, 0x4b, 0x1f, 0x4e, 0x80, 0x48, 0xfc, 0x49, 0x84, 0x7b, 0xc, 0x6, 0xd8, 0x0, 0x70, 0x0, 0xd8, 0x1, 0x8c, 0x7, 0x7 },
+{ 0x8d, 0xb5, 0x1, 0x4, 0x10, 0x88, 0x13, 0xfe, 0x54, 0x20, 0x54, 0x20, 0x55, 0xfc, 0x54, 0x20, 0x54, 0x20, 0x57, 0xfe, 0x54, 0x40, 0x54, 0x80, 0x7d, 0xfe, 0x3, 0x10, 0xc, 0x10, 0x0, 0x10, 0x1, 0xff },
+{ 0x8d, 0xb6, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x7f, 0xff, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x7, 0xfe, 0x4, 0x20, 0xc, 0x20, 0x18, 0x20, 0x30, 0x20, 0x60, 0x20, 0x0, 0x20, 0x7, 0xff, 0x0, 0x0 },
+{ 0x8d, 0xb7, 0x4, 0x10, 0x2, 0x20, 0x3f, 0xfe, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x2, 0x0, 0x4, 0x0, 0xf, 0xfc, 0x18, 0x40, 0x60, 0x40, 0x0, 0x40, 0x1f, 0xff },
+{ 0x8d, 0xb8, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x2, 0xa0, 0x6, 0xb0, 0xc, 0x98, 0x18, 0x8c, 0x70, 0x7, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x8d, 0xb9, 0x0, 0x20, 0x30, 0x20, 0x18, 0x20, 0x9, 0x24, 0x1, 0x26, 0x63, 0x23, 0x32, 0x21, 0x16, 0x20, 0x0, 0x24, 0x8, 0xe4, 0x8, 0xc, 0x18, 0x8, 0x10, 0x18, 0x30, 0x30, 0x20, 0xe0, 0x63, 0x80 },
+{ 0x8d, 0xba, 0x0, 0x84, 0x0, 0x48, 0x7d, 0xfe, 0x10, 0x20, 0x10, 0x20, 0x11, 0xfc, 0x7c, 0x20, 0x10, 0x20, 0x13, 0xfe, 0x10, 0x40, 0x10, 0x80, 0x1d, 0xfe, 0x73, 0x10, 0xc, 0x10, 0x0, 0x10, 0x1, 0xff },
+{ 0x8d, 0xbb, 0x0, 0x10, 0x7f, 0x10, 0x8, 0x10, 0x8, 0x54, 0x8, 0x56, 0x8, 0xd3, 0x1e, 0x91, 0x13, 0x90, 0x32, 0x12, 0x52, 0x12, 0x12, 0x76, 0x12, 0x4, 0x12, 0xc, 0x1e, 0x18, 0x0, 0x70, 0x1, 0xc0 },
+{ 0x8d, 0xbc, 0x0, 0x20, 0x3e, 0x20, 0x0, 0x20, 0x7f, 0x7f, 0x0, 0x50, 0x3e, 0xd0, 0x0, 0x10, 0x0, 0x1e, 0x3e, 0x10, 0x0, 0x10, 0x0, 0x10, 0x3e, 0x1e, 0x22, 0x10, 0x22, 0x10, 0x22, 0x10, 0x3e, 0x10 },
+{ 0x8d, 0xbd, 0x8, 0x92, 0x1c, 0xd6, 0x16, 0x54, 0x32, 0x10, 0x20, 0xfe, 0x7e, 0x82, 0x8, 0x82, 0x8, 0xfe, 0x7e, 0x82, 0x8, 0x82, 0x4a, 0xfe, 0x6a, 0x82, 0x28, 0x82, 0xe, 0xfe, 0x38, 0x44, 0x61, 0x83 },
+{ 0x8d, 0xbe, 0x30, 0x20, 0x19, 0x24, 0x1, 0x26, 0x63, 0x23, 0x36, 0x25, 0x0, 0xec, 0xc, 0x18, 0x38, 0x70, 0x63, 0xc0, 0x0, 0x80, 0x7f, 0xff, 0x2, 0x42, 0xe, 0x6c, 0x78, 0x30, 0xf, 0x1c, 0x38, 0x7 },
+{ 0x8d, 0xbf, 0x0, 0x80, 0x0, 0x80, 0x8, 0x88, 0x8, 0x88, 0x8, 0x88, 0x1c, 0x9c, 0x16, 0xb4, 0x32, 0xa6, 0x60, 0x83, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x8d, 0xc0, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xff, 0x10, 0x0, 0x12, 0x48, 0x12, 0x48, 0x12, 0x48, 0x15, 0x54, 0x15, 0x54, 0x18, 0xe2, 0x10, 0x40, 0x37, 0xfc, 0x20, 0x40, 0x60, 0x40, 0x1f, 0xff, 0x0, 0x0 },
+{ 0x8d, 0xc1, 0x10, 0x20, 0x11, 0x24, 0x11, 0x24, 0x11, 0x24, 0x7d, 0x24, 0x12, 0xaa, 0x12, 0xaa, 0x14, 0x71, 0x10, 0x20, 0x1c, 0x20, 0x73, 0xfe, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x17, 0xff, 0x30, 0x0 },
+{ 0x8d, 0xc2, 0x8, 0x20, 0xb, 0xfe, 0x18, 0x20, 0x11, 0xfc, 0x10, 0x20, 0x37, 0xff, 0x30, 0x0, 0x51, 0xfc, 0x11, 0x4, 0x11, 0xfc, 0x11, 0x4, 0x11, 0xfc, 0x11, 0x4, 0x11, 0xfc, 0x10, 0x88, 0x13, 0x6 },
+{ 0x8d, 0xc3, 0x4, 0x20, 0x5, 0x22, 0xd, 0x22, 0x9, 0xfe, 0x18, 0x88, 0x10, 0x90, 0x31, 0xfe, 0x51, 0x10, 0x13, 0x10, 0x15, 0xfe, 0x11, 0x10, 0x11, 0x10, 0x11, 0xfe, 0x11, 0x10, 0x11, 0x10, 0x11, 0xff },
+{ 0x8d, 0xc4, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x7f, 0xff, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x1c },
+{ 0x8d, 0xc5, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x0, 0x0, 0x7f, 0xff, 0x11, 0x0, 0x1f, 0x7e, 0x11, 0x22, 0x1f, 0x36, 0x11, 0x14, 0x11, 0x8, 0x1f, 0x1c, 0x71, 0x77, 0x1, 0x0 },
+{ 0x8d, 0xc6, 0x4, 0x20, 0x4, 0x24, 0x3f, 0xa6, 0x4, 0x22, 0x4, 0x20, 0x7f, 0xff, 0x0, 0x20, 0x0, 0x22, 0x3f, 0xb2, 0x20, 0x96, 0x20, 0x94, 0x20, 0x9c, 0x20, 0x88, 0x3f, 0x9d, 0x0, 0x77, 0x3, 0xc2 },
+{ 0x8d, 0xc7, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x2, 0x22, 0x22, 0x1f, 0xfc, 0x2, 0x20, 0x1f, 0xfc, 0x2, 0x20, 0x7f, 0xff, 0x4, 0x10, 0x1c, 0x9c, 0x70, 0x87, 0xf, 0xf8, 0x0, 0x80, 0x3f, 0xfe },
+{ 0x8d, 0xc8, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x84, 0x7f, 0xff, 0x0, 0x84, 0x1f, 0xfc, 0x1, 0x0, 0x7f, 0xff, 0x2, 0x10, 0x4, 0x20, 0xf, 0xc0, 0x2, 0x78, 0x3c, 0xe },
+{ 0x8d, 0xc9, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x2, 0x20, 0x82, 0x1f, 0xfc, 0x4, 0x10, 0x2, 0x20, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80 },
+{ 0x8d, 0xca, 0x1, 0x84, 0x7, 0xc, 0x7c, 0x8, 0x8, 0x98, 0x4d, 0xb2, 0x65, 0x6, 0x20, 0x4, 0x4, 0xc, 0x7f, 0x98, 0x4, 0x31, 0xc, 0x3, 0xf, 0x2, 0x15, 0x86, 0x34, 0xc, 0x64, 0x18, 0x4, 0x30 },
+{ 0x8d, 0xcb, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x7f, 0xff, 0x0, 0x40, 0x0, 0x48, 0x0, 0x58, 0x0, 0x70, 0x0, 0x40, 0x1, 0xc0, 0x7, 0x40, 0x1c, 0x40, 0x70, 0x40, 0x0, 0x40, 0x1, 0xc0 },
+{ 0x8d, 0xcc, 0x10, 0x6, 0x10, 0x3c, 0x13, 0xe0, 0x10, 0x42, 0x7a, 0x66, 0x13, 0x24, 0x11, 0x0, 0x10, 0x20, 0x18, 0x20, 0x77, 0xff, 0x10, 0xa8, 0x10, 0xa8, 0x11, 0xac, 0x13, 0x26, 0x16, 0x23, 0x30, 0x20 },
+{ 0x8d, 0xcd, 0x4, 0x20, 0x4, 0x24, 0x3f, 0xa6, 0x4, 0x22, 0x4, 0x20, 0x7f, 0xff, 0x0, 0x20, 0x4, 0x22, 0x4, 0x32, 0x7f, 0xd6, 0xc, 0x14, 0xf, 0x1c, 0x15, 0x88, 0x34, 0x1d, 0x64, 0x77, 0x5, 0xc2 },
+{ 0x8d, 0xce, 0x0, 0x80, 0x8, 0x80, 0x8, 0xfe, 0x8, 0x80, 0x7f, 0xff, 0x0, 0x28, 0x0, 0x24, 0x1f, 0xfe, 0x10, 0x10, 0x17, 0xd2, 0x11, 0x16, 0x15, 0x5c, 0x15, 0x49, 0x31, 0x1d, 0x23, 0x37, 0x60, 0xe2 },
+{ 0x8d, 0xcf, 0x0, 0x20, 0x30, 0x20, 0x1f, 0xff, 0x9, 0x4, 0x0, 0xd8, 0x60, 0x70, 0x31, 0xdc, 0x17, 0x7, 0x1, 0x4, 0x9, 0xfc, 0x9, 0x4, 0x19, 0xfc, 0x11, 0x4, 0x33, 0x4, 0x22, 0x4, 0x66, 0x4 },
+{ 0x8d, 0xd0, 0x4, 0x42, 0xc, 0xc6, 0x19, 0x8c, 0x33, 0x18, 0x22, 0x10, 0x19, 0x8c, 0xc, 0xc6, 0x4, 0x42, 0x0, 0x80, 0x8, 0x82, 0x18, 0x86, 0x31, 0xcc, 0x3, 0x60, 0x6, 0x30, 0x1c, 0x1c, 0x70, 0x7 },
+{ 0x8d, 0xd1, 0x0, 0xc, 0x0, 0x78, 0x1f, 0xc0, 0x1, 0x4, 0x11, 0x84, 0x18, 0x8c, 0x8, 0x8, 0x0, 0x80, 0x7f, 0xff, 0x2, 0xa0, 0x2, 0xa0, 0x6, 0xb0, 0xc, 0x98, 0x18, 0x8c, 0x70, 0x87, 0x0, 0x80 },
+{ 0x8d, 0xd2, 0x0, 0x0, 0x1f, 0xfe, 0x10, 0x2, 0x10, 0x2, 0x1f, 0xfe, 0x10, 0x0, 0x17, 0x4e, 0x10, 0x40, 0x17, 0x4e, 0x10, 0x0, 0x12, 0x40, 0x13, 0xfe, 0x34, 0x40, 0x2f, 0xff, 0x60, 0x40, 0x0, 0x40 },
+{ 0x8d, 0xd3, 0x0, 0x40, 0x7e, 0x40, 0x11, 0xf8, 0x10, 0x48, 0x10, 0x48, 0x10, 0xc9, 0x3c, 0x89, 0x25, 0x87, 0x64, 0x20, 0x24, 0x20, 0x25, 0xfe, 0x24, 0x20, 0x24, 0x20, 0x3c, 0x20, 0x0, 0x20, 0x0, 0x20 },
+{ 0x8d, 0xd4, 0x4, 0x20, 0x24, 0x20, 0x24, 0x26, 0x27, 0xbc, 0x24, 0x20, 0x24, 0x21, 0x27, 0xb3, 0x3c, 0x1e, 0x60, 0x0, 0x0, 0x0, 0x7f, 0xff, 0x2, 0x0, 0x7, 0xfc, 0x1c, 0x4, 0x74, 0x4, 0x7, 0xfc },
+{ 0x8d, 0xd5, 0x8, 0x0, 0xf, 0x7e, 0x18, 0x82, 0x35, 0xc6, 0x63, 0x6c, 0x16, 0x30, 0xc, 0x18, 0x1b, 0xec, 0x70, 0x7, 0x0, 0x0, 0x3f, 0xfe, 0x0, 0x80, 0x4, 0x90, 0x1c, 0x9c, 0x70, 0x87, 0x3, 0x80 },
+{ 0x8d, 0xd6, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x4, 0x10, 0x2, 0x20, 0x1, 0xc0, 0x3, 0x60, 0xe, 0x38, 0x7b, 0xef, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x88, 0xa, 0xa8, 0x1c, 0x98, 0x11, 0x88, 0x30, 0x8 },
+{ 0x8d, 0xd7, 0x8, 0x0, 0x18, 0xfe, 0x30, 0x92, 0x62, 0x92, 0x36, 0x92, 0xc, 0x92, 0x18, 0x92, 0x34, 0xfe, 0x7e, 0x92, 0xa, 0x92, 0x8, 0x92, 0x2a, 0x92, 0x2a, 0x92, 0x68, 0x92, 0x48, 0xfe, 0x8, 0x0 },
+{ 0x8d, 0xd8, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x4, 0x38, 0x1f, 0xe0, 0x0, 0x84, 0x18, 0xcc, 0xc, 0x58, 0x0, 0x90, 0x7f, 0xff, 0x2, 0xa0, 0x6, 0xb0, 0x1c, 0x9c, 0x70, 0x87, 0x0, 0x80 },
+{ 0x8d, 0xd9, 0x4, 0x20, 0x4, 0x24, 0x3f, 0xa6, 0x4, 0x22, 0x4, 0x20, 0x7f, 0xff, 0x0, 0x20, 0x4, 0x32, 0x7f, 0xd6, 0x8, 0x14, 0x14, 0x9c, 0x35, 0x8, 0x52, 0x1d, 0x11, 0x15, 0x1c, 0xb7, 0x30, 0x62 },
+{ 0x8d, 0xda, 0x4, 0x24, 0x4, 0x26, 0x3f, 0xa2, 0x4, 0x20, 0x7f, 0xff, 0x4, 0x20, 0x7f, 0xe2, 0x4, 0x32, 0x3f, 0x96, 0x24, 0x94, 0x3f, 0x9c, 0x24, 0x88, 0x3f, 0x9d, 0x4, 0x15, 0x7f, 0xb7, 0x4, 0x62 },
+{ 0x8d, 0xdb, 0x1, 0x0, 0x3d, 0xde, 0x25, 0x22, 0x26, 0xa6, 0x25, 0x54, 0x28, 0x88, 0x29, 0x4, 0x26, 0xfb, 0x24, 0x0, 0x24, 0x0, 0x27, 0xff, 0x2c, 0x20, 0x21, 0x24, 0x23, 0x26, 0x26, 0x23, 0x20, 0xe0 },
+{ 0x8d, 0xdc, 0x4, 0x2, 0x4, 0x12, 0x7f, 0xf2, 0x10, 0x92, 0x9, 0x12, 0x6, 0x12, 0x19, 0x92, 0x70, 0xf2, 0x10, 0x92, 0x1f, 0x92, 0x10, 0x92, 0x1f, 0x82, 0x10, 0x82, 0x30, 0x82, 0x20, 0x82, 0x60, 0x8e },
+{ 0x8d, 0xdd, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x7f, 0xff, 0x2, 0x0, 0xa, 0x20, 0xc, 0x20, 0x8, 0x20, 0x19, 0xfe, 0x28, 0x20, 0x48, 0x20, 0x8, 0x20, 0x8, 0x20, 0x8, 0x20, 0xb, 0xff, 0x8, 0x0 },
+{ 0x8d, 0xde, 0x8, 0x4, 0x8, 0x4, 0x8, 0x4, 0x7e, 0xff, 0x8, 0xc, 0x8, 0xc, 0x1c, 0x1c, 0x1a, 0x14, 0x19, 0x34, 0x28, 0x24, 0x28, 0x64, 0x48, 0xc4, 0x9, 0x84, 0x8, 0x4, 0x8, 0x4, 0x8, 0x1c },
+{ 0x8d, 0xdf, 0x0, 0x0, 0x3f, 0xfe, 0x22, 0x22, 0x22, 0x22, 0x3f, 0xfe, 0x0, 0x0, 0x2, 0x20, 0x3e, 0x3e, 0x2, 0x20, 0x3e, 0x3e, 0x2, 0x20, 0x1e, 0x20, 0x72, 0x3f, 0x6, 0x20, 0xc, 0x20, 0x38, 0x20 },
+{ 0x8d, 0xe0, 0x0, 0x4, 0x3e, 0x4, 0x22, 0x4, 0x22, 0x4, 0x3e, 0xff, 0x22, 0xc, 0x22, 0xc, 0x22, 0x1c, 0x3e, 0x14, 0x22, 0x34, 0x22, 0x64, 0x22, 0xc4, 0x3e, 0x4, 0x14, 0x4, 0x36, 0x4, 0x62, 0x1c },
+{ 0x8d, 0xe1, 0x0, 0x0, 0x33, 0xfe, 0x18, 0x88, 0x8, 0x88, 0x0, 0x88, 0x0, 0x88, 0x0, 0x88, 0x3, 0xff, 0x8, 0x28, 0x8, 0x68, 0x18, 0x48, 0x10, 0xc8, 0x31, 0x88, 0x23, 0x8, 0x6e, 0x8, 0x0, 0x38 },
+{ 0x8d, 0xe2, 0x10, 0x0, 0x11, 0xff, 0x11, 0x0, 0x11, 0x0, 0x7d, 0x0, 0x11, 0xfe, 0x11, 0x42, 0x11, 0x46, 0x11, 0x64, 0x11, 0x2c, 0x1d, 0x38, 0x73, 0x10, 0x2, 0x38, 0x6, 0x6c, 0xc, 0xc6, 0x1, 0x83 },
+{ 0x8d, 0xe3, 0x0, 0x0, 0x3d, 0xff, 0x25, 0x0, 0x25, 0x0, 0x25, 0x0, 0x2d, 0xfe, 0x29, 0x42, 0x25, 0x46, 0x25, 0x64, 0x25, 0x2c, 0x2d, 0x38, 0x23, 0x10, 0x22, 0x38, 0x26, 0x6c, 0x2c, 0xc6, 0x21, 0x83 },
+{ 0x8d, 0xe4, 0x0, 0x0, 0x11, 0xfe, 0x11, 0x22, 0x11, 0x22, 0x11, 0xfe, 0x7d, 0x22, 0x11, 0x22, 0x11, 0xfe, 0x10, 0x48, 0x10, 0xcc, 0x1d, 0xce, 0x73, 0x4b, 0x0, 0x48, 0x0, 0x48, 0x0, 0xc8, 0x1, 0x88 },
+{ 0x8d, 0xe5, 0x11, 0x4, 0x11, 0x4, 0x11, 0x4, 0x7f, 0xdf, 0x10, 0x55, 0x10, 0xd5, 0x38, 0x95, 0x35, 0x9f, 0x31, 0x55, 0x53, 0x55, 0x55, 0x15, 0x11, 0x1f, 0x11, 0x4, 0x11, 0x4, 0x11, 0x4, 0x11, 0x4 },
+{ 0x8d, 0xe6, 0x0, 0x8, 0xe, 0x30, 0x1, 0xc0, 0x1e, 0x38, 0x1, 0x0, 0x7f, 0xff, 0x2, 0x0, 0x4, 0x0, 0xf, 0xfc, 0x14, 0x4, 0x67, 0xfc, 0x4, 0x4, 0x7, 0xfc, 0x4, 0x4, 0x4, 0x4, 0x4, 0x1c },
+{ 0x8d, 0xe7, 0x2, 0x2, 0x3, 0x6, 0x1, 0x8c, 0x78, 0x88, 0x4b, 0xfe, 0x48, 0x20, 0x48, 0x20, 0x48, 0x20, 0x4f, 0xff, 0x48, 0x50, 0x48, 0x50, 0x78, 0xd8, 0x0, 0x88, 0x1, 0x8c, 0x3, 0x6, 0x6, 0x3 },
+{ 0x8d, 0xe8, 0x0, 0x20, 0x10, 0x20, 0x13, 0xfe, 0x54, 0x50, 0x54, 0xd8, 0x55, 0x8c, 0x54, 0x0, 0x57, 0xff, 0x54, 0x4, 0x55, 0xe4, 0x55, 0x24, 0x7d, 0x24, 0x1, 0x24, 0x1, 0xe4, 0x0, 0x4, 0x0, 0x1c },
+{ 0x8d, 0xe9, 0x10, 0x20, 0x10, 0x20, 0x13, 0xfe, 0x10, 0x50, 0x7c, 0xd8, 0x11, 0x8c, 0x10, 0x0, 0x17, 0xff, 0x10, 0x4, 0x11, 0xe4, 0x1d, 0x24, 0x71, 0x24, 0x1, 0x24, 0x1, 0xe4, 0x0, 0x4, 0x0, 0x1c },
+{ 0x8d, 0xea, 0x0, 0x20, 0x7c, 0x20, 0x13, 0xfe, 0x10, 0x50, 0x10, 0xd8, 0x11, 0x8c, 0x3c, 0x0, 0x27, 0xff, 0x24, 0x4, 0x65, 0xe4, 0x25, 0x24, 0x25, 0x24, 0x25, 0x24, 0x3d, 0xe4, 0x0, 0x4, 0x0, 0x1c },
+{ 0x8d, 0xeb, 0x3f, 0x1e, 0x21, 0x62, 0x3f, 0x1c, 0x8, 0x63, 0x2f, 0x3e, 0x28, 0x22, 0x3e, 0x3e, 0x60, 0x80, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xff, 0x24, 0x92, 0x62, 0x4a, 0x40, 0x6 },
+{ 0x8d, 0xec, 0x4, 0x80, 0x4, 0x80, 0xc, 0x80, 0x9, 0xff, 0x19, 0x20, 0x13, 0x20, 0x36, 0x20, 0x50, 0x3e, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x3e, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20 },
+{ 0x8d, 0xed, 0x48, 0x82, 0x69, 0xa2, 0x29, 0x22, 0x8, 0x22, 0x3f, 0x22, 0x21, 0x22, 0x21, 0x22, 0x3f, 0x22, 0x21, 0x22, 0x21, 0x22, 0x3f, 0x22, 0x21, 0x2, 0x21, 0x2, 0x21, 0x2, 0x21, 0x2, 0x27, 0xe },
+{ 0x8d, 0xee, 0x0, 0x80, 0x0, 0x80, 0x78, 0x80, 0x49, 0xff, 0x49, 0x20, 0x4b, 0x20, 0x4e, 0x20, 0x48, 0x3e, 0x48, 0x20, 0x48, 0x20, 0x48, 0x20, 0x78, 0x3e, 0x0, 0x20, 0x0, 0x20, 0x0, 0x20, 0x0, 0x20 },
+{ 0x8d, 0xef, 0x10, 0x40, 0x10, 0x40, 0x17, 0xfe, 0x14, 0x92, 0x7d, 0x92, 0x13, 0x10, 0x16, 0x1f, 0x11, 0x0, 0x19, 0xff, 0x73, 0x40, 0x16, 0x7e, 0x10, 0x40, 0x10, 0x7e, 0x10, 0x40, 0x10, 0x40, 0x30, 0x40 },
+{ 0x8d, 0xf0, 0x0, 0x80, 0x0, 0x80, 0x78, 0x80, 0x49, 0xff, 0x49, 0x20, 0x4b, 0x20, 0x4e, 0x20, 0x78, 0x3e, 0x48, 0x20, 0x48, 0x20, 0x48, 0x20, 0x48, 0x3e, 0x78, 0x20, 0x0, 0x20, 0x0, 0x20, 0x0, 0x20 },
+{ 0x8d, 0xf1, 0x20, 0x80, 0x31, 0xbe, 0x11, 0x22, 0x7f, 0xe2, 0x4, 0x22, 0x4, 0x3e, 0x24, 0xa2, 0x24, 0xa2, 0x24, 0xa2, 0x24, 0xbe, 0x3f, 0xa2, 0x4, 0x22, 0xc, 0x62, 0x8, 0x42, 0x18, 0xc2, 0x31, 0x8e },
+{ 0x8d, 0xf2, 0x10, 0x0, 0x13, 0xfe, 0x12, 0x52, 0x7e, 0x52, 0x12, 0x52, 0x12, 0x52, 0x3a, 0x52, 0x37, 0xff, 0x32, 0x52, 0x52, 0x52, 0x52, 0x52, 0x12, 0x52, 0x12, 0x52, 0x12, 0x52, 0x12, 0x52, 0x12, 0x56 },
+{ 0x8d, 0xf3, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x22, 0x22, 0x26, 0x22, 0x1c, 0x20, 0x72, 0x3f, 0x2, 0x0, 0x7, 0xfe, 0x1c, 0x80, 0x70, 0xfc, 0x0, 0x80, 0x0, 0xfc, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80 },
+{ 0x8d, 0xf4, 0x8, 0x10, 0x8, 0x10, 0x1f, 0xbf, 0x34, 0x28, 0x62, 0x44, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x11, 0xcc, 0x6, 0xb0, 0x1c, 0x9c, 0x70, 0x87, 0x0, 0x80 },
+{ 0x8d, 0xf5, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x21, 0x2, 0x22, 0x22, 0xe, 0x48, 0x1, 0x84, 0x3f, 0xfe, 0x0, 0x82, 0x4, 0x90, 0x1c, 0x9c, 0x70, 0x87, 0x0, 0x80 },
+{ 0x8d, 0xf6, 0x8, 0x24, 0x1c, 0x24, 0x16, 0x24, 0x32, 0xff, 0x20, 0x24, 0x7e, 0x24, 0x8, 0x24, 0x8, 0xff, 0x7f, 0x0, 0x8, 0x7e, 0x4a, 0x42, 0x6a, 0x42, 0x28, 0x7e, 0xe, 0x42, 0x38, 0x42, 0x60, 0x7e },
+{ 0x8d, 0xf7, 0x8, 0x21, 0x9, 0x33, 0x9, 0x92, 0x7e, 0x96, 0x8, 0x84, 0x8, 0x0, 0x1c, 0x20, 0x1a, 0x20, 0x19, 0xff, 0x28, 0x44, 0x28, 0xc4, 0x48, 0x8c, 0x8, 0xe8, 0x8, 0x3c, 0x8, 0x66, 0x9, 0xc3 },
+{ 0x8d, 0xf8, 0x10, 0x10, 0x1e, 0x10, 0x32, 0xfe, 0x24, 0x10, 0x7e, 0x10, 0x2a, 0x10, 0x2b, 0xff, 0x3e, 0x0, 0x2a, 0x10, 0x2a, 0x10, 0x3e, 0xfe, 0x0, 0x10, 0x55, 0x10, 0x55, 0x10, 0x54, 0x10, 0x41, 0xff },
+{ 0x8d, 0xf9, 0x10, 0x20, 0x10, 0x20, 0x1f, 0x3f, 0x34, 0x68, 0x66, 0xcc, 0x2, 0x4, 0x8, 0x90, 0x8, 0x90, 0x7f, 0xff, 0x8, 0x90, 0x8, 0x90, 0x8, 0x90, 0x8, 0xf0, 0x8, 0x0, 0x8, 0x0, 0xf, 0xfe },
+{ 0x8d, 0xfa, 0x0, 0x20, 0x3f, 0x20, 0x21, 0x20, 0x3f, 0x20, 0x21, 0x23, 0x3f, 0x3e, 0x0, 0x20, 0x7f, 0xa0, 0x4, 0x20, 0x14, 0x20, 0x17, 0x21, 0x14, 0x33, 0x14, 0x1e, 0x3c, 0x0, 0x27, 0x0, 0x61, 0xff },
+{ 0x8d, 0xfb, 0x0, 0x0, 0x1f, 0xfc, 0x12, 0x44, 0x12, 0x44, 0x12, 0x44, 0x12, 0x44, 0x12, 0x44, 0x7f, 0xff, 0x12, 0x44, 0x12, 0x44, 0x12, 0x44, 0x12, 0x44, 0x12, 0x44, 0x12, 0x44, 0x12, 0x44, 0x12, 0x4c },
+{ 0x8d, 0xfc, 0x0, 0x2, 0x3f, 0xd2, 0x20, 0x52, 0x20, 0x52, 0x3f, 0xd2, 0x22, 0x12, 0x22, 0x12, 0x2f, 0xd2, 0x2a, 0x52, 0x2a, 0x52, 0x2a, 0x52, 0x2a, 0x42, 0x6a, 0x42, 0x4a, 0xc2, 0x42, 0x2, 0x2, 0xe },
+{ 0x8e, 0x40, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x24, 0x2, 0x27, 0x7a, 0x8, 0x88, 0x35, 0x50, 0x12, 0x20, 0xc, 0x18, 0x73, 0xe7, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x80, 0xc, 0x98, 0x38, 0x8e, 0x3, 0x80 },
+{ 0x8e, 0x41, 0x11, 0x11, 0x13, 0x33, 0x12, 0x22, 0x16, 0x66, 0x7b, 0x33, 0x11, 0x11, 0x10, 0x40, 0x10, 0x7e, 0x18, 0xc2, 0x71, 0x86, 0x13, 0x44, 0x10, 0x2c, 0x10, 0x18, 0x10, 0x30, 0x10, 0xe0, 0x33, 0x80 },
+{ 0x8e, 0x42, 0x11, 0xfc, 0x11, 0x4, 0x11, 0xfc, 0x11, 0x4, 0x79, 0xfc, 0x10, 0x0, 0x17, 0xff, 0x12, 0x40, 0x1b, 0xde, 0x72, 0x4a, 0x13, 0xca, 0x12, 0x4e, 0x12, 0x44, 0x13, 0xce, 0x16, 0x5b, 0x30, 0x40 },
+{ 0x8e, 0x43, 0x10, 0x20, 0x10, 0x20, 0x17, 0xff, 0x14, 0x1, 0x7d, 0xff, 0x12, 0x52, 0x15, 0x54, 0x12, 0x88, 0x19, 0x4, 0x76, 0xfb, 0x10, 0x0, 0x13, 0xfe, 0x11, 0x24, 0x13, 0x26, 0x16, 0x23, 0x30, 0x60 },
+{ 0x8e, 0x44, 0x8, 0x40, 0x8, 0x40, 0x8, 0x40, 0x7f, 0x40, 0x8, 0x40, 0x8, 0x40, 0x1c, 0x40, 0x1a, 0x40, 0x19, 0x40, 0x28, 0x40, 0x28, 0x40, 0x48, 0x40, 0x8, 0x40, 0x8, 0x41, 0x8, 0x63, 0x8, 0x3e },
+{ 0x8e, 0x45, 0x2, 0x0, 0x22, 0x78, 0x14, 0x48, 0x8, 0x48, 0x14, 0x48, 0x62, 0xc8, 0x9, 0x8f, 0x8, 0x0, 0x7e, 0xfc, 0x8, 0x44, 0x1c, 0x6c, 0x1a, 0x28, 0x2a, 0x10, 0x48, 0x38, 0x8, 0x6c, 0x9, 0xc7 },
+{ 0x8e, 0x46, 0x2, 0x20, 0x7f, 0xff, 0x2, 0x20, 0x0, 0x10, 0x3c, 0xfe, 0x24, 0x44, 0x24, 0x28, 0x29, 0xff, 0x29, 0x0, 0x25, 0x50, 0x25, 0x7e, 0x25, 0x90, 0x2d, 0x7e, 0x21, 0x10, 0x22, 0x10, 0x20, 0xff },
+{ 0x8e, 0x47, 0x10, 0x24, 0x10, 0x2c, 0x7c, 0x28, 0x14, 0x7f, 0x15, 0x48, 0x37, 0x48, 0x60, 0xc8, 0x9, 0x7e, 0x8, 0x48, 0x7f, 0x48, 0x8, 0x48, 0x1c, 0x7e, 0x1a, 0x48, 0x29, 0x48, 0x48, 0x48, 0x8, 0x7f },
+{ 0x8e, 0x48, 0x0, 0x80, 0x1, 0x0, 0x1f, 0xfc, 0x10, 0x4, 0x1f, 0xfc, 0x10, 0x4, 0x1f, 0xfc, 0x0, 0x0, 0x1c, 0x9c, 0x0, 0x80, 0x1c, 0x9c, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80 },
+{ 0x8e, 0x49, 0x10, 0x10, 0x1e, 0x10, 0x32, 0xff, 0x24, 0x10, 0x7f, 0x7e, 0x29, 0x10, 0x29, 0xff, 0x3f, 0x0, 0x29, 0x7e, 0x29, 0x42, 0x3f, 0x7e, 0x0, 0x42, 0x0, 0x7e, 0x55, 0x42, 0x55, 0x42, 0x40, 0x4e },
+{ 0x8e, 0x4a, 0x10, 0x1, 0x13, 0xe9, 0x12, 0x29, 0x12, 0x29, 0x7e, 0x29, 0x13, 0xe9, 0x11, 0x9, 0x11, 0x9, 0x11, 0xe9, 0x1d, 0x29, 0x71, 0x29, 0x11, 0x21, 0x13, 0x21, 0x12, 0x61, 0x12, 0x41, 0x36, 0xc7 },
+{ 0x8e, 0x4b, 0x8, 0x10, 0x1c, 0x10, 0x17, 0xff, 0x32, 0x10, 0x20, 0xfe, 0x7e, 0x10, 0x9, 0xff, 0x8, 0x0, 0x7e, 0xfe, 0x8, 0x82, 0x4a, 0xfe, 0x6a, 0x82, 0x28, 0xfe, 0xe, 0x82, 0x38, 0x82, 0x60, 0x86 },
+{ 0x8e, 0x4c, 0x10, 0x10, 0x1e, 0x10, 0x32, 0x10, 0x25, 0xff, 0x7e, 0x44, 0x2a, 0xc6, 0x2b, 0x83, 0x3e, 0x44, 0x2a, 0x44, 0x2a, 0x6c, 0x3e, 0x38, 0x0, 0x10, 0x55, 0x38, 0x55, 0x6c, 0x54, 0xc6, 0x41, 0x83 },
+{ 0x8e, 0x4d, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xfc, 0x12, 0x44, 0x12, 0x44, 0x12, 0x44, 0x12, 0x44, 0x12, 0x44, 0x12, 0x44, 0x12, 0x44, 0x12, 0x44, 0x12, 0x44, 0x12, 0x44, 0x12, 0x44, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x8e, 0x4e, 0x0, 0x0, 0x3, 0xff, 0x78, 0x50, 0x48, 0x50, 0x48, 0x50, 0x49, 0xfe, 0x49, 0x52, 0x79, 0x52, 0x49, 0x52, 0x49, 0x52, 0x49, 0x9e, 0x49, 0x2, 0x79, 0x2, 0x1, 0x2, 0x1, 0x2, 0x1, 0xfe },
+{ 0x8e, 0x4f, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x8e, 0x50, 0x0, 0x80, 0x1, 0xc0, 0x3, 0x60, 0xe, 0x38, 0x78, 0x8f, 0x8, 0x88, 0x14, 0x94, 0x22, 0xa2, 0x8, 0x88, 0x14, 0x94, 0x22, 0xa2, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80 },
+{ 0x8e, 0x51, 0x2, 0x0, 0x6, 0x10, 0x4, 0x18, 0xf, 0xe8, 0x1, 0x0, 0x7f, 0xff, 0x2, 0x20, 0x6, 0x30, 0x1c, 0xdc, 0x71, 0x87, 0x7, 0x30, 0x1c, 0xe0, 0x3, 0x8c, 0x1e, 0x38, 0x0, 0xe0, 0x1f, 0x80 },
+{ 0x8e, 0x52, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x3f, 0xfe, 0x0, 0x0 },
+{ 0x8e, 0x53, 0x10, 0x40, 0x10, 0xc4, 0x10, 0x86, 0x11, 0xfa, 0x50, 0x20, 0x5b, 0xff, 0x54, 0x48, 0x50, 0x84, 0x13, 0x13, 0x10, 0x60, 0x11, 0x88, 0x10, 0x31, 0x11, 0xc3, 0x10, 0xe, 0x10, 0x38, 0x11, 0xe0 },
+{ 0x8e, 0x54, 0x12, 0x48, 0x12, 0x48, 0x17, 0xe8, 0x12, 0x4f, 0x7a, 0x4a, 0x17, 0xea, 0x10, 0x12, 0x13, 0xca, 0x1a, 0x4a, 0x73, 0xce, 0x12, 0x44, 0x13, 0xc4, 0x12, 0x4e, 0x12, 0x4a, 0x12, 0x4a, 0x32, 0xdb },
+{ 0x8e, 0x55, 0x14, 0x20, 0x14, 0x20, 0x7f, 0x20, 0x14, 0x3f, 0x14, 0x64, 0x7f, 0x44, 0x0, 0xcc, 0x3e, 0x28, 0x22, 0x28, 0x3e, 0x38, 0x22, 0x10, 0x3e, 0x38, 0x22, 0x28, 0x22, 0x6c, 0x22, 0x46, 0x26, 0xc3 },
+{ 0x8e, 0x56, 0x10, 0x24, 0x10, 0x26, 0x10, 0x22, 0x7d, 0xff, 0x10, 0x20, 0x11, 0xfe, 0x38, 0x20, 0x35, 0xff, 0x34, 0x20, 0x50, 0x32, 0x50, 0x16, 0x10, 0x1c, 0x10, 0x38, 0x10, 0xed, 0x13, 0x87, 0x10, 0x2 },
+{ 0x8e, 0x57, 0x11, 0x0, 0x11, 0xde, 0x15, 0x2, 0x1b, 0xd4, 0x52, 0x48, 0x55, 0x54, 0x50, 0xa3, 0x13, 0x0, 0x1d, 0x22, 0x10, 0xa8, 0x13, 0xff, 0x38, 0xa8, 0x2c, 0xa8, 0x25, 0xac, 0x63, 0x26, 0x40, 0x20 },
+{ 0x8e, 0x58, 0x0, 0x0, 0x7d, 0xfe, 0x11, 0x52, 0x11, 0x52, 0x11, 0x52, 0x11, 0x52, 0x7d, 0x52, 0x13, 0xff, 0x11, 0x52, 0x11, 0x52, 0x11, 0x52, 0x11, 0x52, 0x1d, 0x52, 0x71, 0x52, 0x1, 0x52, 0x1, 0x56 },
+{ 0x8e, 0x59, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xff, 0x4, 0x10, 0x6, 0x30, 0x2, 0x20, 0x1f, 0xff, 0x10, 0x0, 0x12, 0x40, 0x13, 0xfc, 0x14, 0x40, 0x10, 0x40, 0x33, 0xfc, 0x20, 0x40, 0x60, 0x40, 0xf, 0xff },
+{ 0x8e, 0x5a, 0x10, 0x40, 0x10, 0x40, 0x3e, 0xff, 0x29, 0x20, 0x44, 0x10, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x2, 0x20, 0x7f, 0xff, 0x4, 0x20, 0x18, 0x20 },
+{ 0x8e, 0x5b, 0x10, 0x40, 0x1f, 0x7f, 0x24, 0x90, 0x4f, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x7f, 0xff, 0x4, 0x90, 0x1b, 0x2c, 0x61, 0x53, 0x1f, 0xf8, 0x4, 0x90, 0x38, 0x8e },
+{ 0x8e, 0x5c, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x1, 0x40, 0x6, 0x30, 0x1c, 0x9c, 0x70, 0x87, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x0, 0x82, 0x3, 0xff, 0x7e, 0x1 },
+{ 0x8e, 0x5d, 0x0, 0x44, 0x3d, 0xef, 0x0, 0x44, 0x7d, 0xef, 0x0, 0x44, 0x3c, 0xaa, 0x1, 0x1, 0x0, 0xfe, 0x3c, 0x82, 0x0, 0xfe, 0x0, 0x82, 0x3c, 0xfe, 0x24, 0x82, 0x24, 0xfe, 0x24, 0x44, 0x3d, 0x83 },
+{ 0x8e, 0x5e, 0x4, 0x10, 0x3f, 0x7e, 0x4, 0x10, 0x7f, 0x7f, 0xa, 0x28, 0x11, 0x44, 0x60, 0x3, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x4, 0x10, 0x38, 0xe },
+{ 0x8e, 0x5f, 0x0, 0x20, 0x7f, 0x62, 0x14, 0x42, 0x14, 0xff, 0x7f, 0x25, 0x55, 0x24, 0x55, 0x47, 0x55, 0xa0, 0x67, 0x3e, 0x41, 0x62, 0x41, 0xc6, 0x7f, 0x2c, 0x41, 0x18, 0x41, 0x3c, 0x7f, 0x66, 0x0, 0xc3 },
+{ 0x8e, 0x60, 0x4, 0x0, 0x7, 0x7e, 0x4, 0x22, 0x1f, 0x94, 0x71, 0x8, 0x16, 0x34, 0x78, 0x83, 0x3, 0x60, 0xc, 0x98, 0x77, 0xf7, 0x4, 0x10, 0x7, 0xf0, 0x4, 0x10, 0x7, 0xf4, 0x4, 0x48, 0x3f, 0x3f },
+{ 0x8e, 0x61, 0x8, 0x2, 0x8, 0xe, 0x7f, 0xb8, 0x8, 0x20, 0x3f, 0x20, 0x29, 0x3f, 0x29, 0x24, 0x3f, 0x24, 0x29, 0x24, 0x29, 0x24, 0x3f, 0x24, 0x8, 0x24, 0x7f, 0xe4, 0x8, 0x44, 0x8, 0xc4, 0x8, 0x4 },
+{ 0x8e, 0x62, 0x4, 0x2, 0x7f, 0x8e, 0x4, 0x38, 0x3f, 0xa0, 0x24, 0xbf, 0x3f, 0xa4, 0x24, 0xa4, 0x3f, 0xe4, 0x4, 0x44, 0x7f, 0x84, 0x4, 0x4, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8 },
+{ 0x8e, 0x63, 0x0, 0x20, 0x7f, 0x24, 0x10, 0x22, 0x11, 0xff, 0x1e, 0x20, 0x13, 0xfe, 0x32, 0x20, 0x23, 0xff, 0x3a, 0x20, 0x6e, 0x32, 0x6, 0x16, 0x4, 0x1c, 0xc, 0x38, 0x18, 0x6d, 0x31, 0xc7, 0x60, 0x2 },
+{ 0x8e, 0x64, 0x4, 0x20, 0x4, 0x20, 0xc, 0x20, 0x8, 0x20, 0x18, 0x20, 0x17, 0xff, 0x30, 0x20, 0x50, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x13, 0xfe, 0x10, 0x0 },
+{ 0x8e, 0x65, 0x8, 0x0, 0xb, 0xfe, 0x18, 0xc, 0x10, 0x18, 0x10, 0x20, 0x30, 0x20, 0x30, 0x20, 0x57, 0xff, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0xe0 },
+{ 0x8e, 0x66, 0x4, 0x0, 0x7, 0xfe, 0xc, 0x2, 0x8, 0x2, 0x1b, 0xf2, 0x10, 0x2, 0x30, 0x2, 0x53, 0xf2, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x13, 0xf2, 0x10, 0x2, 0x10, 0x2, 0x10, 0x2, 0x10, 0xe },
+{ 0x8e, 0x67, 0x4, 0x20, 0x4, 0x20, 0xf, 0xff, 0x8, 0x20, 0x1b, 0xfe, 0x12, 0x22, 0x32, 0x22, 0x52, 0x22, 0x13, 0xfe, 0x10, 0x20, 0x11, 0x20, 0x10, 0xe0, 0x10, 0x40, 0x10, 0xf0, 0x11, 0x9c, 0x17, 0x7 },
+{ 0x8e, 0x68, 0x4, 0x2, 0x4, 0x12, 0x7f, 0xd2, 0x4, 0x12, 0x4, 0x12, 0x7f, 0xd2, 0x44, 0x52, 0x44, 0x52, 0x44, 0xd2, 0xe, 0x12, 0xd, 0x12, 0x15, 0x82, 0x34, 0xc2, 0x64, 0x2, 0x4, 0x2, 0x4, 0xe },
+{ 0x8e, 0x69, 0x0, 0x0, 0x7f, 0xfe, 0x0, 0x2, 0x0, 0x2, 0x1f, 0xf2, 0x0, 0x2, 0x0, 0x2, 0xf, 0xe2, 0x8, 0x22, 0x8, 0x22, 0x8, 0x22, 0xf, 0xe2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0xe },
+{ 0x8e, 0x6a, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x3f, 0xfe, 0x0, 0x80, 0x19, 0x80, 0xd, 0x0, 0x3, 0x80, 0x6, 0xe0, 0x1c, 0x38, 0x70, 0xf },
+{ 0x8e, 0x6b, 0x0, 0x0, 0x3e, 0xfe, 0x22, 0x2, 0x22, 0x2, 0x3e, 0x7a, 0x0, 0x2, 0x7f, 0x2, 0x55, 0x7a, 0x55, 0x4a, 0x55, 0x4a, 0x7f, 0x4a, 0x55, 0x7a, 0x55, 0x2, 0x55, 0x2, 0x55, 0x2, 0x57, 0xe },
+{ 0x8e, 0x6c, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xfe, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x26, 0x22, 0x24, 0x32, 0x2c, 0x1e, 0x38, 0x2, 0x20, 0x2, 0x20, 0x2, 0x3f, 0xfe, 0x0, 0x0, 0x0, 0x0 },
+{ 0x8e, 0x6d, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x0, 0x0 },
+{ 0x8e, 0x6e, 0x8, 0x20, 0x8, 0x20, 0x8, 0x60, 0x8, 0x44, 0x7e, 0x46, 0x12, 0xc2, 0x12, 0x9f, 0x13, 0xf1, 0x32, 0x0, 0x26, 0x0, 0x24, 0xfe, 0x7c, 0x82, 0xa, 0x82, 0x1a, 0x82, 0x30, 0x82, 0x60, 0xfe },
+{ 0x8e, 0x6f, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10, 0x9, 0xff, 0x7e, 0x10, 0x12, 0x10, 0x12, 0xfe, 0x12, 0x92, 0x32, 0x92, 0x26, 0x92, 0x24, 0x92, 0x7c, 0x92, 0xa, 0x96, 0x1a, 0x10, 0x30, 0x10, 0x60, 0x10 },
+{ 0x8e, 0x70, 0x0, 0x80, 0x30, 0x80, 0x19, 0xfe, 0x9, 0x22, 0x2, 0x24, 0x8, 0x70, 0x18, 0xd8, 0x31, 0x8c, 0x67, 0x7, 0x1, 0x0, 0x7f, 0xff, 0x2, 0x10, 0x4, 0x20, 0xf, 0xc0, 0x2, 0x78, 0x3c, 0xe },
+{ 0x8e, 0x71, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x18, 0x0, 0x30, 0x0, 0x60, 0x0, 0xc0, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x3, 0x80 },
+{ 0x8e, 0x72, 0x0, 0x0, 0x3f, 0xfe, 0x20, 0x2, 0x20, 0x2, 0x3f, 0xfe, 0x20, 0x0, 0x20, 0x0, 0x3f, 0xff, 0x24, 0x0, 0x27, 0xa0, 0x2c, 0xa6, 0x39, 0xbc, 0x25, 0x20, 0x63, 0x21, 0x46, 0x23, 0x1c, 0x1e },
+{ 0x8e, 0x73, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x9c, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80 },
+{ 0x8e, 0x74, 0x4, 0x0, 0x9, 0xff, 0x3e, 0x10, 0x22, 0x10, 0x22, 0xfe, 0x22, 0x92, 0x3e, 0x92, 0x20, 0x92, 0x20, 0x92, 0x3e, 0x92, 0x22, 0x92, 0x22, 0x92, 0x22, 0x92, 0x22, 0x96, 0x3e, 0x10, 0x0, 0x10 },
+{ 0x8e, 0x75, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x0, 0x0, 0x1, 0x80, 0x4, 0xc0, 0x14, 0x46, 0x14, 0x3, 0x34, 0x9, 0x66, 0x18, 0x3, 0xf0 },
+{ 0x8e, 0x76, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x0, 0x0, 0x1, 0x80, 0x14, 0xc6, 0x14, 0x43, 0x34, 0x9, 0x66, 0x18, 0x3, 0xf0 },
+{ 0x8e, 0x77, 0x8, 0x80, 0x8, 0x8e, 0x8, 0xf8, 0x8, 0x80, 0x7e, 0x81, 0x8, 0xc3, 0x8, 0x7e, 0x8, 0x0, 0xe, 0x0, 0x78, 0xfe, 0x8, 0x82, 0x8, 0x82, 0x8, 0xfe, 0x8, 0x82, 0x8, 0x82, 0x38, 0xfe },
+{ 0x8e, 0x78, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xf8, 0x4, 0x8, 0x6, 0x18, 0x2, 0x30, 0x3, 0x60, 0x1, 0xc0, 0x3, 0x60, 0x6, 0x30, 0x1c, 0x1c, 0x70, 0x7 },
+{ 0x8e, 0x79, 0x0, 0x20, 0x7f, 0xa0, 0x3, 0x40, 0x6, 0x7f, 0xc, 0x84, 0x8, 0xc4, 0x9, 0x44, 0xe, 0x6c, 0x38, 0x28, 0x68, 0x38, 0x8, 0x10, 0x8, 0x38, 0x8, 0x28, 0x8, 0x6c, 0x8, 0xc6, 0x39, 0x83 },
+{ 0x8e, 0x7a, 0x12, 0x2, 0x12, 0xe, 0x7f, 0xb8, 0x12, 0x20, 0x12, 0x20, 0x1e, 0x3f, 0x12, 0x24, 0x12, 0x24, 0x1e, 0x24, 0x12, 0x24, 0x12, 0x24, 0x7f, 0xa4, 0x12, 0x24, 0x13, 0x64, 0x31, 0x44, 0x60, 0xc4 },
+{ 0x8e, 0x7b, 0x8, 0x40, 0x8, 0x40, 0x8, 0x80, 0x7e, 0xff, 0x11, 0x80, 0x11, 0x10, 0x1e, 0x96, 0x12, 0x9a, 0x12, 0xb2, 0x12, 0xd2, 0x13, 0x96, 0x12, 0x90, 0x32, 0x90, 0x22, 0x81, 0x22, 0xc3, 0x6e, 0x7e },
+{ 0x8e, 0x7c, 0x10, 0x0, 0x10, 0x3c, 0x1f, 0xe0, 0x10, 0x0, 0x10, 0x2, 0x18, 0x6, 0xf, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x4, 0x10, 0x4, 0x1f, 0xfc, 0x10, 0x4, 0x10, 0x4, 0x1f, 0xfc },
+{ 0x8e, 0x7d, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x7d, 0xff, 0x10, 0x10, 0x10, 0x10, 0x39, 0xfe, 0x34, 0x82, 0x34, 0xc6, 0x50, 0x44, 0x50, 0x6c, 0x10, 0x38, 0x10, 0x38, 0x10, 0x6c, 0x10, 0xc6, 0x11, 0x83 },
+{ 0x8e, 0x7e, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x8, 0x80, 0x8, 0x80, 0x8, 0xfc, 0x8, 0x80, 0x8, 0x80, 0x8, 0x80, 0x8, 0x80, 0x8, 0x80, 0x8, 0x80, 0x8, 0x80, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x8e, 0x80, 0x0, 0x0, 0x7f, 0xff, 0x8, 0x40, 0x8, 0x40, 0xf, 0x40, 0x9, 0x46, 0x19, 0x5c, 0x11, 0x70, 0x3b, 0x40, 0x6e, 0x40, 0x6, 0x40, 0x4, 0x40, 0xc, 0x40, 0x18, 0x41, 0x30, 0x63, 0x60, 0x3e },
+{ 0x8e, 0x81, 0x0, 0xc, 0x0, 0x78, 0x1f, 0xc0, 0x10, 0x40, 0x10, 0x40, 0x10, 0x40, 0x10, 0x40, 0x1f, 0xff, 0x10, 0x40, 0x10, 0x60, 0x10, 0x20, 0x10, 0x20, 0x10, 0x30, 0x10, 0x11, 0x1f, 0x1b, 0x70, 0xe },
+{ 0x8e, 0x82, 0x4, 0x80, 0x45, 0x1f, 0x2b, 0xc4, 0x1a, 0x44, 0x12, 0x5f, 0x32, 0x55, 0x53, 0xd5, 0x12, 0x15, 0x12, 0x15, 0x33, 0xd5, 0x52, 0x55, 0x12, 0x55, 0x12, 0x55, 0x12, 0x57, 0x33, 0xc4, 0x60, 0x4 },
+{ 0x8e, 0x83, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10, 0x7e, 0x90, 0x2, 0x90, 0x6, 0x9e, 0x4, 0x90, 0xc, 0x90, 0x18, 0x90, 0x3c, 0x90, 0x6a, 0x90, 0xa, 0x90, 0x8, 0x90, 0x8, 0x90, 0xb, 0xff, 0x8, 0x0 },
+{ 0x8e, 0x84, 0x3, 0x10, 0xe, 0x10, 0x78, 0x10, 0x8, 0x30, 0x8, 0x20, 0x7f, 0x20, 0x8, 0x20, 0x8, 0x20, 0x1c, 0x60, 0x1a, 0x44, 0x29, 0x44, 0x28, 0x46, 0x48, 0xc2, 0x8, 0x9e, 0x8, 0xf3, 0xb, 0x81 },
+{ 0x8e, 0x85, 0x0, 0x80, 0x1, 0x80, 0x3, 0x8, 0x6, 0x18, 0x18, 0x30, 0xc, 0x64, 0x6, 0xc6, 0x1, 0x82, 0x7f, 0xff, 0x0, 0x81, 0x0, 0x80, 0x8, 0x88, 0x18, 0x8c, 0x30, 0x86, 0x60, 0x83, 0x0, 0x80 },
+{ 0x8e, 0x86, 0x8, 0x2, 0x18, 0xe, 0x30, 0xf8, 0x62, 0x88, 0x36, 0x88, 0xc, 0x88, 0x18, 0x88, 0x34, 0xff, 0x7e, 0x88, 0xa, 0x88, 0x8, 0x88, 0x2a, 0x8c, 0x2a, 0x84, 0x68, 0x85, 0x48, 0xe7, 0xb, 0x82 },
+{ 0x8e, 0x87, 0x4, 0x20, 0x24, 0x26, 0x27, 0xbc, 0x24, 0x20, 0x24, 0x21, 0x27, 0xb3, 0x3c, 0x1e, 0x60, 0x80, 0x3, 0x8, 0xc, 0x30, 0x2, 0xc2, 0x7f, 0xff, 0x0, 0x81, 0x4, 0x90, 0x1c, 0x9c, 0x70, 0x87 },
+{ 0x8e, 0x88, 0x0, 0x10, 0x3c, 0x10, 0x24, 0x10, 0x25, 0xff, 0x24, 0x10, 0x3c, 0x10, 0x25, 0xfe, 0x24, 0x82, 0x24, 0xc6, 0x3c, 0x44, 0x24, 0x6c, 0x24, 0x38, 0x24, 0x38, 0x24, 0x6c, 0x64, 0xc6, 0x4d, 0x83 },
+{ 0x8e, 0x89, 0x0, 0x40, 0x3e, 0x4e, 0x22, 0x78, 0x22, 0x40, 0x22, 0x41, 0x3e, 0x63, 0x22, 0x3e, 0x22, 0x0, 0x22, 0x0, 0x3e, 0x7e, 0x22, 0x42, 0x22, 0x42, 0x22, 0x7e, 0x22, 0x42, 0x62, 0x42, 0x46, 0x7e },
+{ 0x8e, 0x8a, 0x0, 0x0, 0x3f, 0xfe, 0x2, 0x0, 0x2, 0x10, 0x6, 0x10, 0x4, 0xf8, 0x1f, 0x8c, 0x0, 0x0, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x8e, 0x8b, 0x8, 0x0, 0x8, 0xfe, 0x8, 0x82, 0x7e, 0x82, 0x2, 0xfe, 0x6, 0x82, 0x4, 0x82, 0xc, 0xfe, 0x18, 0x82, 0x3c, 0x82, 0x6a, 0xfe, 0xa, 0x48, 0x8, 0x48, 0x8, 0x49, 0x8, 0xc9, 0x9, 0x87 },
+{ 0x8e, 0x8c, 0x0, 0x0, 0x3d, 0xfe, 0x0, 0x2, 0x7e, 0x2, 0x0, 0xf2, 0x3c, 0x2, 0x0, 0x2, 0x0, 0xf2, 0x3c, 0x92, 0x0, 0x92, 0x0, 0x92, 0x3c, 0xf2, 0x24, 0x2, 0x24, 0x2, 0x24, 0x2, 0x3c, 0xe },
+{ 0x8e, 0x8d, 0x0, 0x10, 0x3e, 0x10, 0x0, 0xfe, 0x7f, 0x10, 0x0, 0x10, 0x3e, 0x10, 0x1, 0xff, 0x0, 0x4, 0x3e, 0x4, 0x1, 0xff, 0x0, 0x4, 0x3e, 0x44, 0x22, 0x64, 0x22, 0x24, 0x22, 0x4, 0x3e, 0x1c },
+{ 0x8e, 0x8e, 0x0, 0xa, 0x3c, 0x9, 0x0, 0x9, 0x7e, 0x8, 0x1, 0xff, 0x3c, 0x8, 0x0, 0x8, 0x1, 0xf8, 0x3c, 0x48, 0x0, 0x48, 0x0, 0x48, 0x3c, 0x4c, 0x24, 0x74, 0x25, 0xc5, 0x24, 0x7, 0x3c, 0x2 },
+{ 0x8e, 0x8f, 0x0, 0x10, 0x3c, 0x10, 0x0, 0x10, 0x7e, 0xff, 0x0, 0x10, 0x3c, 0x10, 0x0, 0x10, 0x0, 0xfe, 0x3c, 0x0, 0x0, 0x10, 0x0, 0x18, 0x3c, 0x2a, 0x24, 0xa3, 0x24, 0xa5, 0x25, 0xa4, 0x3d, 0x1c },
+{ 0x8e, 0x90, 0x0, 0x10, 0x3d, 0x10, 0x1, 0xbf, 0x7e, 0xa9, 0x0, 0xa, 0x3c, 0x9c, 0x0, 0x94, 0x1, 0xb6, 0x3d, 0x63, 0x0, 0x0, 0x0, 0xfe, 0x3c, 0x82, 0x24, 0x82, 0x24, 0x82, 0x24, 0x82, 0x3c, 0xfe },
+{ 0x8e, 0x91, 0x30, 0x80, 0x1d, 0xfe, 0x3, 0x22, 0x0, 0x74, 0xc, 0xd8, 0x3b, 0x8c, 0x60, 0x7, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x4, 0x10, 0x38, 0xe },
+{ 0x8e, 0x92, 0x0, 0x0, 0x3e, 0xfc, 0x22, 0x84, 0x22, 0x84, 0x3e, 0xfc, 0x22, 0x84, 0x22, 0x84, 0x22, 0xfc, 0x3e, 0x20, 0x22, 0x7f, 0x23, 0x95, 0x22, 0x25, 0x3e, 0xc9, 0x14, 0x13, 0x36, 0x62, 0x62, 0xe },
+{ 0x8e, 0x93, 0xa, 0x24, 0xa, 0x6c, 0xa, 0x48, 0x2a, 0xff, 0x2a, 0x48, 0x2a, 0x48, 0x2e, 0xc8, 0x2b, 0x7e, 0x2a, 0x48, 0x2a, 0x48, 0x2a, 0x48, 0x2a, 0x7e, 0x2a, 0x48, 0x2e, 0x48, 0x3a, 0xc8, 0x61, 0x7f },
+{ 0x8e, 0x94, 0x8, 0x0, 0x1d, 0xfe, 0x16, 0x2, 0x32, 0x2, 0x28, 0xf2, 0x7e, 0x2, 0x22, 0x2, 0x3e, 0xf2, 0x22, 0x92, 0x3e, 0x92, 0x20, 0x92, 0x24, 0xf2, 0x24, 0x2, 0x2e, 0x2, 0x3a, 0x2, 0x60, 0xe },
+{ 0x8e, 0x95, 0x0, 0x80, 0x8, 0x80, 0x8, 0xfc, 0x8, 0x80, 0x8, 0x80, 0x7f, 0xff, 0x10, 0x4, 0x14, 0x94, 0x12, 0xa4, 0x17, 0xf4, 0x10, 0x84, 0x11, 0xc4, 0x12, 0xa4, 0x14, 0x94, 0x10, 0x4, 0x1f, 0xfc },
+{ 0x8e, 0x96, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x1f, 0xfc, 0x10, 0x84, 0x1f, 0xfc, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x84, 0x7f, 0xff, 0x0, 0x84, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x80, 0x3, 0x80 },
+{ 0x8e, 0x97, 0x8, 0x4, 0xa, 0x4, 0x1a, 0x4, 0x12, 0x4, 0x32, 0xc4, 0x32, 0x64, 0x52, 0x24, 0x12, 0x4, 0x12, 0x4, 0x12, 0xc, 0x12, 0x8, 0x12, 0x8, 0x12, 0xdc, 0x13, 0x96, 0x1e, 0x33, 0x10, 0x61 },
+{ 0x8e, 0x98, 0x4, 0x20, 0x4, 0x20, 0xd, 0xfe, 0x8, 0x20, 0x18, 0x20, 0x10, 0x20, 0x33, 0xff, 0x50, 0x4, 0x10, 0x4, 0x13, 0xff, 0x10, 0x4, 0x10, 0xc4, 0x10, 0x64, 0x10, 0x24, 0x10, 0x4, 0x10, 0x1c },
+{ 0x8e, 0x99, 0x0, 0x0, 0x13, 0xfc, 0x12, 0x4, 0x12, 0x4, 0x12, 0x4, 0x13, 0xfc, 0x12, 0x4, 0x12, 0x4, 0x12, 0x4, 0x13, 0xfc, 0x10, 0x0, 0x4, 0x40, 0x4, 0x40, 0xc, 0x41, 0x18, 0x63, 0x70, 0x3e },
+{ 0x8e, 0x9a, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x2, 0x20, 0x2, 0xf, 0xf8, 0x0, 0x30, 0x0, 0x60, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x3, 0x80 },
+{ 0x8e, 0x9b, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x10, 0x0, 0x10, 0x3f, 0xfe, 0x0, 0x10, 0xc, 0x10, 0x6, 0x10, 0x2, 0x10, 0x0, 0x10, 0x0, 0x70 },
+{ 0x8e, 0x9c, 0x8, 0x8, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x8, 0x20, 0x11, 0x44, 0xa, 0x28, 0x4, 0x10, 0xa, 0x24, 0x3d, 0x7e, 0x0, 0x2, 0x1, 0x80, 0x14, 0xc6, 0x14, 0x4b, 0x36, 0x19, 0x63, 0xf0 },
+{ 0x8e, 0x9d, 0x10, 0x10, 0x10, 0x10, 0x11, 0xfe, 0x10, 0x10, 0x7c, 0x10, 0x10, 0x10, 0x13, 0xff, 0x10, 0x4, 0x1c, 0x4, 0x73, 0xff, 0x10, 0x4, 0x11, 0x84, 0x10, 0xc4, 0x10, 0x44, 0x10, 0x4, 0x70, 0x1c },
+{ 0x8e, 0x9e, 0x0, 0x20, 0x0, 0x20, 0x79, 0xfe, 0x48, 0x20, 0x48, 0x20, 0x48, 0x20, 0x7b, 0xff, 0x48, 0x4, 0x48, 0x4, 0x4b, 0xff, 0x48, 0x4, 0x78, 0xc4, 0x0, 0x64, 0x0, 0x24, 0x0, 0x4, 0x0, 0x1c },
+{ 0x8e, 0x9f, 0x1, 0x0, 0x1, 0x0, 0x31, 0x0, 0x19, 0xfe, 0xb, 0x2, 0x2, 0x46, 0x6, 0x44, 0x0, 0x40, 0x8, 0x40, 0x8, 0xe0, 0x18, 0xa0, 0x11, 0xb0, 0x31, 0x10, 0x23, 0x18, 0x66, 0xc, 0xc, 0x7 },
+{ 0x8e, 0xa0, 0x0, 0x84, 0x30, 0xcc, 0x18, 0x48, 0xb, 0xff, 0x0, 0x84, 0x60, 0x84, 0x31, 0x8, 0x11, 0x8, 0x2, 0x52, 0x9, 0x4a, 0x8, 0x84, 0x18, 0x84, 0x11, 0x4a, 0x31, 0x4a, 0x23, 0xdf, 0x62, 0x51 },
+{ 0x8e, 0xa1, 0x0, 0x20, 0x30, 0x20, 0x18, 0x60, 0x8, 0x44, 0x0, 0xc4, 0x60, 0x9e, 0x33, 0xf3, 0x10, 0x0, 0x0, 0x0, 0x8, 0x0, 0x9, 0xfe, 0x19, 0x2, 0x11, 0x2, 0x31, 0x2, 0x21, 0x2, 0x61, 0xfe },
+{ 0x8e, 0xa2, 0x0, 0x0, 0x7f, 0xff, 0x8, 0x88, 0x10, 0x84, 0x3f, 0xfe, 0x60, 0x83, 0x2a, 0xaa, 0x24, 0x92, 0x2a, 0xaa, 0x20, 0x82, 0x2a, 0xaa, 0x24, 0x92, 0x2a, 0xaa, 0x20, 0x82, 0x20, 0x82, 0x20, 0x8e },
+{ 0x8e, 0xa3, 0x7f, 0xff, 0x10, 0x84, 0x3f, 0xfe, 0x6a, 0xab, 0x24, 0x92, 0x2a, 0xaa, 0x20, 0x82, 0x2a, 0xaa, 0x24, 0x92, 0x2a, 0xaa, 0x0, 0x0, 0x3f, 0xfe, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x90, 0x7f, 0xff },
+{ 0x8e, 0xa4, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xff, 0x10, 0x20, 0x51, 0xfc, 0x30, 0x20, 0x10, 0x20, 0x17, 0xff, 0x10, 0x8, 0x30, 0x8, 0x57, 0xff, 0x11, 0x8, 0x31, 0x88, 0x20, 0x88, 0x60, 0x8, 0x0, 0x38 },
+{ 0x8e, 0xa5, 0x0, 0x84, 0x0, 0xcc, 0x7c, 0x48, 0x13, 0xff, 0x10, 0x84, 0x10, 0x84, 0x11, 0x8, 0x39, 0x8, 0x2a, 0x52, 0x69, 0x4a, 0x28, 0x84, 0x28, 0x84, 0x29, 0x4a, 0x29, 0x4a, 0x3b, 0xdf, 0x2, 0x51 },
+{ 0x8e, 0xa6, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x8, 0x88, 0x8, 0x88, 0x18, 0x8c, 0x30, 0x86, 0x60, 0x83, 0x0, 0x80, 0x3, 0x80 },
+{ 0x8e, 0xa7, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x80, 0x1, 0x0, 0x3f, 0xfe, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x2e },
+{ 0x8e, 0xa8, 0x0, 0x0, 0x7f, 0xff, 0x8, 0x10, 0x8, 0x10, 0xf, 0xf0, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10, 0xf, 0xf0, 0x8, 0x10, 0x8, 0x10, 0x8, 0x1f, 0xf, 0xf0, 0x78, 0x10, 0x0, 0x10, 0x0, 0x10 },
+{ 0x8e, 0xa9, 0x0, 0x80, 0x1, 0x80, 0x1, 0x0, 0x1f, 0xfc, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x1f, 0xfc, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x1f, 0xfc, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x1f, 0xfc },
+{ 0x8e, 0xaa, 0x4, 0x20, 0x4, 0x20, 0x7f, 0xff, 0x4, 0x20, 0x0, 0x10, 0x3e, 0xfe, 0x22, 0x10, 0x22, 0x10, 0x3f, 0xff, 0x22, 0x4, 0x23, 0xff, 0x22, 0x44, 0x22, 0x64, 0x3e, 0x24, 0x0, 0x4, 0x0, 0x1c },
+{ 0x8e, 0xab, 0x6, 0x10, 0x1c, 0x10, 0x71, 0xff, 0x10, 0x82, 0x10, 0xc6, 0x10, 0x44, 0x7c, 0x44, 0x11, 0xff, 0x10, 0x10, 0x10, 0x10, 0x7d, 0xff, 0x44, 0x10, 0x44, 0x10, 0x44, 0x10, 0x44, 0x10, 0x7c, 0x10 },
+{ 0x8e, 0xac, 0x0, 0x20, 0x18, 0x20, 0xc, 0x20, 0x4, 0x7f, 0x0, 0x41, 0x60, 0xc1, 0x31, 0x83, 0x13, 0x62, 0x0, 0x36, 0x8, 0x14, 0x8, 0xc, 0x18, 0x18, 0x10, 0x30, 0x30, 0x60, 0x21, 0xc0, 0x67, 0x0 },
+{ 0x8e, 0xad, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xff, 0x11, 0x20, 0x11, 0x20, 0x1f, 0xfe, 0x11, 0x22, 0x11, 0x22, 0x1f, 0xfe, 0x10, 0x0, 0x14, 0x26, 0x17, 0xbc, 0x34, 0x20, 0x24, 0x21, 0x67, 0xb3, 0x1c, 0x1e },
+{ 0x8e, 0xae, 0x0, 0x24, 0x0, 0x26, 0x0, 0x22, 0x0, 0x20, 0x7f, 0xff, 0x0, 0x20, 0x0, 0x20, 0x3f, 0xa0, 0x4, 0x30, 0x4, 0x10, 0x4, 0x10, 0x4, 0x18, 0x5, 0xc8, 0x1f, 0xd, 0x70, 0x7, 0x0, 0x2 },
+{ 0x8e, 0xaf, 0x0, 0x88, 0x38, 0x8a, 0x3, 0xeb, 0x7c, 0x9, 0x2, 0x28, 0x39, 0x48, 0x7, 0xff, 0x0, 0x8, 0x3b, 0xe9, 0x2, 0x29, 0x2, 0x2a, 0x3b, 0xee, 0x2a, 0x24, 0x2a, 0x25, 0x2b, 0xeb, 0x38, 0x12 },
+{ 0x8e, 0xb0, 0x0, 0x20, 0x0, 0x40, 0x7d, 0xfc, 0x55, 0x4, 0x55, 0xfc, 0x55, 0x4, 0x7d, 0xfc, 0x55, 0x0, 0x55, 0xff, 0x55, 0x0, 0x55, 0xfe, 0x7c, 0x2, 0x2, 0xaa, 0x6, 0xaa, 0x4, 0x6, 0x0, 0x1c },
+{ 0x8e, 0xb1, 0x8, 0x20, 0x8, 0x20, 0x8, 0x20, 0x1f, 0x7f, 0x14, 0x50, 0x36, 0xd8, 0x62, 0x8, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x8e, 0xb2, 0x8, 0x8, 0x8, 0x8, 0x7f, 0x88, 0x8, 0x8, 0x3f, 0x7f, 0x29, 0x49, 0x29, 0x49, 0x3f, 0x49, 0x29, 0x49, 0x29, 0x7f, 0x3f, 0x49, 0x8, 0x49, 0x7f, 0xc9, 0x8, 0x49, 0x8, 0x7f, 0x8, 0x0 },
+{ 0x8e, 0xb3, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x2, 0x20, 0x82, 0x20, 0x82, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x0, 0x4, 0x10, 0x4, 0x10, 0xc, 0x18, 0x18, 0xc, 0x30, 0x6, 0x60, 0x3 },
+{ 0x8e, 0xb4, 0x0, 0x0, 0x3f, 0xfe, 0x0, 0x80, 0x7f, 0xff, 0x40, 0x81, 0x5e, 0xbd, 0x40, 0x81, 0x1e, 0xbc, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x80, 0x0, 0xf0, 0x0, 0x9c, 0x0, 0x86, 0x0, 0x80, 0x0, 0x80 },
+{ 0x8e, 0xb5, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x7, 0x4, 0x7c, 0x7, 0xc0, 0x7c, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x2, 0x4, 0x2, 0x4, 0x6, 0x6, 0x4, 0x3, 0xfc, 0x0, 0x0 },
+{ 0x8e, 0xb6, 0x0, 0x80, 0x0, 0x80, 0x7c, 0x80, 0x44, 0x82, 0x44, 0x86, 0x44, 0x8c, 0x44, 0xb8, 0x44, 0xe0, 0x47, 0x80, 0x44, 0x80, 0x44, 0x80, 0x44, 0x80, 0x7c, 0x80, 0x0, 0x81, 0x0, 0xc3, 0x0, 0x7e },
+{ 0x8e, 0xb7, 0x8, 0x20, 0x8, 0x20, 0x3e, 0x20, 0x8, 0x20, 0x8, 0xfc, 0x7f, 0x24, 0x22, 0x24, 0x14, 0xa4, 0x7f, 0x64, 0x8, 0x24, 0x8, 0x34, 0x3e, 0x54, 0x8, 0x54, 0x8, 0xc5, 0x9, 0x85, 0xb, 0x3 },
+{ 0x8e, 0xb8, 0x0, 0x80, 0x8, 0x80, 0x8, 0x80, 0x1f, 0xfc, 0x10, 0x80, 0x30, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x1, 0x40, 0x3, 0x60, 0x2, 0x20, 0x6, 0x30, 0xc, 0x18, 0x18, 0xc, 0x70, 0x7 },
+{ 0x8e, 0xb9, 0x10, 0x10, 0x10, 0x10, 0x10, 0xff, 0x12, 0x80, 0x7d, 0xa0, 0x24, 0xbe, 0x24, 0xc8, 0x24, 0x88, 0x6d, 0x88, 0x4a, 0xff, 0x48, 0x88, 0x78, 0x9c, 0x15, 0x94, 0x11, 0x36, 0x33, 0x22, 0x60, 0x63 },
+{ 0x8e, 0xba, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x2, 0x20, 0x2, 0x1f, 0xfc, 0x2, 0x0, 0x4, 0x10, 0xf, 0xf8, 0x0, 0x88, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x8e, 0xbb, 0x0, 0xe, 0x0, 0xf8, 0x3f, 0x80, 0x8, 0x88, 0x4, 0x90, 0x7f, 0xff, 0x2, 0xa0, 0x6, 0xb0, 0x1c, 0x9c, 0x70, 0x87, 0x0, 0x0, 0x5, 0x80, 0x14, 0xc6, 0x14, 0x4b, 0x36, 0x19, 0x63, 0xf0 },
+{ 0x8e, 0xbc, 0x0, 0x0, 0x23, 0xfc, 0x32, 0x4, 0x12, 0x4, 0x3, 0xfc, 0x42, 0x4, 0x62, 0x4, 0x23, 0xfc, 0x0, 0x0, 0x10, 0x90, 0x14, 0x92, 0x16, 0x96, 0x32, 0x94, 0x20, 0x90, 0x6f, 0xff, 0x40, 0x0 },
+{ 0x8e, 0xbd, 0x0, 0x20, 0x20, 0x20, 0x37, 0xff, 0x10, 0xa8, 0x1, 0xac, 0x47, 0x27, 0x60, 0x70, 0x21, 0xdc, 0x7, 0x7, 0x10, 0x20, 0x11, 0x24, 0x10, 0xa8, 0x30, 0x70, 0x21, 0xac, 0x27, 0x27, 0x60, 0x60 },
+{ 0x8e, 0xbe, 0x0, 0x40, 0x0, 0x40, 0x1f, 0xff, 0x52, 0x0, 0x32, 0x0, 0x17, 0xfe, 0x14, 0x40, 0x1c, 0x40, 0x30, 0x40, 0x5f, 0xff, 0x10, 0xa0, 0x11, 0xb0, 0x31, 0x10, 0x23, 0x18, 0x66, 0xc, 0x1c, 0x7 },
+{ 0x8e, 0xbf, 0x1, 0x86, 0x1f, 0x7c, 0x10, 0x40, 0x1f, 0x7f, 0x14, 0x48, 0x34, 0x88, 0x60, 0x0, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x4, 0x10, 0x38, 0xe },
+{ 0x8e, 0xc0, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x2, 0x20, 0x82, 0xf, 0xf8, 0x0, 0x80, 0x0, 0x80, 0xf, 0xf8, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x1, 0x40, 0x3, 0x60, 0xe, 0x38, 0x78, 0xf },
+{ 0x8e, 0xc1, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x8, 0x0, 0x7f, 0xbf, 0x21, 0x21, 0x33, 0x22, 0x12, 0x24, 0x7f, 0xa2, 0x0, 0x21, 0x3f, 0x21, 0x21, 0x21, 0x21, 0x27, 0x21, 0x20, 0x3f, 0x20 },
+{ 0x8e, 0xc2, 0x10, 0x20, 0x3f, 0x3f, 0x24, 0x50, 0x42, 0x88, 0x8, 0x40, 0x8, 0xff, 0x15, 0x84, 0x14, 0x48, 0x34, 0x30, 0x55, 0xcf, 0x14, 0x10, 0x15, 0xff, 0x14, 0x54, 0x14, 0xd6, 0x11, 0x93, 0x10, 0x10 },
+{ 0x8e, 0xc3, 0x8, 0x0, 0xb, 0xfe, 0x1a, 0x22, 0x12, 0x22, 0x33, 0xfe, 0x32, 0x22, 0x52, 0x22, 0x12, 0x22, 0x13, 0xfe, 0x10, 0x0, 0x10, 0xa0, 0x12, 0xb2, 0x12, 0x93, 0x16, 0x85, 0x14, 0x8c, 0x10, 0x78 },
+{ 0x8e, 0xc4, 0x4, 0x20, 0x24, 0x23, 0x27, 0xbe, 0x24, 0x20, 0x24, 0x21, 0x27, 0xb3, 0x3c, 0x1e, 0x60, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x2, 0xa0, 0x6, 0xb0, 0xc, 0x98, 0x18, 0x8c, 0x70, 0x87, 0x0, 0x80 },
+{ 0x8e, 0xc5, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x4, 0x90, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfc, 0x0, 0x18, 0x0, 0x30, 0x0, 0x60, 0x9, 0xc0, 0xb, 0x0, 0x1e, 0x0, 0x37, 0xc0, 0x60, 0x7f },
+{ 0x8e, 0xc6, 0x0, 0x0, 0x1f, 0xfe, 0x10, 0x2, 0x10, 0x2, 0x1f, 0xfe, 0x14, 0x44, 0x12, 0x48, 0x1f, 0xff, 0x11, 0x50, 0x16, 0x4e, 0x11, 0x0, 0x3f, 0xff, 0x22, 0x10, 0x67, 0xe0, 0x0, 0x98, 0x1f, 0x6 },
+{ 0x8e, 0xc7, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x4, 0x90, 0x2, 0x40, 0x12, 0x44, 0x12, 0x12, 0x21, 0xf2, 0x0, 0x0, 0x10, 0x10, 0xa, 0xa, 0x51, 0x51, 0x50, 0x50, 0x51, 0x51, 0xf, 0xf },
+{ 0x8e, 0xc8, 0x8, 0x10, 0x18, 0x10, 0x11, 0xff, 0x64, 0x0, 0x2c, 0x7c, 0x18, 0x44, 0x10, 0x7c, 0x24, 0x0, 0x7d, 0xff, 0x15, 0x1, 0x11, 0x7d, 0x55, 0x45, 0x55, 0x45, 0x51, 0x7d, 0x11, 0x1, 0x11, 0x3 },
+{ 0x8e, 0xc9, 0x0, 0x80, 0x1, 0xc0, 0x3, 0x60, 0x6, 0x30, 0x1c, 0x9c, 0x70, 0x87, 0xf, 0xf8, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8 },
+{ 0x8e, 0xca, 0x0, 0x0, 0x3f, 0xfe, 0x20, 0x2, 0x24, 0x2, 0x27, 0xf2, 0x4, 0x0, 0x4, 0x0, 0x7, 0xe0, 0x0, 0x20, 0x0, 0x20, 0x7f, 0xff, 0x0, 0x20, 0x0, 0x20, 0x0, 0x60, 0x0, 0x40, 0x3, 0xc0 },
+{ 0x8e, 0xcb, 0x2, 0x4, 0x4, 0x4, 0x1f, 0x4, 0x11, 0x4, 0x11, 0x7f, 0x1f, 0x4, 0x11, 0x4, 0x11, 0x24, 0x1f, 0x34, 0x11, 0x14, 0x11, 0x84, 0x7f, 0x4, 0x5, 0x4, 0x19, 0x4, 0x61, 0x4, 0x7, 0x1c },
+{ 0x8e, 0xcc, 0x10, 0x20, 0x10, 0x70, 0x10, 0xd8, 0x79, 0x8c, 0x17, 0x27, 0x10, 0x20, 0x11, 0xfc, 0x10, 0x20, 0x18, 0x20, 0x77, 0xff, 0x10, 0x0, 0x11, 0xfc, 0x11, 0x4, 0x11, 0x4, 0x11, 0x4, 0x31, 0xfc },
+{ 0x8e, 0xcd, 0x8, 0x20, 0x8, 0x20, 0x3f, 0x20, 0x8, 0x7f, 0x8, 0x44, 0x8, 0xc4, 0x7f, 0xa4, 0x12, 0x2c, 0x12, 0x28, 0x33, 0x38, 0x52, 0x90, 0x12, 0x10, 0x12, 0x38, 0x32, 0x2c, 0x22, 0x66, 0x66, 0xc3 },
+{ 0x8e, 0xce, 0x8, 0x4, 0x1c, 0x44, 0x16, 0x64, 0x33, 0x24, 0x21, 0x4, 0x7e, 0x44, 0x48, 0x64, 0x8, 0x24, 0x7f, 0x84, 0x8, 0x7, 0x2a, 0x3c, 0x2a, 0xe4, 0x6b, 0x4, 0x49, 0x4, 0x8, 0x4, 0x38, 0x4 },
+{ 0x8e, 0xcf, 0x0, 0x82, 0x0, 0x86, 0x1f, 0xfc, 0x0, 0x98, 0x0, 0xb0, 0x7f, 0xff, 0x1, 0x80, 0xf, 0xf8, 0x78, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x0, 0x0, 0x12, 0x22, 0x33, 0x33, 0x61, 0x11 },
+{ 0x8e, 0xd0, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10, 0x7e, 0x10, 0x2, 0x10, 0x6, 0xfe, 0x4, 0x10, 0xc, 0x10, 0x18, 0x10, 0x3e, 0x10, 0x6b, 0x10, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10, 0x9, 0xff, 0x8, 0x0 },
+{ 0x8e, 0xd1, 0x8, 0x10, 0x18, 0x10, 0x30, 0x10, 0x62, 0x54, 0x36, 0x56, 0xc, 0xd3, 0x19, 0x90, 0x32, 0x12, 0x7e, 0x12, 0xa, 0x76, 0x8, 0x4, 0x2a, 0xc, 0x2a, 0x18, 0x6a, 0x30, 0x48, 0x60, 0x9, 0xc0 },
+{ 0x8e, 0xd2, 0x1, 0x8, 0x1, 0x8, 0x1f, 0xf0, 0x1, 0x10, 0x1, 0x20, 0x1, 0x40, 0x7f, 0xff, 0x1, 0x0, 0x2, 0x0, 0x7, 0xf8, 0x1c, 0x8, 0x64, 0x8, 0x7, 0xf8, 0x4, 0x8, 0x4, 0x8, 0x7, 0xf8 },
+{ 0x8e, 0xd3, 0x0, 0x42, 0x38, 0x82, 0x1, 0xe2, 0x7d, 0x22, 0x1, 0x3f, 0x39, 0xe2, 0x1, 0x22, 0x1, 0x32, 0x39, 0xea, 0x1, 0x2a, 0x1, 0x22, 0x3b, 0xe2, 0x28, 0xa2, 0x29, 0x22, 0x2a, 0x22, 0x38, 0x66 },
+{ 0x8e, 0xd4, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x0, 0x80, 0xf, 0xf8, 0x8, 0x88, 0x8, 0x88, 0xf, 0xf8, 0x8, 0x88, 0x8, 0x88, 0xf, 0xf8, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80 },
+{ 0x8e, 0xd5, 0x0, 0x10, 0x30, 0x10, 0x1b, 0xff, 0xa, 0x0, 0x2, 0x44, 0x3, 0xff, 0x2, 0x44, 0x7a, 0x44, 0xa, 0x7c, 0xa, 0x0, 0xa, 0x0, 0xc, 0xaa, 0x9, 0xab, 0x19, 0x29, 0x34, 0x0, 0x63, 0xff },
+{ 0x8e, 0xd6, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x7e, 0xff, 0x52, 0x81, 0x52, 0x81, 0x52, 0x20, 0x52, 0x22, 0x52, 0x2e, 0x7e, 0x38, 0x10, 0x20, 0x12, 0x20, 0x12, 0x20, 0x1f, 0x21, 0x71, 0x33, 0x0, 0x1e },
+{ 0x8e, 0xd7, 0x0, 0x0, 0x7f, 0xbf, 0x12, 0x21, 0x12, 0x23, 0x12, 0x22, 0x12, 0x26, 0x12, 0x24, 0x7f, 0xa2, 0xa, 0x21, 0xa, 0x21, 0x1a, 0x21, 0x12, 0x21, 0x32, 0x2f, 0x22, 0x20, 0x62, 0x20, 0xe, 0x20 },
+{ 0x8e, 0xd8, 0x4, 0x88, 0x4, 0x88, 0xc, 0x88, 0xb, 0xfe, 0x18, 0x88, 0x10, 0x88, 0x30, 0x88, 0x57, 0xff, 0x10, 0x0, 0x11, 0xfc, 0x11, 0x4, 0x11, 0x4, 0x11, 0xfc, 0x11, 0x4, 0x11, 0x4, 0x11, 0xfc },
+{ 0x8e, 0xd9, 0x4, 0x0, 0x4, 0x0, 0x4, 0x0, 0xf, 0xfe, 0x8, 0x2, 0x18, 0x2, 0x30, 0x2, 0x67, 0x2, 0x1, 0x82, 0x0, 0xc2, 0x0, 0x42, 0x0, 0x2, 0x0, 0x2, 0x0, 0x6, 0x0, 0xc, 0x0, 0x78 },
+{ 0x8e, 0xda, 0x0, 0x0, 0xf, 0xfc, 0x8, 0x4, 0x8, 0x4, 0x8, 0x4, 0x8, 0x4, 0xf, 0xfc, 0x8, 0x80, 0x8, 0xc0, 0x8, 0x40, 0x8, 0x60, 0x8, 0x20, 0x18, 0x30, 0x10, 0x18, 0x30, 0xc, 0x60, 0x7 },
+{ 0x8e, 0xdb, 0x8, 0x40, 0x8, 0x40, 0x8, 0x40, 0x7e, 0x7e, 0x8, 0xc2, 0x8, 0x82, 0x19, 0x82, 0x1c, 0x62, 0x1a, 0x32, 0x2a, 0x12, 0x28, 0x2, 0x48, 0x2, 0x8, 0x2, 0x8, 0x6, 0x8, 0x4, 0x8, 0x1c },
+{ 0x8e, 0xdc, 0x8, 0x40, 0x8, 0x40, 0x8, 0x40, 0xa, 0x7e, 0x2a, 0xc2, 0x2a, 0x82, 0x29, 0x82, 0x68, 0x62, 0x48, 0x32, 0x8, 0x12, 0x1c, 0x2, 0x14, 0x2, 0x16, 0x2, 0x32, 0x6, 0x20, 0x4, 0x60, 0x1c },
+{ 0x8e, 0xdd, 0x0, 0x1c, 0x3f, 0xf0, 0x11, 0x4, 0x8, 0x88, 0x3f, 0xfe, 0x22, 0x22, 0x3f, 0xfe, 0x0, 0x0, 0x3f, 0x4, 0x21, 0x7f, 0x3f, 0x4, 0x21, 0x64, 0x3f, 0x34, 0x22, 0x4, 0x3f, 0x4, 0x61, 0x1c },
+{ 0x8e, 0xde, 0x0, 0x20, 0x7f, 0x20, 0x14, 0x20, 0x14, 0x3e, 0x7f, 0x62, 0x55, 0x42, 0x55, 0xc2, 0x55, 0x32, 0x57, 0x1a, 0x61, 0xa, 0x41, 0x2, 0x41, 0x2, 0x7f, 0x2, 0x41, 0x6, 0x41, 0x4, 0x7f, 0x1c },
+{ 0x8e, 0xdf, 0x6, 0x0, 0x1c, 0xfe, 0x68, 0x82, 0x8, 0x82, 0x4a, 0x82, 0x2c, 0x82, 0x8, 0xfe, 0x7e, 0x90, 0x8, 0x90, 0x18, 0x90, 0x1c, 0x98, 0x2a, 0x88, 0x28, 0x8c, 0x49, 0x84, 0x9, 0x6, 0xb, 0x3 },
+{ 0x8e, 0xe0, 0x8, 0x0, 0x1c, 0xfe, 0x16, 0x82, 0x32, 0x82, 0x20, 0xfe, 0x7e, 0x82, 0x8, 0x82, 0x8, 0xfe, 0x7f, 0x20, 0x8, 0x7f, 0x4a, 0x95, 0x6a, 0x25, 0x28, 0xc9, 0xe, 0x13, 0x38, 0x62, 0x60, 0xe },
+{ 0x8e, 0xe1, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x4, 0x10, 0x1, 0x0, 0x1, 0x0, 0x7f, 0xff, 0x2, 0x0, 0x4, 0x0, 0xf, 0xfc, 0x14, 0x4, 0x64, 0x4, 0x4, 0x4, 0x4, 0x4, 0x7, 0xfc },
+{ 0x8e, 0xe2, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x2, 0x28, 0x2, 0xf, 0x0, 0x8, 0xfe, 0x8, 0x42, 0x7f, 0x46, 0x8, 0x64, 0x2a, 0x2c, 0x2a, 0x38, 0x6b, 0x10, 0x49, 0x38, 0x8, 0x6c, 0x38, 0xc7 },
+{ 0x8e, 0xe3, 0x0, 0x0, 0x3f, 0x7e, 0x1, 0x2, 0x1, 0x2, 0x3f, 0x7e, 0x20, 0x40, 0x20, 0x40, 0x3f, 0x7e, 0x1, 0x2, 0x31, 0x62, 0x19, 0x32, 0x3, 0x6, 0xd, 0x1a, 0x33, 0x66, 0x2, 0x4, 0xe, 0x1c },
+{ 0x8e, 0xe4, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x1, 0x0, 0x7f, 0xff, 0x2, 0x0, 0xf, 0xfc, 0x78, 0x4, 0x8, 0x4, 0xf, 0xfc, 0x0, 0x80, 0x14, 0xc6, 0x14, 0x4b, 0x36, 0x19, 0x63, 0xf0 },
+{ 0x8e, 0xe5, 0x3, 0x0, 0x1, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x8e, 0xe6, 0x0, 0x0, 0x7f, 0x80, 0x11, 0x7e, 0x11, 0x22, 0x11, 0x22, 0x1f, 0x22, 0x11, 0x36, 0x11, 0x14, 0x11, 0x14, 0x1f, 0x1c, 0x11, 0x8, 0x11, 0x1c, 0x11, 0x14, 0x1f, 0x36, 0x71, 0x22, 0x1, 0x63 },
+{ 0x8e, 0xe7, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x2, 0x20, 0x2, 0x0, 0x20, 0x0, 0x20, 0x7f, 0xff, 0x0, 0x20, 0xc, 0x20, 0x6, 0x20, 0x2, 0x20, 0x0, 0x20, 0x0, 0x20, 0x0, 0x20, 0x0, 0xe0 },
+{ 0x8e, 0xe8, 0x0, 0x18, 0x0, 0xf0, 0x1f, 0x80, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x3, 0x80 },
+{ 0x8e, 0xe9, 0x0, 0x80, 0x8, 0x80, 0x8, 0x80, 0x1f, 0xfc, 0x10, 0x80, 0x30, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x2, 0xa0, 0x6, 0xb0, 0x4, 0x90, 0xc, 0x98, 0x18, 0x8c, 0x30, 0x86, 0x60, 0x83, 0x0, 0x80 },
+{ 0x8e, 0xea, 0x0, 0x10, 0x7e, 0x50, 0x10, 0x50, 0x10, 0x7e, 0x1e, 0xd0, 0x12, 0x90, 0x12, 0x10, 0x3a, 0xff, 0x2e, 0x54, 0x64, 0x54, 0x4, 0x54, 0xc, 0xd6, 0x8, 0x92, 0x19, 0x93, 0x30, 0x10, 0x0, 0x10 },
+{ 0x8e, 0xeb, 0x4, 0x20, 0x44, 0x20, 0x2b, 0xff, 0x12, 0x1, 0x12, 0x1, 0x28, 0x8, 0x48, 0x8, 0xb, 0xff, 0x18, 0x8, 0x19, 0x88, 0x28, 0xc8, 0x48, 0x48, 0x8, 0x8, 0x8, 0x8, 0x18, 0x8, 0x70, 0x38 },
+{ 0x8e, 0xec, 0x0, 0x20, 0x1, 0x20, 0x7d, 0x20, 0x13, 0xfe, 0x12, 0x20, 0x16, 0x20, 0x78, 0x20, 0x17, 0xff, 0x10, 0xa8, 0x10, 0xa8, 0x11, 0xac, 0x1d, 0x24, 0x73, 0x26, 0x6, 0x23, 0x0, 0x20, 0x0, 0x20 },
+{ 0x8e, 0xed, 0x2, 0xc, 0xe, 0x38, 0x78, 0xf0, 0x8, 0x10, 0x9, 0xff, 0x7e, 0x10, 0x8, 0xfe, 0x8, 0x92, 0x1c, 0xfe, 0x1a, 0x92, 0x28, 0xfe, 0x28, 0x10, 0x48, 0xfe, 0x8, 0x10, 0x8, 0x10, 0x9, 0xff },
+{ 0x8e, 0xee, 0x0, 0xc, 0x3c, 0x38, 0x24, 0xf0, 0x24, 0x10, 0x25, 0xff, 0x3c, 0x10, 0x24, 0xfe, 0x24, 0x92, 0x24, 0xfe, 0x3c, 0x92, 0x24, 0xfe, 0x24, 0x10, 0x24, 0xfe, 0x24, 0x10, 0x64, 0x10, 0x4d, 0xff },
+{ 0x8e, 0xef, 0x8, 0x0, 0x9, 0xff, 0x3e, 0xa0, 0x8, 0xae, 0x8, 0xe2, 0x7e, 0xaa, 0x8, 0xaa, 0x8, 0xee, 0x28, 0xa4, 0x2e, 0xa6, 0x28, 0xea, 0x29, 0xb3, 0x28, 0x21, 0x38, 0x20, 0x6e, 0x0, 0x43, 0xff },
+{ 0x8e, 0xf0, 0x0, 0x0, 0x37, 0xff, 0x18, 0x50, 0x8, 0x50, 0x3, 0xfe, 0x62, 0x52, 0x32, 0x52, 0x12, 0x52, 0x2, 0x52, 0xa, 0x9e, 0xb, 0x2, 0x1a, 0x2, 0x13, 0xfe, 0x32, 0x2, 0x22, 0x2, 0x63, 0xfe },
+{ 0x8e, 0xf1, 0x8, 0x8, 0xc, 0x18, 0x4, 0x10, 0x7f, 0xff, 0x0, 0x80, 0x1, 0x0, 0x1f, 0xfc, 0x10, 0x4, 0x10, 0x4, 0x1f, 0xfc, 0x10, 0x4, 0x10, 0x4, 0x1f, 0xfc, 0x10, 0x4, 0x10, 0x4, 0x1f, 0xfc },
+{ 0x8e, 0xf2, 0x8, 0x0, 0xb, 0xfe, 0x18, 0x20, 0x17, 0xff, 0x14, 0x21, 0x35, 0xad, 0x34, 0x21, 0x51, 0xac, 0x10, 0x0, 0x17, 0xff, 0x10, 0x20, 0x17, 0xff, 0x14, 0x91, 0x14, 0x91, 0x14, 0x91, 0x14, 0x93 },
+{ 0x8e, 0xf3, 0x0, 0xc, 0x0, 0x78, 0x3f, 0xc4, 0x11, 0xc, 0x8, 0x88, 0x7f, 0xff, 0x40, 0x1, 0x40, 0x1, 0x1f, 0xf8, 0x4, 0x18, 0x6, 0x30, 0x3, 0x60, 0x1, 0xc0, 0x3, 0x60, 0xe, 0x38, 0x78, 0xf },
+{ 0x8e, 0xf4, 0x0, 0x0, 0x1, 0xfe, 0x79, 0x2, 0x49, 0x2, 0x49, 0x2, 0x49, 0x2, 0x49, 0x2, 0x49, 0xfe, 0x48, 0x48, 0x48, 0x48, 0x78, 0x48, 0x0, 0xc8, 0x0, 0x88, 0x1, 0x89, 0x3, 0x9, 0xe, 0x7 },
+{ 0x8e, 0xf5, 0x1, 0x0, 0x1, 0x0, 0x3f, 0xfe, 0x1, 0x0, 0x1f, 0xfc, 0x1, 0x0, 0x3f, 0xfe, 0x2, 0x0, 0x2, 0x8, 0x7f, 0xff, 0x4, 0x8, 0xd, 0x88, 0x18, 0xc8, 0x30, 0x48, 0x60, 0x8, 0x0, 0x38 },
+{ 0x8e, 0xf6, 0x10, 0x6, 0x10, 0x3c, 0x13, 0xe2, 0x11, 0x22, 0x7c, 0x94, 0x13, 0xff, 0x12, 0x1, 0x12, 0x1, 0x11, 0xfc, 0x1c, 0x84, 0x70, 0xcc, 0x10, 0x58, 0x10, 0x70, 0x10, 0xd8, 0x11, 0x8c, 0x37, 0x7 },
+{ 0x8e, 0xf7, 0x10, 0x82, 0x10, 0x82, 0x17, 0xf2, 0x78, 0x82, 0x13, 0xef, 0x10, 0x2, 0x3b, 0xe2, 0x36, 0x2a, 0x32, 0x2a, 0x53, 0xea, 0x50, 0x2, 0x12, 0x22, 0x11, 0x42, 0x10, 0x72, 0x17, 0x82, 0x10, 0x6 },
+{ 0x8e, 0xf8, 0x8, 0x6, 0x18, 0x1c, 0x11, 0xf1, 0x64, 0x92, 0x2c, 0x4a, 0x19, 0xff, 0x11, 0x1, 0x25, 0x1, 0x7c, 0xfe, 0x14, 0x42, 0x10, 0x66, 0x54, 0x2c, 0x54, 0x38, 0x54, 0x6c, 0x10, 0xc6, 0x11, 0x83 },
+{ 0x8e, 0xf9, 0x0, 0x0, 0x3f, 0xfe, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x82, 0x2e, 0xba, 0x20, 0x82, 0xe, 0xb8, 0x0, 0x0, 0x7f, 0xff, 0x1, 0x0, 0x3f, 0xfe, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x2e },
+{ 0x8e, 0xfa, 0x0, 0x0, 0x3f, 0xfe, 0x20, 0x2, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x21, 0xc2, 0x21, 0x42, 0x21, 0x42, 0x23, 0x62, 0x22, 0x22, 0x26, 0x32, 0x2c, 0x1a, 0x20, 0x2, 0x3f, 0xfe, 0x0, 0x0 },
+{ 0x8e, 0xfb, 0x4, 0x0, 0x4, 0x0, 0x25, 0xfe, 0x24, 0x42, 0x24, 0x42, 0x24, 0x46, 0x24, 0x64, 0x24, 0x2c, 0x24, 0x28, 0x24, 0x38, 0x24, 0x10, 0x3c, 0x38, 0x64, 0x28, 0x4, 0x6c, 0x4, 0xc6, 0x5, 0x83 },
+{ 0x8e, 0xfc, 0x0, 0x0, 0x1f, 0xfe, 0x10, 0x2, 0x10, 0x82, 0x13, 0xf2, 0x10, 0x82, 0x10, 0x82, 0x17, 0xfa, 0x10, 0x2, 0x13, 0xf2, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x33, 0xf2, 0x20, 0x2, 0x60, 0xe },
+{ 0x8f, 0x40, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x2, 0x20, 0x2, 0x27, 0xf2, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x80, 0x8, 0x88, 0x8, 0x88, 0x18, 0x8c, 0x30, 0x86, 0x60, 0x83, 0x3, 0x80 },
+{ 0x8f, 0x41, 0x4, 0xa, 0x4, 0xb, 0x4, 0x9, 0x7f, 0xc8, 0x0, 0x3f, 0x3f, 0x88, 0x20, 0x88, 0x20, 0x88, 0x3f, 0x88, 0x4, 0x1c, 0x15, 0x14, 0x15, 0x94, 0x34, 0xb4, 0x64, 0x25, 0x4, 0x65, 0x1c, 0xc3 },
+{ 0x8f, 0x42, 0x8, 0x2, 0x8, 0x42, 0x8, 0x42, 0x8, 0x42, 0x8, 0x42, 0x2a, 0x52, 0x2b, 0x5a, 0x29, 0x4a, 0x69, 0x4a, 0x48, 0x42, 0x8, 0x42, 0x8, 0x42, 0x18, 0x42, 0x10, 0x42, 0x30, 0x2, 0x60, 0x2 },
+{ 0x8f, 0x43, 0x8, 0x80, 0x8, 0x80, 0x19, 0xff, 0x11, 0x4, 0x32, 0x8c, 0x34, 0xd8, 0x54, 0x70, 0x14, 0xdc, 0x17, 0x87, 0x14, 0x60, 0x15, 0xcc, 0x14, 0x38, 0x15, 0xe3, 0x14, 0xe, 0x10, 0x78, 0x13, 0xc0 },
+{ 0x8f, 0x44, 0x2, 0x10, 0xe, 0x10, 0x78, 0x51, 0x8, 0xd3, 0x7e, 0x92, 0x8, 0x38, 0x1c, 0x28, 0x1a, 0x6c, 0x28, 0xc6, 0x49, 0x83, 0x8, 0x0, 0x1, 0x80, 0x14, 0xc6, 0x14, 0x4b, 0x36, 0x19, 0x63, 0xf0 },
+{ 0x8f, 0x45, 0x10, 0x20, 0x10, 0x70, 0x10, 0x50, 0x10, 0xd8, 0x7d, 0x8c, 0x13, 0x6, 0x16, 0xfb, 0x10, 0x0, 0x1c, 0x0, 0x71, 0xfc, 0x11, 0x4, 0x11, 0x4, 0x11, 0x4, 0x11, 0x4, 0x11, 0x4, 0x31, 0xfc },
+{ 0x8f, 0x46, 0x21, 0x2, 0x31, 0x22, 0x11, 0x22, 0x1, 0x22, 0x1, 0x22, 0x45, 0xb2, 0x65, 0x6a, 0x2d, 0x6a, 0x9, 0x22, 0x1, 0x22, 0x11, 0x22, 0x11, 0x22, 0x33, 0x22, 0x22, 0x22, 0x26, 0x2, 0x6c, 0x2 },
+{ 0x8f, 0x47, 0x0, 0xc, 0x0, 0x78, 0x1f, 0xc0, 0x0, 0x80, 0x7f, 0xff, 0x2, 0xa0, 0x6, 0xb0, 0x1c, 0x9c, 0x70, 0x7, 0xf, 0xe0, 0x2, 0x20, 0x2, 0x3c, 0x6, 0x4, 0x4, 0x4, 0xc, 0xc, 0x38, 0x38 },
+{ 0x8f, 0x48, 0x6, 0x20, 0x1c, 0x20, 0x70, 0x22, 0x11, 0x22, 0x11, 0x26, 0x7d, 0x24, 0x13, 0x2c, 0x12, 0x20, 0x38, 0x70, 0x34, 0x50, 0x50, 0x50, 0x50, 0xd8, 0x10, 0x88, 0x11, 0x8c, 0x13, 0x6, 0x16, 0x3 },
+{ 0x8f, 0x49, 0x8, 0x40, 0x18, 0x40, 0x10, 0xfc, 0x60, 0x84, 0x29, 0x8c, 0x1b, 0x58, 0x10, 0x30, 0x24, 0x78, 0x7c, 0xcc, 0x13, 0x87, 0x10, 0x70, 0x54, 0x18, 0x54, 0x0, 0x54, 0xe0, 0x10, 0x38, 0x10, 0xc },
+{ 0x8f, 0x4a, 0x8, 0x10, 0x18, 0xfe, 0x10, 0x12, 0x65, 0xff, 0x2c, 0x12, 0x18, 0xfe, 0x10, 0x10, 0x25, 0x55, 0x7d, 0x55, 0x15, 0x11, 0x11, 0x7d, 0x55, 0x11, 0x55, 0x39, 0x55, 0x55, 0x11, 0x11, 0x12, 0x11 },
+{ 0x8f, 0x4b, 0x0, 0x0, 0x7e, 0xfe, 0x22, 0x42, 0x32, 0x62, 0x12, 0x26, 0x6, 0x1a, 0x1a, 0x62, 0x61, 0x2, 0x2, 0x0, 0x1f, 0xfc, 0x10, 0x4, 0x10, 0x4, 0x1f, 0xfc, 0x10, 0x4, 0x10, 0x4, 0x1f, 0xfc },
+{ 0x8f, 0x4c, 0x0, 0x40, 0x0, 0x80, 0x1f, 0xfc, 0x10, 0x4, 0x1f, 0xfc, 0x10, 0x4, 0x1f, 0xfc, 0x10, 0x4, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x1, 0x40, 0x3, 0x60, 0xe, 0x38, 0x78, 0xf },
+{ 0x8f, 0x4d, 0x0, 0x40, 0x0, 0x80, 0xf, 0xf8, 0x8, 0x8, 0x9, 0x88, 0x8, 0xc8, 0x8, 0x48, 0x8, 0x8, 0x7f, 0xff, 0x8, 0x8, 0x8, 0x88, 0x8, 0x88, 0x18, 0x88, 0x10, 0x88, 0x30, 0x8, 0x60, 0x38 },
+{ 0x8f, 0x4e, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x50, 0x0, 0x80, 0x1f, 0xfc, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x84, 0x1f, 0xfc, 0x2, 0x50, 0x2, 0x50, 0x6, 0x64, 0xc, 0x7d, 0x18, 0x43, 0x70, 0x7e },
+{ 0x8f, 0x4f, 0x0, 0x40, 0x0, 0x80, 0x1f, 0xfc, 0x12, 0x24, 0x12, 0x24, 0x7f, 0xff, 0x0, 0x20, 0x8, 0x62, 0x18, 0xc6, 0x37, 0xac, 0x60, 0xb0, 0x8, 0x90, 0x18, 0x98, 0x30, 0x8c, 0x60, 0x87, 0x0, 0x80 },
+{ 0x8f, 0x50, 0x4, 0x20, 0x3f, 0xbf, 0x11, 0x20, 0x7f, 0xbe, 0x11, 0x2, 0x1f, 0x3e, 0x11, 0x20, 0x1f, 0x3e, 0x11, 0x21, 0x13, 0x1f, 0x0, 0x80, 0x7f, 0xff, 0x2, 0x42, 0x7c, 0x24, 0x7, 0xd8, 0x1c, 0x7 },
+{ 0x8f, 0x51, 0x12, 0x24, 0x3f, 0x7f, 0x64, 0xc8, 0x3f, 0x7e, 0x24, 0x48, 0x3f, 0x7e, 0x24, 0x48, 0x7f, 0xff, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x4, 0x1f, 0xfc },
+{ 0x8f, 0x52, 0x0, 0x8a, 0x3c, 0x8b, 0x24, 0x89, 0x27, 0xe8, 0x24, 0x3f, 0x25, 0xc8, 0x3d, 0x48, 0x9, 0x48, 0x9, 0x5c, 0x2d, 0xd4, 0x28, 0x94, 0x29, 0xd4, 0x29, 0xb4, 0x2a, 0x95, 0x3c, 0xb5, 0x61, 0xa3 },
+{ 0x8f, 0x53, 0x8, 0x7c, 0x8, 0x44, 0x7f, 0x7c, 0x8, 0x0, 0x3e, 0xff, 0x2a, 0x44, 0x2a, 0x44, 0x3e, 0x7c, 0x2a, 0x44, 0x2a, 0x44, 0x3e, 0x7c, 0x8, 0x44, 0x7f, 0x47, 0x8, 0x7c, 0x9, 0xc4, 0x8, 0x4 },
+{ 0x8f, 0x54, 0x0, 0x0, 0x33, 0xfe, 0x1a, 0x2, 0xa, 0x22, 0x2, 0xfa, 0x2, 0x22, 0x2, 0xfa, 0x72, 0x2, 0x12, 0xfa, 0x12, 0x8a, 0x12, 0x8a, 0x12, 0xfa, 0x12, 0x2, 0x34, 0x6, 0x28, 0x0, 0x47, 0xff },
+{ 0x8f, 0x55, 0x8, 0x8, 0xc, 0x18, 0x4, 0x10, 0x7f, 0xff, 0x2, 0x40, 0x2, 0x40, 0x3f, 0xfe, 0x22, 0x42, 0x22, 0x4a, 0x24, 0x3a, 0x38, 0x2, 0x20, 0x2, 0x3f, 0xfe, 0x20, 0x2, 0x20, 0x2, 0x3f, 0xfe },
+{ 0x8f, 0x56, 0x0, 0x1, 0x7f, 0x49, 0x14, 0x49, 0x14, 0x49, 0x7f, 0x49, 0x55, 0x49, 0x55, 0xdb, 0x55, 0xdb, 0x67, 0x49, 0x41, 0x49, 0x41, 0x49, 0x7f, 0x49, 0x41, 0x49, 0x41, 0x49, 0x7f, 0xc1, 0x0, 0x81 },
+{ 0x8f, 0x57, 0x4, 0x40, 0x8, 0x80, 0x1f, 0xfe, 0x70, 0x80, 0x1f, 0xfc, 0x10, 0x80, 0x1f, 0xfc, 0x10, 0x80, 0x1f, 0xfe, 0x0, 0x80, 0x7f, 0xff, 0x2, 0xa0, 0x6, 0xb0, 0x1c, 0x9c, 0x70, 0x87, 0x0, 0x80 },
+{ 0x8f, 0x58, 0x0, 0x10, 0x7f, 0x20, 0x14, 0x7e, 0x14, 0x52, 0x7f, 0x52, 0x55, 0x7e, 0x55, 0x52, 0x55, 0x52, 0x67, 0x7e, 0x41, 0x2a, 0x41, 0x2c, 0x7f, 0x2d, 0x41, 0x2f, 0x41, 0x28, 0x7f, 0x69, 0x0, 0xcf },
+{ 0x8f, 0x59, 0x4, 0x20, 0x4, 0x20, 0xc, 0x20, 0x8, 0x20, 0x18, 0x20, 0x10, 0x20, 0x37, 0xff, 0x50, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20 },
+{ 0x8f, 0x5a, 0x4, 0xc0, 0x4, 0x60, 0xc, 0x20, 0x9, 0xfe, 0x18, 0x20, 0x10, 0x20, 0x30, 0x20, 0x50, 0x20, 0x11, 0xfe, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x13, 0xff, 0x10, 0x0 },
+{ 0x8f, 0x5b, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x2, 0x0, 0x2, 0x8, 0x6, 0x8, 0x4, 0x7c, 0x1f, 0xc4, 0x2, 0x40, 0x2, 0x40, 0x2, 0x40, 0x6, 0x40, 0x4, 0x40, 0xc, 0x41, 0x18, 0x63, 0x70, 0x3e },
+{ 0x8f, 0x5c, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80 },
+{ 0x8f, 0x5d, 0x9, 0x4, 0x19, 0x8c, 0x10, 0x88, 0x30, 0x88, 0x67, 0xff, 0x8, 0x20, 0x18, 0x20, 0x11, 0x20, 0x31, 0x3e, 0x71, 0x20, 0x11, 0x20, 0x11, 0x20, 0x13, 0xa0, 0x12, 0xe0, 0x16, 0x38, 0x14, 0xf },
+{ 0x8f, 0x5e, 0x0, 0x48, 0x0, 0x4c, 0x0, 0x44, 0x7f, 0xff, 0x0, 0x40, 0x8, 0x40, 0x8, 0x42, 0x8, 0x66, 0x7f, 0x24, 0x8, 0x2c, 0x8, 0x38, 0x18, 0x10, 0x10, 0x38, 0x30, 0x6d, 0x61, 0xc7, 0x7, 0x2 },
+{ 0x8f, 0x5f, 0x0, 0x0, 0x1f, 0xf8, 0x2, 0x30, 0x1, 0x40, 0x3f, 0xfe, 0x1, 0x44, 0x3, 0x48, 0xe, 0x40, 0x38, 0x40, 0x0, 0x80, 0x7f, 0xff, 0x2, 0xa0, 0x6, 0xb0, 0x1c, 0x9c, 0x70, 0x87, 0x0, 0x80 },
+{ 0x8f, 0x60, 0x0, 0x20, 0x30, 0x20, 0x18, 0x20, 0x8, 0x20, 0x0, 0x20, 0x60, 0x20, 0x37, 0xff, 0x10, 0x20, 0x0, 0x20, 0x8, 0x20, 0x8, 0x20, 0x18, 0x20, 0x10, 0x20, 0x30, 0x20, 0x20, 0x20, 0x60, 0x20 },
+{ 0x8f, 0x61, 0x0, 0x10, 0x30, 0x10, 0x18, 0x90, 0x8, 0x9e, 0x0, 0x90, 0x60, 0x90, 0x30, 0x90, 0x13, 0xff, 0x0, 0x0, 0x9, 0x86, 0x8, 0xcc, 0x18, 0x48, 0x10, 0x0, 0x30, 0xcc, 0x21, 0x86, 0x63, 0x3 },
+{ 0x8f, 0x62, 0x48, 0x48, 0x24, 0x8a, 0x0, 0xb, 0x3f, 0x89, 0x24, 0x88, 0x3f, 0xff, 0x24, 0x88, 0x3f, 0x88, 0x0, 0x8, 0x7f, 0xdc, 0x0, 0x14, 0x3f, 0x94, 0x20, 0x96, 0x20, 0xb2, 0x3f, 0xa2, 0x0, 0x63 },
+{ 0x8f, 0x63, 0x10, 0xa2, 0x10, 0xa2, 0x21, 0x94, 0x29, 0x14, 0x4b, 0x7f, 0x30, 0x88, 0x10, 0x88, 0x25, 0xa8, 0x7d, 0x28, 0x13, 0x2e, 0x11, 0x28, 0x59, 0x28, 0x55, 0x28, 0x51, 0x38, 0x11, 0x28, 0x11, 0x4f },
+{ 0x8f, 0x64, 0x0, 0x18, 0x0, 0xf0, 0x1f, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x1f, 0xfc, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x84, 0x1f, 0xfc, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff },
+{ 0x8f, 0x65, 0x8, 0x10, 0x1c, 0x10, 0x16, 0x10, 0x32, 0xff, 0x20, 0x20, 0x7e, 0x64, 0x8, 0x44, 0x8, 0xfe, 0x7f, 0x2a, 0x8, 0x28, 0x4a, 0x28, 0x6a, 0x28, 0x28, 0x68, 0xf, 0x49, 0x38, 0xc9, 0x61, 0x87 },
+{ 0x8f, 0x66, 0x8, 0x0, 0x8, 0xfe, 0x8, 0x42, 0xf, 0x42, 0x8, 0x46, 0x8, 0x64, 0x8, 0x24, 0x7f, 0xac, 0x8, 0x28, 0x2a, 0x38, 0x2a, 0x10, 0x6b, 0x38, 0x49, 0x28, 0x8, 0x6c, 0x8, 0xc6, 0x39, 0x83 },
+{ 0x8f, 0x67, 0x0, 0x0, 0x1f, 0xf8, 0x10, 0x8, 0x10, 0x8, 0x17, 0xe8, 0x11, 0x8, 0x11, 0xe8, 0x11, 0x28, 0x13, 0x28, 0x12, 0xa8, 0x16, 0x68, 0x10, 0x48, 0x10, 0xcc, 0x31, 0x85, 0x23, 0x7, 0x60, 0x2 },
+{ 0x8f, 0x68, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x2, 0x28, 0x2, 0xb, 0xff, 0x18, 0x10, 0x10, 0x20, 0x31, 0xfe, 0x51, 0x2, 0x11, 0x2, 0x11, 0xfe, 0x11, 0x2, 0x11, 0x2, 0x11, 0x2, 0x11, 0xfe },
+{ 0x8f, 0x69, 0x1, 0x0, 0x31, 0x7e, 0x19, 0x12, 0x9, 0xd2, 0x1, 0x12, 0x61, 0x16, 0x31, 0x14, 0x17, 0xd4, 0x1, 0x1c, 0x11, 0x8, 0x15, 0x48, 0x15, 0x5c, 0x35, 0x54, 0x2d, 0x16, 0x29, 0x32, 0x63, 0x63 },
+{ 0x8f, 0x6a, 0x8, 0x0, 0x8, 0xfe, 0x8, 0x82, 0x7e, 0x82, 0x2, 0x82, 0x6, 0x82, 0x4, 0x82, 0xc, 0xfe, 0x18, 0x28, 0x3e, 0x28, 0x6b, 0x28, 0x8, 0x28, 0x8, 0x68, 0x8, 0x49, 0x8, 0xc9, 0x9, 0x87 },
+{ 0x8f, 0x6b, 0x10, 0x20, 0x10, 0x20, 0x23, 0xfe, 0x2a, 0x2, 0x4a, 0x82, 0x30, 0xff, 0x10, 0x88, 0x25, 0x90, 0x7d, 0x3e, 0x13, 0x22, 0x11, 0x22, 0x59, 0x3e, 0x55, 0x22, 0x55, 0x22, 0x11, 0x22, 0x11, 0x3e },
+{ 0x8f, 0x6c, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x84, 0x7f, 0xff, 0x0, 0x84, 0x1f, 0xfc, 0x0, 0x80, 0x14, 0x94, 0x12, 0xa4, 0x17, 0xf4, 0x10, 0x84, 0x11, 0xc4, 0x12, 0xa4, 0x34, 0x94, 0x20, 0x84, 0x60, 0x84 },
+{ 0x8f, 0x6d, 0x8, 0x20, 0x7f, 0x20, 0x0, 0x20, 0x3e, 0xfc, 0x22, 0x24, 0x3e, 0x24, 0x0, 0xa4, 0x3e, 0x64, 0x4, 0x34, 0x7f, 0x55, 0x8, 0x87, 0x38, 0x2, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x7f, 0xff },
+{ 0x8f, 0x6e, 0x8, 0x20, 0x7f, 0x20, 0x0, 0x20, 0x3e, 0xfc, 0x22, 0x24, 0x3e, 0x24, 0x0, 0xa4, 0x3e, 0x64, 0x4, 0x34, 0x7f, 0x55, 0x8, 0x87, 0x38, 0x2, 0x0, 0x0, 0x12, 0x22, 0x33, 0x33, 0x61, 0x11 },
+{ 0x8f, 0x6f, 0x0, 0x80, 0x0, 0x80, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x3f, 0xfe, 0x0, 0x0 },
+{ 0x8f, 0x70, 0x8, 0x80, 0x18, 0xae, 0x10, 0xb0, 0x30, 0x90, 0x63, 0xe0, 0x8, 0x9f, 0x18, 0x84, 0x12, 0xa4, 0x32, 0xa4, 0x72, 0xa4, 0x12, 0xa4, 0x16, 0xb4, 0x14, 0x94, 0x10, 0x84, 0x10, 0x84, 0x10, 0xc },
+{ 0x8f, 0x71, 0x0, 0x24, 0x30, 0x26, 0x18, 0x22, 0x8, 0x20, 0x3, 0xff, 0x0, 0x20, 0x0, 0x20, 0x78, 0xa8, 0x8, 0xa8, 0x9, 0xac, 0x9, 0x24, 0xb, 0x26, 0x8, 0x20, 0x18, 0x20, 0x34, 0x0, 0x63, 0xff },
+{ 0x8f, 0x72, 0x8, 0x80, 0x9, 0x84, 0x19, 0x4, 0x13, 0xfe, 0x30, 0x92, 0x31, 0x90, 0x53, 0x1f, 0x16, 0x80, 0x10, 0xfc, 0x11, 0x84, 0x13, 0xc, 0x16, 0xd8, 0x10, 0x50, 0x10, 0x70, 0x11, 0xdc, 0x17, 0x7 },
+{ 0x8f, 0x73, 0x0, 0x80, 0x11, 0x84, 0x11, 0x4, 0x13, 0xfe, 0x54, 0x92, 0x54, 0x90, 0x55, 0x9f, 0x57, 0x40, 0x54, 0x7c, 0x54, 0xc4, 0x55, 0x8c, 0x57, 0x58, 0x7c, 0x30, 0x0, 0x78, 0x0, 0xcc, 0x3, 0x87 },
+{ 0x8f, 0x74, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x0, 0x80, 0x1f, 0xfc, 0x1, 0x40, 0x7f, 0xff, 0x2, 0x20, 0x4, 0x10, 0x1f, 0xfc, 0x74, 0x17, 0x4, 0x10, 0x7, 0xf0, 0x4, 0x10, 0x4, 0x10, 0x7, 0xf0 },
+{ 0x8f, 0x75, 0x0, 0x6, 0x78, 0x3c, 0x4b, 0xe2, 0x49, 0x26, 0x48, 0x94, 0x7b, 0xff, 0x4a, 0x1, 0x4a, 0x81, 0x48, 0xe2, 0x79, 0xbf, 0x49, 0x2a, 0x4a, 0xea, 0x48, 0x4a, 0x78, 0xdf, 0x1, 0x82, 0x3, 0x2 },
+{ 0x8f, 0x76, 0x10, 0x40, 0x10, 0xc4, 0x10, 0x84, 0x7d, 0xfe, 0x0, 0x4a, 0x44, 0x48, 0x44, 0x8f, 0x65, 0x40, 0x2c, 0x7c, 0x28, 0xc4, 0x9, 0x8c, 0xc, 0x58, 0x30, 0x30, 0x60, 0x78, 0x0, 0xcc, 0x3, 0x87 },
+{ 0x8f, 0x77, 0x0, 0xc, 0x0, 0x78, 0x3f, 0xc4, 0x11, 0xc, 0x8, 0x88, 0x7f, 0xff, 0x40, 0x1, 0x48, 0x5, 0xf, 0x7e, 0x19, 0x24, 0x33, 0x24, 0x6a, 0x24, 0x6, 0xff, 0xc, 0x4, 0x18, 0x4, 0x70, 0x4 },
+{ 0x8f, 0x78, 0x0, 0x20, 0x3f, 0x62, 0x24, 0x42, 0x24, 0xff, 0x3e, 0x25, 0x24, 0x24, 0x24, 0x47, 0x3e, 0xa0, 0x24, 0x3e, 0x24, 0x62, 0x3f, 0xd6, 0x0, 0x94, 0x55, 0x88, 0x54, 0x9c, 0x41, 0xb6, 0x3, 0x63 },
+{ 0x8f, 0x79, 0x0, 0x48, 0x30, 0xd8, 0x18, 0x90, 0x9, 0xff, 0x3, 0x10, 0x5, 0x10, 0x1, 0x10, 0x1, 0xfe, 0x9, 0x10, 0x9, 0x10, 0x19, 0x10, 0x11, 0xfe, 0x31, 0x10, 0x21, 0x10, 0x61, 0x10, 0x1, 0xff },
+{ 0x8f, 0x7a, 0x8, 0x6, 0x18, 0x3c, 0x13, 0xe0, 0x32, 0x10, 0x63, 0xff, 0xa, 0x10, 0x1a, 0xfe, 0x12, 0x82, 0x32, 0x82, 0x72, 0xfe, 0x12, 0x82, 0x16, 0x82, 0x14, 0xfe, 0x1c, 0x82, 0x10, 0x82, 0x10, 0xfe },
+{ 0x8f, 0x7b, 0x4, 0x0, 0x4, 0x0, 0xf, 0xfe, 0x8, 0x2, 0x18, 0x2, 0x37, 0xe2, 0x64, 0x22, 0x4, 0x22, 0x7, 0xe2, 0x4, 0x22, 0x4, 0x22, 0x4, 0x22, 0x7, 0xe2, 0x0, 0x6, 0x0, 0x4, 0x0, 0x1c },
+{ 0x8f, 0x7c, 0x10, 0x6, 0x10, 0x3c, 0x11, 0xe0, 0x7d, 0x10, 0x11, 0xff, 0x11, 0x10, 0x39, 0x7e, 0x35, 0x42, 0x55, 0x42, 0x51, 0x7e, 0x11, 0x42, 0x13, 0x42, 0x12, 0x7e, 0x16, 0x42, 0x10, 0x42, 0x10, 0x7e },
+{ 0x8f, 0x7d, 0x0, 0x80, 0x7e, 0x80, 0x10, 0xfe, 0x11, 0x82, 0x11, 0x2, 0x1c, 0xf2, 0x14, 0x92, 0x34, 0x92, 0x24, 0xf2, 0x74, 0x92, 0x1c, 0x92, 0x8, 0x92, 0x18, 0xf2, 0x10, 0x6, 0x30, 0x4, 0x60, 0x1c },
+{ 0x8f, 0x7e, 0x0, 0x20, 0x20, 0x20, 0x37, 0xff, 0x10, 0x0, 0x1, 0xfc, 0x41, 0x4, 0x61, 0xfc, 0x20, 0x0, 0x3, 0xfe, 0x10, 0xc, 0x10, 0x10, 0x17, 0xff, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x60, 0xe0 },
+{ 0x8f, 0x80, 0x0, 0x48, 0x30, 0x90, 0x19, 0xfe, 0x63, 0x20, 0x35, 0xfc, 0x1, 0x20, 0x9, 0xfc, 0x19, 0x20, 0x31, 0x20, 0x61, 0xfe, 0x0, 0x0, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80 },
+{ 0x8f, 0x81, 0x0, 0x0, 0x27, 0xdf, 0x34, 0x51, 0x17, 0xdf, 0x4, 0x51, 0x47, 0xdf, 0x64, 0x1, 0x24, 0xf9, 0x4, 0x21, 0x14, 0x21, 0x14, 0xf9, 0x14, 0x21, 0x34, 0x21, 0x25, 0xfd, 0x24, 0x1, 0x64, 0x7 },
+{ 0x8f, 0x82, 0x0, 0x6, 0x0, 0x7c, 0x1f, 0xc0, 0x10, 0x40, 0x1f, 0xff, 0x10, 0x40, 0x13, 0xfc, 0x12, 0x4, 0x12, 0x4, 0x13, 0xfc, 0x12, 0x4, 0x12, 0x4, 0x33, 0xfc, 0x22, 0x4, 0x62, 0x4, 0x3, 0xfc },
+{ 0x8f, 0x83, 0x8, 0x10, 0x18, 0x13, 0x10, 0x1e, 0x65, 0xf0, 0x2c, 0x10, 0x18, 0x92, 0x10, 0x92, 0x24, 0x92, 0x7e, 0x92, 0x12, 0x92, 0x10, 0xfe, 0x54, 0x10, 0x54, 0x10, 0x54, 0x11, 0x50, 0x13, 0x10, 0xe },
+{ 0x8f, 0x84, 0x0, 0x0, 0x30, 0x92, 0x19, 0xb6, 0x9, 0x24, 0x3, 0x6c, 0x2, 0x48, 0x4, 0x90, 0x74, 0x90, 0x12, 0x48, 0x13, 0x6c, 0x11, 0x24, 0x11, 0xb6, 0x10, 0x92, 0x30, 0x0, 0x28, 0x0, 0x67, 0xff },
+{ 0x8f, 0x85, 0x0, 0x84, 0x30, 0x48, 0x1b, 0xff, 0x8, 0x50, 0x1, 0xfe, 0x1, 0x52, 0x1, 0x9e, 0x79, 0x2, 0x9, 0xfe, 0x9, 0x2, 0x9, 0xfe, 0x8, 0x4, 0xb, 0xff, 0x18, 0x84, 0x34, 0x4c, 0x63, 0xff },
+{ 0x8f, 0x86, 0x0, 0x8, 0x7f, 0x8, 0x14, 0x7f, 0x14, 0x0, 0x7f, 0x3e, 0x55, 0x22, 0x55, 0x3e, 0x55, 0x0, 0x67, 0x3e, 0x41, 0x4, 0x41, 0x8, 0x7f, 0x7f, 0x41, 0x8, 0x41, 0x8, 0x7f, 0x8, 0x0, 0x38 },
+{ 0x8f, 0x87, 0x2, 0x0, 0x22, 0xff, 0x2a, 0x10, 0x2a, 0x7e, 0x2a, 0x42, 0x2a, 0x42, 0x2a, 0x7e, 0x2a, 0x42, 0x2a, 0x42, 0x2a, 0x7e, 0x2a, 0x42, 0x2a, 0x42, 0x62, 0x7e, 0x42, 0x24, 0x2, 0x66, 0x2, 0xc3 },
+{ 0x8f, 0x88, 0x10, 0x0, 0x10, 0x7c, 0x10, 0x44, 0x1e, 0x44, 0x12, 0x44, 0x32, 0x44, 0x22, 0x44, 0x76, 0x44, 0x54, 0x44, 0x1c, 0x44, 0x8, 0xc5, 0x1c, 0x85, 0x15, 0x83, 0x36, 0x0, 0x23, 0x0, 0x61, 0xff },
+{ 0x8f, 0x89, 0x8, 0x0, 0x8, 0x0, 0x9, 0xfe, 0x7e, 0x22, 0x2, 0x22, 0x6, 0x22, 0xc, 0x22, 0x9, 0x22, 0x1b, 0x22, 0x3e, 0x62, 0x6b, 0x42, 0x9, 0x42, 0x8, 0xc6, 0x8, 0x84, 0x9, 0x84, 0xb, 0x1c },
+{ 0x8f, 0x8a, 0x0, 0x6, 0x3f, 0x9c, 0x0, 0x70, 0x0, 0x40, 0x1f, 0x40, 0x11, 0x7f, 0x11, 0x44, 0x11, 0x44, 0x1f, 0x44, 0x10, 0x44, 0x10, 0x44, 0x10, 0xc4, 0x30, 0x84, 0x21, 0x84, 0x63, 0x4, 0x0, 0x4 },
+{ 0x8f, 0x8b, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x9, 0xf, 0xfb, 0x0, 0x86, 0x1f, 0xfc, 0x0, 0x90, 0x7f, 0xff, 0x0, 0x40, 0x7, 0xfc, 0x7c, 0x4, 0x7, 0xfc, 0x4, 0x4, 0x4, 0x4, 0x7, 0xfc },
+{ 0x8f, 0x8c, 0x3, 0xfe, 0x2, 0x52, 0x7a, 0x52, 0x4b, 0xfe, 0x48, 0x21, 0x49, 0xfe, 0x48, 0x24, 0x78, 0x28, 0x4b, 0xff, 0x48, 0x10, 0x48, 0xfe, 0x4f, 0x82, 0x78, 0xfe, 0x0, 0x82, 0x0, 0x82, 0x0, 0xfe },
+{ 0x8f, 0x8d, 0x0, 0x40, 0x20, 0x42, 0x33, 0xfe, 0x10, 0x44, 0x0, 0x4c, 0x40, 0x48, 0x67, 0xfe, 0x20, 0x20, 0x0, 0x40, 0x11, 0xfc, 0x17, 0x4, 0x11, 0x4, 0x31, 0xfc, 0x21, 0x4, 0x21, 0x4, 0x61, 0xfc },
+{ 0x8f, 0x8e, 0x0, 0x40, 0x0, 0x40, 0x1f, 0xff, 0x10, 0x0, 0x11, 0x8, 0x11, 0x8, 0x1f, 0xff, 0x11, 0x8, 0x11, 0x8, 0x11, 0x8, 0x11, 0xf8, 0x30, 0x0, 0x20, 0x0, 0x64, 0x92, 0xc, 0xdb, 0x18, 0x49 },
+{ 0x8f, 0x8f, 0x8, 0x20, 0x18, 0x22, 0x10, 0xfe, 0x64, 0x24, 0x2c, 0x24, 0x18, 0x28, 0x11, 0xff, 0x24, 0x10, 0x7c, 0x20, 0x14, 0x7e, 0x11, 0xc2, 0x54, 0x42, 0x54, 0x7e, 0x54, 0x42, 0x10, 0x42, 0x10, 0x7e },
+{ 0x8f, 0x90, 0x0, 0x0, 0x3f, 0xfe, 0x22, 0x22, 0x22, 0x22, 0x3f, 0xfe, 0x0, 0x84, 0x1f, 0xfc, 0x0, 0x90, 0x7f, 0xff, 0x0, 0x80, 0x7, 0xfc, 0x7c, 0x4, 0x7, 0xfc, 0x4, 0x4, 0x4, 0x4, 0x7, 0xfc },
+{ 0x8f, 0x91, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x84, 0x7f, 0xff, 0x0, 0x84, 0x1f, 0xfc, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x4, 0x1f, 0xfc, 0x10, 0x4, 0x1f, 0xfc },
+{ 0x8f, 0x92, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x3f, 0xfe, 0x22, 0x22, 0x3f, 0xfe, 0x0, 0x84, 0x1f, 0xfc, 0x0, 0x90, 0x7f, 0xff, 0x1, 0x0, 0xf, 0xfc, 0x78, 0x4, 0xf, 0xfc, 0x8, 0x4, 0xf, 0xfc },
+{ 0x8f, 0x93, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x3c, 0x22, 0x0, 0xfe, 0x7e, 0x24, 0x0, 0x28, 0x3d, 0xff, 0x0, 0x10, 0x3c, 0x7e, 0x1, 0xc2, 0x3c, 0x7e, 0x24, 0x42, 0x24, 0x42, 0x3c, 0x7e },
+{ 0x8f, 0x94, 0x0, 0x20, 0x3c, 0x22, 0x0, 0xfe, 0x7e, 0x24, 0x0, 0x24, 0x3c, 0x28, 0x1, 0xff, 0x0, 0x10, 0x3c, 0x20, 0x0, 0x7e, 0x1, 0xc2, 0x3c, 0x42, 0x24, 0x7e, 0x24, 0x42, 0x24, 0x42, 0x3c, 0x7e },
+{ 0x8f, 0x95, 0x0, 0x20, 0x3e, 0x20, 0x22, 0x20, 0x22, 0x20, 0x22, 0xfe, 0x3e, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x3e, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x66, 0x3f, 0x44, 0x60, 0xc4, 0x1, 0x9c },
+{ 0x8f, 0x96, 0x8, 0x0, 0x1c, 0xfe, 0x16, 0x42, 0x33, 0x42, 0x21, 0x46, 0x7e, 0x64, 0x48, 0x2c, 0x8, 0x28, 0x7f, 0x38, 0x8, 0x10, 0x2a, 0x10, 0x2a, 0x38, 0x6b, 0x28, 0x49, 0x6c, 0x8, 0x46, 0x18, 0xc3 },
+{ 0x8f, 0x97, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x7f, 0xff, 0x2, 0x10, 0x2, 0x10, 0x6, 0x10, 0x4, 0x30, 0xc, 0x20, 0x8, 0x60, 0x1f, 0x40, 0x1, 0xe0, 0x3, 0x38, 0xe, 0xc, 0x38, 0x6 },
+{ 0x8f, 0x98, 0x0, 0x40, 0x0, 0x40, 0x1f, 0xff, 0x10, 0x0, 0x17, 0xfc, 0x10, 0x8, 0x11, 0x10, 0x10, 0xa0, 0x1f, 0xff, 0x10, 0x42, 0x10, 0x46, 0x10, 0x44, 0x30, 0x40, 0x20, 0x40, 0x60, 0x40, 0x1, 0xc0 },
+{ 0x8f, 0x99, 0x8, 0x20, 0x18, 0x70, 0x10, 0x50, 0x30, 0xd8, 0x61, 0x8c, 0xb, 0x6, 0x1e, 0xfb, 0x10, 0x20, 0x30, 0x20, 0x73, 0xfe, 0x10, 0x20, 0x11, 0x24, 0x11, 0x24, 0x13, 0x26, 0x16, 0x23, 0x10, 0xe0 },
+{ 0x8f, 0x9a, 0x4, 0x0, 0x4, 0x0, 0x7f, 0xbe, 0x8, 0xa2, 0x19, 0xa2, 0x11, 0x22, 0x3f, 0x22, 0x5, 0xa2, 0x18, 0xbe, 0x70, 0x0, 0x1, 0x80, 0x14, 0xc6, 0x14, 0x43, 0x34, 0x9, 0x26, 0x18, 0x63, 0xf0 },
+{ 0x8f, 0x9b, 0x10, 0x8, 0x39, 0xe8, 0x2d, 0x28, 0x65, 0x28, 0x1, 0x3f, 0x7d, 0xe9, 0x11, 0x29, 0x11, 0x29, 0x7d, 0x29, 0x11, 0xe9, 0x55, 0x29, 0x55, 0x29, 0x51, 0x29, 0x1d, 0xfb, 0x33, 0x12, 0x60, 0x36 },
+{ 0x8f, 0x9c, 0x0, 0x20, 0x3c, 0x70, 0x24, 0x50, 0x24, 0xd8, 0x25, 0x8c, 0x29, 0x6, 0x2a, 0xfb, 0x24, 0x20, 0x24, 0x20, 0x27, 0xfe, 0x24, 0x20, 0x24, 0xa4, 0x2c, 0xa4, 0x21, 0xa6, 0x23, 0x23, 0x20, 0x60 },
+{ 0x8f, 0x9d, 0x9, 0x0, 0xb, 0xfe, 0x1a, 0x0, 0x15, 0xfc, 0x11, 0x4, 0x31, 0xfc, 0x31, 0x4, 0x51, 0xfc, 0x10, 0x0, 0x17, 0xff, 0x11, 0x0, 0x13, 0xfe, 0x16, 0x92, 0x11, 0x22, 0x16, 0x46, 0x11, 0x9c },
+{ 0x8f, 0x9e, 0x9, 0x22, 0x8, 0xa4, 0x1b, 0xff, 0x12, 0x1, 0x12, 0xfd, 0x30, 0x84, 0x30, 0xfc, 0x50, 0x0, 0x11, 0xfe, 0x11, 0x2, 0x11, 0xfe, 0x11, 0x2, 0x11, 0xfe, 0x11, 0x2, 0x11, 0xfe, 0x13, 0x3 },
+{ 0x8f, 0x9f, 0x0, 0x20, 0x3d, 0x24, 0x24, 0xa8, 0x24, 0x20, 0x25, 0xfe, 0x3c, 0x48, 0x24, 0x48, 0x27, 0xff, 0x24, 0x84, 0x3d, 0xa6, 0x27, 0x23, 0x24, 0xfc, 0x24, 0x24, 0x24, 0x64, 0x64, 0xc4, 0x4d, 0x9c },
+{ 0x8f, 0xa0, 0x0, 0x0, 0x3f, 0xfe, 0x20, 0x0, 0x20, 0x3c, 0x23, 0xe0, 0x22, 0x0, 0x23, 0xfe, 0x22, 0x20, 0x22, 0x20, 0x26, 0x20, 0x24, 0x20, 0x2c, 0x20, 0x20, 0x20, 0x20, 0x0, 0x3f, 0xfe, 0x0, 0x0 },
+{ 0x8f, 0xa1, 0x0, 0x10, 0x0, 0xd0, 0x3, 0x90, 0x1e, 0x10, 0x2, 0x10, 0x2, 0x10, 0x2, 0x10, 0x7f, 0xff, 0x2, 0x10, 0x2, 0x10, 0x2, 0x10, 0x6, 0x10, 0x4, 0x10, 0xc, 0x10, 0x18, 0x10, 0x70, 0x10 },
+{ 0x8f, 0xa2, 0x0, 0x0, 0x3f, 0xfe, 0x0, 0x82, 0x0, 0x82, 0x1, 0x82, 0x3, 0x6, 0x6, 0x4, 0x1c, 0x1c, 0x70, 0x0, 0xf, 0xfc, 0x8, 0x4, 0x8, 0x4, 0x8, 0x4, 0x8, 0x4, 0x8, 0x4, 0xf, 0xfc },
+{ 0x8f, 0xa3, 0x1, 0x22, 0x1, 0xa6, 0x78, 0xa4, 0x48, 0xa4, 0x48, 0x20, 0x49, 0xfe, 0x49, 0x2, 0x49, 0x2, 0x49, 0xfe, 0x49, 0x2, 0x49, 0x2, 0x79, 0xfe, 0x1, 0x2, 0x1, 0x2, 0x1, 0x2, 0x1, 0xe },
+{ 0x8f, 0xa4, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x4, 0x10, 0x2, 0x20, 0x3f, 0xfe, 0x22, 0x42, 0x22, 0x42, 0x24, 0x7e, 0x38, 0x2, 0x23, 0xe2, 0x22, 0x22, 0x22, 0x22, 0x23, 0xe2, 0x20, 0x2, 0x20, 0xe },
+{ 0x8f, 0xa5, 0x0, 0x0, 0x0, 0xfe, 0x7c, 0x82, 0x44, 0x82, 0x44, 0xfe, 0x44, 0x82, 0x44, 0x82, 0x44, 0xfe, 0x44, 0x0, 0x45, 0xff, 0x7d, 0x1, 0x1, 0x1, 0x1, 0xff, 0x1, 0x1, 0x1, 0x1, 0x1, 0xff },
+{ 0x8f, 0xa6, 0x10, 0x84, 0x8, 0x88, 0x7f, 0xff, 0x40, 0x1, 0x4f, 0xf9, 0x8, 0x8, 0xf, 0xf8, 0x20, 0x0, 0x3f, 0xf8, 0x20, 0x1, 0x3f, 0xff, 0x10, 0x4, 0x1f, 0xfc, 0x10, 0x4, 0x10, 0x4, 0x1f, 0xfc },
+{ 0x8f, 0xa7, 0x4, 0xe, 0x24, 0xf9, 0x34, 0x22, 0x14, 0x94, 0x4, 0x44, 0x5, 0xff, 0x1c, 0x4, 0x74, 0x64, 0x4, 0x34, 0x4, 0xc, 0x0, 0x80, 0x7f, 0xff, 0x1, 0x40, 0x3, 0x60, 0xe, 0x38, 0x78, 0xf },
+{ 0x8f, 0xa8, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x4, 0x10, 0x6, 0x30, 0x2, 0x20, 0x7f, 0xff, 0x0, 0x0, 0x2, 0x0, 0x7f, 0xff, 0x4, 0x10, 0x8, 0x30, 0x1e, 0x60, 0x3, 0xc0, 0x6, 0x78, 0x3c, 0xe },
+{ 0x8f, 0xa9, 0x8, 0x0, 0x8, 0x7e, 0x8, 0x42, 0x8, 0x42, 0x7e, 0x7e, 0x12, 0x42, 0x12, 0x42, 0x12, 0x7e, 0x32, 0x0, 0x26, 0xff, 0x24, 0x81, 0x7c, 0x81, 0xa, 0xff, 0x19, 0x81, 0x30, 0x81, 0x60, 0xff },
+{ 0x8f, 0xaa, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x40, 0x1, 0x48, 0x89, 0xc, 0x98, 0x4, 0x90, 0x1f, 0xfc, 0x10, 0x4, 0x1f, 0xfc, 0x10, 0x4, 0x1f, 0xfc, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x1c },
+{ 0x8f, 0xab, 0x8, 0x6, 0x8, 0x1c, 0x9, 0xf1, 0x48, 0x23, 0x69, 0x36, 0x29, 0x94, 0x8, 0x80, 0x8, 0x4, 0xb, 0xff, 0x18, 0x4, 0x38, 0xc4, 0x68, 0x64, 0x8, 0x24, 0x8, 0x4, 0x8, 0x4, 0x8, 0x1c },
+{ 0x8f, 0xac, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x8, 0x88, 0x8, 0x88, 0x8, 0x88, 0x18, 0x8c, 0x10, 0x84, 0x30, 0x86, 0x20, 0x82, 0x60, 0x83, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x3, 0x80 },
+{ 0x8f, 0xad, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x8, 0x90, 0x8, 0x98, 0x18, 0x8c, 0x10, 0x86, 0x30, 0x83, 0x60, 0x88, 0x0, 0x98, 0x3, 0x90, 0x0, 0x30, 0x0, 0x60, 0x1, 0xc0, 0x7, 0x0, 0x3c, 0x0 },
+{ 0x8f, 0xae, 0x0, 0x80, 0x10, 0x84, 0x18, 0x8c, 0xc, 0x98, 0x4, 0x90, 0x3f, 0xfe, 0x20, 0x2, 0x20, 0x2, 0x27, 0xf2, 0x24, 0x12, 0x24, 0x12, 0x24, 0x12, 0x27, 0xf2, 0x20, 0x2, 0x20, 0x2, 0x20, 0xe },
+{ 0x8f, 0xaf, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x1f, 0xff, 0x10, 0x0, 0x10, 0x40, 0x10, 0x40, 0x10, 0x40, 0x17, 0xfe, 0x10, 0x40, 0x10, 0x40, 0x10, 0x40, 0x30, 0x40, 0x20, 0x40, 0x60, 0x40, 0xf, 0xff },
+{ 0x8f, 0xb0, 0x0, 0x40, 0x0, 0x40, 0x1f, 0xff, 0x10, 0x0, 0x10, 0x40, 0x10, 0x40, 0x1f, 0xff, 0x11, 0x50, 0x11, 0x50, 0x11, 0x58, 0x13, 0x48, 0x12, 0x4c, 0x36, 0x46, 0x2c, 0x43, 0x60, 0x40, 0x0, 0x40 },
+{ 0x8f, 0xb1, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xff, 0x21, 0x8, 0x29, 0x28, 0x25, 0x48, 0x21, 0x1f, 0x2f, 0xf2, 0x28, 0x2a, 0x2b, 0xaa, 0x2a, 0xae, 0x2a, 0xa4, 0x6b, 0xa4, 0x48, 0x2e, 0x48, 0x2a, 0x8, 0x7b },
+{ 0x8f, 0xb2, 0x4, 0x4, 0x4, 0xc, 0x7f, 0xc8, 0x20, 0x98, 0x11, 0x32, 0x7f, 0xc6, 0x0, 0x4, 0x3f, 0x8c, 0x20, 0x98, 0x3f, 0xb0, 0x20, 0x82, 0x3f, 0x82, 0x4, 0x6, 0x7f, 0xcc, 0x4, 0x18, 0x4, 0x70 },
+{ 0x8f, 0xb3, 0x0, 0x0, 0x3f, 0xfc, 0x0, 0x18, 0x0, 0x60, 0x0, 0x88, 0x78, 0x89, 0xb, 0xeb, 0x8, 0x8e, 0x8, 0x88, 0xb, 0xe8, 0x8, 0x88, 0x18, 0x8c, 0x13, 0xe4, 0x30, 0x86, 0x60, 0x83, 0x3, 0x80 },
+{ 0x8f, 0xb4, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0xa4, 0x7c, 0xa4, 0x11, 0xa6, 0x11, 0x22, 0x13, 0x23, 0x10, 0x24, 0x1c, 0xe4, 0x70, 0xc, 0x10, 0x8, 0x10, 0x18, 0x10, 0x30, 0x10, 0x60, 0x31, 0xc0 },
+{ 0x8f, 0xb5, 0x10, 0x0, 0x13, 0xfe, 0x10, 0x42, 0x10, 0x42, 0x7c, 0xc2, 0x10, 0x86, 0x11, 0x84, 0x13, 0x1c, 0x1c, 0x0, 0x71, 0xfe, 0x11, 0x2, 0x11, 0x2, 0x11, 0x2, 0x11, 0x2, 0x11, 0x2, 0x31, 0xfe },
+{ 0x8f, 0xb6, 0x10, 0x84, 0x18, 0x8c, 0x8, 0x88, 0x7f, 0xff, 0x40, 0x1, 0x4f, 0xf9, 0x8, 0x8, 0xf, 0xf8, 0x0, 0x0, 0xf, 0xf8, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x3, 0x80 },
+{ 0x8f, 0xb7, 0x10, 0x20, 0x10, 0x20, 0x13, 0xff, 0x10, 0x20, 0x7d, 0xfe, 0x10, 0x22, 0x13, 0xff, 0x10, 0x22, 0x1d, 0xfe, 0x70, 0x20, 0x11, 0x20, 0x11, 0x3e, 0x11, 0x20, 0x13, 0xa0, 0x12, 0xe0, 0x36, 0x3f },
+{ 0x8f, 0xb8, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x0, 0x0, 0x3, 0x90, 0x1e, 0x10, 0x2, 0x10, 0x7f, 0xff, 0x2, 0x10, 0x2, 0x10, 0x6, 0x10, 0xc, 0x10, 0x38, 0x10 },
+{ 0x8f, 0xb9, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x0, 0x0, 0x3f, 0xfe, 0x20, 0x2, 0x20, 0x2, 0x3f, 0xfe, 0x20, 0x2, 0x20, 0x2, 0x3f, 0xfe },
+{ 0x8f, 0xba, 0x0, 0x0, 0x1, 0xfe, 0x7c, 0x22, 0x44, 0x22, 0x44, 0x62, 0x44, 0x46, 0x44, 0xc4, 0x7d, 0x9c, 0x44, 0x0, 0x44, 0xfe, 0x44, 0x82, 0x44, 0x82, 0x7c, 0x82, 0x0, 0x82, 0x0, 0x82, 0x0, 0xfe },
+{ 0x8f, 0xbb, 0x0, 0x0, 0x7, 0xf0, 0x4, 0x10, 0x4, 0x10, 0x7, 0xf0, 0x4, 0x10, 0x4, 0x10, 0x7, 0xf0, 0x0, 0x0, 0x3f, 0x7e, 0x21, 0x42, 0x21, 0x42, 0x3f, 0x7e, 0x21, 0x42, 0x21, 0x42, 0x3f, 0x7e },
+{ 0x8f, 0xbc, 0x8, 0x44, 0x8, 0x44, 0x8, 0x44, 0x7e, 0xc6, 0x8, 0x82, 0x8, 0x82, 0x19, 0xa3, 0x1c, 0x20, 0x1a, 0x20, 0x2a, 0x20, 0x28, 0x64, 0x48, 0x44, 0x8, 0x44, 0x8, 0x4e, 0x8, 0x7a, 0x9, 0xc3 },
+{ 0x8f, 0xbd, 0x8, 0x10, 0x8, 0x92, 0x8, 0xd6, 0x7e, 0x54, 0x8, 0x10, 0x8, 0xfe, 0x1c, 0x82, 0x1a, 0x82, 0x1a, 0xfe, 0x28, 0x82, 0x28, 0x82, 0x48, 0xfe, 0x8, 0x82, 0x8, 0x82, 0x8, 0x82, 0x8, 0x8e },
+{ 0x8f, 0xbe, 0x8, 0x10, 0x8, 0x10, 0x8, 0xfe, 0x7e, 0x44, 0x8, 0x28, 0x9, 0xff, 0x1c, 0x0, 0x1a, 0xfe, 0x1a, 0x82, 0x28, 0xfe, 0x28, 0x82, 0x48, 0xfe, 0x8, 0x10, 0x9, 0xff, 0x8, 0x10, 0x8, 0x10 },
+{ 0x8f, 0xbf, 0x8, 0x48, 0x8, 0x50, 0x8, 0xff, 0x7e, 0x90, 0x9, 0x90, 0xa, 0xfe, 0x18, 0x90, 0x1c, 0x90, 0x1a, 0xfe, 0x2a, 0x90, 0x28, 0x90, 0x48, 0xff, 0x8, 0x0, 0x8, 0xaa, 0x9, 0xab, 0x9, 0x1 },
+{ 0x8f, 0xc0, 0x0, 0x0, 0x33, 0xfe, 0x18, 0x42, 0x8, 0x42, 0x0, 0xc2, 0x60, 0x86, 0x31, 0x84, 0x13, 0x1c, 0x0, 0x0, 0x9, 0xfe, 0x9, 0x2, 0x19, 0x2, 0x11, 0x2, 0x31, 0x2, 0x21, 0x2, 0x61, 0xfe },
+{ 0x8f, 0xc1, 0x0, 0x20, 0x32, 0x22, 0x1b, 0x26, 0x9, 0x24, 0x0, 0x20, 0x63, 0xfe, 0x32, 0x2, 0x12, 0x2, 0x3, 0xfe, 0xa, 0x2, 0xa, 0x2, 0x1b, 0xfe, 0x12, 0x2, 0x32, 0x2, 0x22, 0x2, 0x62, 0xe },
+{ 0x8f, 0xc2, 0x0, 0x20, 0x30, 0xa0, 0x18, 0xbe, 0x8, 0xa0, 0x0, 0xa0, 0x63, 0xff, 0x30, 0x20, 0x10, 0xa4, 0x1, 0xa6, 0xb, 0x23, 0x8, 0x24, 0x18, 0x6c, 0x10, 0x8, 0x30, 0x18, 0x20, 0x70, 0x63, 0xc0 },
+{ 0x8f, 0xc3, 0x1, 0x0, 0x21, 0x3e, 0x31, 0x22, 0x17, 0xe2, 0x1, 0x22, 0x41, 0x3e, 0x63, 0xa2, 0x23, 0x62, 0x5, 0x22, 0x15, 0x22, 0x11, 0x3e, 0x11, 0x22, 0x31, 0x22, 0x21, 0x22, 0x21, 0x22, 0x61, 0x3e },
+{ 0x8f, 0xc4, 0x8, 0x10, 0x8, 0x10, 0x8, 0xfe, 0xa, 0x10, 0x2a, 0x92, 0x2a, 0x82, 0x29, 0xff, 0x68, 0x82, 0x48, 0x82, 0x8, 0x0, 0x1d, 0xff, 0x14, 0x48, 0x16, 0x48, 0x32, 0xc8, 0x21, 0x89, 0x63, 0x7 },
+{ 0x8f, 0xc5, 0x4, 0x40, 0x8, 0x80, 0x1f, 0xfe, 0x30, 0x80, 0x50, 0x80, 0x1f, 0xfc, 0x10, 0x80, 0x10, 0x80, 0x1f, 0xfc, 0x10, 0x80, 0x10, 0x80, 0x1f, 0xff, 0x0, 0x0, 0x12, 0x22, 0x33, 0x33, 0x61, 0x11 },
+{ 0x8f, 0xc6, 0x0, 0x0, 0x3e, 0xfe, 0x22, 0x12, 0x22, 0x32, 0x22, 0x62, 0x3e, 0xce, 0x22, 0x0, 0x22, 0x7e, 0x22, 0x42, 0x22, 0x42, 0x3e, 0x42, 0x0, 0x7e, 0x0, 0x0, 0x12, 0x22, 0x33, 0x33, 0x61, 0x11 },
+{ 0x8f, 0xc7, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xff, 0x10, 0x0, 0x50, 0x0, 0x37, 0xfe, 0x10, 0x40, 0x10, 0x40, 0x32, 0x40, 0x52, 0x7c, 0x12, 0x40, 0x12, 0x40, 0x32, 0x40, 0x22, 0x40, 0x62, 0x40, 0xf, 0xff },
+{ 0x8f, 0xc8, 0x0, 0x80, 0x4, 0x90, 0xc, 0x9c, 0x18, 0x87, 0x73, 0x98, 0x0, 0x60, 0xf, 0xfc, 0x78, 0x4, 0x8, 0x4, 0xf, 0xfc, 0x8, 0x4, 0x8, 0x4, 0xf, 0xfc, 0x8, 0x4, 0x8, 0x4, 0xf, 0xfc },
+{ 0x8f, 0xc9, 0x0, 0x10, 0x7e, 0x92, 0x10, 0xd6, 0x10, 0x54, 0x10, 0x10, 0x10, 0xfe, 0x3c, 0x82, 0x24, 0x82, 0x64, 0xfe, 0x24, 0x82, 0x24, 0x82, 0x24, 0xfe, 0x24, 0x82, 0x3c, 0x82, 0x0, 0x82, 0x0, 0x8e },
+{ 0x8f, 0xca, 0x0, 0x48, 0x7e, 0x50, 0x10, 0xff, 0x10, 0x90, 0x11, 0x90, 0x12, 0xfe, 0x3c, 0x90, 0x24, 0x90, 0x64, 0xfe, 0x24, 0x90, 0x24, 0x90, 0x24, 0xff, 0x24, 0x0, 0x3c, 0xaa, 0x1, 0xab, 0x1, 0x29 },
+{ 0x8f, 0xcb, 0x8, 0x82, 0x8, 0xc6, 0x8, 0x44, 0x7e, 0xfe, 0x2, 0x10, 0x6, 0x10, 0x4, 0x10, 0xc, 0xfe, 0x18, 0x10, 0x3c, 0x10, 0x6a, 0x10, 0x9, 0xff, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10 },
+{ 0x8f, 0xcc, 0x2, 0x40, 0xe, 0x40, 0x78, 0x40, 0x8, 0xff, 0x8, 0x90, 0x7e, 0x90, 0x8, 0x10, 0x18, 0x10, 0x1c, 0x54, 0x1a, 0x54, 0x2a, 0xd6, 0x28, 0x92, 0x49, 0x93, 0x8, 0x10, 0x8, 0x10, 0x8, 0x70 },
+{ 0x8f, 0xcd, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x4, 0x10, 0x2, 0x20, 0x7f, 0xff, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80 },
+{ 0x8f, 0xce, 0x8, 0x20, 0x8, 0x20, 0x1f, 0x7f, 0x34, 0x50, 0x62, 0x88, 0x0, 0x0, 0x0, 0x1c, 0x1f, 0xf0, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x1, 0x40, 0x3, 0x60, 0x6, 0x30, 0x1c, 0x1c, 0x70, 0x7 },
+{ 0x8f, 0xcf, 0x10, 0x10, 0x54, 0x10, 0x54, 0x10, 0x55, 0xff, 0x11, 0x0, 0x7d, 0x10, 0x11, 0x10, 0x11, 0x10, 0x39, 0x7e, 0x35, 0x10, 0x51, 0x10, 0x51, 0x10, 0x13, 0x10, 0x12, 0x10, 0x16, 0xff, 0x10, 0x0 },
+{ 0x8f, 0xd0, 0x8, 0x0, 0x19, 0xfe, 0x10, 0x22, 0x64, 0x22, 0x2c, 0x62, 0x18, 0x46, 0x10, 0xc4, 0x25, 0x9c, 0x7e, 0x0, 0x12, 0xfe, 0x10, 0x82, 0x54, 0x82, 0x54, 0x82, 0x54, 0x82, 0x10, 0x82, 0x10, 0xfe },
+{ 0x8f, 0xd1, 0x10, 0x84, 0x18, 0x8c, 0xc, 0x98, 0x4, 0x90, 0x0, 0x80, 0x1f, 0xfc, 0x10, 0x4, 0x10, 0x4, 0x1f, 0xfc, 0x10, 0x4, 0x10, 0x4, 0x1f, 0xfc, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x1c },
+{ 0x8f, 0xd2, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x0, 0x0, 0x3f, 0xfe, 0x20, 0x2, 0x3f, 0xfe, 0x20, 0x2, 0x20, 0x2, 0x3f, 0xfe },
+{ 0x8f, 0xd3, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x8, 0x6, 0x8, 0x3c, 0x4b, 0xe1, 0x69, 0x12, 0x28, 0x80, 0x8, 0x4, 0xb, 0xff, 0x38, 0x84, 0x68, 0xc4, 0x8, 0x44, 0x8, 0x4, 0x8, 0x1c },
+{ 0x8f, 0xd4, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x8, 0x80, 0x1f, 0xfe, 0x30, 0x80, 0x5f, 0xfc, 0x10, 0x80, 0x1f, 0xfc, 0x10, 0x80, 0x1f, 0xff, 0x0, 0x0, 0x12, 0x22, 0x33, 0x33, 0x61, 0x11 },
+{ 0x8f, 0xd5, 0x8, 0x60, 0x1b, 0xde, 0x10, 0x80, 0x37, 0xf0, 0x60, 0x80, 0xb, 0xe0, 0x1a, 0xbf, 0x13, 0xe4, 0x32, 0xa4, 0x73, 0xe4, 0x10, 0x84, 0x13, 0xe4, 0x10, 0x84, 0x10, 0xf4, 0x17, 0x84, 0x10, 0xc },
+{ 0x8f, 0xd6, 0x10, 0x84, 0x8, 0x88, 0x3f, 0xfe, 0x20, 0x2, 0x27, 0xf2, 0x4, 0x10, 0x4, 0x10, 0x7, 0xf0, 0x0, 0x80, 0x7f, 0xff, 0x2, 0x44, 0x6, 0x6c, 0x1c, 0x28, 0x74, 0x30, 0x7, 0x9c, 0x1c, 0x7 },
+{ 0x8f, 0xd7, 0x0, 0x0, 0x3c, 0x48, 0x0, 0x48, 0x7e, 0x4c, 0x0, 0xc4, 0x3c, 0x86, 0x0, 0x82, 0x1, 0xa3, 0x3c, 0x20, 0x0, 0x20, 0x0, 0x64, 0x3c, 0x44, 0x24, 0x46, 0x24, 0xc2, 0x24, 0x9e, 0x3d, 0xf3 },
+{ 0x8f, 0xd8, 0x0, 0x0, 0x3d, 0xfe, 0x0, 0x10, 0x7e, 0x10, 0x0, 0x10, 0x3c, 0x90, 0x0, 0x90, 0x0, 0x9e, 0x3c, 0x90, 0x0, 0x90, 0x0, 0x90, 0x3c, 0x90, 0x24, 0x90, 0x24, 0x90, 0x27, 0xff, 0x3c, 0x0 },
+{ 0x8f, 0xd9, 0x0, 0x0, 0x3d, 0xfe, 0x0, 0x22, 0x7e, 0x22, 0x0, 0x62, 0x3c, 0x46, 0x0, 0xc4, 0x1, 0x8c, 0x3c, 0x0, 0x0, 0xfe, 0x0, 0x82, 0x3c, 0x82, 0x24, 0x82, 0x24, 0x82, 0x24, 0x82, 0x3c, 0xfe },
+{ 0x8f, 0xda, 0x0, 0x82, 0x3c, 0xc6, 0x0, 0x44, 0x7e, 0xfe, 0x0, 0x10, 0x3c, 0x10, 0x0, 0x10, 0x0, 0xfe, 0x3c, 0x10, 0x0, 0x10, 0x0, 0x10, 0x3d, 0xff, 0x24, 0x10, 0x24, 0x10, 0x24, 0x10, 0x3c, 0x10 },
+{ 0x8f, 0xdb, 0x2, 0x0, 0x7, 0xf0, 0xc, 0x20, 0x18, 0x40, 0x7f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x1, 0x2, 0x6, 0x86, 0x39, 0x4c, 0x6, 0x60, 0x38, 0xd8, 0x7, 0x4c, 0x7c, 0x47, 0x1, 0xc0 },
+{ 0x8f, 0xdc, 0x10, 0x84, 0x8, 0x88, 0x3f, 0xfe, 0x20, 0x2, 0x27, 0xf2, 0x4, 0x10, 0x7, 0xf0, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x38, 0xe },
+{ 0x8f, 0xdd, 0x24, 0xe, 0x35, 0xf8, 0x14, 0xa2, 0x4, 0x54, 0x1f, 0xff, 0x74, 0x84, 0x4, 0x4c, 0x7f, 0xff, 0x2, 0x40, 0x1f, 0xfc, 0x12, 0x44, 0x1c, 0x7c, 0x10, 0x4, 0x1f, 0xfc, 0x10, 0x4, 0x1f, 0xfc },
+{ 0x8f, 0xde, 0x10, 0x0, 0x39, 0xfe, 0x2c, 0x10, 0x64, 0x10, 0x40, 0x10, 0x7c, 0x90, 0x10, 0x90, 0x10, 0x9e, 0x7c, 0x90, 0x10, 0x90, 0x54, 0x90, 0x54, 0x90, 0x10, 0x90, 0x1c, 0x90, 0x33, 0xff, 0x60, 0x0 },
+{ 0x8f, 0xdf, 0x8, 0x6, 0x1c, 0xfc, 0x16, 0x10, 0x32, 0xff, 0x20, 0x10, 0x7e, 0xfe, 0x8, 0x92, 0x8, 0x92, 0x7e, 0xfe, 0x8, 0x92, 0x4a, 0x92, 0x6a, 0xfe, 0x28, 0x10, 0xe, 0xfe, 0x38, 0x10, 0x61, 0xff },
+{ 0x8f, 0xe0, 0x10, 0x10, 0x38, 0x10, 0x2d, 0xff, 0x64, 0x44, 0x40, 0x28, 0x7d, 0xff, 0x10, 0x0, 0x10, 0xfe, 0x7c, 0x92, 0x10, 0xfe, 0x54, 0x92, 0x54, 0xfe, 0x10, 0x10, 0x1c, 0xfe, 0x30, 0x10, 0x61, 0xff },
+{ 0x8f, 0xe1, 0x0, 0x10, 0x3e, 0x10, 0x22, 0xfe, 0x26, 0x44, 0x24, 0x28, 0x2d, 0xff, 0x28, 0x0, 0x28, 0xfe, 0x24, 0x82, 0x24, 0xfe, 0x24, 0x82, 0x24, 0xfe, 0x2c, 0x10, 0x21, 0xff, 0x20, 0x10, 0x20, 0x10 },
+{ 0x8f, 0xe2, 0x24, 0x10, 0x24, 0x92, 0x7e, 0xd6, 0x24, 0x54, 0x24, 0x10, 0x3c, 0xfe, 0x10, 0x82, 0x7e, 0x82, 0x52, 0xfe, 0x52, 0x82, 0x7e, 0x82, 0x10, 0xfe, 0x7e, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x8e },
+{ 0x8f, 0xe3, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0xfc, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x8f, 0xe4, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x7f, 0xff, 0x0, 0x40, 0x0, 0x40, 0x4, 0x40, 0x6, 0x40, 0x3, 0x40, 0x1, 0xc0, 0x0, 0x80, 0x1, 0xc0, 0x3, 0x60, 0x6, 0x30, 0x1c, 0x1c, 0x70, 0x7 },
+{ 0x8f, 0xe5, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x8, 0x0, 0x30, 0x0, 0xe2, 0x3e, 0xa2, 0x2, 0xb6, 0x6, 0x94, 0xc, 0x98, 0x18, 0x8c, 0x30, 0x86, 0x60, 0x83, 0x3, 0x80, 0x0, 0x0, 0x3f, 0xff, 0x0, 0x0 },
+{ 0x8f, 0xe6, 0x0, 0x38, 0x1f, 0xe0, 0x0, 0x80, 0x3f, 0xfe, 0x8, 0x88, 0x8, 0x88, 0x7f, 0xff, 0x8, 0x88, 0x8, 0x88, 0x3f, 0xfe, 0x2, 0xa0, 0x6, 0xb0, 0xc, 0x98, 0x18, 0x8c, 0x70, 0x87, 0x0, 0x80 },
+{ 0x8f, 0xe7, 0x0, 0x0, 0x3f, 0xfe, 0x20, 0x2, 0x20, 0x2, 0x27, 0xe2, 0x4, 0x20, 0x4, 0x20, 0x4, 0x20, 0x4, 0x20, 0x4, 0x20, 0x4, 0x20, 0x4, 0x20, 0xc, 0x20, 0x8, 0x20, 0x18, 0x31, 0x70, 0x1f },
+{ 0x8f, 0xe8, 0x3, 0x82, 0x1e, 0x12, 0x4, 0x12, 0x3f, 0xd2, 0x14, 0x92, 0x14, 0x92, 0x7f, 0xf2, 0x14, 0x92, 0x14, 0x92, 0x3f, 0xd2, 0xc, 0x12, 0x1f, 0x12, 0x15, 0x82, 0x34, 0xc2, 0x64, 0x2, 0x4, 0xe },
+{ 0x8f, 0xe9, 0x10, 0x14, 0x10, 0x16, 0x10, 0x12, 0x13, 0xff, 0x7e, 0x10, 0x12, 0x10, 0x13, 0xd2, 0x12, 0x52, 0x12, 0x56, 0x12, 0x54, 0x1e, 0x5c, 0x72, 0x48, 0x6, 0x5c, 0x4, 0xd5, 0xc, 0x37, 0x18, 0x62 },
+{ 0x8f, 0xea, 0x10, 0xfc, 0x10, 0x84, 0x10, 0xfc, 0x10, 0x84, 0x7c, 0x84, 0x10, 0xfc, 0x10, 0x0, 0x13, 0xff, 0x10, 0x80, 0x10, 0xff, 0x1d, 0x25, 0x72, 0x6d, 0x0, 0xc9, 0x1, 0x9b, 0x0, 0x32, 0x0, 0xe },
+{ 0x8f, 0xeb, 0x0, 0x20, 0x10, 0x20, 0x13, 0xff, 0x10, 0x48, 0x13, 0x87, 0x7c, 0x48, 0x11, 0xfe, 0x10, 0x48, 0x11, 0xfe, 0x10, 0x48, 0x13, 0xff, 0x1c, 0x49, 0x70, 0xca, 0x7, 0x8c, 0x0, 0xe6, 0x3, 0x83 },
+{ 0x8f, 0xec, 0x10, 0x10, 0x10, 0x10, 0x11, 0xff, 0x10, 0x44, 0x7d, 0x83, 0x14, 0x28, 0x14, 0xfe, 0x34, 0x28, 0x24, 0xfe, 0x2c, 0x28, 0x29, 0xff, 0x78, 0x28, 0x14, 0x6a, 0x15, 0xc4, 0x30, 0x76, 0x61, 0xc3 },
+{ 0x8f, 0xed, 0x10, 0x84, 0x18, 0x8c, 0x8, 0x88, 0x3f, 0xfe, 0x20, 0x2, 0x27, 0xf2, 0x24, 0x12, 0x4, 0x10, 0x7, 0xf0, 0x0, 0x80, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x9c, 0x0, 0x80 },
+{ 0x8f, 0xee, 0x10, 0x20, 0x10, 0x20, 0x13, 0xfe, 0x18, 0x20, 0x55, 0xfc, 0x50, 0x20, 0x57, 0xff, 0x10, 0x0, 0x11, 0xfc, 0x11, 0x4, 0x11, 0xfc, 0x11, 0x4, 0x11, 0xfc, 0x11, 0x4, 0x11, 0x4, 0x11, 0xc },
+{ 0x8f, 0xef, 0x13, 0xff, 0x10, 0x20, 0x10, 0xfc, 0x10, 0x84, 0x7c, 0xfc, 0x10, 0x84, 0x13, 0xff, 0x12, 0x11, 0x1d, 0x4a, 0x71, 0x45, 0x12, 0x3c, 0x10, 0x40, 0x10, 0xfc, 0x13, 0x44, 0x10, 0x38, 0x33, 0xc7 },
+{ 0x8f, 0xf0, 0x1, 0x0, 0x3, 0xf8, 0x6, 0x8, 0xc, 0x10, 0x3b, 0x60, 0x1, 0xc0, 0xf, 0x78, 0x78, 0xf, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x2, 0xa0, 0x6, 0xb0, 0x1c, 0x9c, 0x70, 0x87, 0x0, 0x80 },
+{ 0x8f, 0xf1, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x7e, 0xff, 0x8, 0x8, 0x8, 0x8, 0x18, 0x48, 0x1c, 0x68, 0x1a, 0x28, 0x2a, 0x38, 0x28, 0x10, 0x48, 0x38, 0x8, 0x28, 0x8, 0x6c, 0x8, 0xc6, 0x9, 0x83 },
+{ 0x8f, 0xf2, 0x0, 0x80, 0x30, 0xfc, 0x19, 0x88, 0xb, 0x10, 0x0, 0x20, 0x63, 0xfe, 0x30, 0x22, 0x10, 0x22, 0x7, 0xff, 0x8, 0x22, 0x8, 0x22, 0x1b, 0xfe, 0x10, 0x20, 0x30, 0x20, 0x20, 0x20, 0x60, 0xe0 },
+{ 0x8f, 0xf3, 0x4, 0x10, 0x4, 0x14, 0x24, 0x16, 0x34, 0x12, 0x14, 0x10, 0x5, 0xff, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x1c, 0x38, 0x34, 0x28, 0x64, 0x28, 0x4, 0x6c, 0x4, 0x44, 0x4, 0xc6, 0x5, 0x83 },
+{ 0x8f, 0xf4, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x84, 0x1f, 0xfc, 0x0, 0x0, 0x7f, 0xff, 0x40, 0x1, 0x4f, 0xf9, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x7f, 0xff },
+{ 0x8f, 0xf5, 0x4, 0x20, 0x1c, 0x20, 0x73, 0xff, 0x10, 0x84, 0x13, 0x3, 0x7c, 0x48, 0x11, 0xfe, 0x10, 0x48, 0x39, 0xfe, 0x34, 0x48, 0x51, 0xfe, 0x50, 0x48, 0x10, 0xca, 0x13, 0x84, 0x10, 0xe6, 0x13, 0x83 },
+{ 0x8f, 0xf6, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x0, 0x0, 0x1f, 0xf8, 0x0, 0x62, 0x3e, 0xc6, 0x2, 0xac, 0x4, 0x90, 0x18, 0x8c, 0x63, 0x87, 0x0, 0x0, 0x7f, 0xff, 0x12, 0x22, 0x33, 0x33, 0x61, 0x11 },
+{ 0x8f, 0xf7, 0x0, 0x20, 0x38, 0x20, 0x3, 0xff, 0x7c, 0x84, 0x3, 0x3, 0x38, 0x48, 0x1, 0xfe, 0x0, 0x48, 0x39, 0xfe, 0x0, 0x48, 0x3, 0xff, 0x38, 0x48, 0x28, 0xca, 0x2b, 0x84, 0x28, 0xe6, 0x3b, 0x83 },
+{ 0x8f, 0xf8, 0x0, 0x10, 0x7f, 0x10, 0x14, 0xff, 0x14, 0x24, 0x7f, 0xc3, 0x55, 0x24, 0x55, 0x7e, 0x55, 0x24, 0x67, 0x7e, 0x41, 0x24, 0x41, 0xff, 0x7f, 0x24, 0x41, 0x65, 0x41, 0xc6, 0x7f, 0x72, 0x0, 0xc3 },
+{ 0x8f, 0xf9, 0x10, 0x10, 0x38, 0x10, 0x2d, 0xff, 0x65, 0x1, 0x41, 0x1, 0x7c, 0xfe, 0x10, 0x10, 0x10, 0x10, 0x7c, 0x90, 0x10, 0x9e, 0x54, 0x90, 0x54, 0x90, 0x10, 0x90, 0x1d, 0xd0, 0x31, 0x70, 0x63, 0x1f },
+{ 0x8f, 0xfa, 0x0, 0x0, 0x3, 0xff, 0x7a, 0x1, 0x4b, 0xff, 0x4a, 0x0, 0x4a, 0xfe, 0x4a, 0x10, 0x4a, 0xfe, 0x4a, 0x92, 0x4a, 0xfe, 0x7a, 0x10, 0x7, 0xff, 0x5, 0x15, 0xd, 0x1d, 0x19, 0x75, 0x1, 0x3 },
+{ 0x8f, 0xfb, 0x0, 0x20, 0x10, 0x20, 0x17, 0xfe, 0x10, 0x20, 0x10, 0xfc, 0x78, 0x84, 0x12, 0x84, 0x12, 0xfc, 0x12, 0x84, 0x12, 0x84, 0x12, 0xfc, 0x1a, 0x84, 0x72, 0x84, 0x2, 0xfc, 0x2, 0x0, 0x3, 0xff },
+{ 0x8f, 0xfc, 0x8, 0x20, 0x1c, 0x20, 0x16, 0x20, 0x32, 0x7f, 0x28, 0x50, 0x7e, 0x90, 0x22, 0x7e, 0x3e, 0x52, 0x22, 0x52, 0x3e, 0x52, 0x20, 0x52, 0x24, 0x52, 0x24, 0x52, 0x26, 0x56, 0x3a, 0x10, 0x60, 0x10 },
+{ 0x90, 0x40, 0x10, 0x10, 0x10, 0x14, 0x10, 0x16, 0x10, 0x12, 0x7d, 0xff, 0x10, 0x10, 0x10, 0x10, 0x13, 0xf0, 0x1c, 0x98, 0x70, 0x88, 0x10, 0x88, 0x10, 0x88, 0x10, 0xec, 0x13, 0x85, 0x10, 0x7, 0x30, 0x2 },
+{ 0x90, 0x41, 0x10, 0x10, 0x10, 0x10, 0x11, 0xff, 0x7c, 0x10, 0x10, 0x7e, 0x11, 0x42, 0x19, 0x42, 0x35, 0x7e, 0x35, 0x42, 0x31, 0x42, 0x51, 0x7e, 0x51, 0x42, 0x11, 0x42, 0x11, 0x7e, 0x11, 0x0, 0x11, 0xff },
+{ 0x90, 0x42, 0x0, 0x10, 0x7e, 0x10, 0x11, 0xff, 0x10, 0x10, 0x10, 0x7e, 0x3d, 0x42, 0x25, 0x42, 0x25, 0x7e, 0x75, 0x42, 0x5d, 0x42, 0xd, 0x7e, 0x9, 0x42, 0x19, 0x42, 0x11, 0x7e, 0x31, 0x0, 0x61, 0xff },
+{ 0x90, 0x43, 0x10, 0x0, 0x11, 0xff, 0x11, 0x49, 0x15, 0x49, 0x55, 0xff, 0x54, 0x80, 0x51, 0xff, 0x53, 0x21, 0x11, 0xfd, 0x11, 0x25, 0x39, 0xfd, 0x28, 0x21, 0x2c, 0x29, 0x24, 0x7b, 0x61, 0xca, 0x40, 0x6 },
+{ 0x90, 0x44, 0x10, 0x88, 0x10, 0x8a, 0x33, 0xeb, 0x68, 0x9, 0x2a, 0x28, 0x19, 0x48, 0x17, 0xff, 0x28, 0x8, 0x7d, 0xea, 0x15, 0x2a, 0x11, 0x2e, 0x55, 0xe4, 0x55, 0x24, 0x55, 0x25, 0x11, 0xef, 0x10, 0x1a },
+{ 0x90, 0x45, 0x0, 0x88, 0x7c, 0x8a, 0x2b, 0xeb, 0x28, 0x9, 0x2a, 0x28, 0x39, 0x48, 0x2f, 0xff, 0x28, 0x8, 0x2b, 0xea, 0x3a, 0x2a, 0x2a, 0x2e, 0x2b, 0xe4, 0x2a, 0x24, 0x3a, 0x25, 0x6b, 0xef, 0x8, 0x1a },
+{ 0x90, 0x46, 0x4, 0x0, 0x7, 0xf0, 0xc, 0x10, 0x18, 0x20, 0x7f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x10, 0x1, 0x18, 0x3, 0xf, 0xfe },
+{ 0x90, 0x47, 0x10, 0x8, 0x1e, 0x8, 0x32, 0x8, 0x24, 0x7f, 0x7f, 0x49, 0x29, 0x49, 0x29, 0x49, 0x3f, 0x49, 0x29, 0x49, 0x29, 0x7f, 0x3f, 0x8, 0x21, 0x8, 0x21, 0xa, 0x21, 0xa, 0x61, 0x1f, 0x47, 0x71 },
+{ 0x90, 0x48, 0x0, 0x80, 0x1, 0xc0, 0x3, 0x60, 0x6, 0x30, 0x1c, 0x9c, 0x70, 0x87, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xfa, 0x8, 0x46, 0x8, 0x6c, 0x8, 0x30, 0xf, 0x98, 0x38, 0xe },
+{ 0x90, 0x49, 0x8, 0x10, 0x1c, 0x10, 0x16, 0x10, 0x32, 0xfe, 0x68, 0x92, 0x3e, 0x92, 0x22, 0x92, 0x3e, 0x92, 0x22, 0x92, 0x3e, 0xfe, 0x20, 0x10, 0x24, 0x12, 0x24, 0x12, 0x2e, 0x1e, 0x32, 0x73, 0x61, 0xc1 },
+{ 0x90, 0x4a, 0x0, 0x0, 0x1f, 0xfe, 0x10, 0x0, 0x17, 0xfc, 0x10, 0x0, 0x1f, 0xfe, 0x12, 0x44, 0x32, 0x6c, 0x23, 0xb8, 0x6e, 0xf, 0x0, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x6, 0x10, 0x2, 0x10, 0x0, 0x70 },
+{ 0x90, 0x4b, 0x0, 0x0, 0x1f, 0xfe, 0x10, 0x2, 0x10, 0x2, 0x1f, 0xfe, 0x10, 0x0, 0x10, 0x80, 0x10, 0x80, 0x17, 0xf8, 0x10, 0x88, 0x10, 0x88, 0x10, 0x88, 0x31, 0x88, 0x21, 0x9, 0x63, 0x9, 0xe, 0x7 },
+{ 0x90, 0x4c, 0x4, 0x20, 0x4, 0x20, 0xc, 0x20, 0xb, 0xff, 0x1a, 0x21, 0x12, 0x21, 0x32, 0x21, 0x53, 0xff, 0x12, 0x21, 0x12, 0x21, 0x12, 0x21, 0x13, 0xff, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20 },
+{ 0x90, 0x4d, 0x4, 0x0, 0x4, 0xfc, 0xc, 0x0, 0xb, 0xff, 0x18, 0x0, 0x10, 0xfc, 0x30, 0x0, 0x50, 0x0, 0x10, 0xfc, 0x10, 0x0, 0x10, 0x0, 0x11, 0xfe, 0x11, 0x2, 0x11, 0x2, 0x11, 0x2, 0x11, 0xfe },
+{ 0x90, 0x4e, 0x4, 0x0, 0x5, 0xfc, 0xc, 0x4, 0x9, 0xfc, 0x18, 0x4, 0x11, 0xfc, 0x30, 0x0, 0x57, 0xff, 0x14, 0x1, 0x15, 0xfd, 0x10, 0x84, 0x10, 0xcc, 0x10, 0x58, 0x10, 0x70, 0x11, 0xdc, 0x17, 0x7 },
+{ 0x90, 0x4f, 0x0, 0x0, 0x1f, 0xfe, 0x10, 0x0, 0x17, 0xfc, 0x10, 0x0, 0x1f, 0xff, 0x12, 0x44, 0x12, 0x68, 0x32, 0x30, 0x23, 0xdc, 0x6e, 0x7, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x4, 0x10, 0x4, 0x1f, 0xfc },
+{ 0x90, 0x50, 0x10, 0x0, 0x10, 0xff, 0x10, 0x80, 0x7e, 0x80, 0x12, 0xbe, 0x12, 0x80, 0x12, 0x80, 0x36, 0xff, 0x24, 0xa8, 0x24, 0xa9, 0x7c, 0xab, 0xa, 0xaa, 0x19, 0xac, 0x11, 0x24, 0x33, 0x36, 0x60, 0x63 },
+{ 0x90, 0x51, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x2, 0x29, 0xfa, 0x8, 0x8, 0x49, 0xf8, 0x68, 0x8, 0x29, 0xf8, 0x8, 0x0, 0xb, 0xfe, 0x3a, 0x2, 0x69, 0xf8, 0x8, 0x88, 0x8, 0x70, 0xb, 0x8f },
+{ 0x90, 0x52, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x2, 0x27, 0xf2, 0x8, 0x88, 0x4, 0x90, 0x7f, 0xff, 0x2, 0xa0, 0x4, 0x90, 0x1f, 0xfc, 0x68, 0x8b, 0xf, 0xf8, 0x8, 0x88, 0x8, 0x88, 0xf, 0xf8 },
+{ 0x90, 0x53, 0x0, 0x0, 0x1, 0x80, 0x0, 0xc0, 0x0, 0x60, 0x4, 0x20, 0x4, 0x0, 0x4, 0x0, 0x14, 0xc, 0x14, 0x6, 0x14, 0x2, 0x34, 0xb, 0x24, 0x9, 0x64, 0x18, 0x6, 0x10, 0x3, 0xf0, 0x0, 0x0 },
+{ 0x90, 0x54, 0x10, 0x20, 0x10, 0x20, 0x17, 0xff, 0x10, 0x20, 0x59, 0xfc, 0x55, 0x4, 0x55, 0xfc, 0x51, 0x4, 0x11, 0xfc, 0x11, 0x4, 0x11, 0xfc, 0x10, 0x0, 0x17, 0xff, 0x10, 0x88, 0x11, 0x8c, 0x13, 0x6 },
+{ 0x90, 0x55, 0x10, 0x0, 0x11, 0xff, 0x11, 0x0, 0x11, 0x0, 0x7d, 0x7e, 0x11, 0x0, 0x11, 0x0, 0x11, 0xff, 0x1d, 0x48, 0x71, 0x49, 0x11, 0x4b, 0x11, 0x4a, 0x13, 0x4c, 0x12, 0x44, 0x16, 0x76, 0x30, 0xc3 },
+{ 0x90, 0x56, 0x4, 0x2, 0x4, 0xe, 0x7f, 0xb8, 0x21, 0x20, 0x33, 0x20, 0x12, 0x3f, 0x7f, 0xa4, 0x4, 0x24, 0x4, 0x24, 0x7f, 0xa4, 0x14, 0x24, 0x16, 0x24, 0x35, 0x64, 0x24, 0x44, 0x64, 0xc4, 0x4, 0x4 },
+{ 0x90, 0x57, 0x0, 0x0, 0x3f, 0xfe, 0x2, 0x20, 0x12, 0x24, 0x1a, 0x2c, 0xa, 0x28, 0x2, 0x20, 0x7f, 0xff, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8 },
+{ 0x90, 0x58, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xfe, 0x2, 0xa0, 0x6, 0xb0, 0xc, 0x98, 0x38, 0x8e, 0x4, 0x10, 0x4, 0x10, 0x7f, 0x7f, 0x4, 0x10, 0xe, 0x38, 0x15, 0x54, 0x34, 0xd6, 0x65, 0x93, 0x4, 0x10 },
+{ 0x90, 0x59, 0x10, 0x20, 0x13, 0xfe, 0x10, 0x20, 0x7d, 0xfc, 0x10, 0x50, 0x1b, 0xff, 0x34, 0x88, 0x31, 0x34, 0x36, 0xe3, 0x50, 0x20, 0x53, 0xfe, 0x10, 0xa8, 0x11, 0xac, 0x13, 0x26, 0x16, 0x23, 0x10, 0x20 },
+{ 0x90, 0x5a, 0x0, 0x0, 0x31, 0xfc, 0x18, 0x4, 0x9, 0xfc, 0x0, 0x4, 0x61, 0xfc, 0x30, 0x0, 0x17, 0xff, 0x4, 0x1, 0x5, 0xfd, 0x8, 0x84, 0x8, 0xcc, 0x18, 0x58, 0x10, 0x70, 0x31, 0xdc, 0x67, 0x7 },
+{ 0x90, 0x5b, 0x0, 0x0, 0x33, 0xfe, 0x1a, 0x52, 0xa, 0x52, 0x0, 0xd0, 0x61, 0x9f, 0x33, 0x0, 0x10, 0x20, 0x0, 0x20, 0x7, 0xff, 0x8, 0xa8, 0x8, 0xa8, 0x19, 0xac, 0x13, 0x26, 0x36, 0x23, 0x60, 0x20 },
+{ 0x90, 0x5c, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x3f, 0xfe, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x3f, 0xfe, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80 },
+{ 0x90, 0x5d, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xff, 0x10, 0x40, 0x50, 0xe0, 0x31, 0xb0, 0x13, 0x1c, 0x1e, 0x27, 0x10, 0xe0, 0x33, 0x88, 0x50, 0x38, 0x10, 0xe2, 0x33, 0x86, 0x20, 0x1c, 0x60, 0xf0, 0x7, 0x80 },
+{ 0x90, 0x5e, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x0, 0x80, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x0, 0x0, 0x7f, 0xff, 0x4, 0x10, 0xc, 0x18, 0x38, 0xe },
+{ 0x90, 0x5f, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10, 0x7e, 0xfe, 0x2, 0x92, 0x6, 0x92, 0x4, 0x92, 0xc, 0xfe, 0x18, 0x92, 0x3e, 0x92, 0x6b, 0x92, 0x8, 0xfe, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10 },
+{ 0x90, 0x60, 0x0, 0x80, 0x3f, 0xfe, 0x0, 0x80, 0x1f, 0xfc, 0x1, 0x40, 0x7f, 0xff, 0x4, 0x10, 0x18, 0xec, 0x77, 0x87, 0x0, 0x80, 0x3f, 0xff, 0x2, 0xa0, 0x6, 0xb0, 0x1c, 0x9c, 0x70, 0x87, 0x0, 0x80 },
+{ 0x90, 0x61, 0x8, 0x8, 0x18, 0x8, 0x30, 0x8, 0x62, 0x7f, 0x36, 0x49, 0xc, 0x49, 0x18, 0x49, 0x32, 0x7f, 0x7f, 0x49, 0x9, 0x49, 0x8, 0x49, 0x2a, 0x7f, 0x2b, 0x8, 0x69, 0x8, 0x48, 0x8, 0x8, 0x8 },
+{ 0x90, 0x62, 0x0, 0x0, 0x1f, 0xfe, 0x10, 0x80, 0x10, 0x80, 0x10, 0x80, 0x1f, 0xfc, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x1f, 0xfc, 0x10, 0x80, 0x10, 0x80, 0x10, 0x80, 0x10, 0x80, 0x1f, 0xfe, 0x0, 0x0 },
+{ 0x90, 0x63, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x4, 0x10, 0x1, 0x80, 0x0, 0xc0, 0x0, 0x60, 0x4, 0x20, 0x14, 0xc, 0x14, 0x6, 0x14, 0x3, 0x34, 0x1, 0x24, 0x8, 0x66, 0x18, 0x3, 0xf0 },
+{ 0x90, 0x64, 0x2, 0x20, 0x2, 0x20, 0x7f, 0xff, 0x2, 0x20, 0x4, 0x6, 0x3f, 0xbc, 0x11, 0x20, 0xa, 0x20, 0x7f, 0xbf, 0x4, 0x24, 0x7f, 0xa4, 0x15, 0x24, 0x15, 0x64, 0x35, 0x44, 0x64, 0xc4, 0x4, 0x4 },
+{ 0x90, 0x65, 0x8, 0x0, 0x8, 0x7e, 0x7f, 0x42, 0x22, 0x42, 0x36, 0x7e, 0x14, 0x42, 0x7f, 0x42, 0x8, 0x7e, 0x8, 0x42, 0x7f, 0x42, 0x28, 0x7e, 0x2c, 0x28, 0x6a, 0x28, 0x49, 0x69, 0x48, 0x49, 0x8, 0xc7 },
+{ 0x90, 0x66, 0x0, 0x10, 0x3c, 0x38, 0x0, 0x28, 0x7e, 0x6c, 0x0, 0xc6, 0x3d, 0x93, 0x0, 0x30, 0x0, 0x64, 0x3c, 0xcc, 0x0, 0x18, 0x0, 0x30, 0x3c, 0xe2, 0x24, 0x6, 0x24, 0xc, 0x24, 0x38, 0x3c, 0xe0 },
+{ 0x90, 0x67, 0x0, 0x40, 0x0, 0x80, 0x7, 0xf8, 0x4, 0x8, 0x4, 0x8, 0x7, 0xf8, 0x4, 0x8, 0x4, 0x9, 0x7, 0xfb, 0x4, 0xe, 0x4, 0xc, 0x3f, 0xf8, 0x0, 0x68, 0x1, 0xc8, 0x7, 0x8, 0x3c, 0x38 },
+{ 0x90, 0x68, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x4, 0x10, 0x6, 0x30, 0x2, 0x20, 0x2, 0x20, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80 },
+{ 0x90, 0x69, 0x0, 0x48, 0x30, 0xd8, 0x18, 0x90, 0x9, 0xfe, 0x3, 0x20, 0x5, 0x20, 0x1, 0xfc, 0x79, 0x20, 0x9, 0x20, 0x9, 0xfc, 0x9, 0x20, 0x9, 0x20, 0x9, 0xfe, 0x18, 0x0, 0x34, 0x0, 0x63, 0xff },
+{ 0x90, 0x6a, 0x8, 0x10, 0x1c, 0x10, 0x16, 0x10, 0x33, 0x10, 0x20, 0x10, 0x7e, 0x10, 0x9, 0xff, 0x8, 0x10, 0x7f, 0x10, 0x8, 0x10, 0x4a, 0x10, 0x6a, 0x10, 0x28, 0x10, 0xf, 0x10, 0x38, 0x10, 0x60, 0x10 },
+{ 0x90, 0x6b, 0x1f, 0xfc, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x82, 0x2e, 0xba, 0x20, 0x82, 0xe, 0xb8, 0x0, 0x0, 0x3f, 0xfe, 0x20, 0x0, 0x2f, 0xfc, 0x20, 0x0, 0x3f, 0xff, 0x64, 0x24, 0x47, 0x98, 0x1c, 0xf },
+{ 0x90, 0x6c, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x1, 0xc0, 0x1, 0x40, 0x1, 0x40, 0x3, 0x60, 0x2, 0x20, 0x6, 0x30, 0xc, 0x18, 0x18, 0xc, 0x30, 0x6, 0x60, 0x3 },
+{ 0x90, 0x6d, 0x4, 0x0, 0x4, 0x0, 0xc, 0x0, 0x9, 0xfe, 0x18, 0x0, 0x10, 0x0, 0x30, 0x0, 0x50, 0x0, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x13, 0xff, 0x10, 0x0, 0x10, 0x0 },
+{ 0x90, 0x6e, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xfe, 0x1, 0x2, 0x1, 0x2, 0x19, 0x2, 0xd, 0x2, 0x7, 0x2, 0x2, 0x2, 0x7, 0x2, 0x5, 0x82, 0xc, 0x86, 0x18, 0x4, 0x30, 0x4, 0x60, 0x3c, 0x0, 0x0 },
+{ 0x90, 0x6f, 0x0, 0x40, 0x0, 0x40, 0x1f, 0xff, 0x12, 0x20, 0x1f, 0xfe, 0x12, 0x22, 0x1f, 0xfe, 0x14, 0x20, 0x17, 0xa4, 0x34, 0x39, 0x27, 0xa3, 0x6c, 0x1e, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x7f, 0xff },
+{ 0x90, 0x70, 0x0, 0x6, 0x0, 0x1c, 0x0, 0xf0, 0x3f, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x0, 0x0 },
+{ 0x90, 0x71, 0xf, 0xf8, 0x0, 0x8, 0xf, 0xf8, 0x0, 0x8, 0xf, 0xf8, 0x0, 0x0, 0x3f, 0xbe, 0x4, 0x22, 0x7, 0xa2, 0x3c, 0x3e, 0x0, 0x8, 0x7f, 0xff, 0x4, 0x8, 0x6, 0x8, 0x2, 0x8, 0x0, 0x38 },
+{ 0x90, 0x72, 0x4, 0x10, 0x3f, 0xfe, 0x4, 0x10, 0x4, 0x10, 0x7, 0xf0, 0x4, 0x10, 0x4, 0x10, 0x7, 0xf0, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x11, 0x20, 0x12, 0x20, 0x1c, 0x3e, 0x10, 0x0, 0x1f, 0xfe },
+{ 0x90, 0x73, 0x0, 0x0, 0xf, 0xfc, 0x8, 0x4, 0x8, 0x4, 0x8, 0x4, 0xf, 0xfc, 0x8, 0x8, 0x8, 0x8, 0x9, 0x88, 0x18, 0xcc, 0x10, 0x64, 0x30, 0x6, 0x63, 0x3, 0x1, 0x80, 0x0, 0xc0, 0x0, 0x60 },
+{ 0x90, 0x74, 0x0, 0x0, 0x3f, 0x7e, 0x24, 0x22, 0x3f, 0x36, 0x21, 0x14, 0x3f, 0x18, 0x24, 0x2c, 0x3f, 0x47, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x38 },
+{ 0x90, 0x75, 0x0, 0x0, 0x3d, 0xfc, 0x0, 0x44, 0x7e, 0x44, 0x0, 0x44, 0x3c, 0x44, 0x0, 0x44, 0x1, 0xf4, 0x3c, 0x44, 0x0, 0x44, 0x0, 0x44, 0x3c, 0x44, 0x24, 0x44, 0x24, 0xc5, 0x24, 0x85, 0x3d, 0x83 },
+{ 0x90, 0x76, 0x0, 0x0, 0x33, 0xf8, 0x18, 0x8, 0x8, 0x88, 0x0, 0x88, 0x0, 0x88, 0x0, 0x88, 0x7b, 0xf8, 0x8, 0x88, 0x8, 0x88, 0x8, 0x8c, 0x8, 0x85, 0x8, 0x87, 0x18, 0x82, 0x34, 0x0, 0x63, 0xff },
+{ 0x90, 0x77, 0x0, 0x20, 0x3e, 0x20, 0x23, 0xff, 0x26, 0x20, 0x25, 0xfe, 0x2d, 0x22, 0x29, 0x22, 0x29, 0xfe, 0x25, 0x22, 0x25, 0x22, 0x25, 0xfe, 0x24, 0x20, 0x27, 0xff, 0x2c, 0x20, 0x20, 0x20, 0x20, 0x20 },
+{ 0x90, 0x78, 0x22, 0x0, 0x22, 0xfe, 0x7f, 0x22, 0x22, 0x22, 0x22, 0xa2, 0x3e, 0x62, 0x8, 0x22, 0x7f, 0x22, 0x49, 0x32, 0x49, 0x2a, 0x7f, 0x2a, 0x8, 0x22, 0x7f, 0x62, 0x8, 0x46, 0x8, 0xc4, 0x9, 0x9c },
+{ 0x90, 0x79, 0x8, 0x20, 0x8, 0x20, 0x1f, 0xfe, 0x34, 0x50, 0x66, 0x98, 0x2, 0x8, 0x3f, 0xfe, 0x0, 0x2, 0x1f, 0xe2, 0x0, 0x2, 0x1f, 0xe2, 0x10, 0x22, 0x10, 0x22, 0x1f, 0xe2, 0x0, 0x2, 0x0, 0xe },
+{ 0x90, 0x7a, 0x0, 0x0, 0x3b, 0xfe, 0x1, 0x40, 0x7d, 0x40, 0x1, 0x7e, 0x39, 0xd2, 0x1, 0x52, 0x1, 0x56, 0x39, 0x54, 0x1, 0xdc, 0x1, 0x48, 0x39, 0x48, 0x29, 0x5c, 0x29, 0xd4, 0x2b, 0x66, 0x38, 0x43 },
+{ 0x90, 0x7b, 0x4, 0x0, 0xd, 0xff, 0x18, 0x10, 0x30, 0xfe, 0x64, 0x82, 0xc, 0x82, 0x8, 0xfe, 0x18, 0x82, 0x32, 0x82, 0x66, 0xfe, 0x4, 0x82, 0xc, 0x82, 0x18, 0xfe, 0x30, 0x44, 0x60, 0xc6, 0x1, 0x83 },
+{ 0x90, 0x7c, 0x0, 0x20, 0x7f, 0xa0, 0x14, 0x20, 0x14, 0x7f, 0x7f, 0x50, 0x55, 0x90, 0x55, 0x10, 0x55, 0x1e, 0x67, 0x10, 0x41, 0x10, 0x41, 0x10, 0x7f, 0x1e, 0x41, 0x10, 0x41, 0x10, 0x7f, 0x10, 0x0, 0x10 },
+{ 0x90, 0x7d, 0x0, 0x0, 0x3f, 0xfe, 0x20, 0x2, 0x21, 0x82, 0x2c, 0xca, 0x26, 0x4a, 0x22, 0x1a, 0x20, 0x12, 0x21, 0xb2, 0x20, 0x62, 0x20, 0xb2, 0x23, 0x9a, 0x2e, 0xa, 0x20, 0x2, 0x3f, 0xfe, 0x0, 0x0 },
+{ 0x90, 0x7e, 0x0, 0x0, 0x3f, 0xff, 0x20, 0x0, 0x20, 0x4, 0x3f, 0x84, 0x20, 0x4, 0x2f, 0x7f, 0x29, 0x4, 0x29, 0x24, 0x29, 0x34, 0x2f, 0x14, 0x20, 0x4, 0x69, 0x4, 0x49, 0x4, 0x47, 0x84, 0x1c, 0x1c },
+{ 0x90, 0x80, 0x0, 0x0, 0x33, 0xfe, 0x18, 0x0, 0x9, 0xfc, 0x1, 0x4, 0x1, 0x4, 0x1, 0x4, 0x79, 0xfc, 0x8, 0x0, 0x8, 0x88, 0x8, 0xd8, 0x8, 0x50, 0xb, 0xfe, 0x18, 0x0, 0x34, 0x0, 0x63, 0xff },
+{ 0x90, 0x81, 0x0, 0x80, 0x0, 0x80, 0x78, 0x80, 0x49, 0xff, 0x49, 0x1, 0x4b, 0x23, 0x4e, 0x22, 0x48, 0x20, 0x48, 0x20, 0x48, 0x70, 0x48, 0x50, 0x78, 0xd8, 0x0, 0x88, 0x1, 0x8c, 0x3, 0x6, 0x6, 0x3 },
+{ 0x90, 0x82, 0x0, 0x18, 0x0, 0xf0, 0x1f, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x8, 0x88, 0x8, 0x88, 0x7f, 0xff, 0x8, 0x88, 0x8, 0x88, 0x8, 0x88, 0x3f, 0xfe, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x90, 0x83, 0x4, 0x8, 0x8, 0x8, 0x3e, 0x8, 0x22, 0x7f, 0x22, 0x49, 0x22, 0x49, 0x3e, 0x49, 0x20, 0x49, 0x20, 0x49, 0x3e, 0x49, 0x22, 0x49, 0x22, 0x49, 0x22, 0x4b, 0x22, 0x8, 0x3e, 0x8, 0x0, 0x8 },
+{ 0x90, 0x84, 0x10, 0x44, 0x10, 0xcc, 0x10, 0x88, 0x11, 0xff, 0x7b, 0x10, 0x15, 0x10, 0x11, 0x10, 0x11, 0xfe, 0x19, 0x10, 0x71, 0x10, 0x11, 0x10, 0x11, 0xfe, 0x11, 0x10, 0x11, 0x10, 0x11, 0x10, 0x31, 0xff },
+{ 0x90, 0x85, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x82, 0x7e, 0x86, 0x2, 0x8c, 0x2, 0xd8, 0x6, 0xc0, 0x4, 0xe0, 0xc, 0xa0, 0x8, 0xb0, 0x18, 0x98, 0x30, 0x8c, 0x60, 0x87, 0x0, 0x80, 0x3, 0x80 },
+{ 0x90, 0x86, 0x8, 0x40, 0x8, 0x40, 0x8, 0x40, 0x2a, 0x7f, 0x2e, 0xc1, 0x2c, 0x93, 0x69, 0x92, 0x48, 0x10, 0x8, 0x10, 0x8, 0x38, 0x1c, 0x28, 0x14, 0x28, 0x16, 0x6c, 0x33, 0x44, 0x20, 0xc6, 0x61, 0x83 },
+{ 0x90, 0x87, 0x0, 0xc, 0x78, 0x38, 0x4b, 0xe0, 0x48, 0x20, 0x4b, 0xfe, 0x79, 0x24, 0x49, 0x24, 0x49, 0x24, 0x4f, 0xff, 0x79, 0x24, 0x49, 0x24, 0x49, 0x24, 0x4b, 0xfe, 0x78, 0x20, 0x0, 0x20, 0x7, 0xff },
+{ 0x90, 0x88, 0x8, 0x20, 0x4a, 0x20, 0x6e, 0xfc, 0x2c, 0x24, 0x8, 0x64, 0x7e, 0x45, 0x8, 0xc5, 0x9, 0x83, 0x1c, 0x10, 0x1a, 0x10, 0x2a, 0xff, 0x28, 0x10, 0x48, 0x10, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10 },
+{ 0x90, 0x89, 0x0, 0x0, 0x3f, 0x7e, 0x21, 0x42, 0x13, 0x26, 0xd, 0x1a, 0x31, 0x62, 0x0, 0x80, 0x3f, 0xfe, 0x4, 0x10, 0xa, 0x28, 0x31, 0x46, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80 },
+{ 0x90, 0x8a, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0x7f, 0xff, 0x8, 0x8, 0xf, 0xf8, 0x2, 0x42, 0x6, 0x66, 0x1c, 0x2c, 0x74, 0x30, 0x4, 0x18, 0x7, 0xcc, 0x3c, 0x7 },
+{ 0x90, 0x8b, 0x1, 0x4, 0x31, 0x8c, 0x18, 0x88, 0xb, 0xff, 0x0, 0x40, 0x0, 0x82, 0x3, 0x46, 0x78, 0x6c, 0x8, 0xb0, 0xb, 0x28, 0x8, 0x6c, 0x8, 0xa6, 0xb, 0x23, 0x18, 0xe0, 0x34, 0x0, 0x63, 0xff },
+{ 0x90, 0x8c, 0x0, 0x20, 0x7f, 0x20, 0x14, 0xfc, 0x14, 0x24, 0x7f, 0x24, 0x55, 0x65, 0x55, 0x45, 0x55, 0xc3, 0x55, 0x10, 0x67, 0x10, 0x41, 0xff, 0x41, 0x10, 0x7f, 0x10, 0x41, 0x10, 0x41, 0x10, 0x7f, 0x10 },
+{ 0x90, 0x8d, 0x8, 0x24, 0x1c, 0x2c, 0x16, 0x28, 0x33, 0x7f, 0x20, 0x48, 0x7e, 0xc8, 0x9, 0x48, 0x8, 0x7e, 0x7f, 0x48, 0x8, 0x48, 0x4a, 0x48, 0x6a, 0x7e, 0x28, 0x48, 0xf, 0x48, 0x38, 0x48, 0x60, 0x7f },
+{ 0x90, 0x8e, 0x8, 0x6, 0x1c, 0x1c, 0x16, 0xf0, 0x33, 0x10, 0x20, 0xff, 0x7e, 0x52, 0x8, 0x52, 0x8, 0x52, 0x7e, 0xff, 0x8, 0x52, 0x4a, 0x52, 0x6a, 0x52, 0x28, 0xff, 0xe, 0x10, 0x38, 0x10, 0x60, 0xff },
+{ 0x90, 0x8f, 0x0, 0x8, 0x3d, 0x8, 0x25, 0xbf, 0x24, 0x88, 0x24, 0x1e, 0x28, 0x12, 0x28, 0x32, 0x25, 0x9e, 0x24, 0x92, 0x24, 0x92, 0x24, 0x9e, 0x24, 0x92, 0x2c, 0x92, 0x21, 0x96, 0x23, 0x40, 0x26, 0x3f },
+{ 0x90, 0x90, 0x0, 0x20, 0x1, 0x22, 0x7d, 0x22, 0x11, 0x22, 0x11, 0xfe, 0x10, 0x0, 0x13, 0xff, 0x7c, 0x20, 0x10, 0x40, 0x11, 0xfe, 0x11, 0x52, 0x11, 0x52, 0x1d, 0x52, 0x71, 0x52, 0x1, 0x52, 0x1, 0x56 },
+{ 0x90, 0x91, 0x3e, 0x8, 0x22, 0x88, 0x2e, 0xff, 0x2a, 0x48, 0x2a, 0x1e, 0x7f, 0x12, 0x41, 0x32, 0x3e, 0xde, 0x22, 0x52, 0x3e, 0x52, 0x22, 0x5e, 0x3e, 0x52, 0x22, 0x52, 0x22, 0x56, 0x22, 0xe0, 0x26, 0x9f },
+{ 0x90, 0x92, 0x0, 0x80, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x0, 0x0, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x2, 0x27, 0xf2, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x80, 0x8, 0x88, 0x18, 0x8c, 0x70, 0x87, 0x3, 0x80 },
+{ 0x90, 0x93, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x0, 0x0, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x0, 0x7, 0xf0, 0x4, 0x10, 0x7, 0xf0, 0x0, 0x0, 0x3f, 0xfe, 0x20, 0x2, 0x27, 0xf2, 0x24, 0x12, 0x27, 0xf6 },
+{ 0x90, 0x94, 0x4, 0x10, 0x24, 0x90, 0x35, 0x90, 0x15, 0x3f, 0x7f, 0xa2, 0x14, 0x62, 0x17, 0x12, 0x35, 0x96, 0x64, 0x94, 0x8, 0x14, 0x7f, 0xcc, 0x11, 0x8, 0x13, 0x18, 0x3e, 0x14, 0xb, 0x36, 0x71, 0x63 },
+{ 0x90, 0x95, 0x10, 0x0, 0x11, 0xff, 0x11, 0x0, 0x7d, 0x0, 0x11, 0x2, 0x11, 0x66, 0x39, 0x34, 0x35, 0x1c, 0x35, 0x8, 0x51, 0x1c, 0x51, 0x36, 0x11, 0x62, 0x11, 0x0, 0x11, 0x0, 0x11, 0xff, 0x10, 0x0 },
+{ 0x90, 0x96, 0x8, 0x80, 0x8, 0xfe, 0x3e, 0x22, 0x8, 0xaa, 0x8, 0xfa, 0x7f, 0x26, 0x8, 0x4c, 0x8, 0x80, 0x28, 0xfe, 0x2e, 0x22, 0x28, 0xaa, 0x28, 0xfa, 0x28, 0x26, 0x38, 0xcc, 0x6e, 0x0, 0x43, 0xff },
+{ 0x90, 0x97, 0x10, 0x12, 0x3f, 0x96, 0x48, 0x94, 0x2a, 0xbf, 0x2a, 0xa4, 0x3e, 0xe4, 0x11, 0xa4, 0x23, 0x3e, 0x10, 0x24, 0x3f, 0xa4, 0x48, 0xa4, 0x2a, 0xbe, 0x2a, 0xa4, 0x3e, 0xa4, 0x11, 0xa4, 0x23, 0x3f },
+{ 0x90, 0x98, 0x10, 0x0, 0x11, 0xfe, 0x11, 0x2, 0x11, 0x2, 0x7d, 0xfe, 0x11, 0x10, 0x11, 0x10, 0x11, 0xff, 0x1d, 0x10, 0x71, 0x10, 0x11, 0x7e, 0x11, 0x42, 0x13, 0x42, 0x12, 0x42, 0x16, 0x42, 0x30, 0x7e },
+{ 0x90, 0x99, 0x8, 0x4, 0x8, 0xc, 0x8, 0x18, 0x7e, 0x30, 0x8, 0xe2, 0x8, 0x6, 0x1c, 0xc, 0x1a, 0x18, 0x1a, 0x30, 0x28, 0xe1, 0x28, 0x3, 0x48, 0x6, 0x8, 0xc, 0x8, 0x18, 0x8, 0x70, 0x9, 0xc0 },
+{ 0x90, 0x9a, 0x8, 0x0, 0x8, 0xfc, 0x8, 0x84, 0x7e, 0x84, 0x8, 0xfc, 0x8, 0x84, 0x1c, 0x84, 0x1a, 0xfc, 0x1a, 0x0, 0x29, 0xfe, 0x29, 0x2, 0x49, 0x2, 0x9, 0xfe, 0x9, 0x2, 0x9, 0x2, 0x9, 0xfe },
+{ 0x90, 0x9b, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x2, 0x27, 0xf2, 0x4, 0x10, 0x4, 0x10, 0x7, 0xf0, 0x4, 0x0, 0x7, 0xf8, 0x4, 0x8, 0x4, 0x8, 0x7, 0xf8 },
+{ 0x90, 0x9c, 0x4, 0x0, 0x4, 0x7f, 0x4, 0x8, 0x3f, 0xbe, 0x24, 0xa2, 0x24, 0x22, 0x3f, 0x3e, 0x21, 0x22, 0x33, 0x22, 0x2a, 0x3e, 0x2e, 0x22, 0x24, 0x22, 0x6e, 0x3e, 0x4b, 0x14, 0x19, 0x36, 0x0, 0x63 },
+{ 0x90, 0x9d, 0x0, 0x80, 0x8, 0x98, 0x8, 0x8c, 0x18, 0x96, 0x30, 0xb2, 0x63, 0xe0, 0x0, 0xc8, 0x3, 0x10, 0xf, 0xfe, 0x78, 0x40, 0xf, 0xfc, 0x8, 0x40, 0xf, 0xfc, 0x8, 0x40, 0x8, 0x40, 0xf, 0xff },
+{ 0x90, 0x9e, 0x10, 0x0, 0x11, 0xfe, 0x11, 0x2, 0x7d, 0x2, 0x5, 0xfe, 0xd, 0x10, 0x9, 0x10, 0x1b, 0xff, 0x15, 0x10, 0x39, 0x10, 0x55, 0x7e, 0x15, 0x42, 0x13, 0x42, 0x12, 0x42, 0x16, 0x42, 0x10, 0x7e },
+{ 0x90, 0x9f, 0x0, 0x4, 0x23, 0xe8, 0x34, 0x51, 0x12, 0x8a, 0x1, 0x4, 0x46, 0xfb, 0x60, 0x0, 0x21, 0xfc, 0x1, 0x4, 0x9, 0x4, 0x9, 0xfc, 0x18, 0x0, 0x11, 0x4, 0x31, 0x8c, 0x20, 0x88, 0x67, 0xff },
+{ 0x90, 0xa0, 0x10, 0x0, 0x17, 0xdf, 0x12, 0x49, 0x11, 0x45, 0x78, 0x41, 0x11, 0xc7, 0x16, 0x59, 0x10, 0x41, 0x18, 0x20, 0x71, 0xfe, 0x11, 0x2, 0x11, 0x2, 0x11, 0xfe, 0x11, 0x2, 0x11, 0x2, 0x31, 0xfe },
+{ 0x90, 0xa1, 0x0, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x10, 0x7f, 0xff, 0x0, 0x10, 0x0, 0x10, 0xc, 0x10, 0x6, 0x10, 0x3, 0x10, 0x1, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x70 },
+{ 0x90, 0xa2, 0x0, 0x0, 0x11, 0x8, 0x11, 0x8, 0x11, 0x8, 0x11, 0x8, 0x7f, 0xff, 0x11, 0x8, 0x11, 0x8, 0x11, 0x8, 0x11, 0x8, 0x11, 0xf8, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x1f, 0xfe, 0x0, 0x0 },
+{ 0x90, 0xa3, 0x1, 0x0, 0x21, 0x3f, 0x37, 0xc8, 0x11, 0x1e, 0x7, 0xd2, 0x45, 0x52, 0x65, 0x5e, 0x25, 0x52, 0x7, 0xd2, 0x11, 0x1e, 0x13, 0x12, 0x13, 0x92, 0x35, 0x5e, 0x25, 0x48, 0x29, 0x12, 0x61, 0x21 },
+{ 0x90, 0xa4, 0x8, 0x20, 0x8, 0x20, 0x8, 0x3c, 0x7f, 0xa4, 0x0, 0x64, 0x3f, 0x44, 0x29, 0xcc, 0x29, 0x8, 0x29, 0x8, 0x3f, 0x8, 0x29, 0x1c, 0x29, 0x14, 0x29, 0x34, 0x3f, 0x26, 0x0, 0x62, 0x0, 0xc3 },
+{ 0x90, 0xa5, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x80, 0x8, 0x80, 0x8, 0xfc, 0x1c, 0x80, 0x16, 0x80, 0x33, 0x80, 0x60, 0xff },
+{ 0x90, 0xa6, 0x0, 0x20, 0x0, 0x20, 0x67, 0xff, 0x30, 0x20, 0x13, 0xfe, 0x0, 0x22, 0x7, 0xff, 0x0, 0x22, 0x13, 0xfe, 0x10, 0x40, 0x17, 0xff, 0x30, 0x84, 0x21, 0x8, 0x23, 0xf0, 0x60, 0x5e, 0x7, 0x83 },
+{ 0x90, 0xa7, 0x4, 0x2, 0x14, 0x12, 0x14, 0x12, 0x3f, 0xd2, 0x64, 0x12, 0x4, 0x12, 0x7f, 0xf2, 0x4, 0x12, 0x4, 0x12, 0x3f, 0xd2, 0x24, 0x52, 0x24, 0x52, 0x24, 0x42, 0x24, 0x42, 0x24, 0xc2, 0x4, 0xe },
+{ 0x90, 0xa8, 0x8, 0x10, 0x3f, 0x10, 0x8, 0x10, 0x7f, 0xfc, 0x12, 0x14, 0x2b, 0x94, 0x48, 0x74, 0x3f, 0x24, 0x8, 0x35, 0xf, 0x55, 0x78, 0x3, 0x0, 0x80, 0x3f, 0xfe, 0x1, 0x2, 0x6, 0x6, 0x78, 0x1c },
+{ 0x90, 0xa9, 0x10, 0x10, 0x10, 0x90, 0x10, 0x90, 0x10, 0x90, 0x7c, 0xfe, 0x15, 0x90, 0x15, 0x10, 0x24, 0x10, 0x2c, 0x10, 0x28, 0xfe, 0x48, 0x10, 0x78, 0x10, 0x14, 0x10, 0x14, 0x10, 0x31, 0xff, 0x60, 0x0 },
+{ 0x90, 0xaa, 0x4, 0x0, 0xd, 0xfe, 0x8, 0x20, 0x18, 0x20, 0x30, 0x20, 0x65, 0x20, 0xd, 0x20, 0x9, 0x3e, 0x19, 0x20, 0x39, 0x20, 0x69, 0x20, 0x9, 0x20, 0x9, 0x20, 0x9, 0x20, 0xb, 0xff, 0x8, 0x0 },
+{ 0x90, 0xab, 0x10, 0x20, 0x11, 0x20, 0x11, 0x20, 0x19, 0x20, 0x55, 0xfe, 0x53, 0x20, 0x52, 0x20, 0x50, 0x20, 0x10, 0x20, 0x13, 0xfe, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x17, 0xff, 0x10, 0x0 },
+{ 0x90, 0xac, 0x0, 0x48, 0x0, 0x4c, 0x0, 0x44, 0x1f, 0xfe, 0x10, 0x40, 0x10, 0x40, 0x1f, 0x42, 0x11, 0x66, 0x11, 0x24, 0x11, 0x2c, 0x11, 0x38, 0x11, 0x10, 0x13, 0x39, 0x32, 0x6b, 0x26, 0xce, 0x61, 0x84 },
+{ 0x90, 0xad, 0x0, 0x40, 0x0, 0x40, 0x7f, 0x40, 0x8, 0x7f, 0x8, 0xc4, 0x8, 0x84, 0x29, 0xc4, 0x2e, 0x4c, 0x28, 0x68, 0x28, 0x38, 0x28, 0x10, 0x28, 0x38, 0x2f, 0x28, 0x38, 0x6c, 0x60, 0xc6, 0x1, 0x83 },
+{ 0x90, 0xae, 0x8, 0x20, 0x7f, 0xa0, 0x8, 0x3f, 0x3f, 0x64, 0x29, 0xc4, 0x29, 0x2c, 0x3f, 0x18, 0x1a, 0x34, 0x2b, 0x66, 0x49, 0x3, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x80, 0x8, 0xf8, 0x8, 0x80, 0x7f, 0xff },
+{ 0x90, 0xaf, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x0, 0x80, 0x8, 0x80, 0xf, 0xfc, 0x18, 0x80, 0x30, 0x80, 0xf, 0xf8, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff },
+{ 0x90, 0xb0, 0x0, 0x20, 0x0, 0x20, 0x79, 0xfe, 0x48, 0x20, 0x48, 0xfc, 0x48, 0x20, 0x7b, 0xff, 0x48, 0x0, 0x48, 0xfc, 0x48, 0x84, 0x48, 0xfc, 0x78, 0x84, 0x0, 0xfc, 0x0, 0x84, 0x0, 0x84, 0x0, 0x9c },
+{ 0x90, 0xb1, 0x10, 0x20, 0x10, 0x20, 0x13, 0xff, 0x7c, 0x20, 0x11, 0xfe, 0x10, 0x22, 0x33, 0xff, 0x38, 0x22, 0x35, 0xfe, 0x50, 0x20, 0x53, 0xff, 0x10, 0x44, 0x10, 0x8c, 0x11, 0xf8, 0x10, 0x2e, 0x13, 0xc3 },
+{ 0x90, 0xb2, 0x8, 0x0, 0x9, 0xff, 0x8, 0x28, 0x7e, 0x28, 0x9, 0xff, 0x9, 0x29, 0x1d, 0x29, 0x1b, 0x29, 0x19, 0x29, 0x29, 0x49, 0x29, 0x87, 0x49, 0x1, 0x9, 0x1, 0x9, 0x1, 0x9, 0xff, 0x8, 0x0 },
+{ 0x90, 0xb3, 0x0, 0x0, 0x3f, 0xfe, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x10, 0x80, 0x10, 0x80, 0x10, 0xfc, 0x10, 0x80, 0x10, 0x80, 0x10, 0x80, 0x10, 0x80, 0x10, 0x80, 0x10, 0x80, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x90, 0xb4, 0x0, 0x20, 0x30, 0x20, 0x1b, 0xfe, 0x8, 0x20, 0x1, 0xfc, 0x60, 0x20, 0x37, 0xff, 0x10, 0x0, 0x1, 0xfc, 0x9, 0x4, 0x9, 0xfc, 0x19, 0x4, 0x11, 0xfc, 0x31, 0x4, 0x21, 0x4, 0x61, 0x1c },
+{ 0x90, 0xb5, 0x8, 0x20, 0x29, 0x20, 0x29, 0x20, 0x29, 0x20, 0x3d, 0xfe, 0x6b, 0x20, 0x4a, 0x20, 0x8, 0x20, 0xc, 0x20, 0x39, 0xfc, 0x68, 0x20, 0x8, 0x20, 0x8, 0x20, 0x8, 0x20, 0xb, 0xff, 0x8, 0x0 },
+{ 0x90, 0xb6, 0x0, 0x80, 0x8, 0x80, 0x8, 0x80, 0x8, 0x80, 0x1f, 0xfe, 0x10, 0x80, 0x30, 0x80, 0x60, 0x80, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x90, 0xb7, 0x0, 0x28, 0x0, 0x24, 0x1f, 0xfe, 0x10, 0x20, 0x1f, 0x32, 0x11, 0x14, 0x11, 0x8, 0x31, 0x1d, 0x27, 0x67, 0x60, 0x2, 0x1f, 0xfc, 0x12, 0x44, 0x12, 0x44, 0x12, 0x44, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x90, 0xb8, 0x8, 0x20, 0xa, 0x20, 0x4b, 0xfe, 0x6a, 0x20, 0x28, 0xfc, 0x8, 0x20, 0x7f, 0xff, 0x8, 0x0, 0x1c, 0xfc, 0x1a, 0x84, 0x2a, 0xfc, 0x28, 0x84, 0x48, 0xfc, 0x8, 0x84, 0x8, 0x84, 0x8, 0x9c },
+{ 0x90, 0xb9, 0x7f, 0x0, 0x22, 0x7e, 0x3e, 0x42, 0x22, 0x42, 0x22, 0x42, 0x3e, 0x42, 0x22, 0x42, 0x22, 0x7e, 0x7e, 0x0, 0x2, 0x0, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x80, 0xf, 0xf8, 0x0, 0x80, 0x7f, 0xff },
+{ 0x90, 0xba, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x0, 0x10, 0x0, 0x30, 0x0, 0x20, 0x0, 0x60, 0x0 },
+{ 0x90, 0xbb, 0x14, 0x2, 0x1f, 0x92, 0x24, 0x12, 0x7f, 0xd2, 0x4, 0x12, 0x3f, 0x92, 0x24, 0x82, 0x24, 0x82, 0x25, 0x8e, 0x0, 0x80, 0x7f, 0xff, 0x1, 0x44, 0x6, 0x68, 0x7c, 0x30, 0x7, 0x9c, 0x1c, 0x7 },
+{ 0x90, 0xbc, 0x0, 0x0, 0x7f, 0xff, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x3f, 0xfe, 0x22, 0x22, 0x22, 0x22, 0x26, 0x22, 0x2c, 0x32, 0x38, 0x1e, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x3f, 0xfe, 0x0, 0x0 },
+{ 0x90, 0xbd, 0x0, 0xa, 0x38, 0x9, 0x0, 0x8, 0x7d, 0xff, 0x1, 0x8, 0x39, 0x8, 0x1, 0xe8, 0x1, 0x2a, 0x39, 0x2a, 0x1, 0x2a, 0x1, 0x2c, 0x39, 0x24, 0x29, 0x64, 0x29, 0xd, 0x29, 0x17, 0x3a, 0x62 },
+{ 0x90, 0xbe, 0x8, 0x6, 0x7f, 0x7c, 0x8, 0x40, 0x7f, 0x7f, 0x8, 0x84, 0x1b, 0xe4, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x0, 0xf, 0xf8, 0x0, 0x0, 0xf, 0xf8, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x4, 0x1f, 0xfc },
+{ 0x90, 0xbf, 0x0, 0x10, 0x3c, 0x10, 0x1, 0xff, 0x7e, 0x10, 0x0, 0xfe, 0x3c, 0x10, 0x1, 0xff, 0x0, 0x0, 0x3c, 0xfe, 0x0, 0x82, 0x0, 0xfe, 0x3c, 0x82, 0x24, 0xfe, 0x24, 0x82, 0x24, 0x82, 0x3c, 0x8e },
+{ 0x90, 0xc0, 0x1, 0x6, 0x31, 0x3c, 0x19, 0x20, 0x9, 0x20, 0x7, 0xbf, 0x1, 0x24, 0x1, 0x24, 0x71, 0xa4, 0x17, 0x24, 0x11, 0x24, 0x11, 0x64, 0x11, 0x44, 0x11, 0xc4, 0x33, 0x4, 0x28, 0x0, 0x67, 0xff },
+{ 0x90, 0xc1, 0x0, 0x0, 0x7f, 0x7e, 0x14, 0x42, 0x14, 0x7e, 0x7f, 0x42, 0x55, 0x42, 0x55, 0x7e, 0x55, 0x10, 0x67, 0x50, 0x41, 0x7e, 0x41, 0x90, 0x7f, 0x10, 0x41, 0x7e, 0x41, 0x10, 0x7f, 0x10, 0x0, 0xff },
+{ 0x90, 0xc2, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x38 },
+{ 0x90, 0xc3, 0x8, 0x20, 0x8, 0x3c, 0x7f, 0x44, 0x8, 0x88, 0x3e, 0x7e, 0x8, 0x12, 0x7f, 0x12, 0x0, 0xff, 0x3e, 0x12, 0x22, 0x12, 0x3e, 0x7e, 0x22, 0x10, 0x3e, 0x10, 0x22, 0x10, 0x22, 0x10, 0x26, 0x70 },
+{ 0x90, 0xc4, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x4, 0x10, 0x3, 0x60, 0x1, 0xc0, 0xf, 0x78, 0x78, 0xf, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x18, 0x8, 0x30, 0x8, 0x60, 0x8 },
+{ 0x90, 0xc5, 0x2, 0x82, 0xe, 0xc6, 0x78, 0x44, 0x8, 0xfe, 0x8, 0x82, 0x7e, 0x82, 0x8, 0x82, 0x8, 0x82, 0x1c, 0xfe, 0x1a, 0x28, 0x2a, 0x28, 0x28, 0x28, 0x48, 0x68, 0x8, 0x49, 0x8, 0xc9, 0x9, 0x87 },
+{ 0x90, 0xc6, 0x0, 0x20, 0x3c, 0x3e, 0x24, 0x44, 0x24, 0x88, 0x25, 0xff, 0x3c, 0x80, 0x24, 0x80, 0x24, 0xbc, 0x24, 0xa4, 0x3c, 0xa4, 0x24, 0xa4, 0x24, 0xac, 0x24, 0xa0, 0x24, 0xa1, 0x65, 0x33, 0x4c, 0x1e },
+{ 0x90, 0xc7, 0x4, 0x20, 0x8, 0x40, 0x1f, 0xfe, 0x30, 0x80, 0x5f, 0xfc, 0x10, 0x80, 0x1f, 0xfc, 0x10, 0x80, 0x1f, 0xff, 0x0, 0x0, 0x3f, 0xfc, 0x4, 0x8, 0x3, 0x30, 0x0, 0xc0, 0x7, 0x38, 0x7c, 0xf },
+{ 0x90, 0xc8, 0x0, 0x40, 0x0, 0x40, 0x1f, 0xff, 0x10, 0x0, 0x11, 0x8, 0x17, 0xfe, 0x11, 0x8, 0x11, 0x8, 0x11, 0xf8, 0x10, 0x40, 0x17, 0xfe, 0x14, 0x42, 0x34, 0x42, 0x24, 0x42, 0x64, 0x4e, 0x0, 0x40 },
+{ 0x90, 0xc9, 0x8, 0x48, 0x8, 0x48, 0x9, 0xfe, 0xc, 0x48, 0x2a, 0x48, 0x28, 0x48, 0x2b, 0xff, 0x68, 0x0, 0x48, 0x0, 0x8, 0xfc, 0x8, 0x84, 0x8, 0x84, 0x8, 0xfc, 0x8, 0x84, 0x8, 0x84, 0x8, 0xfc },
+{ 0x90, 0xca, 0x0, 0x24, 0x0, 0x26, 0x0, 0x22, 0x3f, 0xff, 0x20, 0x20, 0x24, 0x20, 0x27, 0xa2, 0x24, 0x32, 0x3f, 0xd6, 0x22, 0x14, 0x2a, 0x9c, 0x2a, 0x88, 0x2a, 0xc8, 0x6a, 0x5d, 0x46, 0x37, 0x40, 0x62 },
+{ 0x90, 0xcb, 0x0, 0x18, 0x0, 0xf0, 0x1f, 0x80, 0x10, 0x0, 0x10, 0x0, 0x1f, 0xff, 0x10, 0x40, 0x10, 0x40, 0x13, 0x40, 0x11, 0xf0, 0x10, 0x5c, 0x30, 0x46, 0x20, 0x40, 0x60, 0x40, 0x0, 0x40, 0x0, 0x40 },
+{ 0x90, 0xcc, 0x2, 0x20, 0x2, 0x20, 0x3f, 0xfe, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x7f, 0xff, 0x0, 0x0, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8 },
+{ 0x90, 0xcd, 0x8, 0x6, 0x8, 0x1c, 0x8, 0xf0, 0x7e, 0x80, 0x8, 0x80, 0x8, 0xff, 0x1c, 0x88, 0x1a, 0x88, 0x1a, 0x88, 0x28, 0x88, 0x28, 0x88, 0x48, 0x88, 0x9, 0x88, 0x9, 0x8, 0xb, 0x8, 0x8, 0x8 },
+{ 0x90, 0xce, 0x0, 0x0, 0x7f, 0xff, 0x1, 0x0, 0x3, 0x0, 0x2, 0x0, 0x6, 0x0, 0x4, 0x0, 0xf, 0xfc, 0x1c, 0x4, 0x34, 0x4, 0x64, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x7, 0xfc, 0x0, 0x0 },
+{ 0x90, 0xcf, 0x4, 0x10, 0x1d, 0xff, 0x70, 0x10, 0x10, 0xfe, 0x10, 0x10, 0x7d, 0xff, 0x10, 0x0, 0x10, 0xfe, 0x38, 0x82, 0x34, 0xfe, 0x34, 0x82, 0x50, 0xfe, 0x50, 0x82, 0x10, 0xfe, 0x10, 0x44, 0x11, 0x83 },
+{ 0x90, 0xd0, 0x10, 0x10, 0x1f, 0xbf, 0x24, 0x44, 0x42, 0x2, 0x8, 0x24, 0x3e, 0xff, 0x8, 0x24, 0x3e, 0x24, 0x8, 0xff, 0x7f, 0x0, 0x8, 0x7e, 0x1c, 0x42, 0x1a, 0x7e, 0x29, 0x42, 0x48, 0x42, 0x8, 0x7e },
+{ 0x90, 0xd1, 0x8, 0x10, 0x19, 0xff, 0x10, 0x10, 0x64, 0xfe, 0x2c, 0x10, 0x19, 0xff, 0x10, 0x0, 0x24, 0xfe, 0x7e, 0x82, 0xa, 0xfe, 0x8, 0x82, 0x2a, 0xfe, 0x2a, 0x82, 0x6a, 0xfe, 0x48, 0x44, 0x9, 0x83 },
+{ 0x90, 0xd2, 0x0, 0x80, 0x0, 0x80, 0x3d, 0x9e, 0x1, 0x40, 0x3a, 0x2e, 0x4, 0x10, 0x1f, 0xfc, 0x68, 0xb, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x38 },
+{ 0x90, 0xd3, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0xf, 0xf8, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x4, 0x10, 0x38, 0xe },
+{ 0x90, 0xd4, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x2, 0x20, 0x12, 0x24, 0x12, 0x26, 0x32, 0x22, 0x22, 0x23, 0x66, 0x21, 0x4, 0x20, 0xc, 0x20, 0x18, 0xe0 },
+{ 0x90, 0xd5, 0x0, 0x20, 0x3e, 0x20, 0x22, 0x20, 0x23, 0xff, 0x22, 0x48, 0x22, 0x48, 0x3e, 0x48, 0x9, 0x4a, 0x29, 0x4a, 0x2f, 0x4b, 0x2a, 0x49, 0x28, 0x48, 0x28, 0xc8, 0x2e, 0x88, 0x39, 0x88, 0x63, 0x38 },
+{ 0x90, 0xd6, 0x0, 0x10, 0x3e, 0xff, 0x22, 0x10, 0x22, 0x7e, 0x22, 0x10, 0x22, 0xff, 0x3e, 0x0, 0x8, 0x7e, 0x28, 0x42, 0x2e, 0x7e, 0x28, 0x42, 0x28, 0x7e, 0x28, 0x42, 0x2e, 0x7e, 0x38, 0x24, 0x60, 0xc3 },
+{ 0x90, 0xd7, 0x0, 0x0, 0x7e, 0xff, 0x8, 0x10, 0x8, 0x7e, 0x18, 0x42, 0x10, 0x42, 0x1e, 0x7e, 0x32, 0x42, 0x32, 0x42, 0x52, 0x7e, 0x12, 0x42, 0x12, 0x42, 0x12, 0x7e, 0x1e, 0x24, 0x0, 0x66, 0x0, 0xc3 },
+{ 0x90, 0xd8, 0x10, 0x0, 0x11, 0xfe, 0x10, 0x22, 0x10, 0x22, 0x13, 0x22, 0x1e, 0x22, 0x70, 0x22, 0x10, 0x22, 0x10, 0x22, 0x10, 0x62, 0x11, 0x42, 0x13, 0x42, 0xe, 0xc6, 0x0, 0x84, 0x1, 0x84, 0x3, 0x1c },
+{ 0x90, 0xd9, 0x10, 0x20, 0x10, 0x20, 0x12, 0x22, 0x12, 0x22, 0x7a, 0x22, 0x12, 0x22, 0x13, 0xfe, 0x10, 0x20, 0x18, 0x20, 0x70, 0x20, 0x12, 0x22, 0x12, 0x22, 0x12, 0x22, 0x12, 0x22, 0x13, 0xfe, 0x30, 0x0 },
+{ 0x90, 0xda, 0x10, 0x20, 0x10, 0x20, 0x13, 0xfe, 0x11, 0x4, 0x79, 0x8c, 0x10, 0x88, 0x17, 0xff, 0x10, 0x40, 0x18, 0x40, 0x77, 0xff, 0x10, 0x84, 0x11, 0xc, 0x13, 0xd8, 0x10, 0x70, 0x11, 0xce, 0x37, 0x3 },
+{ 0x90, 0xdb, 0x10, 0x0, 0x13, 0xff, 0x10, 0x84, 0x10, 0xfc, 0x7c, 0x84, 0x10, 0xfc, 0x10, 0x84, 0x13, 0xff, 0x1c, 0x4, 0x70, 0x0, 0x11, 0x86, 0x10, 0xcc, 0x10, 0x0, 0x10, 0xcc, 0x11, 0x86, 0x33, 0x3 },
+{ 0x90, 0xdc, 0x10, 0x6, 0x10, 0x1c, 0x11, 0xf0, 0x11, 0x0, 0x7d, 0x0, 0x11, 0xff, 0x11, 0x8, 0x11, 0x8, 0x1d, 0x8, 0x71, 0x8, 0x11, 0x8, 0x11, 0x8, 0x13, 0x8, 0x12, 0x8, 0x16, 0x8, 0x30, 0x8 },
+{ 0x90, 0xdd, 0x0, 0x0, 0x3c, 0x7c, 0x0, 0x44, 0x7e, 0x44, 0x0, 0x44, 0x3c, 0xc4, 0x1, 0x87, 0x0, 0x0, 0x3c, 0xfe, 0x0, 0x42, 0x0, 0x66, 0x3c, 0x2c, 0x24, 0x18, 0x24, 0x30, 0x24, 0x6c, 0x3d, 0xc7 },
+{ 0x90, 0xde, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x22, 0x22, 0x26, 0x22, 0x1c, 0x3f, 0x70, 0x0, 0x10, 0x0, 0x11, 0xfe, 0x1e, 0x22, 0x70, 0x22, 0x10, 0x22, 0x12, 0x62, 0xe, 0x46, 0x0, 0xc4, 0x1, 0x9c },
+{ 0x90, 0xdf, 0x10, 0x20, 0x10, 0x20, 0x3f, 0x7f, 0x28, 0x48, 0x44, 0x84, 0x0, 0x0, 0x3f, 0x3e, 0x21, 0x22, 0x3f, 0x22, 0x21, 0x22, 0x3f, 0x22, 0x20, 0x22, 0x22, 0x22, 0x3f, 0x2e, 0x61, 0x20, 0x0, 0x20 },
+{ 0x90, 0xe0, 0x0, 0x82, 0x3c, 0xc6, 0x0, 0x44, 0x7e, 0x0, 0x0, 0xfe, 0x3c, 0x82, 0x0, 0x82, 0x0, 0x82, 0x3c, 0xfe, 0x0, 0x48, 0x0, 0x48, 0x3c, 0x48, 0x24, 0x48, 0x24, 0xc9, 0x24, 0x89, 0x3d, 0x87 },
+{ 0x90, 0xe1, 0x0, 0x0, 0x3f, 0xfe, 0x0, 0x80, 0x7f, 0xff, 0x40, 0x81, 0x5e, 0xbd, 0x40, 0x81, 0x1e, 0xbc, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x4, 0x0, 0x4, 0x1f, 0xfc, 0x0, 0x4, 0x0, 0x4, 0x1f, 0xfc },
+{ 0x90, 0xe2, 0x8, 0x40, 0x18, 0x7c, 0x10, 0x44, 0x64, 0xcc, 0x2d, 0x88, 0x18, 0xfe, 0x10, 0x92, 0x24, 0x92, 0x7e, 0x92, 0xa, 0xfe, 0x8, 0x80, 0x2a, 0x80, 0x2a, 0x80, 0x6a, 0x81, 0x48, 0xc3, 0x8, 0x7e },
+{ 0x90, 0xe3, 0x0, 0x18, 0x0, 0xf0, 0x1f, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8 },
+{ 0x90, 0xe4, 0x11, 0x22, 0x11, 0xb6, 0x10, 0x94, 0x7c, 0xfe, 0x54, 0x92, 0x54, 0x92, 0x54, 0xfe, 0x54, 0x92, 0x54, 0x92, 0x7c, 0xfe, 0x10, 0x10, 0x14, 0x10, 0x15, 0xff, 0x3e, 0x10, 0x62, 0x10, 0x0, 0x10 },
+{ 0x90, 0xe5, 0x4, 0x20, 0x4, 0x20, 0xc, 0x20, 0x8, 0x20, 0x1a, 0x22, 0x12, 0x22, 0x32, 0x22, 0x52, 0x22, 0x12, 0x22, 0x12, 0x22, 0x12, 0x22, 0x12, 0x22, 0x12, 0x22, 0x12, 0x22, 0x13, 0xfe, 0x10, 0x0 },
+{ 0x90, 0xe6, 0x0, 0x80, 0x8, 0x80, 0x8, 0x80, 0xf, 0xfc, 0x18, 0x80, 0x30, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x6, 0x20, 0x4, 0x20, 0xc, 0x21, 0x18, 0x33, 0x70, 0x1e },
+{ 0x90, 0xe7, 0x0, 0x18, 0x0, 0xf0, 0x1f, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80 },
+{ 0x90, 0xe8, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0xff, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xfc, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x1f, 0xfc },
+{ 0x90, 0xe9, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x2, 0x2f, 0xfa, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x90, 0xea, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x1f, 0xfc, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x0, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x6, 0x10, 0x2, 0x10, 0x0, 0x70 },
+{ 0x90, 0xeb, 0x0, 0x80, 0x0, 0x80, 0x4, 0x90, 0xc, 0x98, 0x18, 0x8c, 0x70, 0x87, 0x0, 0x80, 0x3, 0x80, 0x0, 0x0, 0x0, 0x80, 0x7f, 0xff, 0x1, 0x40, 0x3, 0x60, 0x6, 0x30, 0x1c, 0x1c, 0x70, 0x7 },
+{ 0x90, 0xec, 0x0, 0x2, 0x10, 0x2, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x30, 0x82, 0x20, 0x2, 0x60, 0x2, 0x0, 0x2 },
+{ 0x90, 0xed, 0x48, 0x54, 0x6c, 0xd6, 0x24, 0x92, 0x3f, 0x90, 0x24, 0x9f, 0x24, 0xf0, 0x3f, 0x92, 0x24, 0x92, 0x24, 0x96, 0x3f, 0x94, 0x4, 0x1c, 0x4, 0x8, 0x7f, 0xdc, 0x4, 0x14, 0x4, 0x36, 0x4, 0xe3 },
+{ 0x90, 0xee, 0x0, 0x0, 0x3f, 0xff, 0x0, 0x0, 0x1f, 0xfe, 0x10, 0x2, 0x10, 0x2, 0x1f, 0xfe, 0x10, 0x0, 0x17, 0xbe, 0x10, 0x82, 0x14, 0xa2, 0x12, 0x92, 0x31, 0x8e, 0x26, 0x9a, 0x6c, 0xb2, 0x1, 0x86 },
+{ 0x90, 0xef, 0x10, 0x0, 0x13, 0xdf, 0x10, 0x41, 0x13, 0xdf, 0x7e, 0x10, 0x12, 0x51, 0x11, 0xcf, 0x10, 0x0, 0x1c, 0x48, 0x71, 0xfe, 0x10, 0x48, 0x10, 0x48, 0x13, 0xff, 0x10, 0x48, 0x10, 0xcc, 0x33, 0x87 },
+{ 0x90, 0xf0, 0x10, 0x20, 0x10, 0x70, 0x10, 0xd8, 0x7d, 0x8c, 0x13, 0x6, 0x16, 0x3, 0x31, 0xfc, 0x38, 0x20, 0x34, 0x20, 0x54, 0x20, 0x51, 0xfc, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x17, 0xff, 0x10, 0x0 },
+{ 0x90, 0xf1, 0x8, 0x80, 0x8, 0x80, 0x9, 0xff, 0x7f, 0x0, 0xa, 0x0, 0x8, 0xfe, 0x18, 0x92, 0x1c, 0x92, 0x1a, 0x92, 0x2a, 0x92, 0x29, 0xff, 0x48, 0x82, 0x8, 0x82, 0x8, 0x82, 0x8, 0x82, 0x8, 0x8e },
+{ 0x90, 0xf2, 0x0, 0x40, 0x0, 0x80, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x0, 0x82, 0x3e, 0xc6, 0x2, 0xac, 0x6, 0xb0, 0x1c, 0x9c, 0x70, 0x87, 0x3, 0x80 },
+{ 0x90, 0xf3, 0x0, 0x28, 0x30, 0x24, 0x1b, 0xff, 0x8, 0x20, 0x0, 0x20, 0x61, 0xfe, 0x30, 0x20, 0x10, 0x20, 0x3, 0xff, 0x8, 0x20, 0x8, 0x32, 0x18, 0x16, 0x10, 0x1c, 0x30, 0x39, 0x20, 0xed, 0x67, 0x87 },
+{ 0x90, 0xf4, 0x0, 0x20, 0x31, 0x20, 0x19, 0x20, 0x9, 0xfe, 0x3, 0x20, 0x66, 0x20, 0x30, 0x20, 0x17, 0xff, 0x0, 0x88, 0x8, 0x88, 0x8, 0x88, 0x18, 0x88, 0x11, 0x88, 0x31, 0x9, 0x23, 0x9, 0x66, 0x7 },
+{ 0x90, 0xf5, 0x0, 0x40, 0x18, 0x40, 0xd, 0xf8, 0x60, 0x48, 0x30, 0x48, 0x0, 0xc8, 0xc, 0x89, 0x39, 0x89, 0x63, 0x7, 0x0, 0x80, 0x7f, 0xff, 0x2, 0xa0, 0x6, 0xb0, 0x1c, 0x9c, 0x70, 0x87, 0x0, 0x80 },
+{ 0x90, 0xf6, 0x1, 0x4, 0x21, 0x4, 0x37, 0xdf, 0x11, 0x4, 0x7, 0xdf, 0x41, 0x4, 0x62, 0x8a, 0x24, 0x51, 0x0, 0x0, 0xb, 0xfe, 0xa, 0x2, 0x1a, 0x2, 0x13, 0xfe, 0x32, 0x2, 0x22, 0x2, 0x63, 0xfe },
+{ 0x90, 0xf7, 0x4, 0x10, 0x2, 0x20, 0x7f, 0xff, 0x0, 0x0, 0x1f, 0x4, 0x11, 0x24, 0x1f, 0x24, 0x11, 0x24, 0x1f, 0x24, 0x11, 0x4, 0x11, 0x4, 0x13, 0x1c, 0x0, 0x0, 0x12, 0x24, 0x33, 0x36, 0x61, 0x13 },
+{ 0x90, 0xf8, 0x10, 0x0, 0x13, 0xff, 0x10, 0x0, 0x55, 0xfe, 0x55, 0x2, 0x55, 0x2, 0x55, 0xfe, 0x11, 0x0, 0x11, 0xff, 0x11, 0x11, 0x39, 0x99, 0x2d, 0x55, 0x27, 0x33, 0x62, 0x55, 0x46, 0x99, 0x0, 0x33 },
+{ 0x90, 0xf9, 0x8, 0x40, 0x8, 0x40, 0x8, 0xff, 0x7f, 0x80, 0x11, 0x0, 0x10, 0xff, 0x1e, 0x12, 0x12, 0x14, 0x12, 0x50, 0x12, 0x50, 0x12, 0x5e, 0x12, 0x50, 0x32, 0x50, 0x26, 0x70, 0x24, 0xdc, 0x6d, 0x87 },
+{ 0x90, 0xfa, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x22, 0x22, 0x26, 0x22, 0x1c, 0x3f, 0x70, 0x0, 0x1f, 0xfc, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x0, 0x90, 0x3, 0x90, 0xe, 0x10, 0x78, 0x70 },
+{ 0x90, 0xfb, 0x10, 0x20, 0x10, 0x20, 0x3f, 0x7f, 0x44, 0x88, 0x8, 0x4, 0x4, 0x8, 0x7f, 0xff, 0x0, 0x0, 0x1f, 0x4, 0x11, 0x24, 0x1f, 0x24, 0x11, 0x24, 0x1f, 0x24, 0x11, 0x4, 0x11, 0x4, 0x13, 0x1c },
+{ 0x90, 0xfc, 0x8, 0x10, 0x18, 0x20, 0x30, 0xfe, 0x62, 0x82, 0x36, 0xfe, 0xc, 0x82, 0x18, 0x82, 0x32, 0xfe, 0x7e, 0x11, 0xb, 0xd3, 0x8, 0x5a, 0x2a, 0x5c, 0x2a, 0xd4, 0x6a, 0x96, 0x49, 0x93, 0x8, 0x30 },
+{ 0x91, 0x40, 0x10, 0x88, 0x30, 0x8a, 0x23, 0xeb, 0x68, 0x89, 0x28, 0x88, 0x1f, 0xff, 0x11, 0x48, 0x29, 0x4a, 0x7d, 0x5a, 0x13, 0x6a, 0x11, 0x4e, 0x55, 0x44, 0x55, 0x4c, 0x55, 0xed, 0x13, 0x17, 0x10, 0x32 },
+{ 0x91, 0x41, 0x4, 0x10, 0x2, 0x20, 0x3f, 0xfe, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x30, 0xfe, 0x19, 0xa2, 0x63, 0x24, 0x34, 0x70, 0xc, 0x50, 0x18, 0xd8, 0x31, 0x8c, 0x67, 0x7 },
+{ 0x91, 0x42, 0x0, 0x10, 0x3c, 0x20, 0x25, 0xfc, 0x25, 0x4, 0x25, 0xfc, 0x3d, 0x4, 0x25, 0x4, 0x25, 0xfc, 0x24, 0x22, 0x3d, 0xa6, 0x24, 0xb4, 0x24, 0xa8, 0x25, 0xac, 0x25, 0x26, 0x67, 0x23, 0x4c, 0x60 },
+{ 0x91, 0x43, 0x8, 0x4, 0x8, 0x4, 0xf, 0x84, 0x8, 0x84, 0x18, 0xff, 0x10, 0xa4, 0x39, 0xa4, 0x6d, 0x24, 0x7, 0x24, 0x2, 0x24, 0x6, 0xff, 0x4, 0x4, 0xc, 0x4, 0x18, 0x4, 0x30, 0x4, 0x60, 0x4 },
+{ 0x91, 0x44, 0x4, 0x0, 0x8, 0x28, 0x3e, 0x28, 0x22, 0x28, 0x2a, 0x6c, 0x2a, 0x44, 0x22, 0xc6, 0x7f, 0x83, 0x22, 0x0, 0x2a, 0x7c, 0x2a, 0x44, 0x2a, 0x44, 0x2a, 0x44, 0x22, 0x44, 0x62, 0x44, 0x46, 0x7c },
+{ 0x91, 0x45, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x0, 0x80, 0x1f, 0xff, 0x11, 0x20, 0x1f, 0xfe, 0x11, 0x22, 0x1f, 0xfe, 0x12, 0x0, 0x13, 0xff, 0x32, 0x0, 0x23, 0xff, 0x68, 0x1, 0xa, 0x49, 0x11, 0x27 },
+{ 0x91, 0x46, 0x0, 0x10, 0x3c, 0x38, 0x0, 0x6c, 0x7e, 0xc6, 0x1, 0x83, 0x3c, 0x0, 0x0, 0xfe, 0x0, 0x10, 0x3c, 0x10, 0x0, 0x10, 0x0, 0xfe, 0x3c, 0x10, 0x24, 0x10, 0x24, 0x10, 0x25, 0xff, 0x3c, 0x0 },
+{ 0x91, 0x47, 0x0, 0x28, 0x3e, 0x24, 0x22, 0x20, 0x23, 0xfe, 0x3e, 0x20, 0x23, 0xfe, 0x22, 0x20, 0x23, 0xff, 0x3e, 0x20, 0x22, 0x32, 0x22, 0x16, 0x22, 0x1c, 0x3e, 0x8, 0x14, 0x3d, 0x36, 0xe7, 0x62, 0x2 },
+{ 0x91, 0x48, 0x0, 0x28, 0x3e, 0x24, 0x22, 0x20, 0x23, 0xfe, 0x22, 0x20, 0x23, 0xfe, 0x3e, 0x20, 0x9, 0xff, 0x28, 0x20, 0x2e, 0x32, 0x28, 0x16, 0x28, 0x1c, 0x28, 0x8, 0x2e, 0x1d, 0x38, 0x77, 0x61, 0xc2 },
+{ 0x91, 0x49, 0x0, 0x0, 0x27, 0xbe, 0x30, 0x82, 0x17, 0xbe, 0x4, 0x20, 0x4, 0xa2, 0x3, 0x9e, 0x70, 0x90, 0x13, 0xfc, 0x10, 0x90, 0x10, 0x90, 0x17, 0xfe, 0x11, 0x8, 0x36, 0x6, 0x28, 0x0, 0x67, 0xff },
+{ 0x91, 0x4a, 0x0, 0x0, 0x37, 0xff, 0x18, 0x90, 0xb, 0xfe, 0x2, 0x92, 0x3, 0xfe, 0x0, 0x40, 0x7b, 0xff, 0x8, 0x88, 0x9, 0xfc, 0xe, 0xb, 0x9, 0xf8, 0x9, 0x2, 0x18, 0xfe, 0x34, 0x0, 0x63, 0xff },
+{ 0x91, 0x4b, 0x8, 0x28, 0x1c, 0x24, 0x16, 0x20, 0x32, 0xfe, 0x20, 0x20, 0x7e, 0xfe, 0x8, 0x20, 0x8, 0xff, 0x7f, 0x20, 0x8, 0x32, 0x4a, 0x16, 0x6a, 0x1c, 0x28, 0x8, 0xe, 0x1d, 0x38, 0x77, 0x61, 0xc2 },
+{ 0x91, 0x4c, 0x8, 0x10, 0x1c, 0x50, 0x16, 0x50, 0x32, 0xfe, 0x20, 0x90, 0x7e, 0x10, 0x8, 0x10, 0x8, 0xff, 0x7f, 0x28, 0x8, 0x28, 0x4a, 0x28, 0x6a, 0x28, 0x28, 0x68, 0xe, 0x49, 0x38, 0xc9, 0x61, 0x87 },
+{ 0x91, 0x4d, 0x0, 0x0, 0x3f, 0x7e, 0x21, 0x42, 0x3f, 0x7e, 0x21, 0x42, 0x3f, 0x7e, 0x20, 0x2, 0x20, 0x82, 0x20, 0x82, 0x21, 0xc2, 0x21, 0x42, 0x23, 0x62, 0x26, 0x32, 0x2c, 0x1a, 0x20, 0x2, 0x20, 0xe },
+{ 0x91, 0x4e, 0x10, 0x41, 0x1e, 0x63, 0x32, 0x22, 0x24, 0x7f, 0x7f, 0x8, 0x29, 0x8, 0x29, 0x3e, 0x3f, 0x8, 0x29, 0x8, 0x29, 0x8, 0x3f, 0x7f, 0x0, 0x8, 0x2a, 0x88, 0x2a, 0x88, 0x6a, 0x88, 0x40, 0x8 },
+{ 0x91, 0x4f, 0x4, 0x10, 0x6, 0x30, 0x2, 0x20, 0x7f, 0xff, 0x0, 0x0, 0x1f, 0x4, 0x11, 0x24, 0x11, 0x24, 0x1f, 0x24, 0x11, 0x24, 0x11, 0x24, 0x1f, 0x24, 0x11, 0x24, 0x11, 0x4, 0x11, 0x4, 0x13, 0x1c },
+{ 0x91, 0x50, 0x4, 0x10, 0x2, 0x20, 0x3f, 0xfe, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x3f, 0xfe, 0x8, 0x88, 0x4, 0x90, 0x7f, 0xff, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8 },
+{ 0x91, 0x51, 0x1, 0x2, 0x21, 0x6, 0x37, 0xdc, 0x11, 0x10, 0x7, 0xd0, 0x45, 0x5f, 0x65, 0x52, 0x27, 0xd2, 0x5, 0x52, 0x15, 0x52, 0x17, 0xd2, 0x11, 0x12, 0x37, 0xf2, 0x21, 0x22, 0x21, 0x62, 0x61, 0x2 },
+{ 0x91, 0x52, 0x4, 0x28, 0x4, 0x2c, 0xf, 0xa4, 0x8, 0xa0, 0x19, 0xff, 0x35, 0x28, 0x63, 0x28, 0x16, 0x6c, 0xc, 0x44, 0x18, 0xc6, 0x71, 0x83, 0x0, 0x0, 0x12, 0x24, 0x32, 0x26, 0x23, 0x32, 0x61, 0x13 },
+{ 0x91, 0x53, 0x0, 0x80, 0x1, 0xc0, 0x3, 0x60, 0x6, 0x30, 0x1c, 0x1c, 0x70, 0x7, 0xf, 0xf8, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0xf, 0xf8, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x0, 0x0 },
+{ 0x91, 0x54, 0x9, 0x21, 0x9, 0xb3, 0x8, 0x92, 0x7e, 0xfe, 0x2, 0x92, 0x6, 0x92, 0x4, 0xfe, 0xc, 0x92, 0x18, 0x92, 0x3e, 0xfe, 0x6b, 0x10, 0x8, 0x10, 0x9, 0xff, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10 },
+{ 0x91, 0x55, 0x8, 0x82, 0x18, 0x44, 0x11, 0xff, 0x64, 0x10, 0x2c, 0xfe, 0x18, 0x10, 0x11, 0xff, 0x24, 0x92, 0x7e, 0x54, 0xb, 0xff, 0x8, 0x0, 0x2a, 0xfe, 0x2a, 0x82, 0x6a, 0x82, 0x48, 0x82, 0x8, 0xfe },
+{ 0x91, 0x56, 0x0, 0x82, 0x3c, 0x44, 0x25, 0xff, 0x24, 0x10, 0x24, 0xfe, 0x3c, 0x10, 0x25, 0xff, 0x24, 0x92, 0x24, 0x54, 0x3d, 0xff, 0x24, 0x0, 0x24, 0xfe, 0x24, 0x82, 0x24, 0x82, 0x64, 0x82, 0x4c, 0xfe },
+{ 0x91, 0x57, 0x10, 0x0, 0x55, 0xff, 0x55, 0x0, 0x55, 0x7e, 0x11, 0x52, 0x7d, 0x52, 0x11, 0x7e, 0x11, 0x52, 0x39, 0x52, 0x35, 0x7e, 0x51, 0x10, 0x51, 0x10, 0x13, 0x7e, 0x12, 0x10, 0x16, 0x10, 0x10, 0xff },
+{ 0x91, 0x58, 0x0, 0x82, 0x0, 0x44, 0x7d, 0xff, 0x45, 0x11, 0x45, 0x11, 0x45, 0xff, 0x45, 0x11, 0x45, 0x11, 0x45, 0xff, 0x44, 0x0, 0x7c, 0xfe, 0x0, 0x82, 0x0, 0xfe, 0x0, 0x82, 0x0, 0x82, 0x0, 0xfe },
+{ 0x91, 0x59, 0x21, 0x0, 0x12, 0x3e, 0x7f, 0xa2, 0x8, 0x3e, 0x29, 0x22, 0x29, 0x3e, 0x29, 0x22, 0x3f, 0x22, 0x8, 0x22, 0x10, 0x46, 0x60, 0x80, 0xf, 0xf8, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x91, 0x5a, 0x0, 0x0, 0x10, 0xfc, 0x10, 0x84, 0x54, 0x84, 0x54, 0x84, 0x54, 0xfc, 0x54, 0x84, 0x54, 0x84, 0x54, 0x84, 0x54, 0xfc, 0x54, 0x84, 0x7c, 0x84, 0x0, 0x84, 0x0, 0x84, 0x3, 0xff, 0x0, 0x0 },
+{ 0x91, 0x5b, 0x10, 0x88, 0x10, 0x88, 0x13, 0xfe, 0x10, 0x88, 0x78, 0x88, 0x10, 0x88, 0x17, 0xff, 0x10, 0x0, 0x18, 0x0, 0x71, 0xfc, 0x11, 0x4, 0x11, 0x4, 0x11, 0xfc, 0x11, 0x4, 0x11, 0x4, 0x31, 0xfc },
+{ 0x91, 0x5c, 0x4, 0x10, 0xc, 0x18, 0x18, 0xc, 0x7f, 0xff, 0x10, 0x84, 0x14, 0x94, 0x12, 0xa4, 0x10, 0x84, 0x1f, 0xfc, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8 },
+{ 0x91, 0x5d, 0x8, 0x8, 0x4, 0x10, 0x3f, 0xfe, 0x20, 0x82, 0x20, 0x82, 0x3f, 0xfe, 0x20, 0x82, 0x20, 0x82, 0x3f, 0xfe, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x4, 0x1f, 0xfc, 0x10, 0x4, 0x10, 0x4, 0x1f, 0xfc },
+{ 0x91, 0x5e, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x14, 0x54, 0x16, 0x54, 0x35, 0x56, 0x64, 0x93, 0x4, 0x10, 0x0, 0x0, 0x3f, 0xfe, 0x0, 0x82, 0x8, 0x80, 0x8, 0xfc, 0x1c, 0x80, 0x37, 0x80, 0x60, 0xff },
+{ 0x91, 0x5f, 0x4, 0x0, 0x44, 0xfc, 0x28, 0x84, 0x10, 0x84, 0x10, 0x84, 0x28, 0xfc, 0x48, 0x84, 0x8, 0x84, 0x18, 0x84, 0x18, 0xfc, 0x28, 0x84, 0x48, 0x84, 0x8, 0x84, 0x8, 0x84, 0x1b, 0xff, 0x70, 0x0 },
+{ 0x91, 0x60, 0x0, 0x10, 0x7f, 0x10, 0x2, 0xff, 0x4, 0x20, 0x8, 0x60, 0x28, 0x42, 0x28, 0xff, 0x2e, 0x1, 0x28, 0x44, 0x28, 0x54, 0x28, 0x54, 0x28, 0x54, 0x28, 0x54, 0x2e, 0xd5, 0x38, 0x95, 0x61, 0x83 },
+{ 0x91, 0x61, 0x0, 0x10, 0x7e, 0x10, 0x3, 0xff, 0x4, 0x10, 0x8, 0xfe, 0x28, 0x92, 0x28, 0x92, 0x2e, 0x92, 0x28, 0xfe, 0x28, 0x54, 0x28, 0x54, 0x28, 0x54, 0x2e, 0xd6, 0x38, 0x92, 0x61, 0x93, 0x0, 0x10 },
+{ 0x91, 0x62, 0x0, 0x44, 0x7e, 0x44, 0x11, 0xff, 0x10, 0x44, 0x10, 0xee, 0x11, 0x55, 0x3c, 0x44, 0x24, 0x0, 0x65, 0xff, 0x24, 0x11, 0x24, 0x90, 0x24, 0x9e, 0x24, 0x90, 0x3d, 0xd0, 0x1, 0x70, 0x3, 0x1f },
+{ 0x91, 0x63, 0x10, 0x0, 0x10, 0xfc, 0x10, 0x84, 0x7c, 0x84, 0x4, 0x84, 0xc, 0xfc, 0x8, 0x84, 0x18, 0x84, 0x10, 0x84, 0x3c, 0xfc, 0x56, 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x13, 0xff, 0x10, 0x0 },
+{ 0x91, 0x64, 0x2, 0x0, 0xe, 0xfc, 0x78, 0x84, 0x8, 0x84, 0x8, 0x84, 0x7e, 0xfc, 0x8, 0x84, 0x8, 0x84, 0x1c, 0x84, 0x1a, 0xfc, 0x2a, 0x84, 0x28, 0x84, 0x48, 0x84, 0x8, 0x84, 0xb, 0xff, 0x8, 0x0 },
+{ 0x91, 0x65, 0x8, 0x0, 0x4a, 0xfc, 0x6e, 0x84, 0x2c, 0x84, 0x8, 0x84, 0x7e, 0xfc, 0x8, 0x84, 0x8, 0x84, 0x1c, 0x84, 0x1a, 0xfc, 0x2a, 0x84, 0x28, 0x84, 0x48, 0x84, 0x8, 0x84, 0xb, 0xff, 0x8, 0x0 },
+{ 0x91, 0x66, 0x0, 0x80, 0x3f, 0xfe, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x3, 0x8, 0xc, 0x30, 0x2, 0xc4, 0x3f, 0xfe, 0x0, 0x82, 0x4, 0x90, 0x1c, 0x9c, 0x70, 0x87, 0x0, 0x80 },
+{ 0x91, 0x67, 0x8, 0x0, 0x18, 0xfc, 0x10, 0x84, 0x64, 0x84, 0x2c, 0x84, 0x18, 0xfc, 0x10, 0x84, 0x24, 0x84, 0x7e, 0x84, 0xa, 0xfc, 0x8, 0x84, 0x2a, 0x84, 0x2a, 0x84, 0x6a, 0x84, 0x49, 0xff, 0x8, 0x0 },
+{ 0x91, 0x68, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x10, 0x2, 0x1e, 0xe, 0x24, 0x78, 0x7f, 0x8, 0x29, 0x7f, 0x3f, 0x8, 0x29, 0x1c, 0x29, 0x1c, 0x3f, 0x2a, 0x0, 0x2a, 0x55, 0x49, 0x55, 0x8, 0x0, 0x8 },
+{ 0x91, 0x69, 0x0, 0x6, 0x3c, 0x1c, 0x0, 0xf0, 0x7e, 0x80, 0x0, 0x80, 0x3c, 0xff, 0x0, 0x88, 0x0, 0x88, 0x3c, 0x88, 0x0, 0xb8, 0x0, 0x8e, 0x3c, 0x8b, 0x25, 0x88, 0x25, 0x8, 0x27, 0x8, 0x3c, 0x8 },
+{ 0x91, 0x6a, 0x0, 0x0, 0x3e, 0xfc, 0x22, 0x84, 0x26, 0x84, 0x2c, 0x84, 0x28, 0xfc, 0x24, 0x84, 0x22, 0x84, 0x22, 0x84, 0x22, 0xfc, 0x22, 0x84, 0x2e, 0x84, 0x20, 0x84, 0x20, 0x84, 0x23, 0xff, 0x20, 0x0 },
+{ 0x91, 0x6b, 0x4, 0x40, 0x26, 0xde, 0x32, 0x92, 0x17, 0xd2, 0x1, 0x1e, 0x1, 0x12, 0x5, 0x52, 0x75, 0x52, 0x15, 0x5e, 0x17, 0xd2, 0x11, 0x12, 0x11, 0x12, 0x13, 0x12, 0x36, 0x26, 0x28, 0x0, 0x67, 0xff },
+{ 0x91, 0x6c, 0x3, 0x0, 0x3e, 0x7e, 0x20, 0x2, 0x3f, 0x7e, 0x20, 0x2, 0x3f, 0xfe, 0x0, 0x0, 0x10, 0x88, 0x14, 0xc8, 0x12, 0xa8, 0x10, 0x88, 0x14, 0xc8, 0x12, 0xac, 0x10, 0x85, 0x1c, 0xe7, 0x73, 0x82 },
+{ 0x91, 0x6d, 0x9, 0x4, 0x8, 0x88, 0xf, 0xff, 0x1c, 0x21, 0x14, 0x21, 0x37, 0xff, 0x34, 0x21, 0x54, 0x21, 0x17, 0xff, 0x10, 0x0, 0x13, 0xfe, 0x12, 0x2, 0x13, 0xfe, 0x12, 0x2, 0x12, 0x2, 0x13, 0xfe },
+{ 0x91, 0x6e, 0x2, 0x2, 0x7, 0x12, 0xd, 0x92, 0x18, 0xd2, 0x37, 0x72, 0x60, 0x12, 0x1f, 0xd2, 0x10, 0x52, 0x1f, 0xd2, 0x10, 0x52, 0x1f, 0xd2, 0x10, 0x12, 0x3f, 0xc2, 0x28, 0x42, 0x68, 0x42, 0xf, 0xce },
+{ 0x91, 0x6f, 0x0, 0x0, 0x3f, 0x7e, 0x1, 0x22, 0x1, 0x22, 0x1, 0x22, 0x3, 0x22, 0x32, 0x26, 0x1a, 0x34, 0xe, 0x14, 0x4, 0x1c, 0xe, 0x8, 0xb, 0x1c, 0x19, 0x14, 0x10, 0x36, 0x30, 0x62, 0x61, 0xc3 },
+{ 0x91, 0x70, 0x11, 0x44, 0x9, 0x48, 0x7f, 0xff, 0x4, 0x10, 0x3f, 0xfe, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x7f, 0xff, 0x11, 0x0, 0x1f, 0x7e, 0x11, 0x22, 0x1f, 0x14, 0x11, 0x8, 0x7f, 0x14, 0x1, 0x63 },
+{ 0x91, 0x71, 0x0, 0x80, 0x1, 0xc0, 0x3, 0x60, 0xe, 0x38, 0x79, 0xcf, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x18, 0x0, 0x17, 0xfc, 0x34, 0x4, 0x64, 0x4, 0x7, 0xfc },
+{ 0x91, 0x72, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x3e, 0xbe, 0x22, 0xa2, 0x22, 0xa2, 0x3e, 0xbe, 0x0, 0x80, 0x7f, 0xff, 0x8, 0x42, 0x8, 0x66, 0x8, 0x2c, 0x8, 0x30, 0xf, 0x1c, 0x38, 0x7 },
+{ 0x91, 0x73, 0x4, 0x20, 0x4, 0x20, 0x4, 0x20, 0x24, 0x20, 0x34, 0x20, 0x17, 0xff, 0x4, 0x20, 0x4, 0x20, 0x4, 0x20, 0x1c, 0x20, 0x34, 0x20, 0x64, 0x20, 0x4, 0x20, 0x4, 0x20, 0x5, 0xfe, 0x4, 0x0 },
+{ 0x91, 0x74, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x0, 0x80, 0x1f, 0xfc, 0x1, 0x40, 0x7f, 0xff, 0x2, 0x20, 0x4, 0x10, 0x1b, 0xec, 0x60, 0x83, 0x1f, 0xfc, 0x1, 0x40, 0x3, 0x60, 0xe, 0x38, 0x38, 0xe },
+{ 0x91, 0x75, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x24, 0x92, 0x18, 0x8c, 0x24, 0x92, 0x0, 0x80, 0x24, 0x92, 0x18, 0x8c, 0x25, 0xd2, 0x1, 0x40, 0x3, 0x60, 0x6, 0x30, 0x1c, 0x1c, 0x70, 0x7 },
+{ 0x91, 0x76, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x2, 0x20, 0x82, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x2, 0xa0, 0x6, 0xb0, 0x4, 0x90, 0xc, 0x98, 0x18, 0x8c, 0x70, 0x87, 0x0, 0x80, 0x0, 0x80 },
+{ 0x91, 0x77, 0x0, 0x0, 0x1f, 0xfe, 0x10, 0x2, 0x1f, 0xfe, 0x11, 0x10, 0x17, 0xfe, 0x14, 0x42, 0x17, 0xfe, 0x14, 0x42, 0x17, 0xfe, 0x10, 0x0, 0x13, 0xfc, 0x32, 0x4, 0x23, 0xfc, 0x62, 0x4, 0x3, 0xfc },
+{ 0x91, 0x78, 0x0, 0x0, 0x3f, 0xfe, 0x20, 0x0, 0x20, 0x80, 0x20, 0x80, 0x27, 0xf8, 0x24, 0x88, 0x24, 0x88, 0x24, 0x88, 0x24, 0x88, 0x24, 0xb8, 0x20, 0x80, 0x20, 0x80, 0x20, 0x0, 0x3f, 0xfe, 0x0, 0x0 },
+{ 0x91, 0x79, 0x8, 0x80, 0x28, 0x80, 0x3f, 0xfe, 0x69, 0x2a, 0xb, 0x6a, 0x8, 0x5a, 0xe, 0xd2, 0x79, 0xb6, 0x8, 0x64, 0x9, 0xdc, 0x0, 0x0, 0x1, 0x80, 0x14, 0xc6, 0x14, 0x4b, 0x36, 0x19, 0x63, 0xf0 },
+{ 0x91, 0x7a, 0x8, 0x0, 0x8, 0xfe, 0x7e, 0x82, 0x8, 0xfe, 0x1c, 0x82, 0x1a, 0x82, 0x2a, 0xfe, 0x48, 0x82, 0x8, 0x82, 0x8, 0xfe, 0x8, 0x0, 0x1, 0x80, 0x14, 0xc6, 0x14, 0x4b, 0x36, 0x19, 0x63, 0xf0 },
+{ 0x91, 0x7b, 0x10, 0x20, 0x10, 0x20, 0x13, 0xfe, 0x12, 0x22, 0x7a, 0x22, 0x13, 0xfe, 0x12, 0x22, 0x12, 0x22, 0x1b, 0xfe, 0x70, 0x20, 0x17, 0xfe, 0x11, 0x4, 0x10, 0x98, 0x10, 0x70, 0x11, 0xdc, 0x37, 0x7 },
+{ 0x91, 0x7c, 0x10, 0x0, 0x11, 0xfc, 0x10, 0x4, 0x11, 0xfc, 0x78, 0x4, 0x11, 0xfc, 0x10, 0x0, 0x17, 0xff, 0x1c, 0x21, 0x74, 0x21, 0x13, 0xfe, 0x12, 0x22, 0x12, 0x22, 0x12, 0x22, 0x12, 0x26, 0x30, 0x20 },
+{ 0x91, 0x7d, 0x10, 0x6, 0x10, 0x3c, 0x13, 0xe0, 0x78, 0x20, 0x17, 0xff, 0x10, 0x20, 0x13, 0xfe, 0x12, 0x22, 0x1a, 0x22, 0x73, 0xfe, 0x12, 0x22, 0x12, 0x22, 0x13, 0xfe, 0x10, 0x20, 0x10, 0x20, 0x30, 0x20 },
+{ 0x91, 0x7e, 0x10, 0x0, 0x17, 0xfe, 0x11, 0x4, 0x10, 0x88, 0x78, 0x70, 0x11, 0xdc, 0x17, 0x7, 0x10, 0x20, 0x1b, 0xfe, 0x72, 0x22, 0x12, 0x22, 0x13, 0xfe, 0x10, 0x20, 0x10, 0x22, 0x10, 0xff, 0x37, 0x81 },
+{ 0x91, 0x80, 0x10, 0xf8, 0x10, 0x88, 0x10, 0x88, 0x10, 0xf8, 0x78, 0x0, 0x13, 0xde, 0x12, 0x52, 0x12, 0x52, 0x1b, 0xde, 0x70, 0x20, 0x17, 0xff, 0x10, 0xa8, 0x11, 0xac, 0x13, 0x26, 0x16, 0x23, 0x30, 0x20 },
+{ 0x91, 0x81, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x4, 0x10, 0x4, 0x1f, 0xfc, 0x10, 0x4, 0x10, 0x4, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80 },
+{ 0x91, 0x82, 0x2, 0x20, 0x2, 0x20, 0x7f, 0xff, 0x2, 0x20, 0x3f, 0xfe, 0x22, 0x22, 0x3f, 0xfe, 0x22, 0x22, 0x3f, 0xfe, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8 },
+{ 0x91, 0x83, 0x11, 0x4, 0x19, 0x8c, 0x8, 0x88, 0x1f, 0xfc, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x0, 0x80, 0x7f, 0xff, 0x2, 0xa0, 0x6, 0xb0, 0x1c, 0x9c, 0x70, 0x87, 0x0, 0x80 },
+{ 0x91, 0x84, 0x10, 0x20, 0x10, 0x70, 0x10, 0xd8, 0x7d, 0x8c, 0x13, 0x77, 0x10, 0x0, 0x39, 0xfc, 0x35, 0x4, 0x35, 0xfc, 0x51, 0x4, 0x51, 0xfc, 0x11, 0x0, 0x13, 0xfe, 0x12, 0x82, 0x16, 0x82, 0x10, 0xfe },
+{ 0x91, 0x85, 0x10, 0x48, 0x10, 0x48, 0x13, 0xff, 0x7c, 0x48, 0x13, 0xff, 0x12, 0x49, 0x3b, 0xff, 0x36, 0x49, 0x33, 0xff, 0x50, 0x0, 0x51, 0xfe, 0x11, 0x2, 0x11, 0xfe, 0x11, 0x2, 0x11, 0x2, 0x11, 0xfe },
+{ 0x91, 0x86, 0x0, 0x90, 0x20, 0x90, 0x3f, 0xff, 0x10, 0x90, 0x7, 0xfe, 0x44, 0x92, 0x67, 0xfe, 0x24, 0x92, 0x7, 0xfe, 0x8, 0x0, 0xb, 0xfc, 0x1a, 0x4, 0x13, 0xfc, 0x32, 0x4, 0x22, 0x4, 0x63, 0xfc },
+{ 0x91, 0x87, 0x10, 0xf8, 0x10, 0x88, 0x14, 0x88, 0x54, 0xf8, 0x54, 0x0, 0x53, 0xde, 0x52, 0x52, 0x12, 0x52, 0x13, 0xde, 0x10, 0x20, 0x13, 0xfe, 0x38, 0xa8, 0x2d, 0xac, 0x23, 0x26, 0x66, 0x23, 0x40, 0x20 },
+{ 0x91, 0x88, 0x2, 0x0, 0x7, 0xf8, 0xc, 0x30, 0x18, 0x60, 0x70, 0xc0, 0x1f, 0xfc, 0x0, 0x84, 0x0, 0x84, 0x7f, 0xff, 0x0, 0x84, 0x0, 0x84, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x3, 0x80 },
+{ 0x91, 0x89, 0x0, 0x40, 0x0, 0x40, 0x1f, 0xff, 0x10, 0x40, 0x57, 0xfc, 0x34, 0x44, 0x17, 0xfc, 0x14, 0x44, 0x17, 0xfc, 0x30, 0x40, 0x57, 0xfc, 0x12, 0x8, 0x31, 0x10, 0x20, 0xe0, 0x63, 0xb8, 0x1e, 0xf },
+{ 0x91, 0x8a, 0x8, 0x0, 0x8, 0xfe, 0x8, 0x82, 0x7e, 0x82, 0x8, 0x82, 0x8, 0xfe, 0x1c, 0x82, 0x1a, 0x82, 0x1a, 0x82, 0x28, 0xfe, 0x28, 0x82, 0x48, 0x82, 0x8, 0x82, 0x8, 0x82, 0x8, 0xfe, 0x8, 0x0 },
+{ 0x91, 0x8b, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x22, 0x22, 0x26, 0x22, 0x1c, 0x3f, 0x72, 0x0, 0x6, 0x30, 0x4, 0x18, 0xf, 0xfc, 0x38, 0x4, 0x1, 0x80, 0x14, 0xc6, 0x14, 0x4b, 0x36, 0x19, 0x63, 0xf0 },
+{ 0x91, 0x8c, 0x10, 0x48, 0x54, 0x48, 0x57, 0xff, 0x54, 0x48, 0x13, 0xff, 0x7e, 0x49, 0x13, 0xff, 0x12, 0x49, 0x3b, 0xff, 0x34, 0x0, 0x55, 0xfe, 0x51, 0x2, 0x11, 0xfe, 0x11, 0x2, 0x11, 0x2, 0x11, 0xfe },
+{ 0x91, 0x8d, 0x8, 0x44, 0x18, 0x44, 0x10, 0xc6, 0x65, 0xa3, 0x2c, 0x20, 0x18, 0x64, 0x10, 0x44, 0x24, 0x7e, 0x7d, 0xc3, 0x14, 0x10, 0x10, 0x18, 0x54, 0x28, 0x54, 0xa2, 0x54, 0xa3, 0x11, 0xa5, 0x11, 0x1c },
+{ 0x91, 0x8e, 0x8, 0x10, 0x18, 0x10, 0x11, 0xff, 0x65, 0x1, 0x2d, 0x1, 0x18, 0xfe, 0x10, 0x0, 0x24, 0x0, 0x7d, 0xff, 0x14, 0x10, 0x10, 0x10, 0x54, 0x92, 0x54, 0x92, 0x55, 0x93, 0x11, 0x11, 0x10, 0x70 },
+{ 0x91, 0x8f, 0x0, 0x44, 0x7e, 0x44, 0x24, 0xc6, 0x25, 0xa3, 0x3c, 0x20, 0x24, 0x64, 0x24, 0x44, 0x24, 0x7e, 0x3d, 0xc2, 0x24, 0x10, 0x24, 0x18, 0x24, 0x28, 0x3c, 0xa2, 0x64, 0xa3, 0x5, 0xa5, 0x5, 0x1c },
+{ 0x91, 0x90, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80 },
+{ 0x91, 0x91, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x0, 0x0, 0x4, 0x20, 0x24, 0x20, 0x34, 0x20, 0x17, 0xff, 0x4, 0x20, 0x4, 0x20, 0x3c, 0x20, 0x64, 0x20, 0x4, 0x20, 0x5, 0xfe, 0x4, 0x0 },
+{ 0x91, 0x92, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x3f, 0xfe, 0x8, 0x40, 0x1f, 0x46, 0x71, 0x7c, 0x1a, 0x41, 0xc, 0x43, 0x70, 0x3e, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0xc, 0x10, 0x38, 0x10 },
+{ 0x91, 0x93, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x90, 0x1, 0x40, 0x6, 0x30, 0x1d, 0xdc, 0x70, 0x7, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x1f, 0xf8, 0x10, 0x0, 0x37, 0xfc, 0x64, 0x4, 0x7, 0xfc },
+{ 0x91, 0x94, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x31, 0xfc, 0x19, 0x4, 0x1, 0xfc, 0x60, 0x0, 0x33, 0xde, 0x2, 0x52, 0xb, 0xde, 0x18, 0x20, 0x17, 0xff, 0x30, 0xa8, 0x21, 0xac, 0x67, 0x27 },
+{ 0x91, 0x95, 0x4, 0x20, 0x24, 0x20, 0x37, 0xff, 0x14, 0x20, 0x4, 0x20, 0x1c, 0x20, 0x75, 0xfe, 0x4, 0x0, 0x0, 0x80, 0x7f, 0xff, 0x1, 0x44, 0x6, 0x4c, 0x7c, 0x28, 0x4, 0x30, 0x7, 0x9c, 0x3c, 0x7 },
+{ 0x91, 0x96, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x8, 0x80, 0x8, 0xfc, 0x8, 0x80, 0x1c, 0x80, 0x16, 0x80, 0x33, 0x80, 0x60, 0xff },
+{ 0x91, 0x97, 0x1, 0x4, 0x31, 0x8c, 0x18, 0x88, 0xb, 0xfe, 0x0, 0x20, 0x0, 0x20, 0x0, 0x20, 0x7b, 0xff, 0x8, 0x20, 0x8, 0x70, 0x8, 0x50, 0x8, 0xd8, 0x9, 0x8c, 0x1b, 0x6, 0x34, 0x0, 0x63, 0xff },
+{ 0x91, 0x98, 0x0, 0x90, 0x2f, 0xff, 0x30, 0x90, 0x17, 0xfe, 0x4, 0x92, 0x7, 0xfe, 0x4, 0x92, 0x77, 0xfe, 0x10, 0x0, 0x13, 0xfc, 0x12, 0x4, 0x13, 0xfc, 0x12, 0x4, 0x33, 0xfc, 0x28, 0x0, 0x67, 0xff },
+{ 0x91, 0x99, 0x8, 0x10, 0x1c, 0x38, 0x16, 0x6c, 0x32, 0xc6, 0x21, 0xbb, 0x7e, 0x0, 0x8, 0xfe, 0x8, 0x82, 0x7e, 0xfe, 0x8, 0x82, 0x4a, 0xfe, 0x6a, 0x80, 0x29, 0xff, 0xd, 0x41, 0x3b, 0x41, 0x60, 0x7f },
+{ 0x91, 0x9a, 0x0, 0x0, 0x3f, 0xfe, 0x0, 0x80, 0x7f, 0xff, 0x40, 0x81, 0x5e, 0xbd, 0x40, 0x81, 0x1e, 0xbc, 0x0, 0x80, 0x4, 0x7e, 0x7f, 0x42, 0x14, 0x7e, 0x16, 0x42, 0x35, 0x7e, 0x64, 0x42, 0x4, 0x7e },
+{ 0x91, 0x9b, 0x0, 0x0, 0x3f, 0x7e, 0x24, 0x22, 0x24, 0x14, 0x3f, 0x8, 0x24, 0x14, 0x24, 0x6b, 0x3f, 0x8, 0x24, 0x3e, 0x24, 0x2a, 0x3f, 0xaa, 0x0, 0xbe, 0x55, 0x88, 0x54, 0x8a, 0x41, 0x9f, 0x3, 0x71 },
+{ 0x91, 0x9c, 0x8, 0x80, 0x9, 0xf8, 0xb, 0x10, 0x16, 0x20, 0x13, 0xfe, 0x32, 0x22, 0x32, 0x22, 0x53, 0xfe, 0x10, 0x41, 0x11, 0xa3, 0x16, 0x56, 0x11, 0xb0, 0x16, 0x58, 0x11, 0x94, 0x16, 0x33, 0x10, 0xe0 },
+{ 0x91, 0x9d, 0x10, 0x82, 0x10, 0x44, 0x11, 0xff, 0x11, 0x11, 0x7d, 0x11, 0x11, 0xff, 0x11, 0x11, 0x11, 0x11, 0x11, 0xff, 0x10, 0x0, 0x1c, 0xfe, 0x70, 0x82, 0x0, 0xfe, 0x0, 0x82, 0x0, 0x82, 0x0, 0xfe },
+{ 0x91, 0x9e, 0x8, 0x82, 0x8, 0x44, 0x9, 0xff, 0x9, 0x11, 0x2d, 0x11, 0x2b, 0xff, 0x69, 0x11, 0x49, 0x11, 0x9, 0xff, 0x8, 0x0, 0x8, 0xfe, 0x8, 0x82, 0x8, 0xfe, 0x8, 0x82, 0x8, 0x82, 0x8, 0xfe },
+{ 0x91, 0x9f, 0x38, 0x48, 0x2b, 0xff, 0x28, 0x4a, 0x28, 0x49, 0x38, 0x4, 0x2b, 0xff, 0x2a, 0x4, 0x2a, 0xf4, 0x3a, 0xa5, 0x2a, 0xf7, 0x2a, 0x96, 0x2a, 0xf4, 0x2a, 0xac, 0x2a, 0xfd, 0x6c, 0x17, 0x58, 0x62 },
+{ 0x91, 0xa0, 0x2, 0x20, 0x2, 0x20, 0x7f, 0xff, 0x2, 0x24, 0x0, 0x12, 0x1f, 0xff, 0x10, 0x10, 0x17, 0xd2, 0x15, 0x16, 0x17, 0xd4, 0x14, 0x5c, 0x17, 0xc8, 0x15, 0x1c, 0x37, 0xf5, 0x20, 0x67, 0x61, 0xc2 },
+{ 0x91, 0xa1, 0x0, 0x82, 0x3c, 0x44, 0x25, 0xff, 0x25, 0x11, 0x3d, 0x11, 0x25, 0xff, 0x25, 0x11, 0x25, 0x11, 0x3d, 0xff, 0x24, 0x0, 0x24, 0xfe, 0x24, 0x82, 0x3c, 0xfe, 0x14, 0x82, 0x36, 0x82, 0x62, 0xfe },
+{ 0x91, 0xa2, 0x0, 0x20, 0x31, 0x20, 0x19, 0x20, 0xb, 0xfe, 0x2, 0x20, 0x6, 0x20, 0x0, 0x20, 0x77, 0xff, 0x10, 0x0, 0x11, 0xfc, 0x11, 0x4, 0x11, 0x4, 0x11, 0x4, 0x31, 0xfc, 0x28, 0x0, 0x67, 0xff },
+{ 0x91, 0xa3, 0x8, 0x0, 0xb, 0xfe, 0xa, 0x2, 0x1a, 0x2, 0x12, 0x2, 0x32, 0x2, 0x33, 0xfe, 0x50, 0x20, 0x10, 0x20, 0x11, 0x20, 0x11, 0x3e, 0x11, 0x20, 0x13, 0x20, 0x12, 0xa0, 0x12, 0x70, 0x14, 0x1f },
+{ 0x91, 0xa4, 0x8, 0x2, 0xb, 0xd2, 0x1a, 0x52, 0x12, 0x52, 0x13, 0xd2, 0x32, 0x52, 0x32, 0x52, 0x52, 0x52, 0x13, 0xd2, 0x12, 0x52, 0x12, 0x52, 0x12, 0x52, 0x13, 0xc2, 0x11, 0x42, 0x13, 0x62, 0x16, 0x2e },
+{ 0x91, 0xa5, 0x0, 0x2, 0x3f, 0x22, 0x21, 0x22, 0x21, 0x22, 0x3f, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x3f, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x2, 0x3f, 0x2, 0x12, 0x2, 0x33, 0x2, 0x61, 0x8e },
+{ 0x91, 0xa6, 0x0, 0x0, 0x3f, 0x3e, 0x21, 0x22, 0x21, 0x22, 0x3f, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x3f, 0x22, 0x20, 0x22, 0x21, 0x22, 0x21, 0x22, 0x27, 0xae, 0x3c, 0xa0, 0x60, 0x20, 0x0, 0x20 },
+{ 0x91, 0xa7, 0x0, 0x80, 0x1, 0x0, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x0, 0x80, 0x14, 0xc6, 0x14, 0x4b, 0x36, 0x19, 0x63, 0xf0 },
+{ 0x91, 0xa8, 0x10, 0x0, 0x13, 0xfe, 0x12, 0x2, 0x12, 0x2, 0x7a, 0x2, 0x12, 0x2, 0x13, 0xfe, 0x10, 0x20, 0x18, 0x20, 0x71, 0x20, 0x11, 0x3e, 0x11, 0x20, 0x13, 0x20, 0x12, 0xa0, 0x12, 0x70, 0x34, 0x1f },
+{ 0x91, 0xa9, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x2, 0xa0, 0x6, 0xb0, 0xc, 0x98, 0x18, 0x8c, 0x70, 0x87, 0x0, 0x80 },
+{ 0x91, 0xaa, 0x0, 0x2, 0x27, 0xd2, 0x34, 0x52, 0x14, 0x52, 0x7, 0xd2, 0x44, 0x52, 0x64, 0x52, 0x24, 0x52, 0x7, 0xd2, 0x14, 0x52, 0x14, 0x52, 0x14, 0x52, 0x37, 0xc2, 0x22, 0x82, 0x26, 0xc2, 0x6c, 0x6e },
+{ 0x91, 0xab, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x0, 0x80, 0x0, 0x80, 0x8, 0x80, 0x8, 0xfc, 0x8, 0x80, 0x1c, 0x80, 0x16, 0x80, 0x33, 0x80, 0x60, 0xff },
+{ 0x91, 0xac, 0x0, 0x20, 0x20, 0x20, 0x37, 0xff, 0x10, 0x20, 0x3, 0xfe, 0x2, 0x22, 0x2, 0x22, 0x72, 0x22, 0x13, 0xfe, 0x10, 0xa8, 0x11, 0xac, 0x13, 0x26, 0x16, 0x23, 0x30, 0x20, 0x28, 0x0, 0x67, 0xff },
+{ 0x91, 0xad, 0x8, 0x88, 0x9, 0x8c, 0x1b, 0x6, 0x16, 0x23, 0x10, 0x70, 0x30, 0xd8, 0x31, 0x8c, 0x53, 0x6, 0x16, 0x3, 0x10, 0x0, 0x13, 0xfe, 0x12, 0x2, 0x12, 0x2, 0x12, 0x2, 0x12, 0x2, 0x13, 0xfe },
+{ 0x91, 0xae, 0x0, 0x0, 0x1f, 0xfe, 0x10, 0x2, 0x1f, 0xfe, 0x10, 0x0, 0x13, 0xfc, 0x10, 0x40, 0x13, 0xfc, 0x12, 0x44, 0x13, 0xfc, 0x10, 0x40, 0x17, 0xfe, 0x34, 0x52, 0x24, 0x7a, 0x65, 0xca, 0x4, 0x6 },
+{ 0x91, 0xaf, 0x0, 0xa, 0x3c, 0xb, 0x24, 0x9, 0x24, 0x8, 0x3d, 0xff, 0x24, 0x8, 0x24, 0x48, 0x24, 0x49, 0x3d, 0xf9, 0x24, 0x4b, 0x24, 0x4a, 0x24, 0x4e, 0x3c, 0x4c, 0x14, 0x1d, 0x36, 0x37, 0x62, 0xe2 },
+{ 0x91, 0xb0, 0x8, 0x80, 0x8, 0x80, 0x8, 0x80, 0x7f, 0xff, 0x11, 0x0, 0x11, 0x40, 0x1e, 0x7e, 0x12, 0xd0, 0x12, 0x10, 0x12, 0x10, 0x12, 0xff, 0x12, 0x28, 0x12, 0x28, 0x32, 0x6c, 0x26, 0xc6, 0x6d, 0x83 },
+{ 0x91, 0xb1, 0x8, 0x10, 0x18, 0x10, 0x11, 0xff, 0x64, 0x10, 0x2c, 0x10, 0x18, 0xfe, 0x10, 0x0, 0x25, 0xff, 0x7d, 0x1, 0x15, 0x49, 0x10, 0x48, 0x54, 0x48, 0x54, 0x48, 0x54, 0xc9, 0x10, 0x89, 0x11, 0x87 },
+{ 0x91, 0xb2, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x0, 0x0, 0x4, 0x10, 0x4, 0x10, 0xe, 0x38, 0x1b, 0x6c, 0x30, 0x6, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80 },
+{ 0x91, 0xb3, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x7c, 0x10, 0x5, 0xff, 0xd, 0x11, 0x9, 0x11, 0x1b, 0x11, 0x15, 0x11, 0x39, 0xff, 0x55, 0x11, 0x15, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0xff, 0x10, 0x0 },
+{ 0x91, 0xb4, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x4, 0x10, 0x7, 0xf0, 0x4, 0x10, 0x4, 0x10, 0x7, 0xf0, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x0, 0x0, 0x4, 0x10, 0x1c, 0x1c, 0x70, 0x7 },
+{ 0x91, 0xb5, 0x11, 0x4, 0x11, 0x8c, 0x10, 0x88, 0x17, 0xff, 0x78, 0x0, 0x13, 0xc2, 0x12, 0x52, 0x12, 0x52, 0x1b, 0xd2, 0x72, 0x52, 0x12, 0x52, 0x13, 0xd2, 0x12, 0x42, 0x12, 0x42, 0x12, 0x42, 0x32, 0xce },
+{ 0x91, 0xb6, 0x1, 0x0, 0x1, 0x0, 0x7f, 0xff, 0x2, 0x0, 0x6, 0x0, 0x5, 0xfc, 0xc, 0x8, 0x18, 0x10, 0x38, 0x20, 0x6f, 0xff, 0x8, 0x20, 0x8, 0x20, 0x8, 0x20, 0x8, 0x20, 0x8, 0x20, 0x8, 0xe0 },
+{ 0x91, 0xb7, 0x0, 0x6, 0x7c, 0x1c, 0x5, 0xf0, 0x8, 0x40, 0x10, 0xc4, 0x11, 0x8c, 0x10, 0xd8, 0x10, 0x30, 0x1c, 0x62, 0x73, 0xff, 0x10, 0x21, 0x11, 0x24, 0x11, 0x24, 0x13, 0x26, 0x16, 0x23, 0x30, 0x20 },
+{ 0x91, 0xb8, 0x8, 0x8, 0x4, 0x10, 0x7f, 0xff, 0x1, 0x40, 0x1f, 0xfc, 0x11, 0x44, 0x1e, 0x7c, 0x10, 0x4, 0x1f, 0xfc, 0x10, 0x4, 0x1f, 0xfc, 0x0, 0x10, 0x7f, 0xff, 0x8, 0x10, 0x4, 0x10, 0x0, 0x70 },
+{ 0x91, 0xb9, 0x10, 0x0, 0x13, 0xfe, 0x12, 0x2, 0x12, 0x2, 0x7b, 0xfe, 0x10, 0x0, 0x13, 0xfe, 0x12, 0x2, 0x1b, 0xfe, 0x72, 0x2, 0x13, 0xfe, 0x12, 0x2, 0x13, 0xfe, 0x11, 0x4, 0x13, 0x6, 0x36, 0x3 },
+{ 0x91, 0xba, 0x8, 0x4, 0x8, 0x4, 0x8, 0x4, 0x7e, 0xff, 0x8, 0x4, 0x8, 0x4, 0x1c, 0x4, 0x1a, 0x64, 0x19, 0x34, 0x28, 0x14, 0x28, 0x4, 0x48, 0x4, 0x8, 0x4, 0x8, 0x4, 0x8, 0x4, 0x8, 0x1c },
+{ 0x91, 0xbb, 0x0, 0x2, 0x27, 0xce, 0x30, 0x78, 0x10, 0x92, 0x1, 0x26, 0x1, 0x1c, 0x1, 0xc8, 0x77, 0x12, 0x11, 0x7f, 0x11, 0x9, 0x11, 0x2a, 0x11, 0x2a, 0x11, 0x2a, 0x33, 0x8, 0x28, 0x0, 0x67, 0xff },
+{ 0x91, 0xbc, 0x8, 0x20, 0x8, 0x20, 0xa, 0x20, 0x1a, 0x2e, 0x12, 0x3a, 0x32, 0xe2, 0x33, 0xa2, 0x56, 0x22, 0x12, 0x22, 0x12, 0x26, 0x12, 0x20, 0x12, 0x20, 0x12, 0x0, 0x12, 0x1, 0x13, 0x3, 0x11, 0xfe },
+{ 0x91, 0xbd, 0x1, 0x0, 0x3, 0xf0, 0x6, 0x10, 0x1c, 0x30, 0x36, 0x60, 0x2, 0xc0, 0x3, 0x80, 0xe, 0x20, 0x38, 0x7e, 0x0, 0xc2, 0x3, 0x86, 0x6, 0xcc, 0x0, 0x58, 0x0, 0x70, 0x3, 0xc0, 0x1e, 0x0 },
+{ 0x91, 0xbe, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x1, 0x40, 0x1, 0x40, 0x1, 0x40, 0x3, 0x60, 0x2, 0x20, 0x6, 0x30, 0x5, 0x90, 0xc, 0xd8, 0x18, 0x4c, 0x70, 0x7 },
+{ 0x91, 0xbf, 0x0, 0x40, 0x20, 0x40, 0x30, 0x40, 0x10, 0x40, 0x0, 0x40, 0x4f, 0xff, 0x60, 0xa0, 0x20, 0xa0, 0x0, 0xa0, 0x9, 0xb0, 0x9, 0x10, 0x19, 0x18, 0x13, 0x48, 0x32, 0x6c, 0x26, 0x26, 0x6c, 0x3 },
+{ 0x91, 0xc0, 0x0, 0x10, 0x3c, 0x10, 0x0, 0x10, 0x7f, 0xff, 0x1, 0x1, 0x3d, 0x1, 0x0, 0x40, 0x0, 0x46, 0x3c, 0x5c, 0x0, 0x70, 0x0, 0x40, 0x3c, 0x40, 0x24, 0x40, 0x24, 0x41, 0x24, 0x63, 0x3c, 0x3e },
+{ 0x91, 0xc1, 0x0, 0xc, 0x0, 0x38, 0x7b, 0xe0, 0x48, 0x20, 0x4b, 0xfe, 0x49, 0x24, 0x49, 0x24, 0x49, 0x24, 0x4f, 0xff, 0x49, 0x24, 0x49, 0x24, 0x79, 0x24, 0x3, 0xfe, 0x0, 0x20, 0x0, 0x20, 0x7, 0xff },
+{ 0x91, 0xc2, 0x0, 0x20, 0x3c, 0x20, 0x25, 0xff, 0x24, 0x40, 0x28, 0x7e, 0x28, 0xc2, 0x25, 0x7e, 0x24, 0x42, 0x2c, 0x7e, 0x20, 0x42, 0x20, 0x46, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff },
+{ 0x91, 0xc3, 0x0, 0xc, 0x0, 0x78, 0x1f, 0xc0, 0x1, 0x4, 0x11, 0x8c, 0x18, 0x98, 0x9, 0x10, 0x1, 0x0, 0x7f, 0xff, 0x2, 0x10, 0x6, 0x10, 0x4, 0x30, 0xf, 0xa0, 0x0, 0xf0, 0x3, 0x9c, 0x3e, 0x6 },
+{ 0x91, 0xc4, 0x10, 0x40, 0x10, 0x40, 0x13, 0xff, 0x58, 0x80, 0x55, 0xfe, 0x53, 0x10, 0x56, 0xff, 0x10, 0x0, 0x11, 0xfe, 0x11, 0x2, 0x11, 0xfe, 0x11, 0x2, 0x11, 0xfe, 0x11, 0x2, 0x11, 0x2, 0x11, 0xe },
+{ 0x91, 0xc5, 0x8, 0x0, 0x8, 0x0, 0x9, 0xff, 0x8, 0x8, 0x7e, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xe, 0x8, 0x78, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x38, 0x38 },
+{ 0x91, 0xc6, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10, 0x7e, 0xff, 0x8, 0x81, 0x8, 0x81, 0x1c, 0x40, 0x1a, 0x46, 0x1a, 0x5c, 0x28, 0x70, 0x28, 0x40, 0x48, 0x40, 0x8, 0x40, 0x8, 0x41, 0x8, 0x63, 0x8, 0x3e },
+{ 0x91, 0xc7, 0x4, 0x10, 0x8, 0x10, 0x3e, 0x10, 0x22, 0xff, 0x2a, 0x81, 0x2a, 0x81, 0x22, 0x40, 0x7f, 0x46, 0x22, 0x5c, 0x2a, 0x70, 0x2a, 0x40, 0x2a, 0x40, 0x2a, 0x40, 0x22, 0x41, 0x62, 0x63, 0x46, 0x3e },
+{ 0x91, 0xc8, 0x10, 0x40, 0x10, 0x40, 0x13, 0xff, 0x7c, 0x80, 0x11, 0xfe, 0x13, 0x10, 0x38, 0xff, 0x34, 0x0, 0x35, 0xfe, 0x51, 0x2, 0x51, 0xfe, 0x11, 0x2, 0x11, 0xfe, 0x11, 0x2, 0x11, 0x2, 0x11, 0xe },
+{ 0x91, 0xc9, 0x0, 0x10, 0x3c, 0x10, 0x24, 0x10, 0x25, 0xff, 0x25, 0x1, 0x29, 0x1, 0x28, 0x40, 0x24, 0x46, 0x24, 0x5c, 0x24, 0x70, 0x24, 0x40, 0x24, 0x40, 0x2c, 0x40, 0x20, 0x41, 0x20, 0x63, 0x20, 0x3e },
+{ 0x91, 0xca, 0x0, 0x8, 0x3f, 0x88, 0x24, 0x8, 0x24, 0x8, 0x3f, 0x7f, 0x24, 0x8, 0x24, 0x8, 0x3f, 0x1c, 0x24, 0x14, 0x24, 0x14, 0x3f, 0x94, 0x0, 0xb6, 0x55, 0xa2, 0x54, 0xaa, 0x41, 0xab, 0x3, 0x41 },
+{ 0x91, 0xcb, 0x0, 0x91, 0x3f, 0xdb, 0x24, 0x4a, 0x24, 0x7f, 0x3f, 0x49, 0x24, 0x49, 0x24, 0x7f, 0x3f, 0x49, 0x24, 0x49, 0x24, 0x7f, 0x3f, 0x88, 0x0, 0x88, 0x55, 0xff, 0x54, 0x88, 0x41, 0x88, 0x3, 0x8 },
+{ 0x91, 0xcc, 0x8, 0x20, 0x8, 0x20, 0x8, 0x20, 0x18, 0x20, 0x17, 0xff, 0x10, 0xa8, 0x30, 0xa8, 0x50, 0xa8, 0x11, 0xac, 0x11, 0x24, 0x11, 0x24, 0x13, 0x26, 0x16, 0xfb, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20 },
+{ 0x91, 0xcd, 0x10, 0x24, 0x10, 0x6c, 0x10, 0x48, 0x10, 0xff, 0x7d, 0x90, 0x12, 0x90, 0x10, 0x90, 0x10, 0xfe, 0x10, 0x90, 0x10, 0x90, 0x10, 0x90, 0x1c, 0xfe, 0x70, 0x90, 0x0, 0x90, 0x0, 0x90, 0x0, 0xff },
+{ 0x91, 0xce, 0x8, 0x4, 0x8, 0x4, 0x8, 0x4, 0x7f, 0x84, 0x1, 0x7f, 0x1, 0x4, 0x33, 0x4, 0x1a, 0x64, 0xe, 0x34, 0x4, 0x14, 0xe, 0x4, 0xa, 0x4, 0x1b, 0x4, 0x31, 0x4, 0x60, 0x4, 0x0, 0x1c },
+{ 0x91, 0xcf, 0x0, 0x4, 0x7f, 0xc4, 0x4, 0x4, 0x8, 0x4, 0x3f, 0xbf, 0x2a, 0x84, 0x2a, 0x84, 0x2a, 0xa4, 0x2a, 0xb4, 0x2a, 0x94, 0x2a, 0x84, 0x2a, 0x84, 0x2a, 0x84, 0x2a, 0x84, 0x2a, 0x84, 0x21, 0x9c },
+{ 0x91, 0xd0, 0x4, 0x48, 0xc, 0x4c, 0x18, 0x44, 0x33, 0xff, 0x50, 0x20, 0x10, 0x30, 0x10, 0x18, 0x10, 0xd, 0x10, 0x7, 0x10, 0x2, 0x0, 0x80, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x3f, 0xfe, 0x0, 0x0 },
+{ 0x91, 0xd1, 0x8, 0x88, 0x8, 0x88, 0x7f, 0xff, 0x8, 0x88, 0x8, 0x88, 0xf, 0xf8, 0x0, 0x0, 0x3f, 0xfe, 0x20, 0x82, 0x20, 0x82, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x9c, 0x0, 0x80 },
+{ 0x91, 0xd2, 0x8, 0x20, 0x18, 0x20, 0x13, 0xfe, 0x30, 0x20, 0x60, 0x20, 0x8, 0x20, 0x1b, 0xff, 0x10, 0x4, 0x30, 0x4, 0x77, 0xff, 0x11, 0x4, 0x11, 0x84, 0x10, 0x84, 0x10, 0x4, 0x10, 0x4, 0x10, 0x1c },
+{ 0x91, 0xd3, 0x2, 0x0, 0x6, 0x18, 0x4, 0xc, 0xf, 0xfe, 0x38, 0x2, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x0, 0x80, 0x14, 0xc6, 0x14, 0x4b, 0x36, 0x19, 0x63, 0xf0 },
+{ 0x91, 0xd4, 0x8, 0x20, 0x18, 0x26, 0x31, 0x3c, 0x7f, 0xa0, 0x0, 0xa1, 0x3f, 0x1f, 0x21, 0x0, 0x3f, 0x26, 0x21, 0x3c, 0x3f, 0x20, 0x21, 0x21, 0x23, 0x1f, 0x0, 0xc0, 0x14, 0x66, 0x34, 0xb, 0x63, 0xf9 },
+{ 0x91, 0xd5, 0x2, 0x12, 0x1f, 0xd1, 0x2, 0x10, 0x7f, 0xff, 0x0, 0x10, 0x1f, 0x92, 0x14, 0x92, 0x1f, 0x96, 0x14, 0x94, 0x1f, 0x94, 0x9, 0x1c, 0x3f, 0xc8, 0x9, 0x9, 0x7f, 0xdd, 0x9, 0x17, 0x30, 0xb2 },
+{ 0x91, 0xd6, 0x4, 0x10, 0x4, 0x10, 0x3f, 0x7e, 0x4, 0x10, 0x4, 0x10, 0x7f, 0x7f, 0xa, 0x28, 0x19, 0x4c, 0x30, 0x6, 0x6f, 0xfb, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8 },
+{ 0x91, 0xd7, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x0, 0x80, 0x1f, 0xfc, 0x1, 0x40, 0x7f, 0xff, 0x2, 0x20, 0x4, 0x90, 0x18, 0x8c, 0x64, 0x93, 0x6, 0xb0, 0x3, 0xe0, 0xe, 0xb8, 0x38, 0x8e, 0x3, 0x80 },
+{ 0x91, 0xd8, 0x1, 0x24, 0x21, 0x24, 0x37, 0xff, 0x11, 0x24, 0x1, 0x24, 0x41, 0xfc, 0x60, 0x0, 0x27, 0xff, 0x4, 0x21, 0x14, 0x21, 0x13, 0xfe, 0x12, 0x22, 0x32, 0x22, 0x22, 0x22, 0x22, 0x26, 0x60, 0x20 },
+{ 0x91, 0xd9, 0x0, 0x20, 0x3c, 0x20, 0x24, 0x60, 0x24, 0x42, 0x24, 0xc2, 0x3c, 0x9f, 0x25, 0xf1, 0x24, 0x0, 0x24, 0x0, 0x3c, 0xfe, 0x24, 0x82, 0x24, 0x82, 0x24, 0x82, 0x24, 0x82, 0x64, 0x82, 0x4c, 0xfe },
+{ 0x91, 0xda, 0x0, 0x0, 0x3d, 0x3e, 0x25, 0xa2, 0x24, 0xa2, 0x24, 0x3e, 0x3c, 0x22, 0x24, 0x22, 0x27, 0xbe, 0x24, 0xa9, 0x3c, 0xaa, 0x24, 0xac, 0x24, 0xa4, 0x24, 0xb6, 0x24, 0xa3, 0x65, 0x40, 0x4d, 0x3f },
+{ 0x91, 0xdb, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x2, 0x0, 0x6, 0x18, 0x4, 0xc, 0xf, 0xfe, 0x78, 0x3, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8 },
+{ 0x91, 0xdc, 0x4, 0x48, 0xc, 0x44, 0xb, 0xfe, 0x18, 0x40, 0x38, 0x60, 0x68, 0x32, 0x8, 0x1a, 0x8, 0x8e, 0x0, 0x80, 0x7f, 0xff, 0x1, 0x40, 0x6, 0x62, 0x1c, 0x34, 0x74, 0x18, 0x7, 0x8c, 0x1c, 0x7 },
+{ 0x91, 0xdd, 0x4, 0x48, 0xc, 0x44, 0x1b, 0xff, 0x38, 0x20, 0x68, 0x30, 0x8, 0x19, 0x0, 0xf, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x4, 0x10, 0x38, 0xe },
+{ 0x91, 0xde, 0x0, 0x0, 0x31, 0xfc, 0x19, 0x4, 0x9, 0x4, 0x1, 0xfc, 0x1, 0x4, 0x1, 0x4, 0x79, 0xfd, 0x9, 0x23, 0x9, 0x36, 0x9, 0x10, 0x9, 0x18, 0x9, 0xec, 0x1b, 0x6, 0x34, 0x0, 0x63, 0xff },
+{ 0x91, 0xdf, 0x0, 0x20, 0x30, 0x20, 0x1b, 0xfe, 0x8, 0x22, 0x7, 0xff, 0x0, 0x22, 0x3, 0xfe, 0x78, 0x20, 0xb, 0x26, 0x9, 0xac, 0x8, 0x78, 0x9, 0xae, 0xb, 0x23, 0x18, 0x60, 0x34, 0x0, 0x63, 0xff },
+{ 0x91, 0xe0, 0x0, 0x84, 0x3e, 0xcc, 0x22, 0x48, 0x27, 0xff, 0x2c, 0x40, 0x29, 0xa0, 0x28, 0x22, 0x24, 0x56, 0x25, 0x94, 0x24, 0x38, 0x24, 0x58, 0x24, 0x94, 0x2b, 0x16, 0x20, 0x13, 0x20, 0x30, 0x20, 0xe0 },
+{ 0x91, 0xe1, 0x4, 0x24, 0xc, 0x22, 0x39, 0xff, 0x68, 0x20, 0x8, 0x11, 0x1f, 0xfd, 0x10, 0x87, 0x1f, 0xfc, 0x10, 0x84, 0x1f, 0xfc, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x7f, 0xff, 0x12, 0x24, 0x61, 0x13 },
+{ 0x91, 0xe2, 0x10, 0x0, 0x1e, 0x7f, 0x32, 0x41, 0x24, 0x49, 0x7f, 0x5d, 0x29, 0x49, 0x29, 0x49, 0x3f, 0x5d, 0x29, 0x41, 0x29, 0x5d, 0x3f, 0x55, 0x0, 0x55, 0x55, 0x5d, 0x55, 0x41, 0x55, 0x41, 0x0, 0x83 },
+{ 0x91, 0xe3, 0x4, 0x20, 0x4, 0x2c, 0xc, 0x26, 0x8, 0x22, 0x18, 0x20, 0x13, 0xff, 0x30, 0x20, 0x50, 0x20, 0x10, 0x30, 0x10, 0x10, 0x10, 0x10, 0x10, 0x18, 0x10, 0x9, 0x10, 0xd, 0x10, 0x7, 0x10, 0x2 },
+{ 0x91, 0xe4, 0x2, 0x0, 0x2, 0x0, 0x6, 0x8, 0x4, 0xc, 0xc, 0x4, 0x8, 0xfe, 0x7f, 0x83, 0x0, 0x1, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x1f, 0xfc },
+{ 0x91, 0xe5, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x1, 0xc0, 0x1, 0x40, 0x1, 0x40, 0x3, 0x60, 0x2, 0x20, 0x6, 0x30, 0xc, 0x18, 0x18, 0xc, 0x70, 0x7 },
+{ 0x91, 0xe6, 0x10, 0x20, 0x10, 0x20, 0x3f, 0x7f, 0x64, 0x90, 0x2, 0x8, 0x3f, 0xfc, 0x0, 0x84, 0x3f, 0xfc, 0x20, 0x80, 0x20, 0x80, 0x3f, 0xfe, 0x2, 0x82, 0x6, 0x82, 0x1c, 0x86, 0x70, 0x9c, 0x0, 0x80 },
+{ 0x91, 0xe7, 0x0, 0x0, 0x7f, 0x7e, 0x14, 0x42, 0x14, 0x7e, 0x7f, 0x42, 0x55, 0x42, 0x55, 0x7e, 0x55, 0x0, 0x67, 0xff, 0x41, 0x10, 0x41, 0x10, 0x7f, 0x1e, 0x41, 0x50, 0x41, 0x50, 0x7f, 0x70, 0x0, 0x9f },
+{ 0x91, 0xe8, 0x0, 0x0, 0x3e, 0xff, 0x22, 0x10, 0x3e, 0x7e, 0x22, 0x42, 0x22, 0x42, 0x3e, 0x7e, 0x0, 0x42, 0x7f, 0x42, 0x8, 0x7e, 0x28, 0x42, 0x2f, 0x42, 0x28, 0x7e, 0x28, 0x24, 0x78, 0x42, 0x4f, 0xff },
+{ 0x91, 0xe9, 0x0, 0x40, 0x3f, 0xff, 0x24, 0x88, 0x2d, 0xfe, 0x2b, 0x10, 0x39, 0xfe, 0x29, 0x10, 0x29, 0xff, 0x2a, 0x0, 0x27, 0xf8, 0x24, 0x8, 0x27, 0xf8, 0x64, 0x8, 0x47, 0xfe, 0x4a, 0xa2, 0x12, 0x96 },
+{ 0x91, 0xea, 0x0, 0x20, 0x20, 0x20, 0x37, 0xff, 0x11, 0x4, 0x0, 0x88, 0x47, 0xff, 0x60, 0x0, 0x23, 0xfe, 0x2, 0x22, 0xa, 0x22, 0xb, 0xfe, 0x1a, 0x22, 0x12, 0x22, 0x33, 0xfe, 0x20, 0x21, 0x60, 0x1f },
+{ 0x91, 0xeb, 0x21, 0x10, 0x31, 0x10, 0x1f, 0xff, 0x4, 0x50, 0x2, 0x9f, 0x4f, 0xe1, 0x60, 0x1f, 0x27, 0xd0, 0x4, 0x5f, 0x17, 0xd0, 0x14, 0x5f, 0x17, 0xd0, 0x34, 0x5f, 0x24, 0x50, 0x24, 0x51, 0x64, 0xcf },
+{ 0x91, 0xec, 0x0, 0x80, 0x0, 0x80, 0x0, 0xfc, 0x0, 0x80, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80 },
+{ 0x91, 0xed, 0x0, 0x0, 0x7, 0xff, 0x78, 0x40, 0x48, 0xc0, 0x49, 0xa2, 0x4f, 0x22, 0x48, 0x76, 0x48, 0xd4, 0x49, 0x90, 0x4f, 0x38, 0x78, 0x58, 0x0, 0xdc, 0x1, 0x94, 0x3, 0x16, 0xe, 0x33, 0x0, 0xe0 },
+{ 0x91, 0xee, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x2, 0x20, 0x32, 0x21, 0xe2, 0x1f, 0x0, 0x1, 0x0, 0x1, 0x0, 0x7f, 0xff, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x2, 0x1, 0x86, 0x0, 0xfc },
+{ 0x91, 0xef, 0x10, 0x6, 0x10, 0x3c, 0x11, 0xe0, 0x10, 0x20, 0x7c, 0x20, 0x10, 0x20, 0x10, 0x20, 0x13, 0xff, 0x1c, 0x20, 0x70, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x21, 0x10, 0x33, 0x70, 0x1e },
+{ 0x91, 0xf0, 0x10, 0x0, 0x11, 0xfe, 0x11, 0x2, 0x11, 0x2, 0x7d, 0x2, 0x11, 0x2, 0x11, 0xfe, 0x11, 0x10, 0x1d, 0x10, 0x71, 0x10, 0x11, 0x18, 0x11, 0x8, 0x11, 0xc, 0x13, 0x4, 0x12, 0x6, 0x36, 0x3 },
+{ 0x91, 0xf1, 0x10, 0x0, 0x17, 0xff, 0x10, 0x40, 0x10, 0x40, 0x7c, 0x40, 0x10, 0xc0, 0x10, 0x80, 0x10, 0xfe, 0x1d, 0x82, 0x73, 0x82, 0x16, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x30, 0xfe },
+{ 0x91, 0xf2, 0x0, 0x0, 0x31, 0xfe, 0x19, 0x2, 0x9, 0x2, 0x1, 0x2, 0x61, 0x2, 0x31, 0xfe, 0x11, 0x10, 0x1, 0x10, 0x9, 0x10, 0x9, 0x18, 0x19, 0x8, 0x13, 0xc, 0x32, 0x4, 0x26, 0x6, 0x6c, 0x3 },
+{ 0x91, 0xf3, 0x0, 0x0, 0x27, 0xdf, 0x30, 0x41, 0x17, 0xdf, 0x0, 0x41, 0x47, 0xdf, 0x60, 0x88, 0x21, 0x10, 0x3, 0xff, 0x16, 0x20, 0x13, 0xfe, 0x12, 0x20, 0x33, 0xfe, 0x22, 0x20, 0x22, 0x20, 0x63, 0xff },
+{ 0x91, 0xf4, 0x0, 0x0, 0x7d, 0xfe, 0x10, 0x40, 0x10, 0xc0, 0x11, 0xa2, 0x13, 0x26, 0x78, 0x74, 0x10, 0xd0, 0x11, 0x90, 0x13, 0x38, 0x10, 0x58, 0x1c, 0xd4, 0x71, 0x96, 0x3, 0x13, 0x6, 0x30, 0x0, 0xe0 },
+{ 0x91, 0xf5, 0x0, 0x6, 0x3c, 0x1c, 0x0, 0xf0, 0x7e, 0x20, 0x0, 0x20, 0x3c, 0x20, 0x0, 0x20, 0x1, 0xff, 0x3c, 0x20, 0x0, 0x20, 0x0, 0x20, 0x3c, 0x20, 0x24, 0x20, 0x24, 0x21, 0x24, 0x33, 0x3c, 0x1e },
+{ 0x91, 0xf6, 0x10, 0x0, 0x38, 0xfe, 0x2c, 0xaa, 0x64, 0xaa, 0x40, 0xfe, 0x7c, 0x10, 0x10, 0xfe, 0x10, 0x10, 0x7d, 0xff, 0x10, 0x44, 0x54, 0x28, 0x55, 0xff, 0x50, 0x10, 0x1c, 0xfe, 0x30, 0x10, 0x60, 0x10 },
+{ 0x91, 0xf7, 0x0, 0x0, 0x27, 0xfe, 0x34, 0x92, 0x14, 0x92, 0x7, 0xfe, 0x41, 0x0, 0x63, 0xff, 0x26, 0x41, 0xf, 0xf9, 0x12, 0x49, 0x12, 0x49, 0x13, 0xf9, 0x30, 0x51, 0x21, 0xfb, 0x27, 0xa, 0x60, 0x6 },
+{ 0x91, 0xf8, 0x0, 0x44, 0x3c, 0x44, 0x1, 0xff, 0x7e, 0x44, 0x0, 0x44, 0x3c, 0x20, 0x0, 0x20, 0x1, 0xff, 0x3c, 0x40, 0x0, 0x40, 0x0, 0xfe, 0x3d, 0x42, 0x24, 0x42, 0x24, 0x42, 0x24, 0x42, 0x3c, 0x7e },
+{ 0x91, 0xf9, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x0, 0x0, 0x7f, 0xff, 0x4, 0x10, 0x7, 0xf0, 0x4, 0x10, 0x4, 0x10, 0x7, 0xf0, 0x4, 0x10, 0x4, 0x1f, 0x7, 0xf0, 0x7c, 0x10, 0x0, 0x10 },
+{ 0x91, 0xfa, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x4, 0x10, 0x84, 0x10, 0x84, 0x17, 0xf4, 0x14, 0x94, 0x14, 0x94, 0x14, 0x94, 0x14, 0x94, 0x14, 0x94, 0x14, 0x94, 0x14, 0xb5, 0x30, 0x85, 0x20, 0x87, 0x60, 0x2 },
+{ 0x91, 0xfb, 0x10, 0x10, 0x11, 0x11, 0x11, 0x93, 0x7e, 0x92, 0x52, 0x10, 0x52, 0xfe, 0x52, 0x82, 0x52, 0x82, 0x7e, 0xfe, 0x10, 0x82, 0x10, 0x82, 0x14, 0xfe, 0x14, 0x82, 0x1e, 0x82, 0x72, 0x82, 0x0, 0x8e },
+{ 0x91, 0xfc, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x4, 0x10, 0xc, 0x18, 0x18, 0xc, 0x30, 0x6 },
+{ 0x92, 0x40, 0x0, 0x0, 0x3e, 0x7e, 0x22, 0x42, 0x22, 0x42, 0x22, 0x42, 0x22, 0x42, 0x22, 0x42, 0x22, 0x42, 0x22, 0x42, 0x22, 0x42, 0x22, 0x42, 0x22, 0x42, 0x3e, 0x4e, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40 },
+{ 0x92, 0x41, 0x4, 0x0, 0x5, 0xfc, 0xd, 0x4, 0x9, 0x4, 0x19, 0x4, 0x11, 0x4, 0x31, 0xfc, 0x51, 0x4, 0x11, 0x4, 0x11, 0x4, 0x11, 0x4, 0x11, 0xfc, 0x10, 0x0, 0x10, 0x0, 0x17, 0xff, 0x10, 0x0 },
+{ 0x92, 0x42, 0x0, 0x20, 0x30, 0x20, 0x19, 0xfe, 0x8, 0x20, 0x3, 0xff, 0x0, 0x84, 0x0, 0x48, 0x7b, 0xff, 0x8, 0x20, 0x9, 0xfe, 0x8, 0x20, 0xb, 0xff, 0x8, 0x20, 0x18, 0x20, 0x34, 0x0, 0x63, 0xff },
+{ 0x92, 0x43, 0x0, 0x0, 0x1f, 0xff, 0x10, 0x0, 0x10, 0x0, 0x13, 0xfc, 0x10, 0x0, 0x10, 0x0, 0x1f, 0xff, 0x12, 0x40, 0x12, 0x42, 0x12, 0x66, 0x12, 0x2c, 0x32, 0x30, 0x22, 0x18, 0x63, 0xcc, 0xe, 0x7 },
+{ 0x92, 0x44, 0x0, 0x80, 0x7f, 0xff, 0x2, 0x20, 0xc, 0x18, 0x72, 0x47, 0x7, 0xfc, 0x18, 0x80, 0x6f, 0xf8, 0x8, 0x80, 0xf, 0xf8, 0x8, 0x80, 0xf, 0xfe, 0x0, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x2, 0x70 },
+{ 0x92, 0x45, 0x0, 0x84, 0x3c, 0xcc, 0x24, 0x48, 0x25, 0xfe, 0x25, 0x2, 0x3d, 0x2, 0x25, 0x2, 0x25, 0x2, 0x25, 0xfe, 0x3c, 0x48, 0x24, 0x48, 0x24, 0x48, 0x24, 0x48, 0x24, 0xc9, 0x64, 0x89, 0x4d, 0x87 },
+{ 0x92, 0x46, 0x0, 0x0, 0x3f, 0x7e, 0x1, 0x2, 0x3f, 0x7e, 0x20, 0x40, 0x21, 0x42, 0x1f, 0x3e, 0x0, 0x0, 0x2, 0x20, 0x1f, 0xfc, 0x2, 0x20, 0x2, 0x20, 0x7f, 0xff, 0x4, 0x10, 0xc, 0x18, 0x38, 0xe },
+{ 0x92, 0x47, 0x0, 0x0, 0x3f, 0x7e, 0x24, 0x22, 0x3f, 0x36, 0x21, 0x14, 0x3f, 0x1c, 0x24, 0x36, 0x3f, 0x63, 0x0, 0x0, 0x0, 0x80, 0x3f, 0xfe, 0x4, 0x10, 0x6, 0x30, 0x2, 0x20, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x92, 0x48, 0x0, 0x20, 0x30, 0x20, 0x18, 0x20, 0xa, 0x22, 0x2, 0x22, 0x2, 0x22, 0x2, 0x22, 0x7a, 0x22, 0xa, 0x22, 0xa, 0x22, 0xa, 0x22, 0xa, 0x22, 0xb, 0xfe, 0x18, 0x0, 0x34, 0x0, 0x63, 0xff },
+{ 0x92, 0x49, 0x10, 0x0, 0x13, 0xde, 0x12, 0x52, 0x7e, 0x52, 0x12, 0x52, 0x13, 0xde, 0x3a, 0x52, 0x36, 0x52, 0x32, 0x52, 0x53, 0xde, 0x52, 0x52, 0x12, 0x52, 0x12, 0x52, 0x12, 0x52, 0x12, 0x52, 0x14, 0xa6 },
+{ 0x92, 0x4a, 0x2, 0x20, 0x6, 0x30, 0xc, 0x18, 0x38, 0x8e, 0x1, 0xc0, 0x3, 0x60, 0x6, 0x30, 0x1c, 0x1c, 0x70, 0x7, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8 },
+{ 0x92, 0x4b, 0x4, 0x0, 0x45, 0xfe, 0x29, 0x22, 0x11, 0x22, 0x11, 0xfe, 0x29, 0x22, 0x49, 0x22, 0x9, 0x22, 0x19, 0xfe, 0x18, 0x20, 0x28, 0x20, 0x49, 0xfe, 0x8, 0x20, 0x8, 0x20, 0x1b, 0xff, 0x70, 0x0 },
+{ 0x92, 0x4c, 0x10, 0x0, 0x1e, 0xff, 0x32, 0x10, 0x24, 0xff, 0x7e, 0x91, 0x2a, 0xdd, 0x2a, 0x91, 0x3e, 0x5c, 0x2a, 0x0, 0x2a, 0x7e, 0x3e, 0x2, 0x0, 0x2, 0x55, 0x7e, 0x55, 0x2, 0x54, 0x2, 0x40, 0x7e },
+{ 0x92, 0x4d, 0x10, 0x84, 0x10, 0x48, 0x13, 0xff, 0x7c, 0x50, 0x11, 0xfe, 0x11, 0x52, 0x39, 0x9e, 0x35, 0x2, 0x35, 0xfe, 0x51, 0x2, 0x51, 0xfe, 0x10, 0x4, 0x13, 0xff, 0x10, 0x84, 0x10, 0x44, 0x10, 0x1c },
+{ 0x92, 0x4e, 0x0, 0x44, 0x3c, 0x4c, 0x0, 0x48, 0x7e, 0xff, 0x0, 0x88, 0x3d, 0x88, 0x2, 0x88, 0x0, 0xfe, 0x3c, 0x88, 0x0, 0x88, 0x0, 0x88, 0x3c, 0xfe, 0x24, 0x88, 0x24, 0x88, 0x24, 0x88, 0x3c, 0xff },
+{ 0x92, 0x4f, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x9, 0x88, 0x8, 0xc8, 0x8, 0x48, 0x8, 0x8, 0x7f, 0xff, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x18, 0x8, 0x10, 0x8, 0x30, 0x8, 0x60, 0x38 },
+{ 0x92, 0x50, 0x11, 0x4, 0x19, 0x8c, 0x8, 0x88, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80 },
+{ 0x92, 0x51, 0x0, 0x88, 0x7, 0xff, 0x78, 0x88, 0x48, 0x0, 0x4b, 0xfe, 0x4a, 0x22, 0x4a, 0x22, 0x4b, 0xfe, 0x48, 0x20, 0x49, 0xfc, 0x48, 0x20, 0x7b, 0xff, 0x0, 0x50, 0x0, 0xd8, 0x1, 0x8c, 0x7, 0x7 },
+{ 0x92, 0x52, 0x10, 0x0, 0x11, 0xfc, 0x11, 0x4, 0x11, 0x4, 0x7d, 0x4, 0x11, 0x4, 0x11, 0xfc, 0x11, 0x4, 0x11, 0x4, 0x11, 0x4, 0x1d, 0x4, 0x71, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, 0x0, 0x0 },
+{ 0x92, 0x53, 0x10, 0x0, 0x11, 0xfc, 0x11, 0x4, 0x11, 0x4, 0x7d, 0x4, 0x11, 0x4, 0x11, 0xfc, 0x11, 0x4, 0x1d, 0x4, 0x71, 0x4, 0x11, 0x4, 0x11, 0xfc, 0x10, 0x0, 0x10, 0x0, 0x17, 0xff, 0x30, 0x0 },
+{ 0x92, 0x54, 0x10, 0x0, 0x13, 0xfe, 0x12, 0x52, 0x12, 0x52, 0x7c, 0xd0, 0x11, 0x9f, 0x13, 0x0, 0x10, 0x20, 0x1c, 0x20, 0x73, 0xff, 0x10, 0xa8, 0x10, 0xa8, 0x11, 0xac, 0x13, 0x26, 0x16, 0x23, 0x30, 0x20 },
+{ 0x92, 0x55, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x92, 0x56, 0x11, 0x10, 0x7f, 0xd0, 0x11, 0x10, 0x0, 0x1f, 0x3f, 0xb1, 0x24, 0xab, 0x24, 0xea, 0x3f, 0x88, 0x4, 0x8, 0x3f, 0x9c, 0x4, 0x14, 0x7f, 0xd4, 0xa, 0x14, 0x1b, 0x36, 0x31, 0xa2, 0x60, 0x63 },
+{ 0x92, 0x57, 0x0, 0x20, 0x31, 0x22, 0x19, 0x26, 0xb, 0x74, 0x2, 0x50, 0x60, 0xd8, 0x31, 0x8c, 0x13, 0x27, 0x0, 0x20, 0x9, 0x26, 0xb, 0x2c, 0x1a, 0x70, 0x10, 0x50, 0x30, 0xd8, 0x21, 0x8c, 0x67, 0x7 },
+{ 0x92, 0x58, 0x1, 0x4, 0x27, 0xff, 0x31, 0x4, 0x11, 0x4, 0x1, 0xfc, 0x41, 0x4, 0x61, 0x4, 0x21, 0xfc, 0x1, 0x4, 0x11, 0x4, 0x1f, 0xff, 0x12, 0x48, 0x32, 0x48, 0x23, 0x8f, 0x22, 0x0, 0x63, 0xff },
+{ 0x92, 0x59, 0x0, 0x80, 0x10, 0x82, 0x10, 0x82, 0x1f, 0xfe, 0x0, 0x0, 0x1f, 0xff, 0x10, 0x0, 0x10, 0x40, 0x12, 0x44, 0x12, 0x4c, 0x16, 0x58, 0x14, 0xe0, 0x30, 0xb0, 0x21, 0x98, 0x63, 0xc, 0xe, 0x7 },
+{ 0x92, 0x5a, 0x10, 0x0, 0x10, 0xff, 0x3f, 0x0, 0x28, 0x0, 0x68, 0x7e, 0x8, 0x42, 0x7f, 0x42, 0x8, 0x42, 0x8, 0x7e, 0x1c, 0x0, 0x16, 0x42, 0x13, 0x66, 0x31, 0x24, 0x20, 0x4, 0x60, 0xff, 0x0, 0x0 },
+{ 0x92, 0x5b, 0x8, 0x10, 0x9, 0x11, 0x9, 0x11, 0x7f, 0x11, 0x1, 0xff, 0x24, 0x0, 0x25, 0xff, 0x24, 0x10, 0x2c, 0x20, 0x29, 0xff, 0x9, 0x49, 0xf, 0x49, 0x39, 0x49, 0x61, 0x49, 0x1, 0x49, 0x1, 0x4b },
+{ 0x92, 0x5c, 0x10, 0x20, 0x10, 0x20, 0x3f, 0x7f, 0x28, 0x90, 0x44, 0x8, 0x11, 0x4, 0x8, 0x88, 0x1f, 0xfc, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x84, 0x1f, 0xfc, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80 },
+{ 0x92, 0x5d, 0x8, 0x10, 0x18, 0x10, 0x11, 0xff, 0x65, 0x1, 0x2d, 0x1, 0x18, 0xfe, 0x10, 0x10, 0x24, 0x10, 0x7e, 0x90, 0x12, 0x9e, 0x10, 0x90, 0x54, 0x90, 0x54, 0x90, 0x54, 0xd0, 0x11, 0xb0, 0x13, 0x1f },
+{ 0x92, 0x5e, 0x0, 0x10, 0x7e, 0x10, 0x24, 0x10, 0x24, 0xff, 0x24, 0x91, 0x3c, 0x91, 0x24, 0x10, 0x24, 0x10, 0x24, 0x38, 0x3c, 0x28, 0x24, 0x28, 0x24, 0x28, 0x24, 0x68, 0x3c, 0x49, 0x64, 0xc9, 0x5, 0x87 },
+{ 0x92, 0x5f, 0x0, 0x0, 0x3c, 0xfc, 0x24, 0x84, 0x24, 0x84, 0x24, 0x84, 0x3c, 0x84, 0x24, 0xfc, 0x24, 0x84, 0x24, 0x84, 0x3c, 0x84, 0x24, 0x84, 0x24, 0xfc, 0x24, 0x0, 0x24, 0x0, 0x65, 0xff, 0x4c, 0x0 },
+{ 0x92, 0x60, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x81, 0x8, 0x80, 0x8, 0xfc, 0x1e, 0x80, 0x33, 0x80, 0x60, 0xff, 0x0, 0x80, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x0, 0x82, 0x0, 0xff, 0x7f, 0x81 },
+{ 0x92, 0x61, 0x0, 0x2, 0x3b, 0xce, 0x0, 0xb8, 0x7c, 0x88, 0x1, 0x8, 0x39, 0x28, 0x3, 0xae, 0x0, 0xa8, 0x3a, 0xa8, 0x2, 0xa8, 0x2, 0xa8, 0x3b, 0xa8, 0x29, 0x7e, 0x29, 0x0, 0x2b, 0xc0, 0x3a, 0x7f },
+{ 0x92, 0x62, 0x10, 0x60, 0x39, 0xde, 0x2d, 0x12, 0x65, 0x12, 0x1, 0xd2, 0x7d, 0x23, 0x11, 0x0, 0x11, 0xc0, 0x7d, 0x3e, 0x11, 0x12, 0x55, 0x16, 0x55, 0xcc, 0x53, 0x8, 0x11, 0x1c, 0x1d, 0x36, 0x71, 0x63 },
+{ 0x92, 0x63, 0x0, 0x0, 0x3f, 0xfe, 0x20, 0x2, 0x20, 0x22, 0x20, 0x22, 0x2f, 0xfa, 0x20, 0x22, 0x22, 0x22, 0x23, 0x22, 0x21, 0x22, 0x20, 0x22, 0x20, 0x22, 0x20, 0xe2, 0x20, 0x2, 0x3f, 0xfe, 0x0, 0x0 },
+{ 0x92, 0x64, 0x10, 0x20, 0x17, 0xff, 0x10, 0x0, 0x13, 0xfe, 0x7e, 0x2, 0x12, 0xfa, 0x12, 0x8a, 0x12, 0xfa, 0x12, 0x2, 0x13, 0xfe, 0x1d, 0x4, 0x71, 0xfc, 0x1, 0x4, 0x1, 0xfc, 0x1, 0x4, 0x7, 0xff },
+{ 0x92, 0x65, 0x2, 0x42, 0x7b, 0x66, 0x9, 0x24, 0xb, 0xfe, 0xa, 0x22, 0x3a, 0x22, 0x23, 0xfe, 0x22, 0x22, 0x22, 0x22, 0x3b, 0xfe, 0x8, 0x20, 0x8, 0x20, 0xf, 0xff, 0x18, 0x20, 0x10, 0x20, 0x30, 0x20 },
+{ 0x92, 0x66, 0x0, 0x2, 0x22, 0xe, 0x2a, 0xb8, 0x2a, 0xa0, 0x2a, 0xa0, 0x22, 0x20, 0x2f, 0xbf, 0x22, 0x24, 0x27, 0x24, 0x26, 0xa4, 0x2a, 0xa4, 0x22, 0x24, 0x22, 0x24, 0x20, 0x24, 0x3f, 0xe4, 0x0, 0x44 },
+{ 0x92, 0x67, 0x0, 0xc, 0x0, 0x78, 0x7b, 0xc2, 0x49, 0x26, 0x48, 0x94, 0x4b, 0xff, 0x48, 0x40, 0x7b, 0xff, 0x48, 0x40, 0x48, 0x7c, 0x48, 0xc4, 0x48, 0xac, 0x79, 0x98, 0x3, 0x30, 0x6, 0x6c, 0x1, 0xc7 },
+{ 0x92, 0x68, 0x10, 0x20, 0x13, 0xff, 0x10, 0x0, 0x7d, 0xfe, 0x11, 0x2, 0x11, 0x7a, 0x39, 0x4a, 0x35, 0x7a, 0x35, 0x2, 0x51, 0xfe, 0x50, 0x84, 0x10, 0xfc, 0x10, 0x84, 0x10, 0xfc, 0x10, 0x84, 0x13, 0xff },
+{ 0x92, 0x69, 0x2, 0x0, 0xe, 0xf8, 0x38, 0x88, 0x20, 0x88, 0x20, 0x88, 0x3d, 0x88, 0x23, 0xf, 0x20, 0x0, 0x3d, 0xfc, 0x20, 0x84, 0x20, 0xcc, 0x20, 0x48, 0x3c, 0x58, 0x60, 0x30, 0x20, 0xec, 0x23, 0x87 },
+{ 0x92, 0x6a, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x0, 0x0, 0x0, 0x80, 0x3f, 0xfe, 0x0, 0x82, 0x1, 0x82, 0x3, 0x6, 0xe, 0x4, 0x38, 0x1c },
+{ 0x92, 0x6b, 0x0, 0x10, 0x3c, 0x91, 0x0, 0x93, 0x7e, 0xba, 0x1, 0x28, 0x3c, 0x6c, 0x0, 0xc6, 0x1, 0x93, 0x3c, 0x10, 0x0, 0x91, 0x0, 0x93, 0x3d, 0xba, 0x25, 0x28, 0x24, 0x6c, 0x24, 0xc6, 0x3d, 0x83 },
+{ 0x92, 0x6c, 0x8, 0x20, 0x8, 0x20, 0xf, 0xff, 0x18, 0x20, 0x11, 0xfc, 0x35, 0x4, 0x35, 0x4, 0x55, 0xfc, 0x15, 0x4, 0x15, 0x4, 0x15, 0xfc, 0x15, 0x4, 0x15, 0x4, 0x15, 0xfc, 0x14, 0x0, 0x17, 0xff },
+{ 0x92, 0x6d, 0x10, 0x0, 0x10, 0x0, 0x3f, 0x7e, 0x24, 0x42, 0x64, 0x42, 0x4, 0x42, 0x4, 0x42, 0x7f, 0xc2, 0x4, 0x42, 0x4, 0x42, 0xe, 0x42, 0xa, 0x42, 0x1b, 0x42, 0x11, 0x7e, 0x31, 0x80, 0x60, 0x0 },
+{ 0x92, 0x6e, 0x0, 0x10, 0x10, 0x90, 0x10, 0x90, 0x10, 0x96, 0x10, 0x9a, 0x7c, 0xb2, 0x10, 0xd2, 0x13, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x96, 0x1c, 0x90, 0x70, 0x80, 0x0, 0x81, 0x0, 0xc3, 0x0, 0x7e },
+{ 0x92, 0x6f, 0x0, 0x10, 0x7c, 0x90, 0x4, 0x90, 0x4, 0x96, 0x4, 0x9a, 0x3c, 0xb2, 0x20, 0xd2, 0x23, 0x92, 0x20, 0x92, 0x3c, 0x92, 0x4, 0x96, 0x4, 0x90, 0x4, 0x80, 0xc, 0x81, 0x8, 0xc3, 0x38, 0x7e },
+{ 0x92, 0x70, 0x0, 0x0, 0x7e, 0x30, 0x24, 0x10, 0x24, 0x18, 0x3c, 0x48, 0x24, 0x40, 0x24, 0x40, 0x24, 0x42, 0x3d, 0x43, 0x25, 0x41, 0x25, 0x41, 0x25, 0x40, 0x3e, 0x42, 0x64, 0x66, 0x4, 0x3c, 0x4, 0x0 },
+{ 0x92, 0x71, 0x10, 0x0, 0x1f, 0x7e, 0x24, 0x42, 0x4, 0x42, 0x7f, 0xc2, 0x4, 0x42, 0xe, 0x42, 0x1b, 0x7e, 0x70, 0x0, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8 },
+{ 0x92, 0x72, 0x0, 0x20, 0x31, 0x20, 0x19, 0x20, 0x9, 0x26, 0x1, 0x3a, 0x61, 0x62, 0x31, 0xa2, 0x17, 0x22, 0x1, 0x22, 0x9, 0x22, 0x9, 0x26, 0x19, 0x20, 0x11, 0x0, 0x31, 0x1, 0x21, 0x83, 0x60, 0xfe },
+{ 0x92, 0x73, 0x0, 0x40, 0x0, 0x40, 0x1f, 0xff, 0x10, 0x0, 0x52, 0x0, 0x33, 0xde, 0x15, 0x12, 0x11, 0x12, 0x11, 0x12, 0x3f, 0xf2, 0x51, 0x12, 0x13, 0x92, 0x32, 0x92, 0x22, 0xd2, 0x66, 0x5e, 0xc, 0x0 },
+{ 0x92, 0x74, 0x2, 0x24, 0xe, 0x2c, 0x78, 0x28, 0x8, 0x7f, 0x8, 0x48, 0x7e, 0xc8, 0x9, 0x48, 0x8, 0x7e, 0x1c, 0x48, 0x1a, 0x48, 0x2a, 0x48, 0x28, 0x7e, 0x48, 0x48, 0x8, 0x48, 0x8, 0x48, 0x8, 0x7f },
+{ 0x92, 0x75, 0x0, 0x0, 0x3f, 0xfe, 0x22, 0x22, 0x3f, 0xfe, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x7, 0xf8, 0x24, 0x8, 0x27, 0xf8, 0x24, 0x8, 0x27, 0xf8, 0x24, 0x8, 0x27, 0xf8, 0x20, 0x0, 0x3f, 0xff },
+{ 0x92, 0x76, 0x0, 0x20, 0x7e, 0x20, 0x10, 0x20, 0x10, 0x7f, 0x32, 0x44, 0x22, 0xc4, 0x2f, 0x24, 0x79, 0x2c, 0x8, 0x28, 0x8, 0x38, 0x7f, 0x10, 0x8, 0x38, 0x8, 0x28, 0xb, 0x6c, 0x1e, 0xc6, 0x71, 0x83 },
+{ 0x92, 0x77, 0x10, 0x80, 0x10, 0x80, 0x10, 0x8f, 0x7d, 0xf9, 0x56, 0x49, 0x54, 0x49, 0x54, 0x49, 0x57, 0xf9, 0x7c, 0x49, 0x10, 0x49, 0x10, 0x49, 0x14, 0xe9, 0x1c, 0xa9, 0x35, 0xaf, 0x63, 0x10, 0x6, 0x0 },
+{ 0x92, 0x78, 0x0, 0x0, 0x33, 0xfe, 0x1a, 0x2, 0xa, 0x2, 0x3, 0xfe, 0x2, 0x44, 0x2, 0x28, 0x7a, 0xfe, 0xa, 0x10, 0xa, 0xfe, 0xa, 0x10, 0xd, 0xff, 0x8, 0x10, 0x18, 0x10, 0x34, 0x0, 0x63, 0xff },
+{ 0x92, 0x79, 0x0, 0x8, 0x3f, 0xa8, 0x24, 0x28, 0x24, 0x2e, 0x3f, 0x2a, 0x24, 0x3a, 0x24, 0x2a, 0x3f, 0x6a, 0x24, 0x2a, 0x24, 0x2a, 0x3f, 0xae, 0x0, 0xa8, 0x55, 0xa8, 0x54, 0xa1, 0x41, 0xb3, 0x3, 0x1e },
+{ 0x92, 0x7a, 0x10, 0x20, 0x10, 0x20, 0x3f, 0x7f, 0x24, 0x90, 0x42, 0x8, 0x3f, 0x7c, 0x8, 0x44, 0x8, 0x54, 0xf, 0x55, 0x78, 0x83, 0x0, 0x80, 0x7f, 0xff, 0x2, 0xa0, 0xe, 0xb8, 0x78, 0x8f, 0x0, 0x80 },
+{ 0x92, 0x7b, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x1, 0x0, 0x2, 0x10, 0x1c, 0x24, 0x6, 0x42, 0x1, 0xff, 0x7f, 0x1, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc },
+{ 0x92, 0x7c, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10, 0x1f, 0xbf, 0x14, 0x28, 0x34, 0x68, 0x64, 0xc8, 0x4, 0x8, 0x4, 0x8, 0x4, 0x8, 0x4, 0x8, 0x4, 0x8, 0x4, 0x8, 0x4, 0x8, 0x4, 0x8, 0x4, 0x38 },
+{ 0x92, 0x7d, 0x10, 0x20, 0x10, 0x20, 0x1f, 0x7f, 0x34, 0x90, 0x66, 0x18, 0x2, 0x8, 0x0, 0x0, 0x3e, 0xfc, 0x8, 0x84, 0x8, 0xa4, 0x8, 0xb4, 0x8, 0x94, 0xe, 0x84, 0x39, 0x85, 0x61, 0x5, 0x3, 0x3 },
+{ 0x92, 0x7e, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x0, 0x80, 0x3f, 0xfe, 0x2, 0x0, 0xc, 0x24, 0x3, 0x42, 0x7f, 0xff, 0x0, 0x1, 0x1f, 0xfc, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x84, 0x1f, 0xfc },
+{ 0x92, 0x80, 0x0, 0x0, 0x33, 0xff, 0x18, 0x20, 0x8, 0x60, 0x0, 0xd2, 0x3, 0xb6, 0x0, 0x7c, 0x78, 0xd0, 0xb, 0xb8, 0x8, 0x7c, 0x8, 0xd6, 0xb, 0x93, 0x8, 0x30, 0x18, 0xe0, 0x34, 0x0, 0x63, 0xff },
+{ 0x92, 0x81, 0x2, 0x10, 0xe, 0x90, 0x78, 0x90, 0x8, 0xfe, 0x9, 0x90, 0x7f, 0x10, 0x8, 0x10, 0x9, 0xff, 0x1c, 0x10, 0x1a, 0x38, 0x2a, 0x28, 0x28, 0x28, 0x48, 0x6c, 0x8, 0x44, 0x8, 0xc6, 0x9, 0x83 },
+{ 0x92, 0x82, 0x0, 0x80, 0x3f, 0xfe, 0x22, 0x22, 0x24, 0x22, 0x78, 0x3f, 0x0, 0x0, 0x3f, 0xff, 0x2, 0x10, 0x4, 0x8, 0x1f, 0xf4, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x92, 0x83, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x4, 0x90, 0x1, 0xc0, 0x3, 0x60, 0x6, 0x30, 0x1c, 0x9c, 0x70, 0x87, 0xf, 0xf8, 0x0, 0x80, 0x4, 0x90, 0x1c, 0x9c, 0x70, 0x87, 0x0, 0x80 },
+{ 0x92, 0x84, 0x10, 0x10, 0x10, 0x10, 0x11, 0xff, 0x10, 0x82, 0x7c, 0x44, 0x15, 0xff, 0x15, 0x11, 0x15, 0x11, 0x35, 0x7d, 0x25, 0x11, 0x2d, 0x7d, 0x79, 0x45, 0xd, 0x45, 0x1b, 0x7d, 0x31, 0x1, 0x61, 0x3 },
+{ 0x92, 0x85, 0x4, 0x10, 0x2, 0x20, 0x3f, 0xfe, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x7f, 0xff, 0x2, 0x0, 0x7, 0xfc, 0xc, 0x4, 0x1f, 0xfc, 0x74, 0x4, 0x7, 0xfc, 0x4, 0x4, 0x4, 0x4, 0x7, 0xfc },
+{ 0x92, 0x86, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x3f, 0xfe, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80 },
+{ 0x92, 0x87, 0x4, 0x20, 0x4, 0x20, 0xc, 0x20, 0x8, 0x20, 0x1b, 0xff, 0x12, 0x21, 0x32, 0x21, 0x52, 0x21, 0x12, 0x21, 0x12, 0x21, 0x13, 0xff, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20 },
+{ 0x92, 0x88, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x2, 0x20, 0x82, 0x0, 0x80, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc },
+{ 0x92, 0x89, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x80, 0x0, 0x0, 0x14, 0xc6, 0x14, 0x63, 0x34, 0x25, 0x26, 0xc, 0x63, 0xf8 },
+{ 0x92, 0x8a, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x7b, 0xfe, 0x12, 0x22, 0x12, 0x22, 0x12, 0x22, 0x1a, 0x22, 0x73, 0xfe, 0x12, 0x22, 0x12, 0x22, 0x12, 0x22, 0x12, 0x22, 0x13, 0xfe, 0x30, 0x0 },
+{ 0x92, 0x8b, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x10, 0x18, 0x8, 0x17, 0xfc, 0x34, 0x16, 0x67, 0xf3, 0x4, 0x10, 0x4, 0x10, 0x7, 0xf0, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x92, 0x8c, 0x10, 0xc0, 0x10, 0x60, 0x10, 0x20, 0x7c, 0x0, 0x13, 0xfe, 0x10, 0x20, 0x38, 0x20, 0x34, 0x20, 0x30, 0x20, 0x53, 0xfe, 0x50, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x17, 0xff, 0x10, 0x0 },
+{ 0x92, 0x8d, 0x0, 0xc0, 0x30, 0x60, 0x18, 0x20, 0x8, 0x0, 0x3, 0xfe, 0x60, 0x20, 0x30, 0x20, 0x10, 0x20, 0x0, 0x20, 0xb, 0xfe, 0x8, 0x20, 0x18, 0x20, 0x10, 0x20, 0x30, 0x20, 0x27, 0xff, 0x60, 0x0 },
+{ 0x92, 0x8e, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x84, 0x0, 0x84, 0x0, 0xfe, 0x7, 0x82, 0x3c, 0x2, 0x0, 0x0 },
+{ 0x92, 0x8f, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x2, 0x82, 0x4, 0xc6, 0x1c, 0x4c, 0x74, 0x68, 0x4, 0x30, 0x7, 0x9c, 0x3c, 0x7 },
+{ 0x92, 0x90, 0x0, 0x20, 0x3c, 0x30, 0x0, 0x10, 0x7e, 0xfe, 0x0, 0x10, 0x3c, 0x10, 0x0, 0x10, 0x0, 0x10, 0x3c, 0xfe, 0x0, 0x10, 0x0, 0x10, 0x3c, 0x10, 0x24, 0x10, 0x24, 0x10, 0x25, 0xff, 0x3c, 0x0 },
+{ 0x92, 0x91, 0x0, 0x4, 0x7f, 0x4, 0x14, 0x4, 0x14, 0x4, 0x7f, 0x7f, 0x55, 0x4, 0x55, 0x4, 0x55, 0x64, 0x55, 0x34, 0x67, 0x14, 0x41, 0x4, 0x41, 0x4, 0x7f, 0x4, 0x41, 0x4, 0x41, 0x4, 0x7f, 0x1c },
+{ 0x92, 0x92, 0x10, 0x20, 0x38, 0x20, 0x2d, 0xff, 0x64, 0x20, 0x40, 0xfe, 0x7c, 0x20, 0x11, 0xff, 0x10, 0x40, 0x7c, 0x42, 0x11, 0xff, 0x54, 0x42, 0x54, 0xd2, 0x50, 0x9a, 0x1d, 0x8a, 0x33, 0x2, 0x60, 0xe },
+{ 0x92, 0x93, 0x0, 0x10, 0x3f, 0x98, 0x24, 0x8, 0x24, 0x0, 0x3f, 0x7f, 0x24, 0x8, 0x24, 0x8, 0x3f, 0x8, 0x24, 0x8, 0x24, 0x7f, 0x3f, 0x88, 0x0, 0x88, 0x55, 0x88, 0x54, 0x88, 0x41, 0x88, 0x3, 0x7f },
+{ 0x92, 0x94, 0x10, 0x0, 0x13, 0xff, 0x10, 0x20, 0x7f, 0xff, 0x12, 0x21, 0x13, 0xad, 0x32, 0x21, 0x39, 0xac, 0x34, 0x0, 0x51, 0xfe, 0x50, 0x0, 0x13, 0xff, 0x10, 0x80, 0x11, 0xfe, 0x10, 0x2, 0x10, 0xe },
+{ 0x92, 0x95, 0x20, 0x9, 0x3f, 0xc9, 0x12, 0x3f, 0x2, 0xa, 0x5, 0x2a, 0x49, 0x4c, 0x63, 0xbf, 0x25, 0x8, 0x9, 0x10, 0x1, 0x3e, 0x13, 0x52, 0x15, 0x92, 0x19, 0x5e, 0x31, 0x32, 0x23, 0x12, 0x66, 0x1e },
+{ 0x92, 0x96, 0x4, 0x42, 0x44, 0x42, 0x2b, 0xfe, 0x10, 0x44, 0x10, 0x4c, 0x28, 0x48, 0x4f, 0xff, 0x8, 0x20, 0x18, 0x40, 0x19, 0xfc, 0x2f, 0x4, 0x49, 0x4, 0x9, 0xfc, 0x9, 0x4, 0x19, 0x4, 0x71, 0xfc },
+{ 0x92, 0x97, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x4, 0x90, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x2, 0x20, 0x2, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x3, 0x80 },
+{ 0x92, 0x98, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x0, 0x84, 0x1f, 0xfc, 0x0, 0x98, 0x0, 0xb0, 0x7f, 0xff, 0x1, 0xc0, 0x7, 0xf8, 0x1c, 0x8, 0x77, 0xf8, 0x4, 0x8, 0x4, 0x8, 0x7, 0xf8 },
+{ 0x92, 0x99, 0x0, 0x10, 0x3c, 0x10, 0x25, 0xff, 0x25, 0x1, 0x3d, 0x1, 0x24, 0x0, 0x25, 0xff, 0x24, 0x10, 0x3c, 0x10, 0x24, 0x10, 0x24, 0x10, 0x24, 0x10, 0x3c, 0x10, 0x14, 0x10, 0x36, 0x10, 0x62, 0x70 },
+{ 0x92, 0x9a, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x3, 0x80 },
+{ 0x92, 0x9b, 0x2, 0x40, 0x2, 0x40, 0x2, 0x44, 0x32, 0x4c, 0x1a, 0x58, 0xa, 0x70, 0x2, 0x40, 0x2, 0x40, 0xe, 0x70, 0x3a, 0x5c, 0x62, 0x47, 0x6, 0x40, 0x4, 0x40, 0xc, 0x41, 0x18, 0x63, 0x70, 0x3e },
+{ 0x92, 0x9c, 0x0, 0x0, 0x33, 0xfe, 0x1a, 0x2, 0xa, 0x22, 0x2, 0xfa, 0x2, 0x22, 0x2, 0x22, 0x2, 0xfa, 0xa, 0x2, 0xa, 0xfa, 0x1a, 0x8a, 0x12, 0x8a, 0x32, 0xfa, 0x26, 0x2, 0x64, 0x2, 0xc, 0xe },
+{ 0x92, 0x9d, 0x1, 0x24, 0x1, 0x24, 0x7b, 0xff, 0x49, 0x24, 0x49, 0x24, 0x49, 0x3c, 0x49, 0x0, 0x49, 0xfe, 0x48, 0x20, 0x4f, 0xff, 0x78, 0xa8, 0x0, 0xa8, 0x1, 0xac, 0x3, 0x26, 0x6, 0x23, 0x0, 0x20 },
+{ 0x92, 0x9e, 0x0, 0x80, 0x3f, 0xfe, 0x24, 0x22, 0x7f, 0xbf, 0x21, 0x20, 0x12, 0x3e, 0x7f, 0x82, 0x0, 0x3e, 0x3f, 0x20, 0x21, 0x3e, 0x3f, 0x20, 0x21, 0x3e, 0x3f, 0x20, 0x21, 0x3e, 0x21, 0x21, 0x23, 0x1f },
+{ 0x92, 0x9f, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x7e, 0x10, 0x52, 0x1f, 0x52, 0x10, 0x52, 0x10, 0x52, 0x10, 0x52, 0x10, 0x52, 0xfe, 0x56, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0xfe },
+{ 0x92, 0xa0, 0x10, 0x0, 0x10, 0xfe, 0x10, 0x80, 0x7c, 0xfc, 0x54, 0x80, 0x54, 0xfc, 0x54, 0x80, 0x54, 0x80, 0x57, 0xff, 0x54, 0x92, 0x5c, 0x96, 0x10, 0x9c, 0x10, 0x88, 0x10, 0x8c, 0x10, 0xe6, 0x13, 0x83 },
+{ 0x92, 0xa1, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xff, 0x10, 0x0, 0x10, 0x0, 0x17, 0xff, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x30, 0x20, 0x20, 0x20, 0x60, 0x20, 0x0, 0xe0 },
+{ 0x92, 0xa2, 0x0, 0x0, 0x7f, 0xfc, 0x1, 0x4, 0x1, 0x4, 0x1, 0x4, 0x3f, 0xfc, 0x21, 0x0, 0x21, 0x0, 0x21, 0x0, 0x3f, 0xfe, 0x1, 0x2, 0x1, 0x2, 0x1, 0x6, 0x1, 0x4, 0x1, 0x1c, 0x1, 0x0 },
+{ 0x92, 0xa3, 0x0, 0x0, 0x7c, 0xfe, 0x4, 0x80, 0x4, 0xfc, 0x4, 0x80, 0x3c, 0xfc, 0x20, 0x80, 0x20, 0x80, 0x23, 0xff, 0x3c, 0xa2, 0x4, 0xb6, 0x4, 0x94, 0x4, 0x98, 0xc, 0x8c, 0x8, 0xe6, 0x3b, 0x83 },
+{ 0x92, 0xa4, 0x0, 0x2, 0x3f, 0xe2, 0x20, 0x26, 0x22, 0x24, 0x2f, 0xad, 0x22, 0x21, 0x22, 0x23, 0x2f, 0xa2, 0x20, 0x26, 0x2f, 0xac, 0x28, 0xa1, 0x28, 0xa1, 0x2f, 0xa3, 0x20, 0x22, 0x60, 0x26, 0x40, 0xec },
+{ 0x92, 0xa5, 0x8, 0x88, 0x1a, 0xa8, 0x12, 0xa8, 0x32, 0xaf, 0x63, 0xea, 0x8, 0x12, 0x18, 0xa, 0x13, 0xea, 0x30, 0x8a, 0x70, 0x8e, 0x13, 0xe4, 0x10, 0x84, 0x10, 0x8e, 0x10, 0xea, 0x13, 0x9b, 0x10, 0x11 },
+{ 0x92, 0xa6, 0x8, 0x88, 0x1a, 0xa8, 0x32, 0xaf, 0x4b, 0xfa, 0x18, 0x12, 0x33, 0xea, 0x50, 0x8e, 0x13, 0xe4, 0x10, 0x8e, 0x13, 0xfb, 0x10, 0x11, 0x1, 0x80, 0x14, 0xc6, 0x14, 0x4b, 0x36, 0x19, 0x63, 0xf0 },
+{ 0x92, 0xa7, 0x10, 0x50, 0x10, 0x50, 0x12, 0x52, 0x13, 0x56, 0x7d, 0x5c, 0x11, 0x50, 0x10, 0x50, 0x10, 0x50, 0x1c, 0x5c, 0x71, 0xd6, 0x17, 0x52, 0x10, 0x50, 0x10, 0xd0, 0x10, 0x91, 0x11, 0x93, 0x33, 0xe },
+{ 0x92, 0xa8, 0x10, 0x0, 0x10, 0xfc, 0x10, 0x84, 0x7c, 0xfc, 0x54, 0x84, 0x54, 0x84, 0x54, 0xfc, 0x7c, 0x0, 0x57, 0xff, 0x54, 0x80, 0x55, 0xff, 0x7e, 0x49, 0x10, 0x99, 0x13, 0x33, 0x10, 0x62, 0x11, 0x8e },
+{ 0x92, 0xa9, 0x8, 0x0, 0x8, 0x3e, 0x7f, 0xa2, 0x8, 0x22, 0x3f, 0x22, 0x21, 0x3e, 0x21, 0x22, 0x3f, 0x22, 0x21, 0x22, 0x21, 0x3e, 0x3f, 0x22, 0x8, 0x22, 0x7f, 0xa2, 0x8, 0x62, 0x8, 0x42, 0x8, 0xc6 },
+{ 0x92, 0xaa, 0x0, 0x80, 0x30, 0x8f, 0x1f, 0xf9, 0x8, 0x89, 0x3, 0xe9, 0x62, 0x2f, 0x32, 0x29, 0x13, 0xe9, 0x2, 0x29, 0xa, 0x2f, 0xb, 0xe9, 0x18, 0x89, 0x17, 0xf9, 0x30, 0x89, 0x20, 0x99, 0x60, 0xb3 },
+{ 0x92, 0xab, 0x29, 0x24, 0x29, 0x24, 0x2b, 0xff, 0x29, 0x24, 0x29, 0x24, 0x3d, 0x3c, 0x21, 0x0, 0x21, 0xfe, 0x3c, 0x20, 0x27, 0xff, 0x24, 0xa8, 0x24, 0xa8, 0x25, 0xac, 0x25, 0x26, 0x67, 0x23, 0x44, 0x20 },
+{ 0x92, 0xac, 0x0, 0x0, 0x3f, 0x80, 0x24, 0xff, 0x24, 0x84, 0x24, 0x84, 0x24, 0x84, 0x3f, 0x84, 0x24, 0x84, 0x24, 0x84, 0x24, 0x84, 0x24, 0x84, 0x24, 0x84, 0x3f, 0x84, 0x0, 0x4, 0x0, 0x4, 0x0, 0x1c },
+{ 0x92, 0xad, 0x0, 0x90, 0x78, 0x90, 0x48, 0x92, 0x4e, 0x96, 0x4b, 0x94, 0x78, 0x90, 0x48, 0x90, 0x48, 0x90, 0x48, 0x9c, 0x7b, 0x96, 0x4e, 0x93, 0x48, 0x90, 0x49, 0x90, 0x79, 0x11, 0x3, 0x13, 0xe, 0xe },
+{ 0x92, 0xae, 0x0, 0x10, 0x7e, 0x10, 0x25, 0xff, 0x24, 0x10, 0x3c, 0x10, 0x25, 0xff, 0x25, 0x29, 0x25, 0x29, 0x3d, 0xff, 0x24, 0x0, 0x24, 0x10, 0x24, 0x58, 0x3d, 0x4a, 0x65, 0x43, 0x5, 0x45, 0x5, 0x3c },
+{ 0x92, 0xaf, 0x0, 0x0, 0x3c, 0xfe, 0x24, 0x80, 0x24, 0xfc, 0x24, 0x80, 0x3c, 0xfc, 0x24, 0x80, 0x24, 0x80, 0x25, 0xff, 0x3c, 0x92, 0x24, 0x96, 0x24, 0x9c, 0x24, 0x88, 0x24, 0x8c, 0x64, 0xe6, 0x4d, 0x83 },
+{ 0x92, 0xb0, 0x0, 0x0, 0x3c, 0xfc, 0x24, 0x84, 0x24, 0xfc, 0x24, 0x84, 0x3c, 0x84, 0x24, 0xfc, 0x24, 0x0, 0x27, 0xff, 0x3c, 0x80, 0x25, 0xff, 0x26, 0x49, 0x24, 0x99, 0x27, 0x33, 0x64, 0x62, 0x4d, 0x8e },
+{ 0x92, 0xb1, 0x11, 0x24, 0x11, 0x24, 0x13, 0xff, 0x7d, 0x24, 0x55, 0x24, 0x55, 0x3c, 0x55, 0x0, 0x55, 0xfe, 0x7c, 0x20, 0x13, 0xff, 0x10, 0xa8, 0x14, 0xa8, 0x15, 0xac, 0x1d, 0x26, 0x77, 0x23, 0x0, 0x20 },
+{ 0x92, 0xb2, 0x0, 0x0, 0x3c, 0xff, 0x0, 0x81, 0x7e, 0x91, 0x0, 0xbd, 0x3c, 0x91, 0x0, 0x91, 0x0, 0xbd, 0x3c, 0x81, 0x0, 0xbd, 0x0, 0xa5, 0x3c, 0xa5, 0x24, 0xbd, 0x24, 0x81, 0x24, 0x81, 0x3d, 0x7 },
+{ 0x92, 0xb3, 0x0, 0x94, 0x3c, 0x94, 0x1, 0xff, 0x7e, 0x94, 0x0, 0x94, 0x3c, 0x9c, 0x0, 0x80, 0x0, 0xfe, 0x3c, 0x10, 0x1, 0xff, 0x0, 0x54, 0x3c, 0x54, 0x24, 0xd6, 0x24, 0x92, 0x25, 0x93, 0x3c, 0x10 },
+{ 0x92, 0xb4, 0x8, 0x0, 0x8, 0xfe, 0x3e, 0x22, 0x8, 0x22, 0x8, 0x62, 0x8, 0x42, 0x7e, 0xce, 0x8, 0x0, 0x28, 0x7e, 0x2e, 0x42, 0x28, 0x42, 0x28, 0x42, 0x28, 0x42, 0x38, 0x7e, 0x6e, 0x0, 0x43, 0xff },
+{ 0x92, 0xb5, 0x0, 0x28, 0x3e, 0x28, 0x22, 0x29, 0x23, 0xab, 0x22, 0xee, 0x22, 0x28, 0x3e, 0x28, 0x8, 0x28, 0x28, 0x2e, 0x2e, 0xeb, 0x29, 0xa9, 0x28, 0x28, 0x28, 0x68, 0x2e, 0x49, 0x38, 0xc9, 0x61, 0x87 },
+{ 0x92, 0xb6, 0x8, 0x28, 0x1c, 0x28, 0x16, 0x29, 0x32, 0xab, 0x20, 0x6e, 0x7e, 0x28, 0x8, 0x28, 0x8, 0x28, 0x7e, 0x2e, 0x8, 0x6b, 0x4a, 0xa9, 0x6a, 0x28, 0x28, 0x68, 0xe, 0x49, 0x38, 0xc9, 0x61, 0x87 },
+{ 0x92, 0xb7, 0x0, 0x0, 0xf, 0xfc, 0x8, 0x0, 0xf, 0xf8, 0x8, 0x0, 0xf, 0xf8, 0x8, 0x0, 0x8, 0x0, 0x7f, 0xff, 0x9, 0x4, 0x9, 0x8c, 0x8, 0xd8, 0x8, 0x60, 0x8, 0x30, 0xf, 0x1c, 0x38, 0x7 },
+{ 0x92, 0xb8, 0x0, 0x0, 0x1, 0xff, 0x7e, 0x10, 0x8, 0xfe, 0x8, 0x82, 0x8, 0x82, 0x8, 0xfe, 0x8, 0x82, 0x8, 0x82, 0x8, 0xfe, 0x8, 0x82, 0x8, 0x82, 0x8, 0xfe, 0x8, 0x44, 0x38, 0xc6, 0x1, 0x83 },
+{ 0x92, 0xb9, 0x0, 0x80, 0x1, 0x0, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x0, 0xf, 0xff, 0x8, 0x0, 0xf, 0xff, 0x20, 0x1, 0x24, 0x91, 0x66, 0xdb, 0x42, 0x4a, 0x0, 0x6 },
+{ 0x92, 0xba, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xd0, 0x4, 0x10, 0x3f, 0xbf, 0x24, 0x91, 0x24, 0x91, 0x24, 0x91, 0x3f, 0x91, 0xc, 0x11, 0xe, 0x11, 0x15, 0x31, 0x14, 0xa1, 0x24, 0x63, 0x44, 0xc2, 0x5, 0x8e },
+{ 0x92, 0xbb, 0x10, 0x20, 0x11, 0x20, 0x11, 0x3e, 0x11, 0x20, 0x79, 0x20, 0x17, 0xff, 0x10, 0x20, 0x11, 0x24, 0x1b, 0x26, 0x76, 0x23, 0x10, 0x24, 0x10, 0xec, 0x10, 0x18, 0x10, 0x30, 0x10, 0xe0, 0x33, 0x80 },
+{ 0x92, 0xbc, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x7, 0xf8, 0x24, 0x8, 0x24, 0x8, 0x27, 0xf8, 0x24, 0x8, 0x24, 0x8, 0x27, 0xf8, 0x24, 0x8, 0x24, 0x8, 0x27, 0xf8, 0x20, 0x0, 0x3f, 0xff },
+{ 0x92, 0xbd, 0x0, 0x82, 0x3c, 0xc6, 0x24, 0x4c, 0x24, 0x8, 0x24, 0xfe, 0x3c, 0x10, 0x24, 0x10, 0x24, 0x10, 0x25, 0xff, 0x3c, 0x10, 0x24, 0x38, 0x24, 0x28, 0x24, 0x6c, 0x24, 0x44, 0x64, 0xc6, 0x4d, 0x83 },
+{ 0x92, 0xbe, 0x0, 0x20, 0x30, 0x20, 0x18, 0x20, 0xb, 0xfe, 0x2, 0x22, 0x62, 0x22, 0x32, 0x22, 0x10, 0x20, 0x0, 0x70, 0x8, 0x50, 0x8, 0x50, 0x18, 0xd0, 0x10, 0x90, 0x31, 0x91, 0x23, 0x1b, 0x66, 0xe },
+{ 0x92, 0xbf, 0x0, 0x20, 0x0, 0x70, 0x7c, 0xd8, 0x11, 0x8c, 0x13, 0x6, 0x16, 0x23, 0x10, 0x60, 0x7c, 0xc4, 0x11, 0x8c, 0x10, 0x19, 0x10, 0x73, 0x11, 0xc2, 0x1c, 0x6, 0x70, 0xc, 0x0, 0x38, 0x1, 0xe0 },
+{ 0x92, 0xc0, 0x4, 0x1c, 0xd, 0xf0, 0x18, 0x20, 0x77, 0xff, 0x10, 0x20, 0x13, 0xfe, 0x10, 0x0, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x4, 0x10, 0x38, 0xe },
+{ 0x92, 0xc1, 0x8, 0x10, 0x1c, 0x10, 0x15, 0xff, 0x32, 0x10, 0x20, 0xfe, 0x7e, 0x82, 0x8, 0xfe, 0x8, 0x82, 0x7e, 0xfe, 0x8, 0x82, 0x4a, 0xfe, 0x6a, 0x0, 0x29, 0xff, 0xe, 0x44, 0x38, 0xc6, 0x61, 0x83 },
+{ 0x92, 0xc2, 0x0, 0x20, 0x3e, 0x20, 0x23, 0xff, 0x26, 0x20, 0x2d, 0xfe, 0x29, 0x22, 0x29, 0xfe, 0x25, 0x22, 0x25, 0x22, 0x25, 0xfe, 0x24, 0xa8, 0x24, 0xa8, 0x2d, 0xac, 0x23, 0x26, 0x26, 0x23, 0x20, 0x20 },
+{ 0x92, 0xc3, 0x0, 0x20, 0x33, 0xfe, 0x18, 0x22, 0x8, 0x22, 0x7, 0xff, 0x60, 0x22, 0x30, 0x22, 0x13, 0xfe, 0x0, 0x20, 0x8, 0x20, 0xb, 0xfe, 0x18, 0x20, 0x10, 0x20, 0x37, 0xff, 0x20, 0x20, 0x60, 0x20 },
+{ 0x92, 0xc4, 0x0, 0x84, 0x3e, 0x48, 0x23, 0xff, 0x24, 0x20, 0x28, 0x53, 0x25, 0xae, 0x24, 0x58, 0x25, 0xac, 0x24, 0x4a, 0x2d, 0x8b, 0x20, 0x38, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x92, 0xc5, 0x8, 0x44, 0x8, 0x4c, 0x8, 0x88, 0x7e, 0xff, 0x9, 0x88, 0xa, 0x88, 0x1c, 0x88, 0x1a, 0xfe, 0x1a, 0x88, 0x28, 0x88, 0x28, 0x88, 0x48, 0xfe, 0x8, 0x88, 0x8, 0x88, 0x8, 0x88, 0x8, 0xff },
+{ 0x92, 0xc6, 0x10, 0x8, 0x16, 0x10, 0x13, 0x7e, 0x7d, 0x42, 0x10, 0x42, 0x10, 0x42, 0x18, 0x7e, 0x37, 0x40, 0x35, 0x40, 0x51, 0x7e, 0x51, 0x42, 0x11, 0x42, 0x11, 0x42, 0x13, 0x7e, 0x12, 0x80, 0x16, 0x7f },
+{ 0x92, 0xc7, 0x0, 0x20, 0x30, 0x40, 0x19, 0xfc, 0x9, 0x4, 0x1, 0x4, 0x1, 0x4, 0x1, 0xfc, 0x79, 0x0, 0x9, 0x0, 0x9, 0xfc, 0x9, 0x4, 0x9, 0x4, 0x9, 0x4, 0x19, 0xfc, 0x34, 0x0, 0x63, 0xff },
+{ 0x92, 0xc8, 0x10, 0x4, 0x39, 0x8, 0x2d, 0xbe, 0x64, 0xa2, 0x40, 0x22, 0x7c, 0x22, 0x10, 0x3e, 0x13, 0xa0, 0x7c, 0xa0, 0x10, 0xbe, 0x54, 0xa2, 0x54, 0xa2, 0x50, 0xa2, 0x1d, 0xbe, 0x31, 0x40, 0x63, 0x3f },
+{ 0x92, 0xc9, 0x0, 0x40, 0x0, 0x40, 0x1f, 0xff, 0x50, 0x0, 0x37, 0xfc, 0x11, 0x8, 0x10, 0x90, 0x17, 0xfe, 0x14, 0x42, 0x37, 0xfe, 0x54, 0x42, 0x14, 0x42, 0x37, 0xfe, 0x24, 0x42, 0x64, 0x42, 0x4, 0x46 },
+{ 0x92, 0xca, 0x0, 0x0, 0x67, 0xfe, 0x30, 0x8c, 0x10, 0x50, 0x3, 0xfe, 0x2, 0x22, 0x2, 0x22, 0x73, 0xfe, 0x12, 0x22, 0x12, 0x22, 0x13, 0xfe, 0x12, 0x22, 0x12, 0x22, 0x32, 0x26, 0x28, 0x0, 0x67, 0xff },
+{ 0x92, 0xcb, 0x10, 0x0, 0x13, 0xff, 0x12, 0x1, 0x12, 0x1, 0x7d, 0xfe, 0x10, 0x20, 0x10, 0x42, 0x10, 0xa6, 0x13, 0x34, 0x10, 0x50, 0x1c, 0x98, 0x73, 0x3c, 0x0, 0x54, 0x0, 0x96, 0x7, 0x33, 0x0, 0xe0 },
+{ 0x92, 0xcc, 0x8, 0x0, 0x8, 0xfe, 0x8, 0x82, 0x7e, 0xa2, 0x8, 0xb2, 0x8, 0x92, 0x1c, 0x82, 0x1b, 0xff, 0x19, 0x2, 0x29, 0x22, 0x29, 0x32, 0x49, 0x12, 0x9, 0x2, 0x9, 0xff, 0x8, 0x4, 0x8, 0x1c },
+{ 0x92, 0xcd, 0x10, 0x0, 0x13, 0xfe, 0x12, 0x2, 0x12, 0xfa, 0x7e, 0x22, 0x12, 0x22, 0x12, 0x22, 0x12, 0xfa, 0x1e, 0x22, 0x72, 0x2a, 0x12, 0x2a, 0x12, 0x22, 0x12, 0xfa, 0x12, 0x2, 0x13, 0xfe, 0x30, 0x0 },
+{ 0x92, 0xce, 0x11, 0x0, 0x11, 0x3e, 0x17, 0xe2, 0x79, 0x22, 0x11, 0x3e, 0x11, 0x22, 0x37, 0xe2, 0x39, 0x3e, 0x51, 0x22, 0x53, 0xa2, 0x12, 0xbe, 0x12, 0xd4, 0x16, 0x54, 0x14, 0x35, 0x1c, 0x25, 0x10, 0x63 },
+{ 0x92, 0xcf, 0x8, 0x0, 0xb, 0xfe, 0x1a, 0x22, 0x12, 0x22, 0x12, 0x22, 0x32, 0x22, 0x32, 0x22, 0x53, 0xfe, 0x12, 0x22, 0x12, 0x22, 0x12, 0x22, 0x12, 0x22, 0x12, 0x22, 0x12, 0x22, 0x13, 0xfe, 0x10, 0x0 },
+{ 0x92, 0xd0, 0x0, 0x20, 0x37, 0xff, 0x18, 0x20, 0xb, 0xfe, 0x0, 0x20, 0x67, 0xff, 0x30, 0x0, 0x13, 0xfe, 0x2, 0x2, 0xb, 0xfe, 0xa, 0x2, 0x1b, 0xfe, 0x12, 0x2, 0x33, 0xfe, 0x21, 0x4, 0x66, 0x3 },
+{ 0x92, 0xd1, 0x8, 0x0, 0xb, 0xff, 0x8, 0x20, 0x7e, 0x20, 0x8, 0x60, 0x8, 0x40, 0x1c, 0x40, 0x1a, 0xfe, 0x19, 0x82, 0x2b, 0x82, 0x28, 0x82, 0x48, 0x82, 0x8, 0x82, 0x8, 0x82, 0x8, 0xfe, 0x8, 0x0 },
+{ 0x92, 0xd2, 0x0, 0x20, 0x30, 0x20, 0x18, 0x20, 0x8, 0x20, 0x0, 0x20, 0x0, 0x20, 0x3, 0xfe, 0x78, 0x20, 0x8, 0x20, 0x8, 0x20, 0x8, 0x20, 0x8, 0x20, 0x8, 0x20, 0x18, 0x20, 0x34, 0x0, 0x63, 0xff },
+{ 0x92, 0xd3, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x90, 0x1, 0x0, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x0, 0xf, 0xff, 0x8, 0x0, 0x2f, 0xfe, 0x24, 0x92, 0x66, 0xda, 0x42, 0x4e },
+{ 0x92, 0xd4, 0x10, 0x0, 0x33, 0xde, 0x20, 0x42, 0x6b, 0x5a, 0x28, 0x84, 0x19, 0x4a, 0x12, 0x11, 0x24, 0x0, 0x7f, 0xde, 0x14, 0x42, 0x12, 0x42, 0x55, 0x94, 0x54, 0x94, 0x55, 0x48, 0x12, 0x54, 0x14, 0x23 },
+{ 0x92, 0xd5, 0x10, 0x0, 0x39, 0xef, 0x2d, 0x29, 0x65, 0x29, 0x41, 0xef, 0x7c, 0x0, 0x10, 0xfe, 0x10, 0x0, 0x7d, 0xff, 0x10, 0x20, 0x54, 0x40, 0x54, 0xfe, 0x50, 0x2, 0x14, 0x2, 0x38, 0x6, 0x60, 0x1c },
+{ 0x92, 0xd6, 0x10, 0x20, 0x10, 0x20, 0x13, 0xfe, 0x7c, 0x20, 0x11, 0xfc, 0x10, 0x50, 0x3b, 0xff, 0x34, 0x88, 0x31, 0x4, 0x53, 0xfe, 0x55, 0x5, 0x11, 0x4, 0x11, 0xfc, 0x11, 0x4, 0x11, 0x4, 0x11, 0xfc },
+{ 0x92, 0xd7, 0x0, 0x20, 0x33, 0xfe, 0x1a, 0x22, 0xb, 0xfe, 0x0, 0x20, 0x67, 0xff, 0x30, 0x0, 0x13, 0xfe, 0x2, 0x2, 0xb, 0xfe, 0xa, 0x2, 0x1b, 0xfe, 0x12, 0x2, 0x33, 0xfe, 0x21, 0x4, 0x66, 0x3 },
+{ 0x92, 0xd8, 0x10, 0x0, 0x13, 0xfe, 0x10, 0x20, 0x12, 0x22, 0x7d, 0x26, 0x11, 0x24, 0x11, 0x24, 0x10, 0x20, 0x17, 0xff, 0x10, 0x20, 0x1c, 0x20, 0x70, 0x20, 0x0, 0x20, 0x0, 0x20, 0x0, 0x20, 0x0, 0x20 },
+{ 0x92, 0xd9, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x0, 0x3f, 0xfe, 0x21, 0x42, 0x2f, 0xfa, 0x9, 0x48, 0x9, 0x48, 0xf, 0xf8, 0x1, 0x40, 0x1, 0x40, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x92, 0xda, 0x10, 0x0, 0x11, 0xff, 0x10, 0x10, 0x11, 0xff, 0x7d, 0x11, 0x15, 0xdd, 0x35, 0x11, 0x24, 0xdc, 0x2c, 0x0, 0x29, 0xff, 0x28, 0x20, 0x79, 0xff, 0x15, 0x49, 0x35, 0x49, 0x21, 0x49, 0x61, 0x4b },
+{ 0x92, 0xdb, 0x8, 0x10, 0x18, 0x10, 0x10, 0x10, 0x64, 0x10, 0x2d, 0xff, 0x19, 0x11, 0x11, 0x11, 0x25, 0x11, 0x7d, 0x11, 0x15, 0xff, 0x11, 0x11, 0x55, 0x11, 0x55, 0x11, 0x55, 0x11, 0x11, 0xff, 0x10, 0x0 },
+{ 0x92, 0xdc, 0x0, 0xc, 0x0, 0xf8, 0x1f, 0x88, 0x10, 0x8, 0x11, 0x8, 0x11, 0x8, 0x11, 0x8, 0x11, 0x8, 0x11, 0x8, 0x11, 0xc, 0x11, 0x4, 0x11, 0x4, 0x31, 0x4, 0x21, 0x6, 0x21, 0x2, 0x61, 0x3 },
+{ 0x92, 0xdd, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x20, 0x8e, 0x0, 0x80, 0x0, 0x80 },
+{ 0x92, 0xde, 0x8, 0x20, 0x1c, 0x20, 0x16, 0x20, 0x33, 0x7f, 0x21, 0x41, 0x7e, 0xc1, 0x9, 0x81, 0x8, 0x31, 0x7f, 0x19, 0x8, 0x9, 0x4a, 0x1, 0x6a, 0x1, 0x28, 0x1, 0xf, 0x3, 0x38, 0x2, 0x60, 0xe },
+{ 0x92, 0xdf, 0x8, 0x10, 0x8, 0x20, 0x7e, 0xfe, 0x52, 0x82, 0x54, 0xfe, 0x3e, 0x82, 0x28, 0xfe, 0x68, 0x80, 0x3e, 0xff, 0x28, 0x80, 0x28, 0xff, 0x3e, 0x1, 0x29, 0x55, 0x29, 0x55, 0x3e, 0x3, 0x0, 0x6 },
+{ 0x92, 0xe0, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x0, 0x0, 0x7f, 0xff, 0x40, 0x1, 0x4f, 0xf9, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x3, 0x80 },
+{ 0x92, 0xe1, 0x4, 0x6, 0x4, 0x1c, 0xd, 0xf0, 0x9, 0x10, 0x19, 0x10, 0x11, 0x10, 0x31, 0xff, 0x51, 0x10, 0x11, 0x10, 0x11, 0x18, 0x11, 0x8, 0x11, 0xc8, 0x17, 0xc, 0x10, 0x5, 0x17, 0xf7, 0x10, 0x2 },
+{ 0x92, 0xe2, 0x4, 0x20, 0x4, 0x20, 0xf, 0xff, 0x8, 0x0, 0x19, 0xfc, 0x11, 0x4, 0x31, 0xfc, 0x50, 0x0, 0x17, 0xff, 0x14, 0x1, 0x15, 0xfd, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0xe0 },
+{ 0x92, 0xe3, 0x4, 0x20, 0x4, 0x20, 0xc, 0x3f, 0x8, 0x20, 0x1b, 0xfe, 0x12, 0x2, 0x32, 0x2, 0x53, 0xfe, 0x12, 0x2, 0x12, 0x2, 0x13, 0xfe, 0x12, 0x2, 0x12, 0x2, 0x13, 0xfe, 0x11, 0x4, 0x16, 0x3 },
+{ 0x92, 0xe4, 0x21, 0x2, 0x12, 0x12, 0x7f, 0x92, 0x4, 0x92, 0x4, 0x92, 0x3f, 0x92, 0x24, 0x12, 0x24, 0x12, 0x3f, 0xd2, 0x4, 0x52, 0xc, 0x52, 0xc, 0xc2, 0x14, 0x82, 0x35, 0x82, 0x64, 0x2, 0x4, 0xe },
+{ 0x92, 0xe5, 0x0, 0x80, 0x0, 0x80, 0x0, 0xfc, 0x0, 0x80, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x4, 0x10, 0x38, 0xe },
+{ 0x92, 0xe6, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x80, 0xf, 0xf8, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x92, 0xe7, 0x0, 0x0, 0x11, 0xfc, 0x11, 0x4, 0x11, 0xfc, 0x11, 0x4, 0x7d, 0x4, 0x11, 0xfc, 0x10, 0x0, 0x17, 0xff, 0x10, 0x20, 0x11, 0x20, 0x1d, 0x3e, 0x71, 0x20, 0x3, 0xa0, 0x6, 0xe0, 0xc, 0x3f },
+{ 0x92, 0xe8, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x2, 0x20, 0x2, 0xf, 0xf8, 0x0, 0x80, 0x0, 0x80, 0x8, 0x80, 0x8, 0xf8, 0x8, 0x80, 0x8, 0x80, 0x1c, 0x80, 0x16, 0x80, 0x33, 0x80, 0x60, 0xff },
+{ 0x92, 0xe9, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x4, 0x10, 0x6, 0x30, 0x2, 0x20, 0x7f, 0xff, 0x40, 0x81, 0x40, 0x81, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x9c, 0x0, 0x80 },
+{ 0x92, 0xea, 0x0, 0x40, 0x0, 0x40, 0x1f, 0xff, 0x10, 0x0, 0x10, 0xc, 0x13, 0xf8, 0x12, 0x20, 0x12, 0x20, 0x13, 0xff, 0x12, 0x10, 0x12, 0x10, 0x13, 0x98, 0x16, 0x8, 0x30, 0xd, 0x27, 0xe7, 0x60, 0x2 },
+{ 0x92, 0xeb, 0x0, 0x40, 0x0, 0x40, 0x1f, 0xff, 0x10, 0x0, 0x10, 0x6, 0x1f, 0x7c, 0x12, 0x10, 0x14, 0x10, 0x17, 0xff, 0x11, 0x10, 0x15, 0x10, 0x15, 0x10, 0x32, 0x7e, 0x22, 0x0, 0x65, 0x80, 0x8, 0x7f },
+{ 0x92, 0xec, 0x0, 0xc, 0x7e, 0x38, 0x5, 0xe0, 0x8, 0x20, 0x10, 0x20, 0x3c, 0x20, 0x7, 0xff, 0x4, 0x20, 0x2c, 0x20, 0x28, 0x20, 0x28, 0x20, 0x38, 0x20, 0x11, 0xfe, 0x38, 0x0, 0x2e, 0x0, 0x63, 0xff },
+{ 0x92, 0xed, 0x8, 0x10, 0x4, 0x20, 0x7f, 0xfc, 0x0, 0x84, 0x0, 0x84, 0x1f, 0xfc, 0x10, 0x80, 0x10, 0x80, 0x1f, 0xfe, 0x1, 0x82, 0x2, 0x82, 0x6, 0x82, 0xc, 0x86, 0x18, 0x84, 0x70, 0x9c, 0x0, 0x80 },
+{ 0x92, 0xee, 0x11, 0x4, 0x10, 0x88, 0x13, 0xfe, 0x10, 0x22, 0x58, 0x22, 0x55, 0xfe, 0x55, 0x20, 0x51, 0x20, 0x11, 0xff, 0x10, 0x61, 0x10, 0x61, 0x10, 0xa3, 0x11, 0xa2, 0x13, 0x2e, 0x16, 0x20, 0x10, 0x20 },
+{ 0x92, 0xef, 0x10, 0x6, 0x10, 0x1c, 0x11, 0xf0, 0x11, 0x10, 0x7d, 0x10, 0x11, 0x10, 0x11, 0xff, 0x11, 0x10, 0x1d, 0x10, 0x71, 0x18, 0x11, 0x8, 0x11, 0xc8, 0x17, 0xc, 0x10, 0x5, 0x17, 0xf7, 0x30, 0x2 },
+{ 0x92, 0xf0, 0x10, 0x3, 0x17, 0xce, 0x10, 0xb8, 0x10, 0x88, 0x7d, 0x88, 0x11, 0x8, 0x13, 0xff, 0x10, 0x48, 0x1c, 0x48, 0x72, 0xc8, 0x12, 0x88, 0x13, 0x88, 0x11, 0x3f, 0x13, 0x80, 0x12, 0xe0, 0x36, 0x3f },
+{ 0x92, 0xf1, 0x10, 0x0, 0x11, 0xfc, 0x11, 0x4, 0x11, 0xfc, 0x7d, 0x4, 0x11, 0x4, 0x11, 0xfc, 0x10, 0x0, 0x17, 0xff, 0x18, 0x20, 0x71, 0x20, 0x11, 0x3e, 0x11, 0x20, 0x13, 0xa0, 0x12, 0xe0, 0x36, 0x3f },
+{ 0x92, 0xf2, 0x11, 0x4, 0x10, 0x88, 0x13, 0xfe, 0x7c, 0x22, 0x10, 0x22, 0x13, 0xfe, 0x3a, 0x20, 0x36, 0x20, 0x33, 0xff, 0x50, 0x61, 0x50, 0x61, 0x10, 0xa3, 0x11, 0xa2, 0x13, 0x2e, 0x16, 0x20, 0x10, 0x20 },
+{ 0x92, 0xf3, 0x0, 0x0, 0x30, 0x0, 0x1b, 0xff, 0x8, 0x10, 0x0, 0x10, 0x60, 0x10, 0x30, 0x10, 0x10, 0x10, 0x0, 0x10, 0x8, 0x10, 0x8, 0x10, 0x18, 0x10, 0x10, 0x10, 0x30, 0x10, 0x20, 0x10, 0x60, 0x70 },
+{ 0x92, 0xf4, 0x0, 0x10, 0x7e, 0x10, 0x11, 0xff, 0x11, 0x1, 0x11, 0x1, 0x10, 0xfe, 0x3c, 0x10, 0x24, 0x10, 0x64, 0x90, 0x24, 0x9e, 0x24, 0x90, 0x24, 0x90, 0x24, 0x90, 0x3d, 0xd0, 0x1, 0x70, 0x3, 0x1f },
+{ 0x92, 0xf5, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1f, 0x7c, 0x10, 0x4, 0xfe, 0xc, 0x82, 0x8, 0x82, 0x18, 0xfe, 0x30, 0x82, 0x3c, 0x82, 0x56, 0xfe, 0x10, 0x82, 0x10, 0x82, 0x10, 0xfe, 0x10, 0x44, 0x11, 0x83 },
+{ 0x92, 0xf6, 0x2, 0x0, 0xe, 0xfc, 0x78, 0x84, 0x8, 0x84, 0x8, 0x84, 0x7e, 0xfc, 0x8, 0x0, 0x8, 0x0, 0x1d, 0xfe, 0x1a, 0x20, 0x2a, 0x20, 0x28, 0xfc, 0x48, 0x20, 0x8, 0x20, 0xb, 0xff, 0x8, 0x0 },
+{ 0x92, 0xf7, 0x8, 0x10, 0x18, 0x10, 0x31, 0xff, 0x64, 0x44, 0x2c, 0x6c, 0x18, 0x28, 0x31, 0xff, 0x25, 0x11, 0x7d, 0x11, 0x14, 0xfe, 0x10, 0x92, 0x54, 0x92, 0x54, 0x92, 0x54, 0x96, 0x50, 0x10, 0x10, 0x10 },
+{ 0x92, 0xf8, 0x8, 0x2, 0x11, 0xc6, 0x3c, 0x5c, 0x24, 0x44, 0x34, 0xc4, 0x2c, 0x84, 0x25, 0xdf, 0x7e, 0x44, 0x24, 0x44, 0x35, 0x44, 0x2d, 0x44, 0x2d, 0xc4, 0x24, 0x9f, 0x24, 0x80, 0x65, 0xe0, 0x4d, 0x3f },
+{ 0x92, 0xf9, 0x0, 0x0, 0x3e, 0x0, 0x0, 0xff, 0x7f, 0x8, 0x0, 0x8, 0x3e, 0x8, 0x0, 0x8, 0x0, 0x8, 0x3e, 0x8, 0x0, 0x8, 0x0, 0x8, 0x3e, 0x8, 0x22, 0x8, 0x22, 0x8, 0x22, 0x8, 0x3e, 0x38 },
+{ 0x92, 0xfa, 0x0, 0x10, 0x3c, 0x10, 0x1, 0xff, 0x7e, 0x44, 0x0, 0x6c, 0x3c, 0x28, 0x1, 0xff, 0x1, 0x11, 0x3d, 0x11, 0x0, 0xfe, 0x0, 0x92, 0x3c, 0x92, 0x24, 0x92, 0x24, 0x96, 0x24, 0x10, 0x3c, 0x10 },
+{ 0x92, 0xfb, 0x0, 0x10, 0x3c, 0x10, 0x25, 0xff, 0x24, 0x44, 0x24, 0x6c, 0x24, 0x28, 0x3d, 0xff, 0x9, 0x11, 0x29, 0x11, 0x2c, 0xfe, 0x28, 0x92, 0x28, 0x92, 0x28, 0x92, 0x2c, 0x96, 0x38, 0x10, 0x60, 0x10 },
+{ 0x92, 0xfc, 0x0, 0x6, 0x20, 0x1c, 0x33, 0xf0, 0x12, 0x10, 0x3, 0xff, 0x2, 0x10, 0x3, 0xff, 0x72, 0x10, 0x12, 0xfe, 0x12, 0x92, 0x12, 0x92, 0x12, 0x92, 0x14, 0x96, 0x30, 0x10, 0x28, 0x0, 0x67, 0xff },
+{ 0x93, 0x40, 0x0, 0xc0, 0x3, 0x9f, 0x3e, 0x11, 0x22, 0x13, 0x22, 0x12, 0x22, 0x16, 0x3f, 0xd4, 0x22, 0x12, 0x22, 0x11, 0x22, 0x11, 0x23, 0x11, 0x39, 0x11, 0x61, 0x57, 0x1, 0xd0, 0x7c, 0x90, 0x0, 0x10 },
+{ 0x93, 0x41, 0x10, 0x80, 0x9, 0x1f, 0x7f, 0xf1, 0x9, 0x13, 0x3f, 0xd2, 0x29, 0x56, 0x31, 0xd4, 0x20, 0x52, 0x3f, 0xd1, 0x20, 0x51, 0x3f, 0xd1, 0x4, 0x11, 0x7f, 0xf7, 0x9, 0x10, 0x19, 0x90, 0x70, 0xd0 },
+{ 0x93, 0x42, 0x8, 0x0, 0x1c, 0x0, 0x16, 0xff, 0x33, 0x8, 0x21, 0x8, 0x7e, 0x8, 0x8, 0x8, 0x8, 0x8, 0x7f, 0x8, 0x8, 0x8, 0x4a, 0x8, 0x6a, 0x8, 0x28, 0x8, 0xf, 0x8, 0x38, 0x8, 0x60, 0x38 },
+{ 0x93, 0x43, 0x0, 0x0, 0x27, 0xf2, 0x24, 0x12, 0x27, 0xf2, 0x24, 0x12, 0x27, 0xf2, 0x24, 0x12, 0x27, 0xf2, 0x20, 0x2, 0x3f, 0x7e, 0x1, 0x40, 0x7f, 0x7f, 0x11, 0x44, 0x11, 0x44, 0x31, 0x44, 0x61, 0x44 },
+{ 0x93, 0x44, 0x0, 0x0, 0x33, 0xfe, 0x1a, 0x2, 0xa, 0x2, 0x2, 0x2, 0x63, 0xfe, 0x32, 0x0, 0x12, 0x40, 0x2, 0x46, 0xa, 0x5c, 0xa, 0x70, 0x1a, 0x40, 0x16, 0x40, 0x34, 0x41, 0x2c, 0x63, 0x60, 0x3e },
+{ 0x93, 0x45, 0x10, 0x20, 0x10, 0x20, 0x17, 0xff, 0x11, 0x4, 0x78, 0x88, 0x13, 0xfe, 0x12, 0x2, 0x12, 0x22, 0x1a, 0xfa, 0x72, 0x22, 0x12, 0xfa, 0x12, 0x8a, 0x12, 0x8a, 0x12, 0xfa, 0x12, 0x2, 0x32, 0x6 },
+{ 0x93, 0x46, 0x10, 0x0, 0x13, 0xdf, 0x10, 0x41, 0x13, 0xdf, 0x7c, 0x41, 0x13, 0xdf, 0x10, 0x48, 0x10, 0x90, 0x1d, 0xff, 0x73, 0x10, 0x15, 0xfe, 0x11, 0x10, 0x11, 0xfe, 0x11, 0x10, 0x11, 0x10, 0x31, 0xff },
+{ 0x93, 0x47, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xd0, 0x11, 0x1f, 0xa, 0x14, 0x3f, 0xb4, 0x20, 0xa4, 0x24, 0x94, 0x2e, 0x94, 0x24, 0x9c, 0x2e, 0x88, 0x2a, 0x88, 0x2a, 0x9c, 0x2e, 0x94, 0x20, 0x96, 0x21, 0xa3 },
+{ 0x93, 0x48, 0x0, 0x20, 0x30, 0x20, 0x1f, 0xff, 0x9, 0x4, 0x0, 0x88, 0x63, 0xfe, 0x32, 0x2, 0x12, 0x22, 0x2, 0xfa, 0xa, 0x22, 0xa, 0xfa, 0x1a, 0x8a, 0x12, 0x8a, 0x32, 0xfa, 0x22, 0x2, 0x62, 0x6 },
+{ 0x93, 0x49, 0x4, 0x40, 0xc, 0x40, 0x8, 0x40, 0x3e, 0x7e, 0x22, 0xc2, 0x22, 0x82, 0x23, 0x82, 0x22, 0x62, 0x3e, 0x32, 0x22, 0x12, 0x22, 0x2, 0x22, 0x2, 0x22, 0x6, 0x3e, 0x4, 0x0, 0xc, 0x0, 0x38 },
+{ 0x93, 0x4a, 0x8, 0x40, 0x8, 0x40, 0x1f, 0xff, 0x34, 0x90, 0x66, 0x18, 0x2, 0x88, 0x0, 0x80, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc },
+{ 0x93, 0x4b, 0x0, 0x20, 0x60, 0x20, 0x37, 0xff, 0x11, 0x4, 0x0, 0x88, 0x3, 0xfe, 0x2, 0x22, 0x72, 0xfa, 0x12, 0x22, 0x12, 0xfa, 0x12, 0x8a, 0x12, 0xfa, 0x12, 0x2, 0x32, 0x6, 0x28, 0x0, 0x67, 0xff },
+{ 0x93, 0x4c, 0x10, 0x10, 0x38, 0x10, 0x2d, 0xff, 0x64, 0x82, 0x40, 0x44, 0x7d, 0xff, 0x11, 0x1, 0x11, 0x11, 0x7d, 0x7d, 0x11, 0x11, 0x55, 0x7d, 0x55, 0x45, 0x51, 0x45, 0x15, 0x7d, 0x39, 0x1, 0x61, 0x7 },
+{ 0x93, 0x4d, 0x0, 0x0, 0x2f, 0xbe, 0x30, 0x82, 0x10, 0x82, 0x7, 0x9e, 0x44, 0x10, 0x64, 0x10, 0x27, 0x9e, 0x0, 0x82, 0x16, 0xb2, 0x12, 0x92, 0x11, 0x8e, 0x36, 0x9a, 0x2c, 0xb2, 0x21, 0x86, 0x67, 0x1c },
+{ 0x93, 0x4e, 0x8, 0x6, 0x8, 0xfc, 0x7e, 0x80, 0x8, 0x80, 0x8, 0xff, 0xe, 0x88, 0x78, 0x88, 0x9, 0x88, 0xb, 0x8, 0x18, 0x8, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x1f, 0xfc },
+{ 0x93, 0x4f, 0x9, 0x8, 0x19, 0x8, 0x17, 0xe8, 0x31, 0xf, 0x61, 0x5a, 0xa, 0x62, 0x1b, 0xaa, 0x10, 0xa, 0x33, 0xca, 0x72, 0x4e, 0x13, 0xc4, 0x12, 0x44, 0x13, 0xce, 0x12, 0x4a, 0x12, 0x4a, 0x12, 0xdb },
+{ 0x93, 0x50, 0x11, 0x8, 0x11, 0x8, 0x17, 0xe8, 0x11, 0xf, 0x79, 0x5a, 0x12, 0x62, 0x13, 0xaa, 0x10, 0xa, 0x1b, 0xca, 0x72, 0x4e, 0x13, 0xc4, 0x12, 0x44, 0x13, 0xce, 0x12, 0x4a, 0x12, 0x4a, 0x32, 0xdb },
+{ 0x93, 0x51, 0x10, 0x88, 0x10, 0x88, 0x7f, 0xf8, 0x10, 0x8f, 0x7c, 0xaa, 0x55, 0x32, 0x55, 0xd2, 0x7c, 0xa, 0x55, 0xea, 0x55, 0x2e, 0x7d, 0xe4, 0x11, 0x24, 0x7d, 0xee, 0x11, 0x2a, 0x11, 0x2a, 0x11, 0x7b },
+{ 0x93, 0x52, 0x0, 0x20, 0x61, 0x20, 0x31, 0x20, 0x11, 0xfe, 0x3, 0x20, 0x2, 0x20, 0x0, 0x20, 0x77, 0xff, 0x10, 0x20, 0x10, 0x60, 0x10, 0x58, 0x10, 0xcc, 0x11, 0x86, 0x33, 0x2, 0x28, 0x0, 0x67, 0xff },
+{ 0x93, 0x53, 0x8, 0x10, 0x1c, 0x50, 0x16, 0x50, 0x32, 0x7e, 0x20, 0xd0, 0x7e, 0x90, 0x8, 0x10, 0x8, 0xff, 0x7e, 0x10, 0x8, 0x10, 0x4a, 0x38, 0x6a, 0x28, 0x28, 0x6c, 0xe, 0x44, 0x38, 0xc6, 0x61, 0x83 },
+{ 0x93, 0x54, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x1f, 0xfc, 0x12, 0x24, 0x12, 0x24, 0x12, 0x24, 0x1f, 0xfc, 0x12, 0x24, 0x12, 0x24, 0x12, 0x24, 0x7f, 0xff, 0x0, 0x0, 0x4, 0x10, 0x1c, 0x1c, 0x70, 0x7 },
+{ 0x93, 0x55, 0x10, 0x20, 0x10, 0x20, 0x17, 0xff, 0x10, 0x20, 0x7d, 0xfc, 0x11, 0x4, 0x11, 0xfc, 0x11, 0x4, 0x11, 0xfc, 0x11, 0x4, 0x1d, 0xfc, 0x70, 0x0, 0x7, 0xff, 0x1, 0x4, 0x3, 0x6, 0x6, 0x3 },
+{ 0x93, 0x56, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x1, 0x40, 0x1, 0x60, 0x3, 0x20, 0x2, 0x30, 0x6, 0x10, 0xc, 0x18, 0x18, 0xc, 0x70, 0x7 },
+{ 0x93, 0x57, 0x0, 0x0, 0x1f, 0xfe, 0x10, 0x2, 0x10, 0x2, 0x1f, 0xfe, 0x11, 0x10, 0x11, 0x10, 0x17, 0xfe, 0x11, 0x10, 0x11, 0x10, 0x1f, 0xff, 0x12, 0x44, 0x32, 0x68, 0x22, 0x30, 0x63, 0x9c, 0xe, 0x7 },
+{ 0x93, 0x58, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xff, 0x10, 0x0, 0x10, 0x40, 0x10, 0x40, 0x10, 0x7f, 0x10, 0x40, 0x10, 0x40, 0x10, 0x40, 0x13, 0xfc, 0x32, 0x4, 0x22, 0x4, 0x62, 0x4, 0x2, 0x4, 0x3, 0xfc },
+{ 0x93, 0x59, 0x0, 0xc, 0x30, 0x38, 0x1b, 0xe0, 0x8, 0x40, 0x0, 0x40, 0x67, 0xff, 0x30, 0x90, 0x11, 0x98, 0x3, 0xc, 0x16, 0x47, 0x10, 0x40, 0x12, 0x52, 0x32, 0x5b, 0x26, 0x49, 0x24, 0x49, 0x60, 0xc0 },
+{ 0x93, 0x5a, 0x8, 0x10, 0x19, 0xff, 0x11, 0x0, 0x65, 0x7e, 0x2d, 0x52, 0x19, 0x7e, 0x11, 0x52, 0x25, 0x7e, 0x7d, 0x10, 0x11, 0xff, 0x11, 0x24, 0x55, 0xd7, 0x55, 0x10, 0x51, 0x7e, 0x12, 0x10, 0x10, 0xff },
+{ 0x93, 0x5b, 0x3, 0x44, 0xe, 0x44, 0x78, 0x44, 0x8, 0x44, 0x9, 0xff, 0x8, 0x44, 0x7f, 0x44, 0x8, 0x44, 0x8, 0x44, 0x8, 0x7c, 0x3e, 0x44, 0x22, 0x44, 0x22, 0x44, 0x22, 0x44, 0x22, 0x44, 0x3e, 0x7c },
+{ 0x93, 0x5c, 0x0, 0x10, 0x3e, 0x10, 0x22, 0x10, 0x22, 0x10, 0x3e, 0x1f, 0x22, 0x10, 0x22, 0x10, 0x22, 0x10, 0x3e, 0x10, 0x22, 0xfe, 0x22, 0x82, 0x22, 0x82, 0x3e, 0x82, 0x14, 0x82, 0x36, 0x82, 0x62, 0xfe },
+{ 0x93, 0x5d, 0x8, 0x0, 0x8, 0x3e, 0x7f, 0x80, 0x8, 0x0, 0x3f, 0x0, 0x29, 0x0, 0x29, 0x7f, 0x3f, 0x10, 0x29, 0x10, 0x29, 0x10, 0x3f, 0x10, 0x8, 0x32, 0x7f, 0xa2, 0x8, 0x22, 0x8, 0x2f, 0x8, 0x79 },
+{ 0x93, 0x5e, 0x8, 0x0, 0x8, 0xff, 0x7f, 0x10, 0x8, 0x7e, 0x3e, 0x42, 0x22, 0x42, 0x3e, 0x7e, 0x22, 0x42, 0x3e, 0x42, 0x22, 0x7e, 0x3e, 0x42, 0x0, 0x42, 0x7f, 0x7e, 0x12, 0x24, 0x33, 0x66, 0x61, 0xc3 },
+{ 0x93, 0x5f, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0xfe, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xfc, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x1f, 0xfc, 0x0, 0x0, 0x12, 0x24, 0x33, 0x36, 0x61, 0x13 },
+{ 0x93, 0x60, 0x4, 0x0, 0x5, 0xfe, 0xc, 0x0, 0x8, 0x0, 0x18, 0x0, 0x10, 0x0, 0x33, 0xff, 0x50, 0x40, 0x10, 0x40, 0x10, 0x40, 0x10, 0xc4, 0x10, 0x86, 0x10, 0x82, 0x10, 0x9f, 0x11, 0xf1, 0x13, 0x1 },
+{ 0x93, 0x61, 0x0, 0x0, 0x3f, 0xbc, 0x20, 0xa4, 0x20, 0xa4, 0x3f, 0xa4, 0x20, 0x27, 0x29, 0x40, 0x3f, 0x80, 0x29, 0x7e, 0x29, 0x22, 0x3f, 0xb6, 0x20, 0x1c, 0x69, 0x8, 0x49, 0x9c, 0x18, 0xb6, 0x30, 0x63 },
+{ 0x93, 0x62, 0x0, 0x0, 0x27, 0xee, 0x34, 0x2a, 0x14, 0x2a, 0x7, 0xea, 0x44, 0xb, 0x65, 0x50, 0x27, 0xe0, 0x5, 0x5f, 0x15, 0x49, 0x17, 0xeb, 0x14, 0xa, 0x35, 0x44, 0x29, 0x6e, 0x23, 0x2b, 0x66, 0x11 },
+{ 0x93, 0x63, 0x0, 0x0, 0x3f, 0xfe, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x3f, 0xfe, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x3f, 0xfe, 0x0, 0x0 },
+{ 0x93, 0x64, 0x0, 0x0, 0x3f, 0xfe, 0x0, 0x80, 0x7f, 0xff, 0x40, 0x81, 0x5e, 0xbd, 0x40, 0x81, 0x1e, 0xbc, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x84, 0x1f, 0xfd, 0x0, 0x83, 0x0, 0x7e },
+{ 0x93, 0x65, 0x0, 0xc, 0x0, 0x78, 0x1f, 0xc0, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x3f, 0xfe, 0x2, 0x48, 0x2, 0x4c, 0x6, 0x44, 0xc, 0x41, 0x18, 0x63, 0x70, 0x3e },
+{ 0x93, 0x66, 0x0, 0x20, 0x0, 0x20, 0x78, 0x20, 0x48, 0x20, 0x48, 0x20, 0x48, 0x20, 0x4b, 0xfe, 0x48, 0x20, 0x48, 0x20, 0x48, 0x20, 0x48, 0x20, 0x78, 0x20, 0x0, 0x20, 0x0, 0x20, 0x7, 0xff, 0x0, 0x0 },
+{ 0x93, 0x67, 0x10, 0x22, 0x10, 0x22, 0x11, 0xfe, 0x10, 0x24, 0x7c, 0x2c, 0x10, 0x28, 0x13, 0xff, 0x10, 0x10, 0x10, 0x20, 0x10, 0x7e, 0x1c, 0xc2, 0x71, 0x42, 0x6, 0x7e, 0x0, 0x42, 0x0, 0x42, 0x0, 0x7e },
+{ 0x93, 0x68, 0x0, 0x20, 0x30, 0x70, 0x19, 0xdc, 0x67, 0x7, 0x31, 0xfc, 0x0, 0x20, 0xb, 0xff, 0x19, 0x24, 0x33, 0x26, 0x66, 0x63, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x93, 0x69, 0x8, 0x0, 0x8, 0xff, 0x8, 0x10, 0x8, 0x10, 0x7e, 0x10, 0x12, 0x30, 0x12, 0x20, 0x12, 0x3e, 0x36, 0x62, 0x24, 0xe2, 0x25, 0xa2, 0x7c, 0x22, 0xa, 0x22, 0x19, 0x22, 0x31, 0x22, 0x60, 0x3e },
+{ 0x93, 0x6a, 0x0, 0x0, 0x1f, 0xfe, 0x10, 0x2, 0x10, 0x2, 0x1f, 0xfe, 0x10, 0x84, 0x17, 0xfc, 0x10, 0x90, 0x1f, 0xff, 0x10, 0x40, 0x13, 0xfc, 0x1e, 0x4, 0x33, 0xfc, 0x22, 0x4, 0x62, 0x4, 0x3, 0xfc },
+{ 0x93, 0x6b, 0x8, 0x20, 0x18, 0x20, 0x11, 0xfe, 0x30, 0x20, 0x60, 0x20, 0x8, 0x20, 0x1b, 0xff, 0x10, 0x20, 0x30, 0x20, 0x71, 0x20, 0x11, 0x3e, 0x11, 0x20, 0x13, 0xa0, 0x12, 0xa0, 0x12, 0x60, 0x16, 0x3f },
+{ 0x93, 0x6c, 0x0, 0x20, 0x0, 0x20, 0xc, 0x20, 0x7, 0x20, 0x1, 0x20, 0x0, 0x20, 0x18, 0x20, 0xe, 0x20, 0x2, 0x20, 0x0, 0x20, 0x0, 0x3f, 0x7, 0xe0, 0x7c, 0x20, 0x0, 0x20, 0x0, 0x20, 0x0, 0x20 },
+{ 0x93, 0x6d, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10, 0x7f, 0x10, 0x8, 0x10, 0x8, 0xfe, 0x1c, 0x10, 0x1a, 0x10, 0x19, 0x10, 0x28, 0x10, 0x28, 0x10, 0x48, 0x10, 0x8, 0x10, 0x8, 0x10, 0x9, 0xff, 0x8, 0x0 },
+{ 0x93, 0x6e, 0x0, 0x20, 0x30, 0x20, 0x1b, 0xff, 0xa, 0x0, 0x2, 0x24, 0x62, 0xff, 0x32, 0x24, 0x12, 0x3c, 0x2, 0x0, 0xa, 0xfe, 0xa, 0x42, 0x1a, 0x66, 0x16, 0x2c, 0x34, 0x38, 0x2c, 0x6c, 0x61, 0xc7 },
+{ 0x93, 0x6f, 0x0, 0x0, 0x1f, 0x8c, 0x1, 0xd8, 0x33, 0x63, 0x16, 0x36, 0xf, 0xf8, 0x18, 0xc, 0x77, 0xf7, 0x4, 0x10, 0x4, 0x10, 0x7, 0xf0, 0x4, 0x10, 0x6, 0x30, 0x2, 0x20, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x93, 0x70, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x3, 0xe0, 0x6, 0x20, 0xc, 0x40, 0x3f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x2, 0x50, 0x2, 0x58, 0x6, 0x49, 0x1c, 0x63, 0x70, 0x3e },
+{ 0x93, 0x71, 0x0, 0x22, 0x3e, 0x22, 0x22, 0xfe, 0x22, 0x24, 0x3e, 0x2c, 0x22, 0x28, 0x23, 0xff, 0x22, 0x10, 0x3e, 0x20, 0x22, 0x7e, 0x23, 0xc2, 0x22, 0x42, 0x3e, 0x7e, 0x14, 0x42, 0x36, 0x42, 0x62, 0x7e },
+{ 0x93, 0x72, 0x0, 0x20, 0x30, 0x70, 0x18, 0xd8, 0x9, 0x8c, 0x3, 0x7, 0x1, 0xfc, 0x0, 0x20, 0x78, 0x20, 0xb, 0xff, 0x8, 0x20, 0x8, 0xa4, 0x9, 0xa6, 0xb, 0x23, 0x18, 0x60, 0x34, 0x0, 0x63, 0xff },
+{ 0x93, 0x73, 0x4, 0x40, 0x4, 0x5f, 0x3f, 0xd1, 0x4, 0x93, 0x4, 0x92, 0x5, 0x16, 0x7f, 0xf4, 0x4, 0x12, 0x8, 0x11, 0x1f, 0x91, 0x70, 0x91, 0x10, 0x91, 0x1f, 0x91, 0x10, 0x97, 0x10, 0x90, 0x1f, 0x90 },
+{ 0x93, 0x74, 0x10, 0x10, 0x38, 0x10, 0x2d, 0xff, 0x65, 0x0, 0x41, 0x24, 0x7d, 0xff, 0x11, 0x24, 0x11, 0x3c, 0x7d, 0x0, 0x11, 0xfe, 0x55, 0x42, 0x55, 0x66, 0x51, 0x2c, 0x15, 0x38, 0x3a, 0x6c, 0x61, 0xc7 },
+{ 0x93, 0x75, 0x0, 0x6, 0x7e, 0x1c, 0x10, 0xf8, 0x10, 0x88, 0x10, 0x88, 0x10, 0x88, 0x3c, 0xff, 0x24, 0x88, 0x64, 0x88, 0x24, 0x88, 0x24, 0x8c, 0x24, 0xe4, 0x25, 0x84, 0x3c, 0x5, 0x1, 0xf7, 0x0, 0x2 },
+{ 0x93, 0x76, 0x0, 0x0, 0x7e, 0xff, 0x10, 0x80, 0x10, 0x80, 0x10, 0xff, 0x10, 0x90, 0x3c, 0x90, 0x24, 0x9e, 0x64, 0x92, 0x24, 0x92, 0x24, 0x92, 0x24, 0x92, 0x25, 0x92, 0x3d, 0x32, 0x3, 0x22, 0x0, 0x6e },
+{ 0x93, 0x77, 0x4, 0x0, 0x4, 0x0, 0x7f, 0xfe, 0x9, 0x42, 0x1b, 0x66, 0x12, 0x2c, 0x3e, 0x18, 0xb, 0x6c, 0x10, 0x7, 0x60, 0x80, 0x1f, 0xfc, 0x0, 0x84, 0x1, 0x84, 0x3, 0xc, 0xe, 0x8, 0x38, 0x38 },
+{ 0x93, 0x78, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xff, 0x10, 0x0, 0x11, 0x10, 0x1f, 0xfe, 0x11, 0x10, 0x11, 0xf0, 0x10, 0x0, 0x1f, 0xf8, 0x12, 0x8, 0x13, 0x18, 0x31, 0xb0, 0x20, 0xe0, 0x63, 0xb8, 0x1e, 0xf },
+{ 0x93, 0x79, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x93, 0x7a, 0x8, 0x0, 0x9, 0xfe, 0x8, 0x42, 0x8, 0x42, 0x7e, 0x46, 0x12, 0x64, 0x12, 0x24, 0x12, 0x2c, 0x36, 0x28, 0x24, 0x38, 0x24, 0x10, 0x7c, 0x10, 0xa, 0x38, 0x1a, 0x6c, 0x30, 0xc6, 0x61, 0x83 },
+{ 0x93, 0x7b, 0x4, 0x0, 0x4, 0x0, 0x7f, 0xfe, 0x9, 0x42, 0x1b, 0x66, 0x12, 0x2c, 0x3e, 0x18, 0xb, 0x6c, 0x11, 0x7, 0x60, 0x0, 0x1, 0x80, 0x4, 0xc6, 0x14, 0x43, 0x14, 0x9, 0x36, 0x18, 0x63, 0xf0 },
+{ 0x93, 0x7c, 0x8, 0x2, 0xf, 0xe2, 0x9, 0xa, 0x19, 0x4a, 0x12, 0x4a, 0x12, 0xea, 0x37, 0xaa, 0x51, 0xa, 0x11, 0xa, 0x17, 0xea, 0x11, 0xa, 0x11, 0x2, 0x11, 0x2, 0x11, 0xe2, 0x17, 0x2, 0x10, 0xe },
+{ 0x93, 0x7d, 0x10, 0x84, 0x18, 0x8c, 0x8, 0x88, 0x7f, 0xff, 0x40, 0x1, 0x4f, 0xf9, 0x48, 0x9, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x2, 0x40, 0x2, 0x40, 0x6, 0x40, 0xc, 0x41, 0x18, 0x63, 0x70, 0x3e },
+{ 0x93, 0x7e, 0x1, 0x0, 0x1, 0x0, 0x3, 0xf0, 0x6, 0x10, 0xc, 0x30, 0x3b, 0x60, 0x1, 0x80, 0x3, 0xc0, 0x6, 0x70, 0x1c, 0x1c, 0x71, 0xc7, 0x0, 0x60, 0x0, 0x0, 0x7, 0x80, 0x0, 0xe0, 0x0, 0x30 },
+{ 0x93, 0x80, 0x0, 0x20, 0x0, 0x20, 0x37, 0xff, 0x18, 0x20, 0xb, 0xfe, 0x2, 0x22, 0x3, 0xfe, 0x2, 0x22, 0x2, 0x22, 0xb, 0xfe, 0x18, 0xa8, 0x10, 0xac, 0x31, 0xa4, 0x23, 0x26, 0x66, 0x23, 0x0, 0x20 },
+{ 0x93, 0x81, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xfe, 0x1, 0x2, 0x1, 0x2, 0x1, 0x2, 0x1, 0x2, 0x3, 0x2, 0x2, 0x2, 0x2, 0x2, 0x6, 0x2, 0x4, 0x6, 0xc, 0x4, 0x18, 0x4, 0x70, 0x1c, 0x0, 0x0 },
+{ 0x93, 0x82, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xff, 0x10, 0x40, 0x13, 0xfc, 0x10, 0x44, 0x1f, 0xff, 0x10, 0x44, 0x10, 0x44, 0x13, 0xfc, 0x10, 0x0, 0x13, 0xfc, 0x32, 0x4, 0x22, 0x4, 0x62, 0x4, 0x3, 0xfc },
+{ 0x93, 0x83, 0x0, 0x88, 0x10, 0x88, 0x17, 0xff, 0x10, 0x88, 0x10, 0x20, 0x7c, 0x70, 0x10, 0xd8, 0x11, 0x8c, 0x17, 0x77, 0x10, 0x0, 0x10, 0x0, 0x1d, 0xfc, 0x71, 0x4, 0x1, 0x4, 0x1, 0x4, 0x1, 0xfc },
+{ 0x93, 0x84, 0x0, 0x20, 0x10, 0x20, 0x11, 0xff, 0x11, 0x10, 0x11, 0x7e, 0x7d, 0x12, 0x11, 0xff, 0x11, 0x12, 0x11, 0x12, 0x11, 0x7e, 0x11, 0x0, 0x1d, 0x7e, 0x73, 0x42, 0x2, 0x42, 0x6, 0x42, 0x0, 0x7e },
+{ 0x93, 0x85, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x2, 0x20, 0x4, 0x10, 0x1f, 0xfc, 0x74, 0x7, 0x7, 0xf0, 0x4, 0x0, 0x7, 0xf0, 0x4, 0x0, 0x7f, 0xff, 0x4, 0x0, 0xc, 0x8, 0x9, 0xfc, 0x3f, 0x4 },
+{ 0x93, 0x86, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x2, 0x20, 0x2, 0x0, 0x0, 0x7f, 0xff, 0x1, 0x0, 0x3, 0x0, 0x6, 0x0, 0x1f, 0xfc, 0x74, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x7, 0xfc },
+{ 0x93, 0x87, 0x0, 0x80, 0x1, 0x0, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x0, 0xf, 0xff, 0x8, 0x0, 0xf, 0xfe, 0x4, 0x2, 0x44, 0x22, 0x44, 0x22, 0x7f, 0xe6, 0x0, 0x1c },
+{ 0x93, 0x88, 0x0, 0x20, 0x10, 0x40, 0x11, 0xfc, 0x55, 0x4, 0x55, 0xfc, 0x55, 0x4, 0x55, 0xfc, 0x55, 0x0, 0x55, 0xff, 0x55, 0x0, 0x55, 0xfe, 0x7c, 0x2, 0x2, 0xaa, 0x6, 0xaa, 0x4, 0x6, 0x0, 0xc },
+{ 0x93, 0x89, 0x10, 0x20, 0x10, 0x20, 0x10, 0x3f, 0x10, 0x20, 0x59, 0xfc, 0x55, 0x4, 0x55, 0x4, 0x51, 0xfc, 0x11, 0x4, 0x11, 0x4, 0x11, 0xfc, 0x10, 0x20, 0x17, 0xff, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20 },
+{ 0x93, 0x8a, 0x10, 0x0, 0x10, 0xf8, 0x10, 0x88, 0x10, 0x88, 0x7c, 0x88, 0x11, 0x8f, 0x13, 0x0, 0x10, 0x0, 0x1d, 0xfc, 0x70, 0x84, 0x10, 0xcc, 0x10, 0x58, 0x10, 0x30, 0x10, 0x78, 0x10, 0xcc, 0x33, 0x87 },
+{ 0x93, 0x8b, 0x10, 0x88, 0x10, 0x88, 0x17, 0xff, 0x10, 0x88, 0x78, 0x20, 0x10, 0x70, 0x10, 0xd8, 0x11, 0x8c, 0x17, 0x77, 0x18, 0x0, 0x70, 0x0, 0x11, 0xfc, 0x11, 0x4, 0x11, 0x4, 0x11, 0x4, 0x31, 0xfc },
+{ 0x93, 0x8c, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x1f, 0xfc, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x2, 0xa0, 0x6, 0xb0, 0xc, 0x98, 0x18, 0x8c, 0x70, 0x87, 0x0, 0x80 },
+{ 0x93, 0x8d, 0x8, 0x48, 0x8, 0x48, 0xa, 0x49, 0x7f, 0x4b, 0x9, 0x4e, 0x8, 0x48, 0x1c, 0x48, 0x1a, 0x48, 0x1a, 0x4e, 0x29, 0xcb, 0x2b, 0x49, 0x48, 0x48, 0x8, 0xc8, 0x8, 0x89, 0x9, 0x89, 0xb, 0x7 },
+{ 0x93, 0x8e, 0x10, 0x20, 0x10, 0x20, 0x13, 0xff, 0x7c, 0x20, 0x11, 0xfe, 0x10, 0x20, 0x3b, 0xff, 0x34, 0x40, 0x30, 0x44, 0x53, 0xff, 0x50, 0x84, 0x11, 0xa4, 0x11, 0x34, 0x13, 0x14, 0x16, 0x4, 0x10, 0x1c },
+{ 0x93, 0x8f, 0x8, 0x10, 0x8, 0x10, 0x9, 0xff, 0x7e, 0x10, 0x8, 0xfe, 0x8, 0x92, 0x1c, 0xfe, 0x1a, 0x92, 0x1a, 0x92, 0x28, 0xfe, 0x28, 0x54, 0x48, 0x54, 0x8, 0xd6, 0x8, 0x92, 0x9, 0x93, 0x8, 0x10 },
+{ 0x93, 0x90, 0x0, 0x80, 0x30, 0x80, 0x19, 0xfe, 0x9, 0x22, 0x3, 0x24, 0x8, 0x70, 0x18, 0xd8, 0x31, 0x8c, 0x63, 0x7, 0x0, 0x0, 0x1f, 0xfc, 0x12, 0x44, 0x12, 0x44, 0x12, 0x44, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x93, 0x91, 0x2, 0x0, 0x22, 0x0, 0x37, 0xfe, 0x14, 0x2, 0xa, 0x2, 0x43, 0xf2, 0x64, 0x82, 0x20, 0x82, 0x7, 0xf2, 0x10, 0x82, 0x14, 0x92, 0x14, 0x92, 0x34, 0x92, 0x27, 0xf6, 0x20, 0x4, 0x60, 0x1c },
+{ 0x93, 0x92, 0x0, 0x0, 0x30, 0xfc, 0x18, 0x84, 0x8, 0xfc, 0x0, 0x84, 0x60, 0x84, 0x30, 0xfc, 0x10, 0x0, 0x3, 0xff, 0x8, 0x80, 0x9, 0xff, 0x1b, 0x49, 0x10, 0xd9, 0x33, 0xb3, 0x20, 0x62, 0x61, 0xce },
+{ 0x93, 0x93, 0x0, 0x20, 0x30, 0x20, 0x1b, 0xff, 0x8, 0x20, 0x1, 0xfe, 0x60, 0x20, 0x33, 0xff, 0x10, 0x40, 0x0, 0x44, 0xb, 0xff, 0x8, 0x84, 0x19, 0xa4, 0x11, 0x34, 0x33, 0x14, 0x26, 0x4, 0x60, 0x1c },
+{ 0x93, 0x94, 0x8, 0x0, 0x8, 0x0, 0x8, 0xff, 0x9, 0x8, 0x2b, 0x8, 0x2a, 0x8, 0x68, 0x8, 0x48, 0x8, 0x8, 0x8, 0x8, 0x8, 0x1c, 0x8, 0x14, 0x8, 0x16, 0x8, 0x32, 0x8, 0x23, 0x8, 0x60, 0x38 },
+{ 0x93, 0x95, 0x11, 0xe4, 0x12, 0x28, 0x11, 0x71, 0x14, 0xda, 0x55, 0x8c, 0x53, 0x76, 0x56, 0x3, 0x51, 0xfc, 0x11, 0x4, 0x11, 0x4, 0x39, 0xfc, 0x28, 0x88, 0x2c, 0xd8, 0x24, 0x50, 0x63, 0xff, 0x40, 0x0 },
+{ 0x93, 0x96, 0x0, 0x80, 0x10, 0x84, 0x18, 0x8c, 0xc, 0x98, 0x4, 0x90, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x1f, 0xfc, 0x0, 0x4, 0x0, 0x4, 0x0, 0x4, 0x1f, 0xfc, 0x0, 0x0 },
+{ 0x93, 0x97, 0x0, 0x40, 0x0, 0x40, 0x1f, 0xff, 0x50, 0x0, 0x37, 0xfe, 0x10, 0x0, 0x13, 0xfc, 0x12, 0x4, 0x32, 0x4, 0x52, 0x4, 0x13, 0xfc, 0x11, 0x8, 0x31, 0x98, 0x20, 0x90, 0x6f, 0xff, 0x0, 0x0 },
+{ 0x93, 0x98, 0x10, 0x20, 0x10, 0x20, 0x13, 0xfe, 0x7c, 0x20, 0x5, 0xfc, 0xc, 0x20, 0xb, 0xfe, 0x18, 0x40, 0x10, 0x44, 0x3b, 0xff, 0x54, 0x84, 0x11, 0xa4, 0x11, 0x34, 0x13, 0x14, 0x16, 0x4, 0x10, 0x1c },
+{ 0x93, 0x99, 0x8, 0x20, 0x8, 0x20, 0x1f, 0xbf, 0x34, 0x48, 0x62, 0x84, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x10, 0x0, 0x10, 0x3f, 0xfe, 0x4, 0x10, 0x6, 0x10, 0x2, 0x10, 0x0, 0x70 },
+{ 0x93, 0x9a, 0x8, 0x20, 0x8, 0x20, 0x1f, 0x7f, 0x34, 0x48, 0x62, 0x84, 0x1, 0xc0, 0x3, 0x60, 0x6, 0x30, 0x1c, 0x1c, 0x73, 0xe7, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8 },
+{ 0x93, 0x9b, 0x10, 0x40, 0x10, 0x40, 0x3f, 0x7f, 0x24, 0x90, 0x42, 0x8, 0x3f, 0xfe, 0x20, 0x2, 0x27, 0xf2, 0x20, 0x2, 0x27, 0xf2, 0x24, 0x12, 0x24, 0x12, 0x27, 0xf2, 0x20, 0x2, 0x20, 0x2, 0x20, 0xe },
+{ 0x93, 0x9c, 0x10, 0x10, 0x54, 0x10, 0x55, 0xff, 0x55, 0x10, 0x11, 0x7e, 0x7d, 0x12, 0x11, 0xff, 0x11, 0x12, 0x39, 0x12, 0x35, 0x7e, 0x51, 0x0, 0x51, 0x7e, 0x13, 0x42, 0x12, 0x42, 0x16, 0x42, 0x10, 0x7e },
+{ 0x93, 0x9d, 0x8, 0x20, 0x18, 0x20, 0x33, 0xff, 0x60, 0x40, 0x34, 0xc4, 0xc, 0x84, 0x19, 0xfe, 0x32, 0x4b, 0x7e, 0x48, 0xa, 0x48, 0x8, 0x48, 0x2a, 0x48, 0x2a, 0xc8, 0x6a, 0x89, 0x49, 0x89, 0xb, 0x7 },
+{ 0x93, 0x9e, 0x0, 0x2, 0x7f, 0xd2, 0x10, 0x12, 0x10, 0x92, 0x30, 0x92, 0x27, 0xd2, 0x7c, 0x52, 0x4, 0x12, 0x4, 0x12, 0x3f, 0x92, 0x4, 0x12, 0x4, 0x2, 0x4, 0x2, 0x5, 0xc2, 0x1f, 0x2, 0x70, 0xe },
+{ 0x93, 0x9f, 0x2, 0x20, 0x7f, 0xff, 0x2, 0x20, 0xf, 0xf8, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x1f, 0xfc, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x84, 0x1f, 0xfc, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x7f, 0xff },
+{ 0x93, 0xa0, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x0, 0x0, 0x31, 0xfc, 0x19, 0x4, 0x1, 0xfc, 0x61, 0x4, 0x31, 0xfc, 0x0, 0x0, 0xb, 0xff, 0x19, 0x0, 0x13, 0xfe, 0x36, 0x92, 0x21, 0xb2, 0x63, 0x6e },
+{ 0x93, 0xa1, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x0, 0x0, 0x3c, 0x92, 0x24, 0x54, 0x24, 0xfe, 0x3c, 0x28, 0x25, 0xff, 0x24, 0x44, 0x3c, 0x92, 0x25, 0x55, 0x24, 0x38, 0x24, 0xd6, 0x65, 0x93, 0x4c, 0x30 },
+{ 0x93, 0xa2, 0x0, 0x4, 0x3e, 0x4, 0x0, 0x4, 0x7f, 0x4, 0x0, 0xff, 0x3e, 0x4, 0x0, 0x4, 0x0, 0x64, 0x3e, 0x34, 0x0, 0x14, 0x0, 0x4, 0x3e, 0x4, 0x22, 0x4, 0x22, 0x4, 0x22, 0x4, 0x3e, 0x1c },
+{ 0x93, 0xa3, 0x0, 0xa4, 0x3d, 0xfe, 0x24, 0x48, 0x27, 0xff, 0x24, 0x84, 0x3d, 0x7a, 0x26, 0x1, 0x25, 0xfe, 0x24, 0x0, 0x3c, 0xfc, 0x24, 0x0, 0x24, 0xfc, 0x24, 0x0, 0x25, 0xfe, 0x65, 0x2, 0x4d, 0xfe },
+{ 0x93, 0xa4, 0x0, 0x0, 0x3f, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x0, 0x0, 0x4, 0x10, 0x6, 0x10, 0x2, 0x30, 0x0, 0x20, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x93, 0xa5, 0x0, 0x10, 0x3c, 0x12, 0x25, 0xd6, 0x24, 0x58, 0x24, 0x5c, 0x24, 0xd6, 0x3d, 0x93, 0x8, 0x30, 0x28, 0x0, 0x2c, 0xfe, 0x28, 0x82, 0x28, 0x82, 0x28, 0xfe, 0x2c, 0x82, 0x38, 0x82, 0x60, 0xfe },
+{ 0x93, 0xa6, 0x0, 0x50, 0x30, 0x50, 0x1a, 0x52, 0xb, 0x56, 0x1, 0x54, 0x0, 0x50, 0x0, 0x50, 0x79, 0xdc, 0xb, 0x56, 0x8, 0x52, 0x8, 0xd0, 0x8, 0x92, 0x9, 0x92, 0x1b, 0xe, 0x34, 0x0, 0x63, 0xff },
+{ 0x93, 0xa7, 0x0, 0xc, 0x30, 0x38, 0x19, 0xe0, 0x8, 0x20, 0x3, 0xff, 0x0, 0x68, 0x0, 0xa4, 0x7b, 0x23, 0x8, 0xf8, 0x8, 0x48, 0x8, 0x4e, 0x8, 0xc2, 0x9, 0x82, 0x1b, 0xe, 0x34, 0x0, 0x63, 0xff },
+{ 0x93, 0xa8, 0x10, 0xf2, 0x39, 0x15, 0x2c, 0xba, 0x64, 0x6c, 0x40, 0xc6, 0x7d, 0x83, 0x10, 0x7c, 0x10, 0x0, 0x7c, 0xfe, 0x10, 0x82, 0x54, 0x82, 0x54, 0xfe, 0x50, 0x44, 0x1c, 0x6c, 0x30, 0x28, 0x61, 0xff },
+{ 0x93, 0xa9, 0x0, 0x80, 0x3c, 0x80, 0x25, 0xff, 0x27, 0x1, 0x2c, 0x81, 0x28, 0xf9, 0x29, 0x41, 0x24, 0x41, 0x27, 0xfd, 0x24, 0x41, 0x25, 0x49, 0x2d, 0x49, 0x21, 0x49, 0x21, 0xfb, 0x20, 0x2, 0x20, 0xe },
+{ 0x93, 0xaa, 0x0, 0x0, 0x7e, 0xff, 0x0, 0x10, 0x0, 0x7e, 0x3e, 0x42, 0x22, 0x42, 0x22, 0x7e, 0x22, 0x42, 0x3e, 0x42, 0x0, 0x7e, 0x22, 0x42, 0x36, 0x42, 0x14, 0x7e, 0x1f, 0x24, 0x70, 0x66, 0x0, 0xc3 },
+{ 0x93, 0xab, 0x1, 0x24, 0x3c, 0xa8, 0x25, 0xfe, 0x24, 0x48, 0x27, 0xff, 0x3c, 0x84, 0x25, 0xfe, 0x26, 0x91, 0x24, 0xfe, 0x3c, 0x90, 0x24, 0xfe, 0x24, 0x90, 0x24, 0xff, 0x25, 0x55, 0x65, 0x55, 0x4d, 0x3 },
+{ 0x93, 0xac, 0x0, 0x0, 0x3f, 0x7e, 0x21, 0x42, 0x3f, 0x7e, 0x21, 0x42, 0x3f, 0x7e, 0x20, 0x2, 0x2f, 0x12, 0x20, 0xfa, 0x2f, 0x12, 0x29, 0x52, 0x2f, 0x52, 0x2a, 0x12, 0x27, 0x12, 0x2c, 0x32, 0x20, 0x6 },
+{ 0x93, 0xad, 0x8, 0xc8, 0xb, 0x88, 0x9, 0x8, 0x1f, 0xe8, 0x11, 0x1f, 0x37, 0xe9, 0x35, 0x29, 0x57, 0xe9, 0x15, 0x29, 0x17, 0xe9, 0x11, 0x9, 0x17, 0xe9, 0x11, 0x19, 0x11, 0xd3, 0x17, 0x32, 0x10, 0x66 },
+{ 0x93, 0xae, 0x3, 0x90, 0x3e, 0x10, 0x4, 0x10, 0x7f, 0xd0, 0x4, 0x3f, 0x3f, 0x91, 0x24, 0x91, 0x3f, 0x91, 0x24, 0x91, 0x3f, 0x91, 0x4, 0x11, 0x3f, 0x91, 0x4, 0x31, 0x7, 0xa3, 0x1c, 0x62, 0x70, 0xce },
+{ 0x93, 0xaf, 0x0, 0x0, 0x3f, 0xfe, 0x20, 0x2, 0x20, 0x2, 0x27, 0xf2, 0x20, 0x2, 0x20, 0x2, 0x27, 0xf2, 0x24, 0x12, 0x24, 0x12, 0x24, 0x12, 0x27, 0xf2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0xe },
+{ 0x93, 0xb0, 0x8, 0x88, 0xc, 0x98, 0x4, 0x90, 0x3f, 0xfe, 0x20, 0x2, 0x27, 0xf2, 0x4, 0x10, 0x4, 0x10, 0x7, 0xf0, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x93, 0xb1, 0x0, 0x88, 0x37, 0xff, 0x18, 0x40, 0x9, 0xfc, 0x1, 0x4, 0x79, 0xfc, 0x9, 0x4, 0x9, 0xfc, 0x9, 0x4, 0x19, 0xfc, 0x34, 0x0, 0x63, 0xff, 0x0, 0x8, 0x7f, 0xff, 0x4, 0x8, 0x2, 0x38 },
+{ 0x93, 0xb2, 0x10, 0x20, 0x10, 0x20, 0x13, 0xfe, 0x11, 0x4, 0x58, 0x88, 0x57, 0xff, 0x50, 0x0, 0x11, 0xfc, 0x11, 0x24, 0x11, 0xfc, 0x11, 0x24, 0x11, 0xfc, 0x10, 0x20, 0x13, 0xfe, 0x10, 0x20, 0x17, 0xff },
+{ 0x93, 0xb3, 0x10, 0x20, 0x10, 0x20, 0x13, 0xfe, 0x11, 0x4, 0x78, 0x88, 0x17, 0xff, 0x10, 0x0, 0x11, 0xfc, 0x19, 0x24, 0x71, 0xfc, 0x11, 0x24, 0x11, 0xfc, 0x10, 0x20, 0x13, 0xfe, 0x10, 0x20, 0x37, 0xff },
+{ 0x93, 0xb4, 0x0, 0x0, 0x33, 0xfe, 0x1a, 0x2, 0xa, 0x2, 0x2, 0xfa, 0x62, 0x2, 0x32, 0x2, 0x12, 0xfa, 0x2, 0x8a, 0xa, 0x8a, 0xa, 0x8a, 0x1a, 0xfa, 0x12, 0x2, 0x32, 0x2, 0x22, 0x2, 0x62, 0x6 },
+{ 0x93, 0xb5, 0x0, 0x20, 0x78, 0x20, 0x4b, 0xfe, 0x49, 0x4, 0x48, 0x88, 0x7f, 0xff, 0x48, 0x0, 0x49, 0xfc, 0x49, 0x24, 0x79, 0xfc, 0x49, 0x24, 0x49, 0xfc, 0x48, 0x20, 0x7b, 0xfe, 0x0, 0x20, 0x7, 0xff },
+{ 0x93, 0xb6, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x4, 0x10, 0x2, 0x20, 0x7f, 0xff, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x88, 0xf, 0xf8, 0x8, 0x88, 0xf, 0xf8, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x7f, 0xff },
+{ 0x93, 0xb7, 0x0, 0x0, 0x3d, 0xfe, 0x25, 0x2, 0x25, 0x2, 0x25, 0x7a, 0x3d, 0x2, 0x25, 0x2, 0x25, 0x7a, 0x25, 0x4a, 0x3d, 0x4a, 0x25, 0x4a, 0x25, 0x7a, 0x25, 0x2, 0x25, 0x2, 0x65, 0x2, 0x4d, 0x6 },
+{ 0x93, 0xb8, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x10, 0x0, 0x1f, 0xfe, 0x34, 0x2, 0x67, 0xf2, 0x9, 0x2, 0x1f, 0xfa, 0x1, 0x2, 0x9, 0x12, 0x9, 0x12, 0xf, 0xf6, 0x0, 0x4, 0x0, 0x1c },
+{ 0x93, 0xb9, 0x1, 0x4, 0x30, 0x88, 0x1f, 0xff, 0x8, 0x20, 0x1, 0xfc, 0x1, 0x4, 0x1, 0x4, 0x79, 0xfc, 0x9, 0x4, 0x9, 0x4, 0x9, 0xfc, 0x9, 0x4, 0x9, 0x4, 0x19, 0xfc, 0x34, 0x0, 0x63, 0xff },
+{ 0x93, 0xba, 0x10, 0x0, 0x39, 0xfe, 0x2d, 0x2, 0x65, 0x2, 0x41, 0x7a, 0x7d, 0x2, 0x11, 0x2, 0x11, 0x7a, 0x7f, 0x4a, 0x11, 0x4a, 0x55, 0x4a, 0x55, 0x7a, 0x51, 0x2, 0x1d, 0x2, 0x31, 0x2, 0x61, 0x6 },
+{ 0x93, 0xbb, 0x10, 0x20, 0x10, 0x20, 0x10, 0x3e, 0x54, 0x20, 0x54, 0x20, 0x57, 0xff, 0x54, 0x0, 0x54, 0x0, 0x57, 0xff, 0x54, 0x20, 0x54, 0x20, 0x7c, 0x3c, 0x0, 0x26, 0x0, 0x20, 0x0, 0x20, 0x0, 0x20 },
+{ 0x93, 0xbc, 0x20, 0x10, 0x26, 0x20, 0x3c, 0x7e, 0x20, 0x42, 0x20, 0x7e, 0x22, 0x42, 0x1e, 0x7e, 0x0, 0x40, 0x8, 0x7f, 0x8, 0x40, 0x7f, 0x7f, 0x8, 0x1, 0x9, 0x55, 0x9, 0x55, 0x9, 0x3, 0x8, 0x6 },
+{ 0x93, 0xbd, 0x0, 0x0, 0x3f, 0xfe, 0x20, 0x0, 0x21, 0x10, 0x27, 0xfc, 0x21, 0x10, 0x20, 0x80, 0x2f, 0xfe, 0x21, 0x0, 0x23, 0xf8, 0x25, 0x8, 0x21, 0x8, 0x21, 0xf8, 0x20, 0x0, 0x3f, 0xfe, 0x0, 0x0 },
+{ 0x93, 0xbe, 0x4, 0x0, 0xd, 0xfc, 0x19, 0x4, 0x31, 0xfc, 0x65, 0x4, 0xd, 0x4, 0x19, 0xfc, 0x30, 0x0, 0x77, 0xff, 0x10, 0x8, 0x17, 0xff, 0x11, 0x8, 0x11, 0x88, 0x10, 0x88, 0x10, 0x8, 0x10, 0x38 },
+{ 0x93, 0xbf, 0x8, 0x20, 0x18, 0x20, 0x17, 0xff, 0x30, 0x20, 0x63, 0xfe, 0xa, 0x52, 0x1a, 0x52, 0x12, 0x52, 0x33, 0xfe, 0x70, 0x0, 0x10, 0x60, 0x10, 0xb6, 0x12, 0x93, 0x12, 0x85, 0x16, 0xcc, 0x14, 0x78 },
+{ 0x93, 0xc0, 0x0, 0x20, 0x30, 0x20, 0x1b, 0xff, 0x8, 0x20, 0x0, 0x20, 0x61, 0xfe, 0x30, 0x0, 0x13, 0xff, 0x2, 0x1, 0xa, 0x49, 0x8, 0x48, 0x18, 0x48, 0x10, 0x48, 0x30, 0xc9, 0x21, 0x89, 0x63, 0x7 },
+{ 0x93, 0xc1, 0x8, 0x10, 0x28, 0x10, 0x28, 0xfe, 0x28, 0x10, 0x7e, 0x10, 0x48, 0x10, 0x9, 0xff, 0x8, 0x4, 0xe, 0x4, 0x39, 0xff, 0x68, 0x4, 0x8, 0xc4, 0x8, 0x64, 0x8, 0x24, 0x8, 0x4, 0x8, 0x1c },
+{ 0x93, 0xc2, 0x8, 0x0, 0xf, 0x7e, 0x8, 0x22, 0x7f, 0xb4, 0x2a, 0x18, 0x29, 0x2c, 0x58, 0x47, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8 },
+{ 0x93, 0xc3, 0x0, 0x18, 0x0, 0xf0, 0x1f, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x2, 0xa0, 0x6, 0xb0, 0x1c, 0x9c, 0x70, 0x87, 0x0, 0x0, 0x2, 0x40, 0x2, 0x40, 0x6, 0x40, 0xc, 0x41, 0x18, 0x63, 0x70, 0x3e },
+{ 0x93, 0xc4, 0x8, 0x20, 0x8, 0x20, 0x1f, 0x7f, 0x34, 0xd0, 0x62, 0x8, 0xf, 0xfe, 0x8, 0x40, 0xf, 0xfc, 0x8, 0x40, 0xf, 0xfc, 0x8, 0x40, 0xf, 0xfe, 0x0, 0x2, 0x12, 0x4a, 0x32, 0x46, 0x20, 0xc },
+{ 0x93, 0xc5, 0x0, 0x80, 0x3f, 0xfe, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x88, 0x8, 0x88, 0x7f, 0xff, 0x11, 0x8, 0x11, 0x8, 0x1f, 0xfe, 0x0, 0x10, 0x0, 0x70 },
+{ 0x93, 0xc6, 0x4, 0x20, 0x44, 0x20, 0x28, 0x20, 0x13, 0xfe, 0x12, 0x22, 0x2a, 0x22, 0x4a, 0x22, 0xa, 0x22, 0x1a, 0x22, 0x1b, 0xfe, 0x28, 0x20, 0x48, 0x24, 0x8, 0x24, 0x8, 0x3e, 0x19, 0xe2, 0x77, 0x3 },
+{ 0x93, 0xc7, 0x0, 0x10, 0x3c, 0x10, 0x1, 0xff, 0x7e, 0x10, 0x0, 0x10, 0x3c, 0xfe, 0x0, 0x0, 0x1, 0xff, 0x3d, 0x1, 0x1, 0x49, 0x0, 0x48, 0x3c, 0x48, 0x24, 0x48, 0x24, 0x49, 0x24, 0xc9, 0x3d, 0x87 },
+{ 0x93, 0xc8, 0x10, 0x0, 0x11, 0xff, 0x11, 0x0, 0x7d, 0x0, 0x11, 0xff, 0x11, 0x20, 0x39, 0x20, 0x35, 0x3e, 0x35, 0x22, 0x51, 0x22, 0x51, 0x22, 0x13, 0x62, 0x12, 0x46, 0x16, 0x44, 0x10, 0xc4, 0x11, 0x9c },
+{ 0x93, 0xc9, 0x10, 0x80, 0x10, 0xfc, 0x11, 0x88, 0x7d, 0x10, 0x13, 0xfe, 0x11, 0x22, 0x39, 0x22, 0x35, 0xfe, 0x34, 0x20, 0x50, 0xc2, 0x53, 0x26, 0x10, 0xd4, 0x13, 0x38, 0x10, 0xd4, 0x13, 0x13, 0x10, 0x70 },
+{ 0x93, 0xca, 0x0, 0x0, 0x3, 0xe0, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x3e, 0x3e, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x3f, 0xfe, 0x0, 0x0 },
+{ 0x93, 0xcb, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x22, 0x22, 0x22, 0x22, 0x6, 0x20, 0xc, 0x3e, 0x38, 0x0, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x1, 0x40, 0x3, 0x60, 0x6, 0x30, 0x1c, 0x1c, 0x70, 0x7 },
+{ 0x93, 0xcc, 0x10, 0x40, 0x10, 0xdc, 0x13, 0x94, 0x7e, 0x14, 0x12, 0x14, 0x13, 0x94, 0x3a, 0x27, 0x36, 0x0, 0x53, 0xbe, 0x52, 0x12, 0x12, 0x16, 0x12, 0x14, 0x13, 0x88, 0x16, 0x1c, 0x12, 0x16, 0x12, 0x23 },
+{ 0x93, 0xcd, 0x0, 0x0, 0x1f, 0xfe, 0x10, 0x2, 0x10, 0x2, 0x1f, 0xfe, 0x10, 0x40, 0x10, 0x40, 0x17, 0xfe, 0x14, 0x42, 0x14, 0x42, 0x14, 0x42, 0x17, 0xfe, 0x34, 0x42, 0x24, 0x42, 0x64, 0x42, 0x7, 0xfe },
+{ 0x93, 0xce, 0x2, 0x10, 0x2, 0x8, 0x7f, 0xff, 0x0, 0x80, 0x2, 0x61, 0xf, 0xff, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x0, 0xf, 0xff, 0x8, 0x0, 0x2f, 0xfe, 0x64, 0x92, 0x42, 0x4e },
+{ 0x93, 0xcf, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x4, 0x10, 0x0, 0x80, 0x0, 0x80, 0x0, 0xfe, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xfc, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x1f, 0xfc },
+{ 0x93, 0xd0, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x2, 0x2f, 0xfa, 0x0, 0x80, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x4, 0x10, 0xc, 0x18, 0x38, 0xe },
+{ 0x93, 0xd1, 0x0, 0x0, 0x7f, 0xff, 0x2, 0x20, 0x2, 0x20, 0x3f, 0xfe, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x24, 0x3e, 0x38, 0x2, 0x20, 0x2, 0x3f, 0xfe, 0x20, 0x2, 0x20, 0x2, 0x3f, 0xfe, 0x0, 0x0 },
+{ 0x93, 0xd2, 0x2, 0x10, 0x22, 0x1e, 0x37, 0xb2, 0x12, 0x64, 0x7, 0xbe, 0x42, 0xa, 0x6f, 0xca, 0x20, 0x3f, 0x7, 0x8a, 0x14, 0x8a, 0x17, 0xbe, 0x14, 0x88, 0x37, 0x88, 0x24, 0x88, 0x24, 0x88, 0x65, 0x98 },
+{ 0x93, 0xd3, 0x1, 0x0, 0x1, 0x3f, 0x71, 0xc8, 0x57, 0x1e, 0x51, 0x12, 0x55, 0x52, 0x55, 0x5e, 0x55, 0x52, 0x55, 0x52, 0x57, 0xde, 0x51, 0x12, 0x71, 0x12, 0x1, 0x5e, 0x0, 0xd4, 0x0, 0x36, 0x0, 0x63 },
+{ 0x93, 0xd4, 0x0, 0x80, 0x0, 0x8e, 0x0, 0xf8, 0x7f, 0x80, 0x0, 0x80, 0x0, 0x80, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x81, 0x0, 0xc3, 0x0, 0x7e },
+{ 0x93, 0xd5, 0x8, 0x10, 0x8, 0x10, 0x9, 0xff, 0x8, 0x0, 0x2c, 0x7c, 0x2a, 0x44, 0x6a, 0x7c, 0x48, 0x0, 0x8, 0xfe, 0x8, 0x4, 0x8, 0x8, 0x9, 0xff, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10, 0x8, 0x30 },
+{ 0x93, 0xd6, 0x4, 0x20, 0x4, 0x20, 0x7f, 0xe0, 0x0, 0x3f, 0x1f, 0x24, 0x11, 0x64, 0x1f, 0x44, 0x0, 0x2c, 0x3f, 0x28, 0x2, 0x38, 0x4, 0x10, 0x7, 0x90, 0x7c, 0x38, 0x4, 0x2c, 0x4, 0x66, 0x1c, 0xc3 },
+{ 0x93, 0xd7, 0x0, 0x40, 0x30, 0x46, 0x18, 0x7c, 0xf, 0xc0, 0x0, 0x40, 0x60, 0x40, 0x32, 0x44, 0x12, 0x44, 0x2, 0x44, 0xa, 0x44, 0xa, 0x44, 0x1b, 0xfc, 0x10, 0x40, 0x30, 0x41, 0x20, 0x63, 0x60, 0x3e },
+{ 0x93, 0xd8, 0x0, 0x0, 0x3b, 0xff, 0x28, 0x40, 0x28, 0xc0, 0x29, 0xa2, 0x3b, 0x26, 0x28, 0x74, 0x28, 0xd0, 0x29, 0x90, 0x3b, 0x38, 0x28, 0x58, 0x28, 0xd4, 0x29, 0x96, 0x2b, 0x13, 0x68, 0x30, 0x58, 0xe0 },
+{ 0x93, 0xd9, 0x0, 0x6, 0x30, 0x1c, 0x19, 0xf0, 0x9, 0x10, 0x1, 0xff, 0x1, 0x10, 0x1, 0x7e, 0x79, 0x42, 0x9, 0x7e, 0x9, 0x42, 0x9, 0x7e, 0x9, 0x42, 0xa, 0x42, 0x18, 0x7e, 0x34, 0x0, 0x63, 0xff },
+{ 0x93, 0xda, 0x8, 0x0, 0x8, 0xff, 0xf, 0x10, 0x78, 0x7e, 0x8, 0x42, 0x2a, 0x42, 0x2a, 0x7e, 0x2a, 0x42, 0x2a, 0x42, 0x2a, 0x7e, 0x3e, 0x42, 0x8, 0x42, 0x8, 0x7e, 0x9, 0x24, 0x7, 0x66, 0x0, 0xc3 },
+{ 0x93, 0xdb, 0x0, 0x18, 0x0, 0xf0, 0x1f, 0x80, 0x1, 0x0, 0x1, 0x0, 0x7f, 0xff, 0x2, 0x20, 0x6, 0x30, 0xc, 0x18, 0x18, 0xc, 0x7f, 0xff, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8 },
+{ 0x93, 0xdc, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x3f, 0xfe, 0x0, 0x80, 0x7f, 0xff, 0x40, 0x81, 0x5e, 0xbd, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x0, 0x7f, 0xff, 0x4, 0x8, 0x8, 0xfc, 0x3f, 0x86 },
+{ 0x93, 0xdd, 0x8, 0x10, 0x1c, 0x16, 0x16, 0x1c, 0x32, 0xf0, 0x20, 0x10, 0x7e, 0x92, 0x8, 0x92, 0x8, 0x92, 0x7e, 0x92, 0x8, 0x92, 0x4a, 0xfe, 0x6a, 0x10, 0x28, 0x10, 0xe, 0x11, 0x38, 0x1b, 0x60, 0xe },
+{ 0x93, 0xde, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x1, 0x40, 0x3, 0x60, 0x6, 0x30, 0x1c, 0x1c, 0x73, 0xe7, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xfe, 0x0, 0x80, 0x4, 0x90, 0x1c, 0x9c, 0x70, 0x87, 0x3, 0x80 },
+{ 0x93, 0xdf, 0x0, 0x0, 0x7f, 0xbf, 0x8, 0xa1, 0x8, 0xa3, 0x8, 0xa2, 0x7f, 0xa6, 0x8, 0xa4, 0x8, 0xa2, 0x8, 0xa1, 0x7f, 0xa1, 0x8, 0xa1, 0x8, 0xa1, 0x18, 0xa7, 0x11, 0xa0, 0x31, 0x20, 0x67, 0x20 },
+{ 0x93, 0xe0, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x82, 0x20, 0x82, 0x21, 0xc2, 0x21, 0x42, 0x23, 0x62, 0x26, 0x32, 0x2c, 0x1a, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0xe },
+{ 0x93, 0xe1, 0x8, 0x0, 0x8, 0x0, 0x8, 0x0, 0x1f, 0xff, 0x10, 0x80, 0x30, 0x80, 0x60, 0x80, 0x0, 0xfc, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0xfe, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80 },
+{ 0x93, 0xe2, 0x0, 0x0, 0x1f, 0xf8, 0x10, 0x8, 0x10, 0x88, 0x10, 0x88, 0x10, 0x88, 0x12, 0x88, 0x12, 0xe8, 0x12, 0x88, 0x12, 0x88, 0x12, 0x88, 0x12, 0x88, 0x12, 0x8c, 0x32, 0x85, 0x2f, 0xf7, 0x60, 0x2 },
+{ 0x93, 0xe3, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x10, 0x24, 0x10, 0x28, 0x3e, 0x7f, 0x28, 0xc8, 0x8, 0x48, 0x7f, 0x7e, 0x8, 0x48, 0x8, 0x48, 0x1c, 0x7e, 0x16, 0x48, 0x32, 0x48, 0x60, 0x7f },
+{ 0x93, 0xe4, 0x0, 0x8, 0x3a, 0x49, 0x3, 0x6b, 0x7d, 0x2a, 0x0, 0x8, 0x38, 0x7f, 0x0, 0x8, 0x3, 0x9c, 0x38, 0x9c, 0x0, 0xaa, 0x0, 0xaa, 0x38, 0xc9, 0x28, 0x88, 0x29, 0x88, 0x2b, 0x40, 0x3a, 0x3f },
+{ 0x93, 0xe5, 0x2, 0x8a, 0x22, 0x8a, 0x3f, 0xf4, 0x12, 0x9f, 0x0, 0x34, 0x47, 0xd4, 0x65, 0x54, 0x25, 0x5f, 0x7, 0xd4, 0x11, 0x14, 0x17, 0xd4, 0x11, 0x1f, 0x3f, 0xf4, 0x22, 0x94, 0x26, 0xd4, 0x6c, 0x5f },
+{ 0x93, 0xe6, 0x10, 0x20, 0x10, 0x20, 0x17, 0xff, 0x10, 0x50, 0x78, 0xd8, 0x11, 0x8c, 0x17, 0x7, 0x10, 0xf8, 0x18, 0x0, 0x70, 0x0, 0x17, 0xff, 0x10, 0x20, 0x11, 0x24, 0x13, 0x26, 0x16, 0x23, 0x30, 0xe0 },
+{ 0x93, 0xe7, 0x10, 0x0, 0x38, 0xfe, 0x2c, 0x82, 0x64, 0x9e, 0x40, 0x92, 0x7c, 0x92, 0x10, 0x92, 0x11, 0xff, 0x7d, 0x1, 0x11, 0x7d, 0x55, 0x45, 0x55, 0x45, 0x51, 0x7d, 0x1d, 0x1, 0x31, 0x1, 0x61, 0x7 },
+{ 0x93, 0xe8, 0x8, 0x82, 0x8, 0xc6, 0x8, 0x44, 0x9, 0xff, 0x7e, 0x28, 0x8, 0x28, 0x9, 0xff, 0x1d, 0x29, 0x1b, 0x29, 0x29, 0xcf, 0x29, 0x1, 0x49, 0xff, 0x9, 0x1, 0x9, 0x1, 0x9, 0xff, 0x8, 0x0 },
+{ 0x93, 0xe9, 0x0, 0x1, 0x3f, 0xa1, 0x24, 0x29, 0x24, 0x29, 0x3f, 0x29, 0x24, 0x29, 0x24, 0x29, 0x3f, 0x29, 0x24, 0x29, 0x24, 0x29, 0x3f, 0xa9, 0x0, 0xa9, 0x55, 0xa9, 0x54, 0xa1, 0x41, 0xa1, 0x3, 0x41 },
+{ 0x93, 0xea, 0x8, 0x0, 0x18, 0xfe, 0x30, 0x92, 0x62, 0xfe, 0x36, 0x92, 0xc, 0x92, 0x18, 0xfe, 0x32, 0x10, 0x7e, 0xfe, 0xa, 0x92, 0x8, 0xfe, 0x2a, 0x92, 0x2a, 0x92, 0x6a, 0xfe, 0x48, 0x11, 0x8, 0xf },
+{ 0x93, 0xeb, 0x0, 0x0, 0x3, 0xde, 0x7c, 0x42, 0x55, 0x4a, 0x54, 0x84, 0x55, 0x4a, 0x56, 0x11, 0x7c, 0x0, 0x54, 0x0, 0x57, 0xfe, 0x54, 0x52, 0x56, 0x92, 0x7d, 0x14, 0x1, 0x88, 0x2, 0x94, 0xc, 0x23 },
+{ 0x93, 0xec, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x24, 0x12, 0x22, 0x22, 0x27, 0xf2, 0x20, 0x82, 0x20, 0x82, 0x2f, 0xfa, 0x20, 0x82, 0x20, 0x82, 0x20, 0x82, 0x20, 0x8e },
+{ 0x93, 0xed, 0x10, 0x20, 0x10, 0x20, 0x17, 0xff, 0x7c, 0x20, 0x10, 0x20, 0x13, 0xfe, 0x3a, 0x8a, 0x36, 0x52, 0x52, 0xfa, 0x52, 0x22, 0x12, 0x22, 0x12, 0xfa, 0x12, 0x22, 0x12, 0x22, 0x12, 0x22, 0x12, 0x26 },
+{ 0x93, 0xee, 0x10, 0x40, 0x10, 0x40, 0x7e, 0x40, 0x10, 0x7f, 0x7e, 0x41, 0x52, 0xd3, 0x53, 0x92, 0x7e, 0x10, 0x52, 0x10, 0x52, 0x38, 0x7e, 0x28, 0x10, 0x28, 0x7e, 0x6c, 0x10, 0x44, 0x10, 0xc6, 0x11, 0x83 },
+{ 0x93, 0xef, 0x12, 0x24, 0x7f, 0xac, 0x12, 0x28, 0x0, 0x7f, 0x3f, 0x48, 0x29, 0xc8, 0x29, 0x48, 0x3f, 0x7e, 0x8, 0x48, 0x3f, 0x48, 0x8, 0x48, 0x7f, 0xfe, 0x14, 0x48, 0x16, 0x48, 0x33, 0x48, 0x60, 0x7f },
+{ 0x93, 0xf0, 0x0, 0x40, 0x30, 0x40, 0x18, 0x40, 0x8, 0x40, 0x7, 0xff, 0x60, 0x88, 0x30, 0x88, 0x10, 0x88, 0x1, 0x88, 0x9, 0x18, 0x9, 0x10, 0x1b, 0xd0, 0x10, 0x70, 0x30, 0xdc, 0x23, 0x86, 0x6e, 0x2 },
+{ 0x93, 0xf1, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x0, 0x0, 0x0 },
+{ 0x93, 0xf2, 0x0, 0x0, 0x1f, 0xfe, 0x10, 0x2, 0x10, 0x2, 0x10, 0x2, 0x1f, 0xfe, 0x10, 0x0, 0x11, 0x0, 0x11, 0x6, 0x11, 0x3c, 0x11, 0xe0, 0x11, 0x0, 0x31, 0x0, 0x21, 0x1, 0x61, 0x83, 0x0, 0xfe },
+{ 0x93, 0xf3, 0x0, 0x4c, 0x1e, 0x46, 0x0, 0x42, 0x0, 0x40, 0x7f, 0xff, 0x0, 0x20, 0x0, 0x20, 0x0, 0x20, 0x3f, 0x30, 0x0, 0x10, 0x0, 0x10, 0x0, 0x18, 0x3, 0x88, 0x1e, 0xd, 0x70, 0x7, 0x0, 0x2 },
+{ 0x93, 0xf4, 0x0, 0x80, 0x30, 0x80, 0x19, 0xff, 0x9, 0x20, 0x3, 0x20, 0x6, 0x20, 0x0, 0xa4, 0x78, 0xa4, 0x8, 0xa4, 0x9, 0xa6, 0x9, 0x22, 0xb, 0x23, 0x8, 0x20, 0x18, 0x60, 0x34, 0x0, 0x63, 0xff },
+{ 0x93, 0xf5, 0x8, 0x0, 0x8, 0x0, 0xf, 0xfe, 0x18, 0x2, 0x10, 0x2, 0x34, 0x2, 0x64, 0x32, 0x4, 0xe2, 0x7, 0x82, 0x4, 0x2, 0x4, 0x2, 0x4, 0xa, 0x6, 0x1a, 0x3, 0xf6, 0x0, 0x4, 0x0, 0x1c },
+{ 0x93, 0xf6, 0x0, 0x0, 0x3e, 0xff, 0x22, 0x80, 0x22, 0x80, 0x3e, 0xbe, 0x22, 0x80, 0x22, 0x80, 0x22, 0xff, 0x3e, 0xa8, 0x22, 0xa9, 0x22, 0xab, 0x22, 0xaa, 0x3e, 0xac, 0x14, 0xa4, 0x36, 0xb6, 0x63, 0x63 },
+{ 0x93, 0xf7, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x82, 0x21, 0xc2, 0x21, 0x62, 0x23, 0x32, 0x26, 0x9a, 0x20, 0x82, 0x21, 0xc2, 0x21, 0x62, 0x23, 0x32, 0x26, 0x1a, 0x20, 0x2, 0x20, 0x2, 0x20, 0xe },
+{ 0x93, 0xf8, 0x8, 0x0, 0x8, 0x0, 0x8, 0xfe, 0x7f, 0x10, 0x49, 0x10, 0x49, 0x10, 0x49, 0x10, 0x49, 0x10, 0x49, 0x10, 0x7f, 0x10, 0x8, 0x10, 0xa, 0x10, 0xa, 0x10, 0xf, 0x10, 0x39, 0xff, 0x60, 0x0 },
+{ 0x93, 0xf9, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x7, 0xf0 },
+{ 0x93, 0xfa, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x0, 0x0 },
+{ 0x93, 0xfb, 0x1, 0xa0, 0x7, 0x20, 0x7c, 0xa0, 0x29, 0xa0, 0x15, 0x20, 0x0, 0x20, 0x3f, 0xa0, 0x1, 0x20, 0x2, 0x20, 0x4, 0x20, 0x7, 0xe0, 0x7c, 0x20, 0x4, 0x20, 0x4, 0x21, 0x4, 0x33, 0x1c, 0x1e },
+{ 0x93, 0xfc, 0x0, 0x0, 0xf, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x1, 0xc0, 0x1, 0x40, 0x1, 0x40, 0x3, 0x60, 0x2, 0x20, 0x6, 0x30, 0xc, 0x18, 0x18, 0xc, 0x70, 0x7 },
+{ 0x94, 0x40, 0x8, 0x0, 0x8, 0x0, 0x8, 0x0, 0x8, 0x7e, 0x7e, 0x42, 0x12, 0x42, 0x12, 0x42, 0x12, 0x42, 0x36, 0x42, 0x24, 0x42, 0x24, 0x42, 0x7c, 0x42, 0xe, 0x42, 0x1b, 0x7e, 0x31, 0x0, 0x60, 0x0 },
+{ 0x94, 0x41, 0x0, 0x0, 0x1f, 0xfe, 0x10, 0x2, 0x10, 0x2, 0x1f, 0xfe, 0x10, 0x0, 0x10, 0x40, 0x10, 0x42, 0x17, 0x46, 0x11, 0x6c, 0x11, 0x78, 0x13, 0x50, 0x32, 0x58, 0x26, 0x4c, 0x6c, 0x47, 0x1, 0xc0 },
+{ 0x94, 0x42, 0x2, 0x20, 0x2, 0x20, 0x7f, 0xff, 0x2, 0x20, 0x0, 0x0, 0x2, 0x20, 0x3e, 0x3e, 0x2, 0x20, 0x2, 0x20, 0x3e, 0x3e, 0x2, 0x20, 0x2, 0x20, 0x3e, 0x3e, 0x2, 0x20, 0x2, 0x20, 0x7f, 0xff },
+{ 0x94, 0x43, 0x4, 0x6, 0x4, 0x3c, 0xd, 0xe0, 0x8, 0x20, 0x18, 0x20, 0x10, 0x20, 0x30, 0x20, 0x53, 0xff, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x11, 0xfe, 0x10, 0x0 },
+{ 0x94, 0x44, 0x8, 0x6, 0x8, 0x1c, 0x8, 0xf0, 0x8, 0x10, 0x7e, 0x10, 0x12, 0x10, 0x12, 0x10, 0x13, 0xff, 0x36, 0x10, 0x24, 0x10, 0x24, 0x10, 0x7c, 0x10, 0xa, 0x10, 0x19, 0x10, 0x30, 0xfe, 0x60, 0x0 },
+{ 0x94, 0x45, 0x0, 0x0, 0x3f, 0xfe, 0x0, 0x42, 0xc, 0x42, 0x6, 0xc2, 0x1, 0x82, 0x3, 0x86, 0xe, 0xc4, 0x38, 0x5c, 0x0, 0x0, 0x0, 0xc0, 0x2, 0x60, 0x12, 0x26, 0x12, 0xb, 0x33, 0x19, 0x61, 0xf0 },
+{ 0x94, 0x46, 0x0, 0x0, 0x39, 0xfe, 0x0, 0x22, 0x7d, 0xa2, 0x0, 0xe2, 0x38, 0x46, 0x0, 0xe4, 0x1, 0xac, 0x38, 0x0, 0x0, 0x20, 0x0, 0x30, 0x38, 0x52, 0x29, 0x43, 0x29, 0x45, 0x2b, 0x44, 0x3a, 0x3c },
+{ 0x94, 0x47, 0x0, 0x0, 0x31, 0xfe, 0x18, 0x20, 0xb, 0xff, 0x2, 0x21, 0x63, 0xad, 0x32, 0x21, 0x11, 0xac, 0x0, 0x0, 0xb, 0xff, 0x8, 0x20, 0x1b, 0xff, 0x12, 0x49, 0x32, 0x49, 0x22, 0x49, 0x62, 0x4b },
+{ 0x94, 0x48, 0x10, 0x0, 0x17, 0xff, 0x11, 0x24, 0x7a, 0x22, 0xf, 0xff, 0xa, 0x22, 0x1b, 0x76, 0x12, 0xaa, 0x33, 0x76, 0x3a, 0x22, 0x57, 0x76, 0x12, 0xaa, 0x13, 0x76, 0x12, 0x22, 0x12, 0x22, 0x12, 0x6 },
+{ 0x94, 0x49, 0x10, 0x40, 0x10, 0x40, 0x10, 0x40, 0x7c, 0xff, 0x4, 0x90, 0xd, 0x90, 0xb, 0x10, 0x18, 0x54, 0x10, 0x54, 0x3c, 0x54, 0x56, 0xd6, 0x10, 0x92, 0x11, 0x93, 0x10, 0x10, 0x10, 0x10, 0x10, 0x70 },
+{ 0x94, 0x4a, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x82, 0x2a, 0x4a, 0x1a, 0x2c, 0x33, 0xe6, 0x0, 0x0, 0x1f, 0xfc, 0x12, 0x24, 0x1f, 0xfc, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x3, 0x80 },
+{ 0x94, 0x4b, 0x2, 0x20, 0x2, 0x20, 0x7f, 0xff, 0x2, 0x20, 0x4, 0x0, 0xf, 0xfe, 0x19, 0x12, 0x76, 0x22, 0x3, 0xc6, 0x1c, 0xe4, 0x3, 0x1c, 0x0, 0x0, 0x15, 0x86, 0x14, 0xcb, 0x36, 0x19, 0x63, 0xf0 },
+{ 0x94, 0x4c, 0x4, 0x88, 0x44, 0x88, 0x2b, 0xff, 0x10, 0x88, 0x10, 0x88, 0x28, 0x0, 0x4b, 0xfe, 0xa, 0x22, 0x1a, 0x22, 0x1a, 0x22, 0x2b, 0xfe, 0x4a, 0x22, 0xa, 0x22, 0xa, 0x22, 0x1a, 0x22, 0x73, 0xfe },
+{ 0x94, 0x4d, 0x8, 0x10, 0x8, 0x10, 0x3f, 0x10, 0x8, 0x7c, 0x7f, 0x94, 0x12, 0x14, 0x2b, 0x94, 0x5e, 0x74, 0x8, 0x24, 0x1f, 0x75, 0x70, 0xd3, 0x0, 0x0, 0x0, 0x0, 0x12, 0x22, 0x33, 0x33, 0x61, 0x11 },
+{ 0x94, 0x4e, 0x4, 0x0, 0x4, 0x0, 0xf, 0xfe, 0x18, 0x40, 0x30, 0x40, 0x60, 0x40, 0xf, 0xfc, 0x8, 0x40, 0x8, 0x40, 0x8, 0x40, 0x8, 0x40, 0x7f, 0xff, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40 },
+{ 0x94, 0x4f, 0x0, 0x80, 0x1, 0xc0, 0x3, 0x60, 0x6, 0x30, 0x1c, 0x1c, 0x73, 0xe7, 0x0, 0x0, 0xf, 0xf8, 0x0, 0x10, 0x0, 0x30, 0x0, 0x20, 0x5, 0x80, 0x14, 0xc6, 0x14, 0x4b, 0x36, 0x19, 0x63, 0xf0 },
+{ 0x94, 0x50, 0x10, 0x20, 0x10, 0x70, 0x10, 0xd8, 0x79, 0x8c, 0x17, 0x7, 0x10, 0xf8, 0x10, 0x0, 0x13, 0xfe, 0x18, 0x4, 0x70, 0xc, 0x10, 0x68, 0x10, 0x30, 0x12, 0x96, 0x12, 0x83, 0x16, 0xc5, 0x34, 0x7c },
+{ 0x94, 0x51, 0x11, 0xa, 0x11, 0x9, 0x11, 0xc8, 0x79, 0x7f, 0x12, 0xc8, 0x12, 0x48, 0x15, 0x48, 0x10, 0x9c, 0x18, 0x94, 0x71, 0x36, 0x12, 0x63, 0x10, 0x0, 0x12, 0x92, 0x12, 0x92, 0x16, 0xdb, 0x34, 0x49 },
+{ 0x94, 0x52, 0x11, 0xa, 0x11, 0x9, 0x15, 0xc8, 0x55, 0x7f, 0x5a, 0xc8, 0x52, 0x48, 0x55, 0x48, 0x10, 0x9c, 0x10, 0x94, 0x11, 0x36, 0x12, 0x63, 0x38, 0x0, 0x2a, 0x92, 0x2a, 0x92, 0x66, 0xdb, 0x44, 0x49 },
+{ 0x94, 0x53, 0x8, 0x10, 0x49, 0x10, 0x6b, 0x10, 0x2a, 0x10, 0x8, 0x1f, 0x7f, 0x10, 0x8, 0x10, 0x8, 0x10, 0x1c, 0x10, 0x1a, 0xfe, 0x29, 0x82, 0x28, 0x82, 0x48, 0x82, 0x8, 0x82, 0x8, 0x82, 0x8, 0xfe },
+{ 0x94, 0x54, 0x0, 0x0, 0x3f, 0xf0, 0x2, 0x10, 0x2, 0x10, 0x2, 0x10, 0x2, 0x10, 0x2, 0x1e, 0x6, 0x2, 0x4, 0x2, 0x4, 0x2, 0xc, 0x2, 0x8, 0x2, 0x18, 0x6, 0x30, 0x4, 0x60, 0x3c, 0x0, 0x0 },
+{ 0x94, 0x55, 0x0, 0x0, 0x7d, 0xff, 0x4, 0x28, 0x8, 0x28, 0x10, 0xfe, 0x3c, 0xaa, 0x4, 0xaa, 0x4, 0xaa, 0x24, 0xae, 0x34, 0xc2, 0x1c, 0x82, 0x8, 0x82, 0x1c, 0xfe, 0x16, 0x0, 0x33, 0x80, 0x60, 0xff },
+{ 0x94, 0x56, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x0, 0x6, 0x0, 0xc, 0x0, 0x8, 0x0, 0x18, 0x0, 0x30, 0x0, 0x60, 0x0, 0xc0, 0x9, 0x80, 0xb, 0x0, 0x1e, 0x0, 0x33, 0x80, 0x60, 0xff },
+{ 0x94, 0x57, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x14, 0x54, 0x16, 0x54, 0x35, 0x56, 0x24, 0xd2, 0x64, 0x93, 0x4, 0x10, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x94, 0x58, 0x0, 0x80, 0x3f, 0xfe, 0x8, 0x88, 0xf, 0xf8, 0x0, 0x80, 0x7f, 0xff, 0x48, 0x9, 0x12, 0x24, 0x6f, 0xfb, 0x2, 0x20, 0x1f, 0xfc, 0x2, 0x20, 0x7f, 0xff, 0x4, 0x48, 0x78, 0x30, 0xf, 0xf },
+{ 0x94, 0x59, 0x10, 0x21, 0x11, 0x33, 0x11, 0x92, 0x10, 0x96, 0x58, 0x84, 0x54, 0x0, 0x55, 0x5, 0x51, 0x4d, 0x11, 0x69, 0x11, 0x39, 0x11, 0x11, 0x11, 0x39, 0x11, 0x6d, 0x11, 0x45, 0x11, 0x1, 0x11, 0xff },
+{ 0x94, 0x5a, 0x0, 0x50, 0x31, 0xfe, 0x19, 0x52, 0x9, 0xfe, 0x1, 0x52, 0x61, 0xfe, 0x30, 0x0, 0x13, 0xff, 0x2, 0x0, 0xa, 0xfe, 0xa, 0x0, 0x1b, 0xff, 0x12, 0x92, 0x32, 0x9a, 0x24, 0xec, 0x61, 0x87 },
+{ 0x94, 0x5b, 0x8, 0x10, 0x18, 0x10, 0x10, 0x10, 0x61, 0xff, 0x29, 0x11, 0x19, 0x11, 0x11, 0x39, 0x25, 0x29, 0x7d, 0x29, 0x15, 0x6d, 0x11, 0x45, 0x55, 0x1, 0x55, 0x1, 0x55, 0x1, 0x11, 0x1, 0x11, 0x7 },
+{ 0x94, 0x5c, 0x8, 0x20, 0x1a, 0x26, 0x12, 0x3c, 0x3f, 0x20, 0x61, 0x21, 0x0, 0x33, 0x3f, 0x1e, 0x21, 0x0, 0x21, 0x0, 0x3f, 0x20, 0x21, 0x26, 0x21, 0x3c, 0x3f, 0x20, 0x21, 0x21, 0x21, 0x33, 0x23, 0x1e },
+{ 0x94, 0x5d, 0x0, 0x21, 0x3d, 0x33, 0x25, 0x92, 0x24, 0x96, 0x24, 0x84, 0x3c, 0x0, 0x25, 0x5, 0x25, 0x4d, 0x25, 0x69, 0x3d, 0x39, 0x25, 0x11, 0x25, 0x39, 0x25, 0x6d, 0x25, 0x45, 0x65, 0x1, 0x4d, 0xff },
+{ 0x94, 0x5e, 0x0, 0x28, 0x3c, 0xfe, 0x24, 0xaa, 0x24, 0xfe, 0x24, 0xaa, 0x3c, 0xfe, 0x24, 0x0, 0x25, 0xff, 0x25, 0x0, 0x3d, 0x7e, 0x25, 0x0, 0x25, 0xff, 0x25, 0x52, 0x25, 0x4a, 0x66, 0x6c, 0x4c, 0xc7 },
+{ 0x94, 0x5f, 0x1, 0x20, 0xf, 0xfc, 0x9, 0x24, 0xf, 0xfc, 0x9, 0x24, 0xf, 0xfc, 0x0, 0x0, 0x1f, 0xfe, 0x10, 0x0, 0x17, 0xfc, 0x10, 0x0, 0x1f, 0xff, 0x12, 0x44, 0x32, 0x6c, 0x63, 0xb8, 0xe, 0xf },
+{ 0x94, 0x60, 0x0, 0x0, 0x7e, 0x7e, 0x2, 0x42, 0x2, 0x42, 0x3a, 0x7e, 0x2, 0x42, 0x2, 0x42, 0x3a, 0x7e, 0x2a, 0x42, 0x2a, 0x42, 0x2a, 0x7e, 0x3a, 0x24, 0x2, 0x24, 0x2, 0x25, 0x2, 0x65, 0xe, 0xc3 },
+{ 0x94, 0x61, 0x0, 0x0, 0x3f, 0xfc, 0x4, 0x8c, 0x26, 0x58, 0x33, 0x70, 0x11, 0xc0, 0x7, 0x70, 0x1c, 0x1c, 0x70, 0x87, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x0, 0x82, 0x0, 0xff, 0x7f, 0x81 },
+{ 0x94, 0x62, 0x0, 0x0, 0x3f, 0xfc, 0x21, 0x4, 0x21, 0x4, 0x21, 0x4, 0x21, 0x4, 0x21, 0x4, 0x3f, 0xfc, 0x20, 0x0, 0x20, 0x0, 0x20, 0x0, 0x20, 0x0, 0x20, 0x1, 0x30, 0x3, 0x1f, 0xfe, 0x0, 0x0 },
+{ 0x94, 0x63, 0x10, 0x0, 0x13, 0xfe, 0x12, 0x22, 0x12, 0x22, 0x7a, 0x22, 0x12, 0x22, 0x12, 0x22, 0x13, 0xfe, 0x1a, 0x0, 0x72, 0x0, 0x12, 0x0, 0x12, 0x0, 0x12, 0x1, 0x13, 0x3, 0x11, 0xfe, 0x30, 0x0 },
+{ 0x94, 0x64, 0x10, 0x1c, 0x11, 0xf0, 0x12, 0x22, 0x79, 0x24, 0x17, 0xff, 0x10, 0xa8, 0x11, 0xac, 0x1b, 0x26, 0x76, 0x23, 0x10, 0x0, 0x13, 0xfe, 0x12, 0x22, 0x13, 0xfe, 0x12, 0x22, 0x12, 0x22, 0x33, 0xfe },
+{ 0x94, 0x65, 0x7f, 0xff, 0x2, 0x20, 0x3f, 0xfe, 0x22, 0x22, 0x3f, 0xfe, 0x12, 0x0, 0x7f, 0xbe, 0x12, 0x22, 0x1e, 0x22, 0x8, 0x3e, 0x3f, 0x22, 0x29, 0x22, 0x3f, 0x3e, 0x8, 0x22, 0x7f, 0xa2, 0x8, 0x46 },
+{ 0x94, 0x66, 0x10, 0x0, 0x11, 0xfe, 0x11, 0x22, 0x7d, 0x22, 0x11, 0x22, 0x11, 0x22, 0x39, 0x22, 0x35, 0xfe, 0x35, 0x0, 0x51, 0x0, 0x51, 0x0, 0x11, 0x0, 0x11, 0x1, 0x11, 0x83, 0x10, 0xfe, 0x10, 0x0 },
+{ 0x94, 0x67, 0x0, 0x20, 0x30, 0x20, 0x18, 0x20, 0xb, 0xff, 0x2, 0x21, 0x62, 0x22, 0x32, 0x20, 0x13, 0xfe, 0x2, 0x82, 0xa, 0xc6, 0xa, 0x44, 0x1a, 0x6c, 0x16, 0x38, 0x34, 0x6c, 0x2c, 0xc6, 0x61, 0x83 },
+{ 0x94, 0x68, 0x0, 0x6, 0x30, 0x3c, 0x1b, 0xe0, 0xa, 0x6, 0x2, 0x1c, 0x62, 0x70, 0x32, 0x42, 0x12, 0x46, 0x2, 0x6c, 0xa, 0x70, 0xa, 0x50, 0x1a, 0x58, 0x16, 0x4c, 0x34, 0x46, 0x2c, 0x43, 0x60, 0x40 },
+{ 0x94, 0x69, 0x0, 0x0, 0x7f, 0x7f, 0x8, 0x8, 0x3e, 0x3e, 0x8, 0x8, 0x7f, 0x7f, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x0, 0x10, 0x1, 0x18, 0x3, 0xf, 0xfe },
+{ 0x94, 0x6a, 0x0, 0x10, 0x7e, 0x10, 0x10, 0x10, 0x10, 0xff, 0x10, 0x91, 0x10, 0x92, 0x3c, 0x90, 0x24, 0xfe, 0x64, 0xa2, 0x24, 0xb6, 0x24, 0x94, 0x24, 0x9c, 0x25, 0x88, 0x3d, 0x1c, 0x3, 0x36, 0x0, 0x63 },
+{ 0x94, 0x6b, 0x0, 0x20, 0x18, 0x20, 0xd, 0xfe, 0x61, 0x22, 0x31, 0xfc, 0x1, 0x44, 0x9, 0x68, 0x1b, 0x38, 0x36, 0x6c, 0x61, 0xc7, 0x2, 0x0, 0x7f, 0xff, 0x4, 0x10, 0xf, 0xa0, 0x0, 0xf8, 0x3f, 0x8e },
+{ 0x94, 0x6c, 0x3f, 0xfe, 0x22, 0x22, 0x22, 0x22, 0x3f, 0xfe, 0x0, 0x0, 0x1f, 0xfe, 0x10, 0x80, 0x1f, 0xfc, 0x10, 0x80, 0x1f, 0xfc, 0x10, 0x80, 0x1f, 0xff, 0x0, 0x1, 0x24, 0x91, 0x66, 0xdb, 0x42, 0x4e },
+{ 0x94, 0x6d, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x10, 0x1, 0x18, 0x3, 0xf, 0xfe },
+{ 0x94, 0x6e, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x80, 0x10, 0x80, 0x1f, 0xf8, 0x10, 0x80, 0x10, 0x80, 0x1f, 0xf8, 0x10, 0x80, 0x10, 0x80, 0x1f, 0xfe, 0x0, 0x2, 0x29, 0x22, 0x6d, 0xb2, 0x44, 0x96, 0x0, 0xc },
+{ 0x94, 0x6f, 0x4, 0x48, 0x4, 0x48, 0xc, 0x48, 0xb, 0xcf, 0x18, 0x48, 0x10, 0x48, 0x30, 0x48, 0x53, 0xcf, 0x10, 0x48, 0x10, 0x48, 0x11, 0xc8, 0x17, 0x4f, 0x10, 0x48, 0x10, 0xc8, 0x11, 0x88, 0x13, 0x8 },
+{ 0x94, 0x70, 0x0, 0x40, 0x0, 0x40, 0x1f, 0xff, 0x10, 0x0, 0x17, 0xe2, 0x10, 0x95, 0x15, 0xa, 0x12, 0x4, 0x1d, 0xfb, 0x10, 0x90, 0x10, 0x90, 0x17, 0xfe, 0x30, 0x90, 0x21, 0x91, 0x63, 0x13, 0xe, 0xe },
+{ 0x94, 0x71, 0x10, 0x0, 0x17, 0xff, 0x10, 0x20, 0x10, 0x20, 0x7b, 0xfe, 0x10, 0x20, 0x10, 0x20, 0x13, 0xfe, 0x18, 0x20, 0x70, 0x20, 0x10, 0x20, 0x17, 0xff, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x30, 0x20 },
+{ 0x94, 0x72, 0x10, 0x48, 0x10, 0x48, 0x10, 0x48, 0x13, 0xcf, 0x78, 0x48, 0x10, 0x48, 0x10, 0x48, 0x13, 0xcf, 0x18, 0x48, 0x70, 0x48, 0x11, 0xc8, 0x17, 0x4f, 0x10, 0x48, 0x10, 0xc8, 0x11, 0x88, 0x33, 0x8 },
+{ 0x94, 0x73, 0x0, 0x40, 0x3e, 0x40, 0x22, 0x40, 0x22, 0xff, 0x3e, 0x84, 0x23, 0x84, 0x22, 0x44, 0x22, 0x6c, 0x3e, 0x28, 0x22, 0x38, 0x22, 0x10, 0x22, 0x38, 0x3e, 0x28, 0x14, 0x6c, 0x36, 0xc6, 0x63, 0x83 },
+{ 0x94, 0x74, 0x10, 0x0, 0x13, 0xff, 0x10, 0x10, 0x7c, 0x10, 0x10, 0x30, 0x10, 0x20, 0x38, 0x68, 0x34, 0x6c, 0x34, 0xe4, 0x51, 0xa6, 0x53, 0x23, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20 },
+{ 0x94, 0x75, 0x0, 0x0, 0x3f, 0xfe, 0x0, 0x40, 0x0, 0xc0, 0x3, 0xb0, 0xe, 0x9c, 0x78, 0x87, 0x0, 0x80, 0x0, 0x80, 0x0, 0x0, 0x1f, 0xfc, 0x12, 0x44, 0x12, 0x44, 0x12, 0x44, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x94, 0x76, 0x0, 0x10, 0x24, 0x20, 0x24, 0xfe, 0x24, 0x92, 0x24, 0x92, 0x3e, 0xfe, 0x20, 0x92, 0x20, 0x92, 0x20, 0xfe, 0x3c, 0x28, 0x24, 0x48, 0x25, 0xff, 0x24, 0x8, 0x24, 0x8, 0x64, 0x8, 0x44, 0x8 },
+{ 0x94, 0x77, 0x2, 0x40, 0x2, 0x46, 0x7e, 0x7c, 0x2, 0x40, 0x2, 0x41, 0x1e, 0x63, 0x72, 0x3e, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x38 },
+{ 0x94, 0x78, 0x0, 0x10, 0x3c, 0x10, 0x24, 0x10, 0x25, 0xff, 0x24, 0x10, 0x3c, 0x10, 0x24, 0xfe, 0x24, 0x92, 0x24, 0x92, 0x3c, 0x92, 0x24, 0x92, 0x24, 0x92, 0x24, 0x96, 0x24, 0x10, 0x64, 0x10, 0x4c, 0x10 },
+{ 0x94, 0x79, 0x2, 0x20, 0x7e, 0x3f, 0x2, 0x20, 0x3e, 0x3e, 0x2, 0x20, 0x7e, 0x3f, 0x4, 0x20, 0x8, 0x80, 0x7f, 0xff, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x84, 0x1f, 0xfc, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80 },
+{ 0x94, 0x7a, 0x0, 0x0, 0x7f, 0xbe, 0xa, 0x2, 0xa, 0x2, 0x3f, 0x82, 0x2a, 0x82, 0x2a, 0xbe, 0x2a, 0xa0, 0x33, 0xa0, 0x20, 0xa0, 0x20, 0xa0, 0x3f, 0xa0, 0x20, 0xa1, 0x20, 0xb3, 0x3f, 0x9e, 0x0, 0x0 },
+{ 0x94, 0x7b, 0x4, 0x20, 0x4, 0x20, 0xf, 0xfe, 0x9, 0x4, 0x19, 0x8c, 0x10, 0x88, 0x30, 0x88, 0x57, 0xff, 0x10, 0x0, 0x10, 0x0, 0x11, 0xfc, 0x11, 0x4, 0x11, 0x4, 0x11, 0x4, 0x11, 0x4, 0x11, 0xfc },
+{ 0x94, 0x7c, 0x10, 0x20, 0x10, 0x20, 0x13, 0xfe, 0x11, 0x4, 0x7d, 0x8c, 0x10, 0x88, 0x10, 0x88, 0x17, 0xff, 0x10, 0x0, 0x10, 0x0, 0x1d, 0xfc, 0x71, 0x4, 0x1, 0x4, 0x1, 0x4, 0x1, 0x4, 0x1, 0xfc },
+{ 0x94, 0x7d, 0x8, 0x44, 0x8, 0x44, 0x9, 0xff, 0x8, 0x44, 0x7e, 0x7c, 0x12, 0x44, 0x12, 0x44, 0x12, 0x7c, 0x32, 0x10, 0x27, 0xff, 0x24, 0x54, 0x7c, 0x54, 0xa, 0xd6, 0x1a, 0x92, 0x31, 0x93, 0x60, 0x10 },
+{ 0x94, 0x7e, 0x10, 0x80, 0x10, 0x80, 0x11, 0xff, 0x7d, 0x0, 0x13, 0x0, 0x10, 0xfe, 0x38, 0x92, 0x34, 0x92, 0x30, 0x92, 0x53, 0xff, 0x51, 0x22, 0x11, 0x22, 0x11, 0x22, 0x11, 0xff, 0x10, 0x4, 0x10, 0x1c },
+{ 0x94, 0x80, 0x8, 0x44, 0x8, 0x44, 0x9, 0xff, 0x7e, 0x44, 0x8, 0x7c, 0x8, 0x44, 0x1c, 0x44, 0x1a, 0x7c, 0x1a, 0x10, 0x29, 0xff, 0x28, 0x54, 0x48, 0x54, 0x8, 0xd6, 0x8, 0x92, 0x9, 0x93, 0x8, 0x10 },
+{ 0x94, 0x81, 0x8, 0x44, 0x8, 0x44, 0x9, 0xff, 0xa, 0x44, 0x2a, 0x7c, 0x2a, 0x44, 0x68, 0x44, 0x48, 0x7c, 0x8, 0x10, 0x9, 0xff, 0x1c, 0x54, 0x14, 0x54, 0x16, 0xd6, 0x32, 0x92, 0x21, 0x93, 0x60, 0x10 },
+{ 0x94, 0x82, 0x4, 0x0, 0x44, 0xfe, 0x28, 0x82, 0x10, 0x82, 0x10, 0xfe, 0x28, 0x82, 0x48, 0x82, 0x8, 0x82, 0x18, 0xfe, 0x18, 0x82, 0x28, 0x82, 0x48, 0x82, 0x8, 0xfe, 0x8, 0x44, 0x18, 0xc6, 0x71, 0x83 },
+{ 0x94, 0x83, 0x0, 0x0, 0x3f, 0xfe, 0x22, 0x22, 0x22, 0x22, 0x3f, 0xfe, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x4, 0x1f, 0xfc, 0x10, 0x4, 0x1f, 0xfc, 0x10, 0x4, 0x1f, 0xfc, 0x4, 0x10, 0x1c, 0x1c, 0x70, 0x7 },
+{ 0x94, 0x84, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xfe, 0x20, 0x2, 0x22, 0x22, 0x2, 0x20, 0x6, 0x20, 0xc, 0x21, 0x18, 0x33, 0x70, 0x1e },
+{ 0x94, 0x85, 0x0, 0x20, 0x3c, 0x20, 0x25, 0xfe, 0x24, 0x84, 0x3c, 0x84, 0x24, 0xcc, 0x24, 0x48, 0x27, 0xff, 0x3c, 0x0, 0x24, 0x0, 0x24, 0xfc, 0x24, 0x84, 0x3c, 0x84, 0x14, 0x84, 0x36, 0x84, 0x62, 0xfc },
+{ 0x94, 0x86, 0x0, 0x20, 0x3c, 0x20, 0x25, 0xfe, 0x24, 0x84, 0x24, 0xcc, 0x28, 0x48, 0x28, 0x48, 0x2b, 0xff, 0x24, 0x0, 0x24, 0x0, 0x24, 0xfc, 0x24, 0x84, 0x3c, 0x84, 0x20, 0x84, 0x20, 0x84, 0x20, 0xfc },
+{ 0x94, 0x87, 0x0, 0x0, 0x30, 0xfc, 0x18, 0x0, 0xb, 0xff, 0x0, 0x0, 0x0, 0xfc, 0x0, 0x0, 0x78, 0xfc, 0x8, 0x0, 0x8, 0xfc, 0x8, 0x84, 0x8, 0x84, 0x8, 0x84, 0x18, 0xfc, 0x34, 0x0, 0x63, 0xff },
+{ 0x94, 0x88, 0x10, 0x0, 0x10, 0xfe, 0x10, 0x92, 0x7c, 0xfe, 0x54, 0x92, 0x54, 0x92, 0x54, 0xfe, 0x54, 0x10, 0x54, 0xfe, 0x7c, 0x92, 0x10, 0xfe, 0x14, 0x92, 0x14, 0x92, 0x1e, 0xfe, 0x72, 0x11, 0x0, 0xf },
+{ 0x94, 0x89, 0x4, 0x0, 0x1d, 0xfe, 0x70, 0x20, 0x11, 0x22, 0x11, 0xa6, 0x7c, 0xa4, 0x10, 0xa4, 0x10, 0x20, 0x3b, 0xff, 0x34, 0x20, 0x54, 0x20, 0x50, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20 },
+{ 0x94, 0x8a, 0x10, 0x2, 0x11, 0xf2, 0x10, 0x12, 0x3e, 0x12, 0x28, 0x12, 0x68, 0xf2, 0x8, 0x82, 0x7f, 0x82, 0x8, 0x82, 0x8, 0xf2, 0x1c, 0x12, 0x14, 0x12, 0x16, 0x12, 0x32, 0x32, 0x60, 0x22, 0x0, 0xe2 },
+{ 0x94, 0x8b, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x0, 0x0, 0x6, 0x10, 0x3c, 0x52, 0x8, 0x52, 0x7e, 0xd6, 0x8, 0x94, 0x1c, 0x38, 0x1a, 0x28, 0x28, 0x6c, 0x48, 0x44, 0x8, 0xc6, 0x9, 0x83 },
+{ 0x94, 0x8c, 0x4, 0x10, 0x4, 0x30, 0xc, 0x20, 0x9, 0xfe, 0x19, 0x2, 0x11, 0x2, 0x31, 0x2, 0x51, 0x2, 0x11, 0xfe, 0x11, 0x2, 0x11, 0x2, 0x11, 0x2, 0x11, 0x2, 0x11, 0x2, 0x11, 0xfe, 0x10, 0x0 },
+{ 0x94, 0x8d, 0x0, 0x2, 0x3f, 0x12, 0x1, 0x12, 0x3f, 0x12, 0x1, 0x12, 0x1, 0x12, 0x7f, 0xd2, 0x4, 0x12, 0x24, 0x92, 0x35, 0x92, 0x15, 0x12, 0xe, 0x2, 0x15, 0x2, 0x35, 0x82, 0x64, 0xc2, 0x1c, 0xe },
+{ 0x94, 0x8e, 0x10, 0x24, 0x10, 0x22, 0x13, 0xff, 0x10, 0x20, 0x11, 0xfe, 0x7d, 0x22, 0x11, 0xfe, 0x11, 0x22, 0x11, 0xfe, 0x10, 0x4, 0x13, 0xff, 0x10, 0x84, 0x10, 0xc4, 0x10, 0x44, 0x10, 0x4, 0x10, 0x1c },
+{ 0x94, 0x8f, 0x10, 0x10, 0x10, 0x30, 0x10, 0x20, 0x11, 0xfe, 0x7d, 0x2, 0x11, 0x2, 0x11, 0x2, 0x11, 0x2, 0x1d, 0xfe, 0x71, 0x2, 0x11, 0x2, 0x11, 0x2, 0x11, 0x2, 0x11, 0x2, 0x11, 0xfe, 0x30, 0x0 },
+{ 0x94, 0x90, 0x10, 0x10, 0x10, 0x30, 0x10, 0x20, 0x7d, 0xfe, 0x11, 0x2, 0x11, 0x2, 0x39, 0x2, 0x35, 0x2, 0x35, 0xfe, 0x51, 0x2, 0x51, 0x2, 0x11, 0x2, 0x11, 0x2, 0x11, 0x2, 0x11, 0xfe, 0x10, 0x0 },
+{ 0x94, 0x91, 0x0, 0x20, 0x30, 0x60, 0x18, 0x40, 0xb, 0xfe, 0x2, 0x2, 0x62, 0x2, 0x32, 0x2, 0x12, 0x2, 0x3, 0xfe, 0xa, 0x2, 0xa, 0x2, 0x1a, 0x2, 0x12, 0x2, 0x32, 0x2, 0x23, 0xfe, 0x60, 0x0 },
+{ 0x94, 0x92, 0x0, 0x80, 0x1, 0x80, 0x1, 0x0, 0x1f, 0xfc, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x1f, 0xfc, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x1f, 0xfc, 0x0, 0x0 },
+{ 0x94, 0x93, 0x8, 0x40, 0x8, 0x40, 0x1f, 0x7f, 0x34, 0x90, 0x62, 0x8, 0x0, 0x20, 0x18, 0x40, 0xd, 0xfe, 0x1, 0x2, 0x31, 0x2, 0x19, 0x2, 0x1, 0xfe, 0x5, 0x2, 0xd, 0x2, 0x19, 0x2, 0x31, 0xfe },
+{ 0x94, 0x94, 0x8, 0x10, 0x49, 0x30, 0x6b, 0x20, 0x2a, 0xfe, 0x8, 0x82, 0x7e, 0x82, 0x8, 0x82, 0x8, 0x82, 0x1c, 0xfe, 0x1a, 0x82, 0x2a, 0x82, 0x28, 0x82, 0x48, 0x82, 0x8, 0x82, 0x8, 0xfe, 0x8, 0x0 },
+{ 0x94, 0x95, 0x8, 0x8, 0x10, 0x18, 0x3e, 0x10, 0x22, 0x7e, 0x2a, 0x42, 0x2a, 0x42, 0x22, 0x42, 0x7f, 0x42, 0x22, 0x7e, 0x2a, 0x42, 0x2a, 0x42, 0x2a, 0x42, 0x2a, 0x42, 0x22, 0x42, 0x62, 0x7e, 0x46, 0x0 },
+{ 0x94, 0x96, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x0, 0x4, 0x20, 0x22, 0x37, 0xff, 0x10, 0x20, 0x43, 0xfe, 0x62, 0x22, 0x23, 0xfe, 0x2, 0x22, 0x13, 0xfe, 0x10, 0x4, 0x37, 0xff, 0x21, 0x4, 0x60, 0x9c },
+{ 0x94, 0x97, 0x0, 0x10, 0x30, 0x30, 0x18, 0x20, 0x9, 0xfe, 0x1, 0x2, 0x1, 0x2, 0x1, 0x2, 0x79, 0xfe, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0x2, 0x9, 0xfe, 0x18, 0x0, 0x34, 0x0, 0x63, 0xff },
+{ 0x94, 0x98, 0x1, 0xfc, 0x79, 0x4, 0x49, 0xfc, 0x49, 0x4, 0x49, 0xfc, 0x48, 0x88, 0x7b, 0xfe, 0x48, 0x88, 0x4f, 0xff, 0x48, 0x88, 0x49, 0x24, 0x4e, 0xab, 0x78, 0x70, 0x1, 0xac, 0x7, 0x27, 0x0, 0x60 },
+{ 0x94, 0x99, 0x0, 0x48, 0x30, 0x48, 0x1b, 0xff, 0x8, 0x48, 0x0, 0x48, 0x61, 0xfe, 0x31, 0x2, 0x11, 0xfe, 0x1, 0x2, 0x9, 0xfe, 0x8, 0x20, 0x1b, 0xff, 0x10, 0x50, 0x30, 0xd8, 0x21, 0x8c, 0x63, 0x7 },
+{ 0x94, 0x9a, 0x11, 0xfc, 0x11, 0x4, 0x11, 0xfc, 0x15, 0x4, 0x55, 0xfc, 0x54, 0x88, 0x5b, 0xfe, 0x50, 0x88, 0x17, 0xff, 0x10, 0x88, 0x11, 0x24, 0x3a, 0xab, 0x28, 0x70, 0x2c, 0xac, 0x65, 0x26, 0x40, 0x60 },
+{ 0x94, 0x9b, 0x8, 0x14, 0x18, 0x12, 0x31, 0xff, 0x62, 0x10, 0x36, 0xfe, 0xc, 0x92, 0x18, 0xfe, 0x32, 0x92, 0x7e, 0xfe, 0xa, 0x4, 0x9, 0xff, 0x2a, 0x44, 0x2b, 0x64, 0x69, 0x24, 0x48, 0x4, 0x8, 0x1c },
+{ 0x94, 0x9c, 0x2, 0x20, 0x2, 0x20, 0x7f, 0xff, 0x2, 0x20, 0x2, 0x20, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x0, 0x80, 0x7f, 0xff, 0x1, 0x40, 0x3, 0x60, 0xe, 0x38, 0x78, 0xf },
+{ 0x94, 0x9d, 0x0, 0x2, 0x3f, 0x66, 0x24, 0x3c, 0x24, 0x18, 0x3f, 0x3c, 0x24, 0x66, 0x24, 0xc2, 0x3f, 0x0, 0x24, 0x22, 0x24, 0x36, 0x3f, 0x94, 0x0, 0x9c, 0x55, 0x88, 0x54, 0x9c, 0x41, 0xb6, 0x3, 0x63 },
+{ 0x94, 0x9e, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x7f, 0xff, 0x1, 0x0, 0x3, 0xf0, 0x6, 0x10, 0xc, 0x30, 0x3b, 0x60, 0x1, 0xc0, 0x3, 0x60, 0xe, 0x38, 0x78, 0xf },
+{ 0x94, 0x9f, 0x0, 0x0, 0x7f, 0xff, 0x2, 0x0, 0x2, 0x0, 0x23, 0x82, 0x28, 0x92, 0x2c, 0xb2, 0x24, 0xa2, 0x20, 0x82, 0x26, 0xe2, 0x2c, 0xb2, 0x38, 0x9a, 0x23, 0x82, 0x20, 0x2, 0x3f, 0xfe, 0x0, 0x0 },
+{ 0x94, 0xa0, 0x8, 0x20, 0x8, 0x20, 0x1f, 0x7f, 0x34, 0x48, 0x62, 0x84, 0x8, 0x0, 0x8, 0x7e, 0x7f, 0x42, 0x8, 0x42, 0x1c, 0x7e, 0x1a, 0x42, 0x29, 0x42, 0x48, 0x7e, 0x8, 0x42, 0x8, 0x42, 0x8, 0x7e },
+{ 0x94, 0xa1, 0x0, 0x44, 0x7f, 0x44, 0x8, 0xc6, 0x9, 0x93, 0x18, 0x38, 0x10, 0x28, 0x1e, 0x6c, 0x32, 0xc6, 0x33, 0x83, 0x52, 0x0, 0x12, 0xfe, 0x12, 0x82, 0x12, 0x82, 0x1e, 0x82, 0x0, 0x82, 0x0, 0xfe },
+{ 0x94, 0xa2, 0x8, 0x20, 0x8, 0x20, 0x1f, 0x7f, 0x34, 0x50, 0x62, 0x8a, 0x0, 0x86, 0x1f, 0xfc, 0x0, 0x98, 0x7f, 0xff, 0x1, 0x80, 0xf, 0xfc, 0x7c, 0x4, 0x7, 0xfc, 0x4, 0x4, 0x4, 0x4, 0x7, 0xfc },
+{ 0x94, 0xa3, 0x7f, 0xa0, 0x0, 0x3f, 0x3f, 0x44, 0x21, 0xa8, 0x3f, 0x18, 0x20, 0xa7, 0x4f, 0xf8, 0x0, 0x88, 0x7f, 0xff, 0x0, 0x88, 0xf, 0xf8, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80 },
+{ 0x94, 0xa4, 0x8, 0x20, 0x8, 0x20, 0x1f, 0x7f, 0x34, 0x50, 0x62, 0x88, 0x0, 0x3c, 0xf, 0xe0, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8 },
+{ 0x94, 0xa5, 0x10, 0x40, 0x10, 0x78, 0x10, 0x40, 0x13, 0xfe, 0x7e, 0x42, 0x12, 0xf8, 0x12, 0x42, 0x3a, 0xfe, 0x36, 0xa4, 0x32, 0xfc, 0x52, 0xa4, 0x52, 0xfc, 0x12, 0x0, 0x15, 0xfe, 0x11, 0x52, 0x13, 0xff },
+{ 0x94, 0xa6, 0x10, 0xc, 0x10, 0x38, 0x13, 0xe0, 0x7d, 0x24, 0x54, 0xa8, 0x57, 0xff, 0x54, 0xa8, 0x54, 0xac, 0x55, 0x26, 0x56, 0x3, 0x55, 0xfc, 0x11, 0x24, 0x11, 0xfc, 0x11, 0x24, 0x11, 0x24, 0x11, 0xfc },
+{ 0x94, 0xa7, 0x0, 0x0, 0x3c, 0xf8, 0x24, 0x88, 0x24, 0x88, 0x24, 0x88, 0x3c, 0x88, 0x24, 0x88, 0x24, 0x88, 0x24, 0x88, 0x3c, 0x88, 0x24, 0x88, 0x24, 0x88, 0x24, 0x88, 0x24, 0x89, 0x64, 0x89, 0x4d, 0x7 },
+{ 0x94, 0xa8, 0x8, 0x0, 0x8, 0xfe, 0x8, 0x92, 0x2a, 0x92, 0x2a, 0x92, 0x2a, 0x92, 0x6c, 0x92, 0x48, 0xfe, 0x8, 0x92, 0x8, 0x92, 0x1c, 0x92, 0x14, 0x92, 0x16, 0x92, 0x32, 0x92, 0x20, 0xfe, 0x60, 0x0 },
+{ 0x94, 0xa9, 0x0, 0x80, 0x1, 0x0, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x0, 0x0, 0x3f, 0xfe, 0x20, 0x82, 0x20, 0x82, 0x3f, 0xfe, 0x20, 0x82, 0x20, 0x82, 0x3f, 0xfe },
+{ 0x94, 0xaa, 0x0, 0x0, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x6, 0x30, 0x4, 0x10, 0x4, 0x10, 0xc, 0x18, 0x8, 0x8, 0x18, 0xc, 0x30, 0x6, 0x60, 0x3, 0x0, 0x0 },
+{ 0x94, 0xab, 0x10, 0x10, 0x38, 0x10, 0x2c, 0x10, 0x64, 0x10, 0x41, 0xff, 0x7c, 0x54, 0x10, 0x54, 0x10, 0x54, 0x7c, 0x54, 0x10, 0xd6, 0x54, 0x92, 0x55, 0x93, 0x50, 0x7c, 0x1c, 0x10, 0x30, 0x10, 0x60, 0x10 },
+{ 0x94, 0xac, 0x0, 0x2, 0x23, 0xf4, 0x34, 0x51, 0x12, 0xda, 0x1, 0x8c, 0x43, 0x6, 0x66, 0x3, 0x21, 0xfc, 0x0, 0x88, 0x10, 0x88, 0x17, 0xff, 0x10, 0x88, 0x30, 0x88, 0x21, 0x89, 0x23, 0x9, 0x66, 0x7 },
+{ 0x94, 0xad, 0x0, 0x0, 0x3f, 0xc8, 0x1, 0x50, 0x23, 0x62, 0x16, 0x34, 0xc, 0x18, 0x1f, 0xfc, 0x72, 0x27, 0x2, 0x20, 0x2, 0x20, 0x7f, 0xff, 0x2, 0x20, 0x6, 0x20, 0xc, 0x21, 0x18, 0x33, 0x70, 0x1e },
+{ 0x94, 0xae, 0x0, 0x0, 0x7f, 0x7a, 0x14, 0x24, 0x14, 0xa5, 0x7f, 0x66, 0x55, 0x42, 0x55, 0xff, 0x55, 0x24, 0x67, 0x24, 0x41, 0x24, 0x41, 0xff, 0x7f, 0x24, 0x41, 0x24, 0x41, 0x65, 0x7f, 0x45, 0x0, 0xc3 },
+{ 0x94, 0xaf, 0x1f, 0x84, 0x10, 0x18, 0x1f, 0x60, 0x10, 0x2, 0x1f, 0xc, 0x10, 0x30, 0x7f, 0xc1, 0x11, 0x6, 0x3e, 0xb8, 0x1, 0x0, 0x7f, 0xff, 0x2, 0x0, 0x7, 0xfc, 0x1d, 0x8, 0x70, 0xf0, 0x7, 0x9f },
+{ 0x94, 0xb0, 0x4, 0x8c, 0x4, 0x86, 0xc, 0x82, 0x8, 0x80, 0x1f, 0xff, 0x10, 0x80, 0x30, 0x84, 0x50, 0xcc, 0x10, 0x58, 0x10, 0x70, 0x10, 0x20, 0x10, 0x70, 0x10, 0xd1, 0x11, 0x9b, 0x17, 0xe, 0x10, 0x4 },
+{ 0x94, 0xb1, 0x3f, 0xfe, 0x22, 0x22, 0x22, 0x22, 0x3f, 0xfe, 0x0, 0x0, 0x3f, 0x2, 0x0, 0x22, 0x7f, 0xa2, 0x0, 0x22, 0x3f, 0x22, 0x0, 0x22, 0x3f, 0x22, 0x0, 0x2, 0x3f, 0x2, 0x21, 0x2, 0x3f, 0xe },
+{ 0x94, 0xb2, 0x10, 0x40, 0x10, 0x40, 0x10, 0x40, 0x17, 0xff, 0x78, 0x40, 0x10, 0x40, 0x10, 0xfc, 0x10, 0x84, 0x18, 0x84, 0x71, 0xcc, 0x11, 0x48, 0x13, 0x78, 0x16, 0x30, 0x10, 0x78, 0x10, 0xcc, 0x33, 0x87 },
+{ 0x94, 0xb3, 0x8, 0x20, 0x8, 0x20, 0x1f, 0x7f, 0x34, 0x50, 0x62, 0x88, 0x0, 0x0, 0x4, 0x48, 0xc, 0x44, 0x1b, 0xff, 0x70, 0x40, 0x10, 0x64, 0x10, 0x2c, 0x10, 0x38, 0x10, 0xf1, 0x13, 0x9b, 0x10, 0xe },
+{ 0x94, 0xb4, 0x0, 0x0, 0x3f, 0x7e, 0x21, 0x42, 0x3f, 0x7e, 0x21, 0x42, 0x3f, 0x7e, 0x20, 0x22, 0x22, 0x92, 0x27, 0xfa, 0x2c, 0x82, 0x34, 0xa2, 0x24, 0x42, 0x24, 0xea, 0x25, 0xba, 0x24, 0x12, 0x20, 0xe },
+{ 0x94, 0xb5, 0x20, 0x10, 0x20, 0x20, 0x20, 0xfc, 0x78, 0x84, 0x28, 0xfc, 0x28, 0x84, 0x28, 0xfc, 0x28, 0x80, 0x28, 0xff, 0x28, 0x80, 0x2a, 0xff, 0x2a, 0x1, 0x66, 0xab, 0x41, 0xa9, 0x1, 0x3, 0x0, 0xe },
+{ 0x94, 0xb6, 0x0, 0x83, 0x0, 0x8e, 0x77, 0xf8, 0x52, 0x28, 0x53, 0x68, 0x51, 0x4f, 0x57, 0xfa, 0x50, 0x8a, 0x50, 0x8a, 0x57, 0xfa, 0x50, 0x8a, 0x71, 0xca, 0x1, 0xaa, 0x2, 0x8a, 0x4, 0x8a, 0x0, 0x92 },
+{ 0x94, 0xb7, 0x10, 0x20, 0x10, 0x20, 0x13, 0xff, 0x10, 0x0, 0x7c, 0xfc, 0x10, 0x84, 0x10, 0xfc, 0x10, 0x0, 0x13, 0xff, 0x12, 0x1, 0x1e, 0x79, 0x72, 0x49, 0x2, 0x49, 0x2, 0x79, 0x2, 0x1, 0x2, 0x7 },
+{ 0x94, 0xb8, 0x10, 0x10, 0x10, 0x38, 0x10, 0x28, 0x7e, 0x6c, 0x52, 0xc6, 0x53, 0x83, 0x52, 0x0, 0x52, 0xfe, 0x52, 0x0, 0x7e, 0x0, 0x10, 0xfe, 0x14, 0x82, 0x14, 0x82, 0x1e, 0x82, 0x32, 0x82, 0x60, 0xfe },
+{ 0x94, 0xb9, 0x4, 0x40, 0xc, 0xc0, 0x8, 0x80, 0x1f, 0xfe, 0x30, 0x80, 0x5f, 0xfc, 0x10, 0x80, 0x1f, 0xfc, 0x10, 0x80, 0x1f, 0xfe, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80 },
+{ 0x94, 0xba, 0x8, 0x20, 0xa, 0x22, 0xb, 0x26, 0x19, 0x24, 0x10, 0x20, 0x33, 0xfe, 0x30, 0x20, 0x50, 0x20, 0x10, 0x20, 0x17, 0xff, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20 },
+{ 0x94, 0xbb, 0x4, 0x2, 0x44, 0x52, 0x64, 0xd2, 0x24, 0x92, 0x4, 0x12, 0x7f, 0xd2, 0x4, 0x12, 0x4, 0x12, 0x4, 0x12, 0x7f, 0xd2, 0x4, 0x12, 0x4, 0x12, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0xe },
+{ 0x94, 0xbc, 0x0, 0x80, 0x10, 0x84, 0x18, 0x8c, 0x8, 0x88, 0x0, 0x80, 0x3f, 0xfe, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80 },
+{ 0x94, 0xbd, 0x0, 0x0, 0x1f, 0xfe, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x1f, 0xfc, 0x12, 0x4, 0x13, 0xc, 0x11, 0x8, 0x11, 0x98, 0x10, 0xb0, 0x30, 0x60, 0x20, 0xe0, 0x61, 0xb0, 0x7, 0x1c, 0x1c, 0x7 },
+{ 0x94, 0xbe, 0x8, 0x0, 0x4a, 0xff, 0x6a, 0x80, 0x2c, 0x80, 0x8, 0x80, 0x7e, 0xfe, 0x8, 0xa2, 0x8, 0xa2, 0xe, 0xb6, 0x78, 0x94, 0x8, 0x9c, 0x8, 0x88, 0x19, 0x9c, 0x11, 0x14, 0x33, 0x36, 0x60, 0x63 },
+{ 0x94, 0xbf, 0x10, 0x0, 0x10, 0xfc, 0x10, 0x84, 0x7e, 0x84, 0x52, 0x84, 0x52, 0xa4, 0x52, 0xb4, 0x52, 0x94, 0x52, 0x94, 0x52, 0x84, 0x56, 0x84, 0x10, 0x84, 0x10, 0x84, 0x11, 0x85, 0x11, 0x5, 0x13, 0x3 },
+{ 0x94, 0xc0, 0x10, 0x80, 0x11, 0x1e, 0x13, 0xd2, 0x12, 0x52, 0x7b, 0x52, 0x12, 0xd3, 0x12, 0x60, 0x17, 0xdf, 0x12, 0x49, 0x1b, 0x4b, 0x72, 0xca, 0x12, 0xce, 0x12, 0x44, 0x12, 0x4e, 0x12, 0x4a, 0x34, 0xdb },
+{ 0x94, 0xc1, 0x0, 0x80, 0x7c, 0xbf, 0x10, 0x88, 0x17, 0xe8, 0x10, 0x48, 0x12, 0x48, 0x3b, 0x48, 0x11, 0x5e, 0x11, 0xc8, 0x10, 0x88, 0x11, 0xc8, 0x1d, 0x68, 0x33, 0x28, 0x66, 0x8, 0xc, 0x3f, 0x0, 0x0 },
+{ 0x94, 0xc2, 0x8, 0x0, 0x8, 0xff, 0x8, 0x80, 0x7e, 0x80, 0x8, 0x80, 0x8, 0xfe, 0x1c, 0xa2, 0x1a, 0xa6, 0x1a, 0xb4, 0x28, 0x94, 0x28, 0x9c, 0x48, 0x88, 0x9, 0x9c, 0x9, 0x14, 0xb, 0x36, 0x8, 0x63 },
+{ 0x94, 0xc3, 0x0, 0x0, 0x31, 0xfc, 0x19, 0x4, 0x9, 0x4, 0x1, 0x4, 0x61, 0x4, 0x31, 0x4, 0x11, 0x4, 0x1, 0x1c, 0x9, 0x0, 0x9, 0x0, 0x19, 0x0, 0x11, 0x1, 0x31, 0x83, 0x20, 0xfe, 0x60, 0x0 },
+{ 0x94, 0xc4, 0x0, 0x0, 0x33, 0xf8, 0x1a, 0x8, 0xa, 0x8, 0x2, 0x8, 0x62, 0xc8, 0x32, 0x68, 0x12, 0x28, 0x2, 0x8, 0xa, 0x8, 0xa, 0x8, 0x1a, 0x8, 0x12, 0x8, 0x36, 0x9, 0x24, 0x9, 0x6c, 0x7 },
+{ 0x94, 0xc5, 0x24, 0x0, 0x24, 0xff, 0x24, 0x80, 0x24, 0x80, 0x24, 0x80, 0x3e, 0xfe, 0x20, 0xa2, 0x20, 0xa2, 0x3c, 0xb6, 0x24, 0x94, 0x24, 0x9c, 0x24, 0x88, 0x25, 0x9c, 0x25, 0x14, 0x67, 0x36, 0x44, 0x63 },
+{ 0x94, 0xc6, 0x4, 0x0, 0x45, 0xfc, 0x29, 0x4, 0x11, 0x4, 0x11, 0x4, 0x29, 0x4, 0x49, 0x4, 0x9, 0x4, 0x19, 0x1c, 0x19, 0x0, 0x29, 0x0, 0x49, 0x0, 0x9, 0x1, 0x9, 0x83, 0x18, 0xfe, 0x70, 0x0 },
+{ 0x94, 0xc7, 0x0, 0x80, 0x7c, 0xff, 0x12, 0x88, 0x12, 0x88, 0x12, 0x88, 0x12, 0x88, 0x7e, 0x88, 0x12, 0xbe, 0x12, 0x88, 0x10, 0x88, 0x10, 0x88, 0x1c, 0x88, 0x31, 0x88, 0x61, 0x8, 0x3, 0x7f, 0x0, 0x0 },
+{ 0x94, 0xc8, 0x0, 0x20, 0x7d, 0x22, 0x55, 0xa6, 0x54, 0xa4, 0x54, 0x20, 0x55, 0xfe, 0x7c, 0x20, 0x54, 0x20, 0x54, 0x20, 0x57, 0xff, 0x54, 0x20, 0x54, 0x20, 0x7c, 0x20, 0x0, 0x20, 0x0, 0x20, 0x0, 0x20 },
+{ 0x94, 0xc9, 0x10, 0x20, 0x3f, 0xa0, 0x60, 0x3f, 0x1f, 0x44, 0x15, 0x2c, 0x7f, 0xa8, 0x29, 0x1c, 0x3f, 0xb6, 0x6, 0x63, 0x1, 0x80, 0x6, 0x10, 0x1, 0x22, 0x7f, 0xff, 0x0, 0x81, 0xc, 0x98, 0x38, 0x8e },
+{ 0x94, 0xca, 0x8, 0x0, 0x10, 0x3c, 0x3e, 0x24, 0x22, 0x24, 0x2a, 0x64, 0x2a, 0xc7, 0x22, 0x0, 0x7f, 0x7e, 0x22, 0x22, 0x2a, 0x26, 0x2a, 0x34, 0x2a, 0x1c, 0x2a, 0x8, 0x22, 0x1c, 0x62, 0x36, 0x46, 0xe3 },
+{ 0x94, 0xcb, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x0, 0xe, 0x33, 0xf8, 0x19, 0x24, 0x0, 0xa8, 0x67, 0xff, 0x30, 0xa8, 0x1, 0x24, 0x17, 0xff, 0x11, 0x24, 0x31, 0xfc, 0x21, 0x24, 0x61, 0xfc },
+{ 0x94, 0xcc, 0x0, 0x0, 0x3c, 0xff, 0x24, 0x80, 0x24, 0x80, 0x3c, 0x80, 0x24, 0xfe, 0x24, 0xa2, 0x24, 0xa2, 0x3c, 0xb6, 0x24, 0x94, 0x24, 0x9c, 0x24, 0x88, 0x3c, 0x9c, 0x15, 0x94, 0x35, 0x36, 0x62, 0x63 },
+{ 0x94, 0xcd, 0x8, 0x20, 0x8, 0x20, 0x1f, 0x7f, 0x34, 0x90, 0x62, 0x8, 0x4, 0x0, 0x3f, 0xbe, 0x4, 0x22, 0x3f, 0xa2, 0x24, 0xa2, 0x3f, 0xa2, 0x24, 0xa6, 0x3f, 0xa0, 0x4, 0x21, 0x3f, 0xb3, 0x4, 0x1e },
+{ 0x94, 0xce, 0x0, 0xc, 0x0, 0x78, 0x3f, 0xc0, 0x8, 0x88, 0xc, 0x98, 0x4, 0x90, 0x0, 0x80, 0x7f, 0xff, 0x2, 0xa0, 0x6, 0xb0, 0x4, 0x90, 0xc, 0x98, 0x18, 0x8c, 0x30, 0x86, 0x60, 0x83, 0x0, 0x80 },
+{ 0x94, 0xcf, 0x8, 0x0, 0x8, 0xff, 0x8, 0x10, 0x9, 0x7e, 0x2b, 0x42, 0x2a, 0x42, 0x68, 0x7e, 0x48, 0x42, 0x8, 0x42, 0x8, 0x7e, 0x1c, 0x42, 0x14, 0x42, 0x16, 0x7e, 0x32, 0x24, 0x23, 0x66, 0x60, 0xc3 },
+{ 0x94, 0xd0, 0x0, 0x0, 0x12, 0xff, 0x12, 0x10, 0x33, 0x7e, 0x21, 0x42, 0x61, 0xc2, 0x0, 0x7e, 0x3f, 0x42, 0x9, 0x42, 0x9, 0x7e, 0x19, 0x42, 0x11, 0x42, 0x13, 0x7e, 0x32, 0x24, 0x66, 0x66, 0x0, 0xc3 },
+{ 0x94, 0xd1, 0x8, 0x0, 0x1c, 0xff, 0x16, 0x80, 0x32, 0x80, 0x28, 0x80, 0x7e, 0xfe, 0x22, 0xa2, 0x3e, 0xa2, 0x22, 0xb6, 0x3e, 0x94, 0x20, 0x9c, 0x24, 0x88, 0x24, 0x9c, 0x2e, 0x94, 0x3b, 0xb6, 0x61, 0x63 },
+{ 0x94, 0xd2, 0x10, 0x80, 0x10, 0xfc, 0x11, 0x88, 0x7b, 0x18, 0x16, 0x10, 0x13, 0xfe, 0x12, 0x22, 0x12, 0x22, 0x1a, 0x22, 0x73, 0xfe, 0x10, 0x90, 0x10, 0x90, 0x11, 0x90, 0x11, 0x11, 0x13, 0x13, 0x36, 0xe },
+{ 0x94, 0xd3, 0x0, 0x80, 0x0, 0xfc, 0x79, 0x88, 0x4b, 0x18, 0x4e, 0x10, 0x4b, 0xfe, 0x4a, 0x22, 0x7a, 0x22, 0x4a, 0x22, 0x4b, 0xfe, 0x48, 0x90, 0x48, 0x90, 0x79, 0x90, 0x1, 0x11, 0x3, 0x13, 0xe, 0xe },
+{ 0x94, 0xd4, 0x0, 0x18, 0x0, 0xf0, 0x1f, 0x80, 0x8, 0x88, 0x4, 0x90, 0x7f, 0xff, 0x2, 0xa0, 0x6, 0xb0, 0x1c, 0x9c, 0x70, 0x7, 0xf, 0xf8, 0x8, 0x88, 0xf, 0xf8, 0x8, 0x88, 0x8, 0x88, 0xf, 0xf8 },
+{ 0x94, 0xd5, 0x4, 0x0, 0x1f, 0x7c, 0x11, 0x44, 0x15, 0x47, 0x7f, 0x80, 0x11, 0x7e, 0x15, 0x22, 0x15, 0x24, 0x31, 0x18, 0x63, 0x67, 0x0, 0x0, 0x1f, 0xfc, 0x12, 0x44, 0x12, 0x44, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x94, 0xd6, 0x4, 0x0, 0x1f, 0x7c, 0x11, 0x44, 0x15, 0x47, 0x7f, 0x80, 0x11, 0x7e, 0x15, 0x24, 0x35, 0x18, 0x63, 0x67, 0x0, 0x0, 0x7f, 0xff, 0x2, 0x0, 0x7, 0xfc, 0x1c, 0x4, 0x74, 0x4, 0x7, 0xfc },
+{ 0x94, 0xd7, 0x4, 0x20, 0x7f, 0xff, 0x4, 0x20, 0x0, 0x18, 0x1f, 0xf0, 0x8, 0x88, 0x4, 0x90, 0x7f, 0xff, 0x2, 0xa0, 0x4, 0x90, 0x18, 0xc, 0x6f, 0xfb, 0x8, 0x88, 0xf, 0xf8, 0x8, 0x88, 0xf, 0xf8 },
+{ 0x94, 0xd8, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x2, 0x20, 0x12, 0x24, 0x36, 0x26, 0x6c, 0x23, 0x0, 0x80, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x84, 0x3, 0xfe, 0x7e, 0x3 },
+{ 0x94, 0xd9, 0x0, 0x0, 0x3f, 0xfe, 0x20, 0x0, 0x21, 0x20, 0x2f, 0x3c, 0x21, 0x20, 0x2f, 0x20, 0x21, 0x3c, 0x23, 0x20, 0x2d, 0x20, 0x21, 0x3c, 0x22, 0x20, 0x2c, 0x20, 0x20, 0x0, 0x3f, 0xfe, 0x0, 0x0 },
+{ 0x94, 0xda, 0x0, 0x80, 0x1, 0x0, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x4, 0x40, 0x8, 0x40, 0x7f, 0xff, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40 },
+{ 0x94, 0xdb, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x80, 0x1, 0x80, 0x3, 0xb0, 0x6, 0x98, 0x1c, 0x8c, 0x70, 0x87, 0x0, 0x80, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x1f, 0xfc },
+{ 0x94, 0xdc, 0x8, 0x0, 0x8, 0xfe, 0x8, 0x2, 0x8, 0x2, 0x7e, 0x2, 0x12, 0x2, 0x12, 0xfe, 0x12, 0x80, 0x32, 0x80, 0x26, 0x80, 0x24, 0x80, 0x7c, 0x80, 0xe, 0x81, 0x1a, 0xc3, 0x30, 0x7e, 0x60, 0x0 },
+{ 0x94, 0xdd, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xff, 0x20, 0x0, 0x24, 0x20, 0x24, 0x20, 0x24, 0x22, 0x24, 0x2e, 0x27, 0xb8, 0x24, 0x20, 0x24, 0x20, 0x24, 0x20, 0x64, 0x20, 0x44, 0x21, 0x47, 0xb3, 0x1c, 0x1e },
+{ 0x94, 0xde, 0x8, 0x20, 0x18, 0x20, 0x10, 0x20, 0x33, 0xff, 0x62, 0x21, 0xa, 0x22, 0x1a, 0x20, 0x13, 0xfe, 0x32, 0x82, 0x72, 0xc6, 0x12, 0x4c, 0x16, 0x78, 0x14, 0x30, 0x1c, 0x78, 0x10, 0xcc, 0x13, 0x87 },
+{ 0x94, 0xdf, 0x2, 0x20, 0x2, 0x20, 0x7e, 0x3f, 0x2, 0x20, 0x3e, 0x3e, 0x2, 0x20, 0x1e, 0x20, 0x72, 0x3f, 0x6, 0x20, 0xc, 0x20, 0x39, 0x80, 0x4, 0xc0, 0x14, 0x46, 0x14, 0xb, 0x36, 0x19, 0x63, 0xf0 },
+{ 0x94, 0xe0, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x0, 0x1f, 0xfe, 0x10, 0x2, 0x1f, 0xfe, 0x10, 0x0, 0x10, 0x90, 0x17, 0x9e, 0x10, 0x90, 0x17, 0x9e, 0x10, 0x90, 0x33, 0x90, 0x2c, 0x9f, 0x61, 0x90, 0x3, 0x10 },
+{ 0x94, 0xe1, 0x12, 0x10, 0x12, 0x10, 0x12, 0x10, 0x12, 0x12, 0x7a, 0x16, 0x13, 0xdc, 0x12, 0x10, 0x12, 0x10, 0x1a, 0x10, 0x72, 0x10, 0x12, 0x10, 0x12, 0x10, 0x12, 0x10, 0x12, 0x11, 0x13, 0xdb, 0x36, 0xe },
+{ 0x94, 0xe2, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x13, 0xff, 0x7a, 0x21, 0x12, 0x22, 0x12, 0x20, 0x13, 0xfe, 0x1a, 0x82, 0x72, 0x86, 0x12, 0xcc, 0x16, 0x58, 0x14, 0x30, 0x1c, 0x78, 0x10, 0xcc, 0x33, 0x87 },
+{ 0x94, 0xe3, 0x2, 0x20, 0x2, 0x20, 0x7e, 0x3f, 0x2, 0x20, 0x3e, 0x3e, 0x2, 0x20, 0x7e, 0x3f, 0x4, 0xa0, 0x8, 0x80, 0x7f, 0xff, 0x4, 0x10, 0x6, 0x30, 0x3, 0x60, 0x1, 0xc0, 0xf, 0x78, 0x78, 0xf },
+{ 0x94, 0xe4, 0x10, 0x40, 0x10, 0x40, 0x10, 0x40, 0x10, 0x40, 0x10, 0x46, 0x1f, 0x5c, 0x10, 0x70, 0x10, 0x40, 0x10, 0x40, 0x10, 0x40, 0x10, 0x40, 0x10, 0x40, 0x10, 0x40, 0x17, 0x41, 0x1c, 0x63, 0x70, 0x3e },
+{ 0x94, 0xe5, 0x0, 0xc0, 0x20, 0x60, 0x30, 0x20, 0x10, 0x84, 0x0, 0x84, 0x40, 0x8c, 0x60, 0x88, 0x22, 0x98, 0x2, 0x96, 0x12, 0xb3, 0x16, 0xe1, 0x14, 0xc0, 0x30, 0x80, 0x23, 0x82, 0x2e, 0xc6, 0x60, 0x7c },
+{ 0x94, 0xe6, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xff, 0x50, 0x40, 0x30, 0x40, 0x17, 0xfe, 0x14, 0x42, 0x14, 0x44, 0x37, 0xf8, 0x55, 0x8, 0x15, 0x98, 0x14, 0xb0, 0x34, 0x60, 0x2c, 0xf0, 0x69, 0x9c, 0x7, 0x7 },
+{ 0x94, 0xe7, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xfe, 0x10, 0x82, 0x10, 0x84, 0x10, 0x80, 0x1f, 0xf8, 0x14, 0x8, 0x16, 0x18, 0x13, 0x30, 0x11, 0x60, 0x30, 0xc0, 0x21, 0xe0, 0x67, 0x38, 0x1c, 0xe },
+{ 0x94, 0xe8, 0x0, 0x20, 0x7e, 0x40, 0x11, 0xfe, 0x11, 0x22, 0x11, 0x22, 0x11, 0xfe, 0x3d, 0x22, 0x25, 0x22, 0x65, 0xfe, 0x24, 0x50, 0x24, 0x90, 0x27, 0xff, 0x24, 0x10, 0x3c, 0x10, 0x0, 0x10, 0x0, 0x10 },
+{ 0x94, 0xe9, 0x4, 0x60, 0x1c, 0x30, 0x70, 0x10, 0x10, 0x44, 0x10, 0x44, 0x7c, 0x4c, 0x10, 0x48, 0x11, 0x58, 0x39, 0x56, 0x35, 0x73, 0x53, 0x61, 0x52, 0x40, 0x10, 0xc0, 0x11, 0x42, 0x16, 0x66, 0x10, 0x3c },
+{ 0x94, 0xea, 0x8, 0x48, 0x18, 0x48, 0x10, 0x48, 0x65, 0xcf, 0x2c, 0x48, 0x18, 0x48, 0x10, 0x48, 0x25, 0xcf, 0x7c, 0x48, 0x14, 0x48, 0x10, 0xc8, 0x55, 0x4f, 0x54, 0x48, 0x54, 0xc8, 0x10, 0x88, 0x11, 0x88 },
+{ 0x94, 0xeb, 0x3f, 0xfe, 0x22, 0x22, 0x22, 0x22, 0x3f, 0xfe, 0x8, 0x0, 0x11, 0x26, 0x7f, 0xbc, 0x0, 0xa0, 0x3f, 0x21, 0x21, 0x1f, 0x3f, 0x0, 0x21, 0x26, 0x3f, 0x3c, 0x21, 0x20, 0x21, 0x21, 0x23, 0x1f },
+{ 0x94, 0xec, 0x0, 0x0, 0x3e, 0xfe, 0x22, 0x92, 0x22, 0x92, 0x22, 0x92, 0x3e, 0x92, 0x22, 0x92, 0x22, 0xfe, 0x22, 0x80, 0x3e, 0x80, 0x22, 0x80, 0x22, 0x80, 0x22, 0x80, 0x22, 0x81, 0x62, 0xc3, 0x46, 0x7e },
+{ 0x94, 0xed, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x7d, 0xff, 0x5, 0x11, 0xd, 0x12, 0x19, 0x10, 0x11, 0xfe, 0x35, 0x42, 0x59, 0x66, 0x15, 0x24, 0x15, 0x3c, 0x13, 0x18, 0x12, 0x3c, 0x16, 0x66, 0x10, 0xc3 },
+{ 0x94, 0xee, 0x0, 0x24, 0x3c, 0x24, 0x0, 0x24, 0x7e, 0xe7, 0x0, 0x24, 0x3c, 0x24, 0x0, 0x24, 0x0, 0xe7, 0x3c, 0x24, 0x0, 0x24, 0x0, 0x64, 0x3d, 0xa7, 0x24, 0x24, 0x24, 0x64, 0x24, 0x44, 0x3c, 0xc4 },
+{ 0x94, 0xef, 0x2, 0x20, 0x7f, 0xfe, 0x2, 0x22, 0x3f, 0xfe, 0x22, 0x20, 0x3f, 0xff, 0x4, 0x21, 0xf, 0xfb, 0x78, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x4, 0x10, 0x38, 0xe },
+{ 0x94, 0xf0, 0x0, 0x8, 0x23, 0x88, 0x32, 0xbe, 0x12, 0x80, 0x2, 0xa2, 0x3, 0x94, 0x2, 0x7f, 0x72, 0x8, 0x17, 0x88, 0x16, 0xbe, 0x1a, 0x88, 0x12, 0x88, 0x12, 0x88, 0x33, 0x88, 0x28, 0x0, 0x67, 0xff },
+{ 0x94, 0xf1, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x7e, 0x3f, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x3e, 0x3e, 0x2, 0x20, 0x2, 0x20, 0x1e, 0x20, 0x72, 0x3f, 0x6, 0x20, 0xc, 0x20, 0x18, 0x20, 0x70, 0x20 },
+{ 0x94, 0xf2, 0x0, 0x0, 0x3f, 0xf2, 0x0, 0x14, 0x5, 0x1c, 0xd, 0x12, 0x39, 0x8, 0x9, 0x5, 0x7f, 0xf3, 0x9, 0x10, 0x9, 0x14, 0x9, 0x18, 0x9, 0x14, 0x19, 0x12, 0x11, 0x18, 0x31, 0xd, 0x61, 0x7 },
+{ 0x94, 0xf3, 0x10, 0x0, 0x14, 0xfe, 0x16, 0x4, 0x7a, 0x68, 0x10, 0x10, 0x10, 0xfe, 0x38, 0x92, 0x36, 0xfe, 0x52, 0x92, 0x52, 0xfe, 0x12, 0x92, 0x12, 0x92, 0x12, 0x92, 0x16, 0x96, 0x15, 0x0, 0x1c, 0xff },
+{ 0x94, 0xf4, 0x10, 0x20, 0x10, 0x20, 0x3f, 0x7f, 0x68, 0xd0, 0x0, 0x8, 0x24, 0x8, 0x7e, 0xff, 0x24, 0x89, 0x3c, 0x88, 0x24, 0xfe, 0x3c, 0xa2, 0x24, 0xb6, 0x7e, 0x9c, 0x14, 0x88, 0x37, 0x14, 0x62, 0x63 },
+{ 0x94, 0xf5, 0x8, 0x88, 0x8, 0x88, 0xf, 0xff, 0x18, 0x88, 0x10, 0x88, 0x13, 0xff, 0x32, 0x0, 0x52, 0xfe, 0x12, 0x92, 0x12, 0xfe, 0x12, 0x92, 0x12, 0x92, 0x12, 0xfe, 0x12, 0x92, 0x14, 0x92, 0x10, 0x96 },
+{ 0x94, 0xf6, 0x0, 0x0, 0x1f, 0xfe, 0x10, 0x2, 0x10, 0x2, 0x1f, 0xfe, 0x10, 0x0, 0x10, 0x18, 0x13, 0xf0, 0x10, 0x80, 0x17, 0xfc, 0x10, 0x80, 0x1f, 0xfe, 0x30, 0x80, 0x20, 0x81, 0x60, 0xc3, 0x0, 0x7e },
+{ 0x94, 0xf7, 0x8, 0x88, 0x1a, 0xa8, 0x12, 0xa8, 0x32, 0xaf, 0x63, 0xea, 0x8, 0x12, 0x18, 0xa, 0x17, 0xfa, 0x31, 0x4a, 0x71, 0x4e, 0x11, 0x44, 0x11, 0x54, 0x13, 0x6e, 0x12, 0x4a, 0x16, 0x1b, 0x10, 0x11 },
+{ 0x94, 0xf8, 0x11, 0x10, 0x11, 0x10, 0x11, 0x10, 0x7d, 0x12, 0x11, 0x16, 0x11, 0xdc, 0x39, 0x10, 0x35, 0x10, 0x35, 0x10, 0x51, 0x10, 0x51, 0x10, 0x11, 0x10, 0x11, 0x10, 0x11, 0x11, 0x11, 0xd3, 0x17, 0xe },
+{ 0x94, 0xf9, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x0, 0x0, 0x10, 0x40, 0x10, 0x46, 0x1f, 0x7c, 0x10, 0x40, 0x10, 0x41, 0x1f, 0x63, 0x70, 0x3e },
+{ 0x94, 0xfa, 0x0, 0x0, 0x7f, 0x7f, 0x8, 0x8, 0x8, 0x8, 0x3e, 0x3e, 0x8, 0x8, 0x8, 0x8, 0xf, 0x7f, 0x78, 0x0, 0x10, 0x40, 0x10, 0x46, 0x1f, 0x7c, 0x10, 0x40, 0x10, 0x41, 0x1f, 0x63, 0x70, 0x3e },
+{ 0x94, 0xfb, 0x0, 0x0, 0x1f, 0xfe, 0x10, 0x82, 0x10, 0x82, 0x1f, 0xfe, 0x10, 0x0, 0x13, 0xfc, 0x12, 0x4, 0x12, 0x4, 0x13, 0xfc, 0x12, 0x4, 0x12, 0x4, 0x33, 0xfc, 0x22, 0x4, 0x62, 0x4, 0x3, 0xfc },
+{ 0x94, 0xfc, 0x4, 0x10, 0x2, 0x20, 0x3f, 0xfe, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x0, 0x0, 0x0, 0x80, 0x7f, 0xff, 0x1, 0x40, 0x3, 0x60, 0xe, 0x38, 0x78, 0xf },
+{ 0x95, 0x40, 0x1, 0x0, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x3f, 0xfe, 0x20, 0x82, 0x3f, 0xfe, 0x20, 0x82, 0x3f, 0xfe, 0x4, 0x10, 0x7f, 0xff, 0x8, 0x10, 0x30, 0x10 },
+{ 0x95, 0x41, 0x8, 0x40, 0x8, 0x40, 0x8, 0x7c, 0x7e, 0xc4, 0x9, 0x8c, 0x8, 0x58, 0x1c, 0x30, 0x1a, 0x78, 0x18, 0xcc, 0x2b, 0x87, 0x28, 0x70, 0x48, 0x18, 0x8, 0x0, 0x8, 0xe0, 0x8, 0x38, 0x8, 0xc },
+{ 0x95, 0x42, 0x4, 0x10, 0x1c, 0x20, 0x71, 0xfe, 0x11, 0x22, 0x11, 0x22, 0x7d, 0xfe, 0x11, 0x22, 0x11, 0x22, 0x39, 0xfe, 0x34, 0x48, 0x50, 0x88, 0x13, 0xff, 0x10, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10, 0x8 },
+{ 0x95, 0x43, 0x0, 0x0, 0x3f, 0xfe, 0x21, 0x20, 0x21, 0x20, 0x21, 0x20, 0x21, 0x20, 0x21, 0x20, 0x23, 0x20, 0x22, 0x22, 0x26, 0x26, 0x2c, 0x1c, 0x20, 0x0, 0x20, 0x0, 0x20, 0x0, 0x3f, 0xfe, 0x0, 0x0 },
+{ 0x95, 0x44, 0x0, 0x0, 0x3f, 0xfe, 0x0, 0x82, 0x0, 0x84, 0x0, 0x80, 0x8, 0x80, 0x8, 0x80, 0x8, 0xfc, 0x8, 0x80, 0x8, 0x80, 0x8, 0x80, 0x1c, 0x80, 0x16, 0x80, 0x33, 0x80, 0x21, 0xc0, 0x60, 0x7f },
+{ 0x95, 0x45, 0x1f, 0x84, 0x10, 0x18, 0x1f, 0x62, 0x10, 0xc, 0x1f, 0x30, 0x10, 0x2, 0x7f, 0xcc, 0x11, 0x30, 0x3e, 0x80, 0x8, 0x40, 0x28, 0x46, 0x2f, 0x7c, 0x28, 0x40, 0x28, 0x41, 0x3f, 0x63, 0x60, 0x3e },
+{ 0x95, 0x46, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xff, 0x4, 0x10, 0x2, 0x20, 0x1f, 0xfe, 0x10, 0x0, 0x10, 0x30, 0x10, 0xe0, 0x17, 0x8c, 0x10, 0x38, 0x10, 0xe0, 0x37, 0x86, 0x20, 0x1c, 0x60, 0x70, 0x7, 0xc0 },
+{ 0x95, 0x47, 0x0, 0x10, 0x3c, 0x10, 0x25, 0xff, 0x24, 0x54, 0x24, 0xd6, 0x3d, 0x93, 0x24, 0x38, 0x24, 0x6c, 0x25, 0xc7, 0x3c, 0x10, 0x24, 0x92, 0x24, 0x54, 0x24, 0x38, 0x24, 0xd6, 0x65, 0x93, 0x4c, 0x30 },
+{ 0x95, 0x48, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x7f, 0xff, 0x2, 0x20, 0xc, 0x3f, 0x71, 0x0, 0x3, 0xf0, 0xe, 0x30, 0x3b, 0x60, 0x1, 0xc0, 0xf, 0x78, 0x78, 0xf },
+{ 0x95, 0x49, 0x0, 0x8, 0x3c, 0x8, 0x24, 0x8, 0x24, 0x8, 0x25, 0xff, 0x3c, 0x8, 0x24, 0x8, 0x24, 0xc8, 0x24, 0x68, 0x3c, 0x28, 0x24, 0x8, 0x24, 0x8, 0x24, 0x8, 0x24, 0x8, 0x64, 0x8, 0x4c, 0x38 },
+{ 0x95, 0x4a, 0x0, 0x0, 0x7b, 0xde, 0x9, 0x2, 0x9, 0x2, 0xb, 0xc2, 0x3a, 0x4e, 0x22, 0x48, 0x22, 0x48, 0x22, 0x48, 0x3b, 0xce, 0xa, 0x42, 0xa, 0x42, 0xa, 0x42, 0x1a, 0x46, 0x13, 0xc4, 0x70, 0x1c },
+{ 0x95, 0x4b, 0x1, 0x80, 0x0, 0xc8, 0x0, 0x48, 0x2, 0x8, 0x2, 0x18, 0x2, 0x10, 0x12, 0x34, 0x12, 0x26, 0x12, 0x62, 0x32, 0x43, 0x22, 0xc1, 0x63, 0x84, 0x2, 0xc, 0xf, 0x8, 0x79, 0xf8, 0x0, 0x0 },
+{ 0x95, 0x4c, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x84, 0x1f, 0xfc, 0x8, 0x88, 0x8, 0x88, 0x7f, 0xff, 0x8, 0x88, 0x8, 0x88, 0x3f, 0xfe, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x80 },
+{ 0x95, 0x4d, 0x10, 0x20, 0x10, 0x20, 0x3f, 0x7f, 0x68, 0x90, 0x4, 0x88, 0x1f, 0xfc, 0x0, 0x84, 0x7f, 0xff, 0x0, 0x84, 0x1f, 0xfc, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80 },
+{ 0x95, 0x4e, 0x0, 0x0, 0x33, 0xff, 0x18, 0x0, 0x8, 0xfc, 0x0, 0x84, 0x0, 0xfc, 0x0, 0x0, 0x79, 0xfe, 0x9, 0x22, 0x9, 0x22, 0x9, 0xfe, 0x9, 0x22, 0x9, 0x22, 0x19, 0xfe, 0x34, 0x0, 0x63, 0xff },
+{ 0x95, 0x4f, 0x10, 0x20, 0x10, 0x70, 0x10, 0x58, 0x7c, 0xcc, 0x11, 0x86, 0x13, 0x3, 0x38, 0xfc, 0x34, 0x0, 0x30, 0x0, 0x53, 0xff, 0x50, 0x40, 0x10, 0x48, 0x10, 0xcc, 0x10, 0x84, 0x10, 0xfe, 0x13, 0x82 },
+{ 0x95, 0x50, 0x8, 0x0, 0x8, 0xff, 0x8, 0x88, 0x8, 0x88, 0x7e, 0x88, 0x12, 0xfe, 0x12, 0x82, 0x12, 0x82, 0x36, 0x82, 0x24, 0xfe, 0x24, 0x88, 0x7c, 0x88, 0xa, 0x88, 0x1a, 0x88, 0x30, 0xff, 0x60, 0x0 },
+{ 0x95, 0x51, 0x10, 0x6, 0x10, 0x1c, 0x13, 0xf2, 0x11, 0x26, 0x7c, 0x94, 0x17, 0xff, 0x14, 0x40, 0x37, 0xff, 0x24, 0x40, 0x2c, 0x7c, 0x28, 0x44, 0x7c, 0xec, 0x15, 0xb8, 0x13, 0x10, 0x36, 0x7c, 0x61, 0xc7 },
+{ 0x95, 0x52, 0x8, 0x0, 0x19, 0xfc, 0x10, 0x44, 0x62, 0x44, 0x26, 0x44, 0xc, 0x44, 0x18, 0x44, 0x35, 0xff, 0x7e, 0x44, 0xa, 0x44, 0x8, 0x44, 0x2a, 0x44, 0x2a, 0x44, 0x68, 0x44, 0x49, 0xff, 0x8, 0x0 },
+{ 0x95, 0x53, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x80, 0x1, 0x80, 0x1, 0x0, 0x1f, 0xfc, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x1f, 0xfc, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x1f, 0xfc },
+{ 0x95, 0x54, 0x0, 0x0, 0x3b, 0xde, 0x0, 0x42, 0x7d, 0x4a, 0x0, 0xc6, 0x39, 0x4a, 0x0, 0x22, 0x0, 0x70, 0x38, 0xdc, 0x3, 0x87, 0x0, 0x30, 0x39, 0xc8, 0x28, 0x32, 0x29, 0xc4, 0x28, 0x18, 0x39, 0xe0 },
+{ 0x95, 0x55, 0x4, 0x20, 0x4, 0x20, 0xf, 0xfe, 0x8, 0x20, 0x1b, 0xfe, 0x10, 0x20, 0x30, 0x20, 0x57, 0xff, 0x10, 0x50, 0x10, 0xd1, 0x11, 0x9b, 0x17, 0xa, 0x11, 0xc, 0x11, 0x4, 0x11, 0xe6, 0x17, 0x3 },
+{ 0x95, 0x56, 0x4, 0x2, 0x7, 0x86, 0x4, 0xc, 0x3f, 0xd8, 0x24, 0x42, 0x27, 0x86, 0x3c, 0xc, 0x24, 0x98, 0x23, 0xb1, 0x20, 0x3, 0x29, 0x6, 0x29, 0xc, 0x29, 0x38, 0x69, 0x0, 0x49, 0x81, 0x10, 0xff },
+{ 0x95, 0x57, 0x8, 0x0, 0x9, 0xff, 0x8, 0x28, 0x7f, 0xff, 0x9, 0x29, 0x9, 0x29, 0x1d, 0xff, 0x1a, 0x0, 0x18, 0xfe, 0x28, 0x0, 0x29, 0xff, 0x48, 0x10, 0x8, 0x94, 0x9, 0x96, 0xb, 0x13, 0x8, 0x70 },
+{ 0x95, 0x58, 0x0, 0x80, 0x0, 0x80, 0x18, 0x81, 0xc, 0x83, 0x4, 0x86, 0x0, 0xcc, 0x7e, 0xd8, 0x2, 0xe0, 0x6, 0xa0, 0x4, 0xb0, 0xc, 0x98, 0x18, 0x8c, 0x30, 0x86, 0x60, 0x83, 0x0, 0x80, 0x3, 0x80 },
+{ 0x95, 0x59, 0x0, 0x0, 0x67, 0xff, 0x30, 0x90, 0x13, 0xfe, 0x2, 0x92, 0x62, 0x92, 0x33, 0xfe, 0x10, 0x0, 0x3, 0xfe, 0x8, 0x0, 0xf, 0xff, 0x18, 0x20, 0x11, 0x24, 0x33, 0x26, 0x26, 0x23, 0x60, 0xe0 },
+{ 0x95, 0x5a, 0x0, 0x6, 0x7f, 0x1c, 0x14, 0x74, 0x7f, 0x54, 0x55, 0x54, 0x55, 0x54, 0x7f, 0x54, 0x0, 0x54, 0x3e, 0x54, 0x0, 0x54, 0x7f, 0x54, 0x8, 0x54, 0x2a, 0x54, 0x2a, 0xdd, 0x4a, 0xb7, 0x19, 0x82 },
+{ 0x95, 0x5b, 0x0, 0x0, 0x7f, 0xff, 0x2, 0x20, 0x3f, 0xfe, 0x22, 0x22, 0x22, 0x22, 0x3f, 0xfe, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x80, 0x8, 0x88, 0x18, 0x8c, 0x70, 0x87, 0x3, 0x80 },
+{ 0x95, 0x5c, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x3, 0x40, 0x6, 0x42, 0x1c, 0x66, 0x74, 0x2c, 0x4, 0x30, 0x4, 0x18, 0x7, 0x8c, 0x3c, 0x7 },
+{ 0x95, 0x5d, 0x0, 0x0, 0x3c, 0xfe, 0x0, 0x10, 0x7e, 0x92, 0x0, 0xd6, 0x3c, 0x54, 0x0, 0x54, 0x0, 0x10, 0x3d, 0xff, 0x0, 0x10, 0x0, 0x10, 0x3c, 0x10, 0x24, 0x10, 0x24, 0x10, 0x24, 0x10, 0x3c, 0x10 },
+{ 0x95, 0x5e, 0x4, 0x40, 0x18, 0x40, 0x65, 0x40, 0x12, 0x7e, 0x4, 0xc2, 0x18, 0x82, 0x65, 0x82, 0x4, 0x62, 0xa, 0x32, 0x12, 0x12, 0x66, 0x2, 0xa, 0x2, 0x12, 0x2, 0x62, 0x6, 0x6, 0x4, 0x1c, 0x1c },
+{ 0x95, 0x5f, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xff, 0x20, 0x0, 0x22, 0x1e, 0x2f, 0xd2, 0x22, 0x12, 0x2f, 0xde, 0x28, 0x52, 0x2f, 0xd2, 0x28, 0x5e, 0x2f, 0xd2, 0x62, 0x12, 0x4f, 0xd2, 0x42, 0x12, 0x2, 0x26 },
+{ 0x95, 0x60, 0x10, 0x88, 0x10, 0x88, 0x17, 0xff, 0x10, 0x88, 0x78, 0x88, 0x10, 0x0, 0x10, 0x0, 0x13, 0xfe, 0x1a, 0x22, 0x72, 0x22, 0x12, 0x22, 0x13, 0xfe, 0x12, 0x22, 0x12, 0x22, 0x12, 0x22, 0x33, 0xfe },
+{ 0x95, 0x61, 0x0, 0x40, 0x0, 0x40, 0x1f, 0xff, 0x50, 0x0, 0x30, 0x0, 0x17, 0xfe, 0x10, 0x40, 0x10, 0x40, 0x37, 0xfe, 0x54, 0x42, 0x14, 0xe2, 0x15, 0xb2, 0x37, 0x1a, 0x24, 0x2, 0x64, 0x2, 0x4, 0xe },
+{ 0x95, 0x62, 0x4, 0x20, 0x1c, 0x20, 0x70, 0x20, 0x10, 0xa8, 0x10, 0xac, 0x7d, 0xa6, 0x13, 0x23, 0x10, 0x20, 0x38, 0x22, 0x34, 0x26, 0x30, 0xe4, 0x50, 0xc, 0x50, 0x18, 0x10, 0x30, 0x10, 0x60, 0x11, 0xc0 },
+{ 0x95, 0x63, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x4, 0x10, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc },
+{ 0x95, 0x64, 0x8, 0x44, 0x1c, 0x44, 0x15, 0xff, 0x32, 0x44, 0x20, 0x44, 0x7e, 0x0, 0x8, 0x0, 0x8, 0xfe, 0x7e, 0x92, 0x8, 0x92, 0x4a, 0x92, 0x6a, 0xfe, 0x28, 0x92, 0xe, 0x92, 0x38, 0x92, 0x60, 0xfe },
+{ 0x95, 0x65, 0x8, 0x4, 0x1c, 0x1c, 0x16, 0x70, 0x32, 0x40, 0x20, 0x40, 0x7e, 0x7e, 0x8, 0x44, 0x8, 0x44, 0x7e, 0x44, 0x8, 0x44, 0x4a, 0xff, 0x6a, 0x0, 0x28, 0x0, 0xe, 0x44, 0x38, 0xc6, 0x61, 0x83 },
+{ 0x95, 0x66, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x0, 0x0, 0x3e, 0x3e, 0x0, 0x0, 0x0, 0x0, 0x7f, 0x7f, 0x8, 0x8, 0x2a, 0x2a, 0x2a, 0x2a, 0x6b, 0x6b, 0x49, 0x49, 0x8, 0x8, 0x18, 0x18 },
+{ 0x95, 0x67, 0x10, 0x0, 0x11, 0xff, 0x10, 0x20, 0x7e, 0x64, 0x52, 0x44, 0x52, 0x5e, 0x52, 0xf2, 0x52, 0x0, 0x7e, 0x10, 0x10, 0x10, 0x10, 0xfe, 0x14, 0x10, 0x1e, 0x10, 0x32, 0x10, 0x61, 0xff, 0x0, 0x0 },
+{ 0x95, 0x68, 0x10, 0x22, 0x1e, 0x26, 0x32, 0xfc, 0x24, 0x28, 0x7f, 0xff, 0x2a, 0x20, 0x2a, 0x46, 0x3f, 0xfc, 0x2a, 0x41, 0x2a, 0x3f, 0x3e, 0x0, 0x0, 0x7e, 0x55, 0x42, 0x55, 0x7e, 0x54, 0x42, 0x40, 0x7e },
+{ 0x95, 0x69, 0x0, 0x0, 0x7, 0xf0, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x7, 0xf0, 0x0, 0x0, 0x3f, 0x7e, 0x21, 0x42, 0x21, 0x42, 0x21, 0x42, 0x21, 0x42, 0x21, 0x42, 0x3f, 0x7e, 0x0, 0x0 },
+{ 0x95, 0x6a, 0x11, 0x4, 0x11, 0xc, 0x11, 0x8, 0x7f, 0xd8, 0x11, 0x32, 0x11, 0x6, 0x33, 0x4, 0x3b, 0x8c, 0x55, 0x58, 0x55, 0x31, 0x11, 0x3, 0x11, 0x2, 0x11, 0x6, 0x11, 0xc, 0x11, 0x18, 0x11, 0x30 },
+{ 0x95, 0x6b, 0x10, 0xa, 0x11, 0xe9, 0x10, 0x9, 0x7c, 0x8, 0xb, 0xff, 0x28, 0x48, 0x28, 0x48, 0x39, 0x48, 0x19, 0x78, 0x11, 0x48, 0x19, 0x4c, 0x39, 0x44, 0x25, 0x44, 0x65, 0x75, 0x41, 0xc7, 0x3, 0x2 },
+{ 0x95, 0x6c, 0x0, 0xc, 0x30, 0x38, 0x19, 0xe0, 0x9, 0x0, 0x1, 0xfe, 0x61, 0x8, 0x31, 0x8, 0x11, 0x8, 0x1, 0x8, 0x9, 0x8, 0xf, 0xff, 0x18, 0x0, 0x11, 0x8, 0x33, 0xc, 0x26, 0x6, 0x6c, 0x3 },
+{ 0x95, 0x6d, 0x1, 0x0, 0x21, 0x3f, 0x35, 0xc8, 0x15, 0x1e, 0x5, 0x12, 0x45, 0x12, 0x6f, 0xde, 0x21, 0x12, 0x5, 0x52, 0x5, 0x3e, 0x29, 0x52, 0x23, 0x52, 0x20, 0x9e, 0x61, 0x8a, 0x43, 0x1b, 0x46, 0x31 },
+{ 0x95, 0x6e, 0x2, 0x20, 0x4, 0x10, 0x1f, 0xfc, 0x71, 0x17, 0x2, 0x10, 0xc, 0x70, 0x38, 0x0, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x4, 0x10, 0x38, 0xe },
+{ 0x95, 0x6f, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x2, 0x2f, 0xfa, 0x4, 0x90, 0x38, 0xae, 0x1, 0xc0, 0xf, 0xf8, 0x78, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x4, 0x10, 0x38, 0xe },
+{ 0x95, 0x70, 0x8, 0x0, 0x28, 0xff, 0x2f, 0x10, 0x28, 0x7e, 0x28, 0x42, 0x7f, 0xc2, 0x8, 0x7e, 0x2a, 0x42, 0x2b, 0x42, 0x69, 0xfe, 0x4a, 0x42, 0x1a, 0x42, 0x6, 0x7e, 0xc, 0x24, 0x18, 0x66, 0x70, 0xc3 },
+{ 0x95, 0x71, 0x10, 0x20, 0x10, 0x20, 0x3f, 0xa0, 0x20, 0x3f, 0x5f, 0x64, 0x15, 0x44, 0x15, 0xc4, 0x15, 0x2c, 0x7f, 0xa8, 0x29, 0x28, 0x29, 0x38, 0x29, 0x10, 0x29, 0x38, 0x3f, 0xac, 0x2, 0x66, 0x6, 0xc3 },
+{ 0x95, 0x72, 0x22, 0x0, 0x36, 0xff, 0x14, 0x40, 0x7f, 0x40, 0x14, 0x40, 0x14, 0x7c, 0x14, 0x44, 0x7f, 0x44, 0x14, 0x64, 0x14, 0x54, 0x14, 0x54, 0x14, 0x44, 0x14, 0x44, 0x34, 0x45, 0x24, 0x75, 0x64, 0xc3 },
+{ 0x95, 0x73, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x40, 0x0, 0xc0, 0x0, 0x80, 0x1, 0xa0, 0x3, 0xb0, 0x6, 0x98, 0xc, 0x8c, 0x18, 0x86, 0x70, 0x83, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80 },
+{ 0x95, 0x74, 0x4, 0x8, 0x4, 0x8, 0xc, 0x8, 0x8, 0x8, 0x1b, 0xff, 0x10, 0x8, 0x30, 0x8, 0x53, 0x8, 0x11, 0x88, 0x10, 0x88, 0x10, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10, 0x38 },
+{ 0x95, 0x75, 0x0, 0x10, 0x10, 0x20, 0x11, 0xfc, 0x11, 0x4, 0x11, 0x4, 0x7d, 0xfc, 0x11, 0x0, 0x11, 0xfc, 0x11, 0x4, 0x11, 0x4, 0x1d, 0xfc, 0x70, 0x20, 0x7, 0xff, 0x0, 0x20, 0x0, 0x20, 0x0, 0x20 },
+{ 0x95, 0x76, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x1, 0x40, 0x3, 0x60, 0x2, 0x20, 0x6, 0x30, 0xc, 0x18, 0x18, 0xc, 0x70, 0x7 },
+{ 0x95, 0x77, 0x10, 0x0, 0x10, 0xfe, 0x10, 0x2, 0x10, 0xfe, 0x7c, 0x2, 0x14, 0xfe, 0x14, 0x0, 0x35, 0xff, 0x25, 0x11, 0x2d, 0x11, 0x28, 0xfe, 0x78, 0x92, 0x14, 0x92, 0x34, 0x92, 0x20, 0x96, 0x60, 0x10 },
+{ 0x95, 0x78, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x2, 0x2f, 0xfa, 0x0, 0x0, 0x7, 0xf0, 0x4, 0x10, 0x7, 0xf0, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc },
+{ 0x95, 0x79, 0x0, 0x0, 0x3f, 0xfe, 0x20, 0x2, 0x2f, 0xfa, 0x0, 0x0, 0x7, 0xf0, 0x4, 0x10, 0x7, 0xf0, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc },
+{ 0x95, 0x7a, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x7f, 0xff, 0x2, 0x0, 0x6, 0x40, 0x4, 0x40, 0xf, 0xfe, 0x1c, 0x42, 0x34, 0x42, 0x64, 0x42, 0x4, 0x42, 0x4, 0x42, 0x4, 0x4e, 0x0, 0x40, 0x0, 0x40 },
+{ 0x95, 0x7b, 0x0, 0x40, 0x0, 0x40, 0x1f, 0xff, 0x10, 0x0, 0x11, 0x4, 0x11, 0x4, 0x13, 0xff, 0x12, 0x4, 0x16, 0x44, 0x1a, 0x64, 0x12, 0x24, 0x12, 0x4, 0x32, 0x4, 0x22, 0x4, 0x62, 0x4, 0x2, 0x1c },
+{ 0x95, 0x7c, 0x10, 0x40, 0x10, 0x40, 0x10, 0x40, 0x53, 0xff, 0x58, 0x40, 0x54, 0xd0, 0x50, 0x90, 0x11, 0xff, 0x13, 0x91, 0x16, 0x91, 0x10, 0x91, 0x10, 0x91, 0x10, 0x91, 0x10, 0x93, 0x10, 0x10, 0x10, 0x10 },
+{ 0x95, 0x7d, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x13, 0xfe, 0x78, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x1b, 0xff, 0x70, 0x50, 0x10, 0x50, 0x10, 0xd8, 0x10, 0x88, 0x11, 0x8c, 0x13, 0x6, 0x36, 0x3 },
+{ 0x95, 0x7e, 0x5, 0x10, 0x4, 0x90, 0x7f, 0xd0, 0x4, 0x3f, 0x3f, 0xa2, 0x24, 0xe2, 0x3f, 0x92, 0x24, 0x96, 0x3f, 0x94, 0x4, 0x1c, 0x7f, 0xc8, 0x8, 0x8, 0xf, 0x9c, 0x18, 0x94, 0x31, 0xb6, 0x67, 0x63 },
+{ 0x95, 0x80, 0x2, 0x40, 0x6, 0x60, 0xc, 0x38, 0x3b, 0x6e, 0x1, 0xc0, 0x3, 0x60, 0xe, 0x38, 0x78, 0xef, 0xf, 0x80, 0x8, 0x0, 0xf, 0xff, 0x8, 0x40, 0x18, 0x40, 0x30, 0x40, 0x60, 0x40, 0x0, 0x40 },
+{ 0x95, 0x81, 0x4, 0x10, 0x6, 0x30, 0x2, 0x20, 0x3f, 0xfe, 0x2, 0x20, 0x12, 0x24, 0x1a, 0x2c, 0xa, 0x28, 0x7f, 0xff, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8 },
+{ 0x95, 0x82, 0x0, 0xc, 0x20, 0x38, 0x37, 0xe2, 0x12, 0x46, 0x3, 0x6c, 0x41, 0x28, 0x63, 0xfe, 0x20, 0x4, 0x0, 0x18, 0x10, 0x20, 0x17, 0xff, 0x10, 0x20, 0x30, 0x20, 0x20, 0x20, 0x60, 0x20, 0x40, 0xe0 },
+{ 0x95, 0x83, 0x2, 0x20, 0x2, 0x20, 0x6, 0x30, 0xc, 0x18, 0x18, 0xc, 0x74, 0x17, 0x4, 0x10, 0x6, 0x30, 0x2, 0x20, 0x3, 0x60, 0x1, 0x40, 0x0, 0x80, 0x1, 0xc0, 0x3, 0x60, 0xe, 0x38, 0x78, 0xf },
+{ 0x95, 0x84, 0x8, 0x20, 0x8, 0x20, 0x1f, 0x7f, 0x34, 0x50, 0x62, 0x88, 0x0, 0x0, 0x4, 0x8, 0xc, 0x8, 0x1b, 0xff, 0x38, 0x8, 0x69, 0x88, 0x8, 0xc8, 0x8, 0x48, 0x8, 0x8, 0x8, 0x8, 0x8, 0x38 },
+{ 0x95, 0x85, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xff, 0x24, 0x8, 0x2d, 0xff, 0x38, 0x88, 0x28, 0x48, 0x28, 0x18, 0x20, 0x80, 0x2f, 0xfc, 0x29, 0x44, 0x2a, 0x24, 0x68, 0x84, 0x49, 0x44, 0x4a, 0x24, 0x8, 0xc },
+{ 0x95, 0x86, 0x0, 0x80, 0x0, 0xfc, 0x0, 0x80, 0x3f, 0xff, 0x20, 0x81, 0x2f, 0xfc, 0x20, 0x81, 0x2f, 0xff, 0x28, 0x42, 0x2f, 0xfe, 0x28, 0x42, 0x2f, 0xfe, 0x64, 0x4, 0x47, 0xfc, 0x44, 0x4, 0x4, 0xc },
+{ 0x95, 0x87, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x4, 0x10, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x1, 0x40, 0x3, 0x60, 0x6, 0x30, 0x1c, 0x1c, 0x70, 0x7 },
+{ 0x95, 0x88, 0x0, 0x44, 0x3c, 0x6c, 0x0, 0x28, 0x7e, 0xff, 0x0, 0x28, 0x3c, 0xaa, 0x0, 0x6c, 0x0, 0x28, 0x3d, 0xff, 0x0, 0x0, 0x0, 0x7c, 0x3c, 0x44, 0x24, 0x7c, 0x24, 0x44, 0x24, 0x44, 0x3c, 0x7c },
+{ 0x95, 0x89, 0x2, 0x0, 0x7, 0xf0, 0xc, 0x20, 0x38, 0x40, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x4, 0x10, 0x38, 0xe },
+{ 0x95, 0x8a, 0x0, 0xa, 0x3c, 0xe9, 0x24, 0x9, 0x24, 0x8, 0x3d, 0xff, 0x24, 0x28, 0x24, 0x28, 0x24, 0xa8, 0x3c, 0xb8, 0x24, 0xa8, 0x24, 0xac, 0x24, 0xa4, 0x3c, 0xa4, 0x14, 0xf5, 0x37, 0x87, 0x62, 0x2 },
+{ 0x95, 0x8b, 0x4, 0x10, 0x4, 0x10, 0x3f, 0x90, 0x4, 0x10, 0x4, 0x10, 0x4, 0x1c, 0x7f, 0xd6, 0x4, 0x13, 0x4, 0x11, 0x17, 0x90, 0x14, 0x10, 0x14, 0x10, 0x14, 0x10, 0x3c, 0x10, 0x27, 0x0, 0x61, 0xff },
+{ 0x95, 0x8c, 0x0, 0x40, 0x0, 0x80, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x0, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80 },
+{ 0x95, 0x8d, 0x0, 0x44, 0x3e, 0x44, 0x22, 0x44, 0x26, 0xc4, 0x24, 0xbf, 0x2c, 0x84, 0x29, 0x84, 0x2a, 0xa4, 0x24, 0xb4, 0x24, 0x94, 0x24, 0x84, 0x24, 0x84, 0x2c, 0x84, 0x20, 0x84, 0x20, 0x84, 0x20, 0x9c },
+{ 0x95, 0x8e, 0x9, 0x0, 0x9, 0x0, 0x1b, 0xff, 0x12, 0x0, 0x36, 0x0, 0x31, 0xfc, 0x51, 0x24, 0x11, 0x24, 0x11, 0x24, 0x1f, 0xff, 0x12, 0x44, 0x12, 0x44, 0x12, 0x44, 0x13, 0xff, 0x10, 0x8, 0x10, 0x38 },
+{ 0x95, 0x8f, 0x11, 0x0, 0x11, 0x0, 0x13, 0xff, 0x17, 0x54, 0x79, 0x54, 0x11, 0x54, 0x17, 0xff, 0x11, 0x54, 0x19, 0x54, 0x71, 0x54, 0x17, 0xff, 0x10, 0x0, 0x10, 0x0, 0x11, 0x54, 0x13, 0x56, 0x36, 0x53 },
+{ 0x95, 0x90, 0x0, 0x14, 0x1f, 0x16, 0x0, 0x12, 0x0, 0x10, 0x7f, 0xff, 0x0, 0x10, 0x2, 0x10, 0x12, 0x10, 0x13, 0xd0, 0x12, 0x18, 0x12, 0x8, 0x12, 0x8, 0x13, 0xcc, 0x1e, 0x5, 0x70, 0x7, 0x0, 0x2 },
+{ 0x95, 0x91, 0x10, 0x0, 0x10, 0x0, 0x3f, 0xfe, 0x6a, 0x48, 0xa, 0x48, 0x7f, 0xff, 0xa, 0x48, 0xa, 0x48, 0x3f, 0xfe, 0x8, 0x4, 0x1f, 0x7e, 0x31, 0x24, 0x6b, 0x24, 0x6, 0xff, 0x1c, 0x4, 0x70, 0x4 },
+{ 0x95, 0x92, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x8, 0x0, 0x1f, 0xfe, 0x30, 0x82, 0x62, 0x42, 0x3f, 0xf2, 0x2, 0x2, 0x1f, 0xe2, 0x12, 0x22, 0x1f, 0xe2, 0x12, 0x22, 0x1f, 0xe6, 0x12, 0x24, 0x12, 0x6c },
+{ 0x95, 0x93, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x10, 0x0, 0x3f, 0xfe, 0x6a, 0x48, 0xa, 0x48, 0x7f, 0xff, 0xa, 0x48, 0xa, 0x48, 0x3f, 0xfe, 0x0, 0x0, 0x12, 0x22, 0x33, 0x33, 0x61, 0x11 },
+{ 0x95, 0x94, 0x8, 0x0, 0x8, 0x3f, 0x7f, 0xa1, 0x21, 0x23, 0x33, 0x22, 0x12, 0x24, 0x12, 0x24, 0x7f, 0xa2, 0x0, 0x21, 0x0, 0x21, 0x3f, 0x21, 0x21, 0x21, 0x21, 0x23, 0x21, 0x20, 0x21, 0x20, 0x3f, 0x20 },
+{ 0x95, 0x95, 0x4, 0x2, 0x4, 0x2, 0x3f, 0x82, 0x4, 0x2, 0x4, 0x3f, 0x7f, 0xc2, 0x0, 0x2, 0x4, 0x22, 0x4, 0x32, 0x3f, 0x92, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x7, 0x82, 0x1c, 0x2, 0x70, 0xe },
+{ 0x95, 0x96, 0x10, 0x0, 0x17, 0xfc, 0x14, 0x4, 0x7c, 0x34, 0x15, 0xe4, 0x14, 0x44, 0x3d, 0xf4, 0x35, 0x54, 0x55, 0x54, 0x55, 0xf4, 0x14, 0x44, 0x14, 0x44, 0x14, 0x54, 0x14, 0x75, 0x15, 0xd5, 0x18, 0x3 },
+{ 0x95, 0x97, 0x0, 0x0, 0x1f, 0xf8, 0x10, 0x8, 0x10, 0xe8, 0x17, 0x88, 0x11, 0x8, 0x17, 0xe8, 0x15, 0x28, 0x15, 0x28, 0x17, 0xe8, 0x11, 0x8, 0x11, 0x8, 0x11, 0x2c, 0x33, 0xf5, 0x2e, 0x17, 0x60, 0x2 },
+{ 0x95, 0x98, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x0, 0x0, 0x7f, 0xff, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0xf, 0xf, 0xf8, 0x78, 0x8, 0x0, 0x8 },
+{ 0x95, 0x99, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x0, 0x40, 0x3e, 0x7c, 0x22, 0xc4, 0x22, 0xa8, 0x3e, 0x10, 0x8, 0x6c, 0x2e, 0xc7, 0x28, 0x0, 0x28, 0x7e, 0x2e, 0x42, 0x38, 0x42, 0x60, 0x7e },
+{ 0x95, 0x9a, 0x4, 0x20, 0x4, 0x2c, 0xc, 0x26, 0x8, 0x22, 0x18, 0x20, 0x17, 0xff, 0x30, 0x20, 0x50, 0x20, 0x10, 0x70, 0x10, 0x50, 0x10, 0x58, 0x10, 0xc8, 0x10, 0x8c, 0x11, 0x84, 0x13, 0x6, 0x16, 0x3 },
+{ 0x95, 0x9b, 0x0, 0x2, 0x7f, 0xd2, 0x0, 0x12, 0x1f, 0x12, 0x11, 0x12, 0x11, 0x12, 0x1f, 0x12, 0x0, 0x12, 0x0, 0x12, 0x3f, 0x92, 0x24, 0x92, 0x24, 0x82, 0x3f, 0x82, 0x24, 0x82, 0x24, 0x82, 0x3f, 0x8e },
+{ 0x95, 0x9c, 0x9, 0x0, 0x19, 0x0, 0x13, 0xfe, 0x36, 0x0, 0x61, 0xfc, 0x9, 0x4, 0x19, 0xfc, 0x11, 0x4, 0x31, 0xfc, 0x70, 0x80, 0x11, 0xf8, 0x13, 0x8, 0x16, 0xd8, 0x10, 0x70, 0x11, 0xdc, 0x17, 0x7 },
+{ 0x95, 0x9d, 0x10, 0x0, 0x11, 0xff, 0x10, 0x0, 0x7c, 0xfe, 0x54, 0x82, 0x54, 0x82, 0x54, 0xfe, 0x54, 0x0, 0x54, 0x0, 0x55, 0xff, 0x5d, 0x11, 0x11, 0x11, 0x11, 0xff, 0x11, 0x11, 0x11, 0x11, 0x11, 0xff },
+{ 0x95, 0x9e, 0x0, 0x0, 0x3e, 0xfe, 0x22, 0x82, 0x22, 0x82, 0x22, 0x86, 0x3e, 0x80, 0x22, 0x80, 0x22, 0xfe, 0x22, 0xa2, 0x3e, 0xb6, 0x22, 0x94, 0x22, 0x9c, 0x22, 0x88, 0x22, 0x9c, 0x62, 0x96, 0x46, 0xb3 },
+{ 0x95, 0x9f, 0x10, 0x0, 0x11, 0xff, 0x10, 0x0, 0x7c, 0xfe, 0x4, 0x82, 0xc, 0x82, 0x8, 0xfe, 0x18, 0x0, 0x10, 0x0, 0x3d, 0xff, 0x57, 0x11, 0x11, 0x11, 0x11, 0xff, 0x11, 0x11, 0x11, 0x11, 0x11, 0xff },
+{ 0x95, 0xa0, 0x0, 0x40, 0x3c, 0x40, 0x24, 0xff, 0x25, 0x80, 0x24, 0x7e, 0x3c, 0x42, 0x24, 0x7e, 0x24, 0x42, 0x24, 0x7e, 0x3c, 0x20, 0x24, 0x7e, 0x24, 0xc2, 0x25, 0xa6, 0x24, 0x18, 0x64, 0x6c, 0x4d, 0xc7 },
+{ 0x95, 0xa1, 0x10, 0x80, 0x10, 0x80, 0x11, 0xff, 0x7d, 0x0, 0x7, 0xfc, 0xc, 0x84, 0x8, 0xfc, 0x1a, 0x84, 0x14, 0xfc, 0x38, 0x40, 0x54, 0xfc, 0x11, 0x84, 0x13, 0x6c, 0x10, 0x38, 0x10, 0x6c, 0x11, 0xc7 },
+{ 0x95, 0xa2, 0x7f, 0xff, 0x2, 0x20, 0x3f, 0xfe, 0x22, 0x22, 0x3f, 0xfe, 0x9, 0x0, 0x1b, 0xff, 0x36, 0x84, 0x68, 0xfc, 0x18, 0x84, 0x30, 0xfc, 0x70, 0x40, 0x10, 0xfe, 0x13, 0x84, 0x10, 0x78, 0x13, 0xcf },
+{ 0x95, 0xa3, 0x2, 0x2, 0x32, 0x52, 0x1a, 0x52, 0xa, 0x52, 0x3, 0xde, 0x62, 0x2, 0x32, 0x2, 0x13, 0xfe, 0x2, 0x2, 0xa, 0x2, 0xb, 0xde, 0x1a, 0x52, 0x12, 0x52, 0x36, 0x52, 0x24, 0x52, 0x6c, 0x2 },
+{ 0x95, 0xa4, 0x2, 0x20, 0x2, 0x20, 0x7f, 0xfe, 0x2, 0x22, 0x2, 0x22, 0x3f, 0xfe, 0x22, 0x20, 0x22, 0x20, 0x3f, 0xff, 0x2, 0x21, 0x2, 0x21, 0x6, 0x23, 0x4, 0x22, 0xc, 0x2e, 0x18, 0x20, 0x70, 0x20 },
+{ 0x95, 0xa5, 0x10, 0x40, 0x10, 0x40, 0x10, 0x40, 0x10, 0x40, 0x7c, 0xc0, 0x10, 0x80, 0x10, 0x80, 0x10, 0x80, 0x1c, 0x80, 0x70, 0x84, 0x11, 0x84, 0x11, 0x6, 0x11, 0x2, 0x11, 0x3e, 0x13, 0xe3, 0x76, 0x1 },
+{ 0x95, 0xa6, 0x0, 0x90, 0x20, 0x90, 0x37, 0xfe, 0x10, 0x92, 0x0, 0x92, 0x47, 0xfe, 0x64, 0x90, 0x24, 0x90, 0x4, 0x90, 0x17, 0xff, 0x10, 0x91, 0x10, 0x91, 0x31, 0x93, 0x21, 0x12, 0x23, 0x16, 0x66, 0x10 },
+{ 0x95, 0xa7, 0x4, 0x40, 0x4, 0x40, 0xc, 0x40, 0x8, 0x40, 0x18, 0xc0, 0x10, 0x80, 0x30, 0x80, 0x50, 0x80, 0x10, 0x80, 0x10, 0x84, 0x11, 0x84, 0x11, 0x6, 0x11, 0x2, 0x11, 0x3e, 0x13, 0xe3, 0x16, 0x1 },
+{ 0x95, 0xa8, 0x8, 0x80, 0x28, 0x80, 0x28, 0x80, 0x28, 0xff, 0x7e, 0xa9, 0x49, 0xa9, 0x9, 0x29, 0x8, 0x29, 0x8, 0x69, 0xe, 0x49, 0x78, 0xd9, 0x9, 0x91, 0x8, 0x31, 0x8, 0x21, 0x8, 0x63, 0x8, 0xe },
+{ 0x95, 0xa9, 0x20, 0x44, 0x3c, 0x44, 0x24, 0x44, 0x48, 0xc4, 0x7c, 0xbf, 0x55, 0x84, 0x55, 0xa4, 0x7e, 0xb4, 0x54, 0x94, 0x54, 0x94, 0x7c, 0x84, 0x0, 0x84, 0x55, 0x84, 0x55, 0x84, 0x54, 0x84, 0x40, 0x9c },
+{ 0x95, 0xaa, 0x2, 0x20, 0x2, 0x20, 0x6, 0x30, 0x4, 0x10, 0xc, 0x18, 0x18, 0xc, 0x30, 0x6, 0x6f, 0xfb, 0x1, 0x8, 0x1, 0x8, 0x1, 0x8, 0x3, 0x8, 0x2, 0x8, 0x6, 0x18, 0xc, 0x10, 0x38, 0x70 },
+{ 0x95, 0xab, 0x1, 0x0, 0x1, 0x0, 0x79, 0x0, 0x49, 0xff, 0x49, 0x49, 0x4b, 0x49, 0x4a, 0x49, 0x4e, 0x49, 0x48, 0xc9, 0x48, 0x99, 0x49, 0x91, 0x7b, 0x31, 0x6, 0x21, 0x0, 0x63, 0x0, 0xc2, 0x0, 0xe },
+{ 0x95, 0xac, 0x0, 0x20, 0x3, 0xfe, 0x78, 0x20, 0x49, 0x4, 0x4f, 0xff, 0x49, 0x4, 0x48, 0x0, 0x4b, 0xfe, 0x4a, 0x2, 0x4b, 0xfe, 0x7a, 0x2, 0x3, 0xfe, 0x2, 0x2, 0x3, 0xfe, 0x1, 0x4, 0x6, 0x3 },
+{ 0x95, 0xad, 0x10, 0x20, 0x11, 0xfe, 0x10, 0x20, 0x10, 0x84, 0x13, 0xff, 0x7c, 0x84, 0x10, 0x0, 0x11, 0xfe, 0x11, 0x2, 0x11, 0xfe, 0x11, 0x2, 0x1d, 0xfe, 0x71, 0x2, 0x1, 0xfe, 0x0, 0x84, 0x3, 0x3 },
+{ 0x95, 0xae, 0x10, 0x20, 0x13, 0xfe, 0x10, 0x20, 0x11, 0x4, 0x17, 0xff, 0x59, 0x4, 0x54, 0x0, 0x53, 0xfe, 0x52, 0x2, 0x13, 0xfe, 0x12, 0x2, 0x13, 0xfe, 0x12, 0x2, 0x13, 0xfe, 0x11, 0x4, 0x16, 0x3 },
+{ 0x95, 0xaf, 0x10, 0x88, 0x10, 0x88, 0x10, 0x88, 0x11, 0x8c, 0x79, 0x4, 0x13, 0x6, 0x16, 0x3, 0x11, 0xfc, 0x18, 0x44, 0x70, 0x44, 0x10, 0x44, 0x10, 0xc4, 0x10, 0x84, 0x11, 0x8c, 0x13, 0x8, 0x36, 0x38 },
+{ 0x95, 0xb0, 0x4, 0x10, 0x4, 0x10, 0x7f, 0x7f, 0x4, 0x10, 0xe, 0x38, 0x15, 0x54, 0x34, 0x96, 0x64, 0x13, 0x0, 0x80, 0x8, 0x84, 0x18, 0x8c, 0x31, 0xd8, 0x3, 0x60, 0x6, 0x30, 0x1c, 0x1c, 0x70, 0x7 },
+{ 0x95, 0xb1, 0x0, 0x80, 0x7f, 0xff, 0x2, 0x20, 0xd, 0x58, 0x72, 0x87, 0xf, 0xf8, 0x38, 0x80, 0xf, 0xf8, 0x8, 0x80, 0xf, 0xf8, 0x8, 0x80, 0x1f, 0xfe, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x84, 0x1f, 0xfc },
+{ 0x95, 0xb2, 0x10, 0x48, 0x54, 0x48, 0x54, 0x48, 0x54, 0xcc, 0x10, 0x84, 0x7d, 0x86, 0x13, 0x3, 0x10, 0xfc, 0x38, 0x24, 0x34, 0x24, 0x34, 0x24, 0x50, 0x64, 0x50, 0x44, 0x10, 0xcc, 0x11, 0x88, 0x13, 0x38 },
+{ 0x95, 0xb3, 0x10, 0x84, 0x8, 0x88, 0x7f, 0xff, 0x2, 0xa0, 0x4, 0x90, 0x1f, 0xfc, 0x68, 0x8b, 0xf, 0xf8, 0x8, 0x88, 0xf, 0xf8, 0x2, 0x20, 0x3f, 0xfe, 0x2, 0x20, 0x7f, 0xff, 0x8, 0x8, 0x30, 0x6 },
+{ 0x95, 0xb4, 0x8, 0x48, 0x18, 0x48, 0x10, 0x48, 0x64, 0xcc, 0x2c, 0x84, 0x19, 0x86, 0x13, 0x3, 0x24, 0xfc, 0x7c, 0x24, 0x14, 0x24, 0x10, 0x24, 0x54, 0x64, 0x54, 0x44, 0x54, 0xcc, 0x11, 0x88, 0x13, 0x38 },
+{ 0x95, 0xb5, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x82, 0x2e, 0xba, 0x20, 0x82, 0x2e, 0xba, 0x0, 0x80, 0x2, 0x20, 0x4, 0x10, 0x1f, 0xfc, 0x71, 0xb, 0x3, 0x8, 0xe, 0x8, 0x38, 0x38 },
+{ 0x95, 0xb6, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x4, 0x10, 0x4, 0x10, 0x6, 0x30, 0x2, 0x20, 0x3, 0x60, 0x1, 0x40, 0x0, 0x80, 0x1, 0xc0, 0x3, 0x60, 0x6, 0x30, 0x1c, 0x1c, 0x70, 0x7 },
+{ 0x95, 0xb7, 0x0, 0x0, 0x3f, 0x7e, 0x21, 0x42, 0x3f, 0x7e, 0x21, 0x42, 0x3f, 0x7e, 0x20, 0x2, 0x2f, 0xfa, 0x22, 0x22, 0x23, 0xe2, 0x22, 0x22, 0x23, 0xe2, 0x22, 0x22, 0x23, 0xe2, 0x2e, 0x22, 0x20, 0x2e },
+{ 0x95, 0xb8, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xfc, 0x10, 0x84, 0x11, 0xc4, 0x11, 0x44, 0x13, 0x64, 0x16, 0x34, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x1c },
+{ 0x95, 0xb9, 0x5, 0x4, 0x5, 0x8c, 0xc, 0x88, 0xb, 0xfe, 0x18, 0x88, 0x10, 0x88, 0x30, 0x88, 0x50, 0x88, 0x17, 0xff, 0x10, 0x88, 0x10, 0x88, 0x10, 0x88, 0x11, 0x88, 0x11, 0x8, 0x13, 0x8, 0x16, 0x8 },
+{ 0x95, 0xba, 0x0, 0x18, 0x0, 0xf0, 0x7, 0x80, 0x4, 0x0, 0x7, 0xfc, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x0, 0x0, 0x4, 0x10, 0xc, 0x18, 0x18, 0xc, 0x30, 0x6 },
+{ 0x95, 0xbb, 0x10, 0x0, 0x13, 0xfe, 0x12, 0x2, 0x12, 0x2, 0x7f, 0xfe, 0x12, 0x84, 0x12, 0x48, 0x13, 0xfe, 0x12, 0x48, 0x12, 0x48, 0x1f, 0xff, 0x72, 0x48, 0x6, 0xc8, 0x4, 0x88, 0xd, 0x88, 0x3, 0x8 },
+{ 0x95, 0xbc, 0x24, 0x90, 0x35, 0x90, 0x15, 0x3f, 0x3f, 0xa2, 0x24, 0xf6, 0x2e, 0x9c, 0x35, 0x88, 0x24, 0x9e, 0x25, 0xb3, 0x0, 0x0, 0x0, 0x80, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x10, 0x9c, 0x0, 0x80 },
+{ 0x95, 0xbd, 0x0, 0x0, 0x3f, 0xfe, 0x0, 0x80, 0x10, 0x84, 0x18, 0x8c, 0xc, 0x98, 0x4, 0x90, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80 },
+{ 0x95, 0xbe, 0x24, 0x90, 0x35, 0x90, 0x15, 0x3f, 0x3f, 0xa2, 0x24, 0xf6, 0x2e, 0x9c, 0x35, 0x88, 0x24, 0x9e, 0x25, 0xb3, 0x0, 0x0, 0x2, 0x10, 0x7f, 0xff, 0x2, 0x10, 0x6, 0x10, 0xc, 0x10, 0x38, 0x10 },
+{ 0x95, 0xbf, 0x10, 0x0, 0x17, 0xff, 0x10, 0x20, 0x7c, 0x20, 0x13, 0xfe, 0x12, 0x22, 0x3a, 0x22, 0x36, 0x72, 0x32, 0x52, 0x52, 0xda, 0x52, 0x8a, 0x12, 0x2, 0x12, 0x2, 0x12, 0x2, 0x12, 0x2, 0x12, 0xe },
+{ 0x95, 0xc0, 0x8, 0x8, 0xc, 0x18, 0x6, 0x30, 0x2, 0x20, 0x3f, 0xfe, 0x2, 0x20, 0x2, 0x20, 0x22, 0x22, 0x22, 0x22, 0x32, 0x26, 0x12, 0x24, 0x12, 0x24, 0x2, 0x20, 0x2, 0x20, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x95, 0xc1, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x0, 0x0, 0x24, 0x90, 0x35, 0x90, 0x15, 0x3f, 0x3f, 0xa2, 0x24, 0xe6, 0x24, 0x94, 0x2e, 0x9c, 0x35, 0x88, 0x24, 0x9c, 0x24, 0x96, 0x25, 0xb3 },
+{ 0x95, 0xc2, 0x0, 0x0, 0x3f, 0x7e, 0x21, 0x42, 0x3f, 0x7e, 0x21, 0x42, 0x3f, 0x7e, 0x20, 0x2, 0x20, 0x42, 0x20, 0x42, 0x27, 0xf2, 0x20, 0xc2, 0x21, 0x42, 0x23, 0x42, 0x26, 0x42, 0x20, 0xc2, 0x20, 0xe },
+{ 0x95, 0xc3, 0x1, 0x10, 0x3d, 0x10, 0x25, 0x16, 0x25, 0xdc, 0x2d, 0x10, 0x29, 0x10, 0x29, 0x11, 0x25, 0xcf, 0x27, 0x0, 0x24, 0x20, 0x24, 0x20, 0x2d, 0xfe, 0x20, 0x20, 0x20, 0x20, 0x23, 0xff, 0x20, 0x0 },
+{ 0x95, 0xc4, 0x0, 0x80, 0x10, 0x84, 0x18, 0x8c, 0xc, 0x98, 0x4, 0x90, 0x0, 0x80, 0x7f, 0xff, 0x2, 0xa0, 0x6, 0xb0, 0x4, 0x90, 0xc, 0x98, 0x18, 0x8c, 0x30, 0x86, 0x60, 0x83, 0x0, 0x80, 0x0, 0x80 },
+{ 0x95, 0xc5, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x80, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x4, 0x10, 0xc, 0x18, 0x38, 0xe },
+{ 0x95, 0xc6, 0x8, 0x8, 0xb, 0x88, 0xa, 0xbe, 0x1a, 0x80, 0x12, 0xa2, 0x32, 0xb6, 0x33, 0x94, 0x52, 0x7f, 0x12, 0x8, 0x13, 0x88, 0x16, 0xbe, 0x16, 0x88, 0x1a, 0x88, 0x12, 0x88, 0x13, 0x88, 0x10, 0x8 },
+{ 0x95, 0xc7, 0x0, 0x8, 0x1f, 0x8, 0x11, 0x7f, 0x11, 0x22, 0x1f, 0x14, 0x10, 0x7f, 0x3f, 0x8, 0x29, 0x7f, 0x69, 0x8, 0xf, 0x8, 0x0, 0x0, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x95, 0xc8, 0x0, 0x40, 0x0, 0x40, 0x1f, 0xff, 0x50, 0x8, 0x37, 0x88, 0x14, 0xbe, 0x14, 0x80, 0x17, 0xa2, 0x34, 0x14, 0x54, 0x3e, 0x17, 0x88, 0x34, 0x88, 0x2c, 0xbe, 0x6c, 0x88, 0x17, 0x88, 0x0, 0x8 },
+{ 0x95, 0xc9, 0x0, 0x10, 0x7f, 0x20, 0x8, 0xfe, 0x8, 0x82, 0x3e, 0x82, 0x8, 0xfe, 0x8, 0x82, 0xf, 0x82, 0x78, 0xfe, 0x0, 0x0, 0x7f, 0xff, 0x1, 0x0, 0x7, 0xfc, 0x7c, 0x4, 0x4, 0x4, 0x7, 0xfc },
+{ 0x95, 0xca, 0x0, 0x2, 0x3f, 0xa2, 0x20, 0xa2, 0x20, 0xa2, 0x20, 0xa2, 0x3f, 0xa2, 0x8, 0x22, 0x8, 0x22, 0xf, 0xa2, 0x8, 0xa2, 0x8, 0xa2, 0x8, 0x82, 0x18, 0x82, 0x11, 0x82, 0x31, 0x2, 0x67, 0xe },
+{ 0x95, 0xcb, 0x24, 0x90, 0x15, 0x1f, 0x3f, 0xb2, 0x24, 0xe2, 0x2e, 0x94, 0x35, 0x88, 0x24, 0x9c, 0x25, 0xb7, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8 },
+{ 0x95, 0xcc, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x1f, 0xfc, 0x12, 0x44, 0x12, 0x44, 0x1f, 0xfc, 0x0, 0x22, 0x1f, 0xff, 0x10, 0x20, 0x17, 0x34, 0x11, 0x9c, 0x30, 0x39, 0x20, 0xed, 0x63, 0x87 },
+{ 0x95, 0xcd, 0x10, 0x20, 0x10, 0x20, 0x3f, 0x7f, 0x68, 0xd0, 0x4, 0x8, 0x1f, 0xfc, 0x10, 0x84, 0x11, 0x44, 0x16, 0x34, 0x0, 0x0, 0x10, 0x46, 0x1f, 0x5c, 0x10, 0x70, 0x10, 0x41, 0x1f, 0x63, 0x70, 0x3e },
+{ 0x95, 0xce, 0x8, 0x0, 0xf, 0xff, 0x8, 0x0, 0x1b, 0xfc, 0x12, 0x4, 0x32, 0x4, 0x33, 0xfc, 0x52, 0x0, 0x13, 0xfe, 0x12, 0x52, 0x16, 0x52, 0x17, 0xfe, 0x1a, 0x52, 0x12, 0x52, 0x12, 0x52, 0x12, 0x56 },
+{ 0x95, 0xcf, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x2, 0x20, 0x12, 0x24, 0x32, 0x26, 0x66, 0x23, 0xc, 0x20, 0x2, 0x0, 0x3, 0xf8, 0x6, 0x10, 0xc, 0x30, 0x3b, 0x60, 0x1, 0xc0, 0xf, 0x78, 0x78, 0xf },
+{ 0x95, 0xd0, 0x8, 0x40, 0x8, 0x40, 0x8, 0x40, 0x8, 0x40, 0xf, 0xff, 0x8, 0x0, 0x8, 0x0, 0x8, 0x0, 0xf, 0xf0, 0x8, 0x10, 0x8, 0x10, 0x18, 0x10, 0x10, 0x10, 0x30, 0x10, 0x60, 0x10, 0x0, 0x10 },
+{ 0x95, 0xd1, 0x10, 0x20, 0x10, 0x20, 0x3f, 0x7f, 0x68, 0xd0, 0x4, 0x8, 0x7f, 0xff, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x4, 0x1f, 0xfc, 0x10, 0x0, 0x3f, 0xfe, 0x31, 0x22, 0x5f, 0xfe, 0x11, 0x22, 0x11, 0x26 },
+{ 0x95, 0xd2, 0x8, 0x0, 0x19, 0xff, 0x10, 0x0, 0x64, 0xfe, 0x2c, 0x82, 0x18, 0x82, 0x10, 0xfe, 0x24, 0x80, 0x7e, 0xfe, 0x12, 0xaa, 0x10, 0xaa, 0x55, 0xfe, 0x55, 0xaa, 0x52, 0xaa, 0x10, 0xaa, 0x10, 0x86 },
+{ 0x95, 0xd3, 0x0, 0x0, 0x30, 0x0, 0x1b, 0xfe, 0x8, 0x42, 0x0, 0x42, 0x0, 0x42, 0x0, 0x42, 0x78, 0x42, 0x8, 0x42, 0x8, 0xc2, 0x8, 0x86, 0x9, 0x84, 0xb, 0x1c, 0x18, 0x0, 0x34, 0x0, 0x63, 0xff },
+{ 0x95, 0xd4, 0x0, 0x0, 0x31, 0xfe, 0x19, 0x0, 0x9, 0x0, 0x1, 0x0, 0x1, 0xfc, 0x1, 0x44, 0x79, 0x44, 0x9, 0x6c, 0xb, 0x28, 0xa, 0x10, 0xe, 0x38, 0x8, 0x6c, 0x19, 0xc7, 0x34, 0x0, 0x63, 0xff },
+{ 0x95, 0xd5, 0x0, 0x0, 0x33, 0xfe, 0x18, 0x0, 0x9, 0xfc, 0x1, 0x4, 0x1, 0xfc, 0x1, 0x0, 0x79, 0xfe, 0x9, 0xaa, 0xb, 0xaa, 0xa, 0xfe, 0xe, 0xaa, 0x8, 0xaa, 0x18, 0xae, 0x34, 0x0, 0x63, 0xff },
+{ 0x95, 0xd6, 0x8, 0x0, 0xf, 0xff, 0x18, 0x20, 0x13, 0xfe, 0x12, 0x22, 0x32, 0x22, 0x33, 0xfe, 0x52, 0x22, 0x12, 0x22, 0x13, 0xfe, 0x10, 0x20, 0x12, 0x60, 0x11, 0x40, 0x10, 0xe0, 0x11, 0xb8, 0x17, 0xf },
+{ 0x95, 0xd7, 0x10, 0x10, 0x1f, 0x10, 0x11, 0x10, 0x33, 0x7e, 0x22, 0x12, 0x7f, 0x92, 0x24, 0x92, 0x24, 0x92, 0x24, 0x92, 0x3f, 0xb2, 0xa, 0x26, 0xa, 0x64, 0x1a, 0xdc, 0x12, 0x1, 0x33, 0x3, 0x61, 0xfe },
+{ 0x95, 0xd8, 0x8, 0x40, 0x8, 0x7c, 0x8, 0x44, 0x8, 0xcc, 0x7e, 0x88, 0x13, 0xfe, 0x12, 0x92, 0x12, 0x92, 0x32, 0x92, 0x26, 0xfe, 0x24, 0x48, 0x7c, 0x48, 0xa, 0xc8, 0x1a, 0x89, 0x31, 0x89, 0x63, 0x7 },
+{ 0x95, 0xd9, 0x2, 0x0, 0x2, 0x10, 0x6, 0x10, 0x4, 0xf8, 0xf, 0x8c, 0x38, 0x6, 0x2, 0x20, 0x2, 0x20, 0x7f, 0xff, 0x2, 0x20, 0x2, 0x20, 0x6, 0x20, 0x4, 0x20, 0xc, 0x20, 0x18, 0x20, 0x30, 0x20 },
+{ 0x95, 0xda, 0x28, 0x80, 0x28, 0xff, 0x7d, 0x88, 0x29, 0x7f, 0x2b, 0x49, 0x39, 0x49, 0x11, 0x7f, 0x7d, 0x49, 0x55, 0x49, 0x55, 0x7f, 0x7d, 0x8, 0x11, 0x28, 0x7d, 0x28, 0x11, 0x1c, 0x11, 0x36, 0x11, 0x63 },
+{ 0x95, 0xdb, 0x4, 0x0, 0x5, 0xfc, 0xd, 0x4, 0x9, 0x4, 0x19, 0x4, 0x11, 0xfc, 0x30, 0x20, 0x50, 0x20, 0x17, 0xff, 0x10, 0xa8, 0x10, 0xa8, 0x11, 0xac, 0x11, 0x24, 0x13, 0x26, 0x16, 0x23, 0x10, 0x20 },
+{ 0x95, 0xdc, 0x8, 0x14, 0x1c, 0x12, 0x16, 0xff, 0x33, 0x10, 0x60, 0x10, 0x8, 0xfe, 0x3e, 0x92, 0x8, 0x92, 0x8, 0xfe, 0x7f, 0x92, 0x0, 0x92, 0x3e, 0xfe, 0x22, 0x92, 0x22, 0x92, 0x22, 0x92, 0x3e, 0x96 },
+{ 0x95, 0xdd, 0x8, 0x14, 0x1c, 0x12, 0x16, 0xff, 0x32, 0x10, 0x20, 0x10, 0x7e, 0xfe, 0x8, 0x92, 0x8, 0x92, 0x7e, 0xfe, 0x8, 0x92, 0x4a, 0x92, 0x6a, 0xfe, 0x28, 0x92, 0xe, 0x92, 0x38, 0x92, 0x60, 0x96 },
+{ 0x95, 0xde, 0x0, 0x0, 0x3f, 0xfe, 0x20, 0x22, 0x20, 0x92, 0x2f, 0xfa, 0x20, 0x82, 0x27, 0xf2, 0x24, 0x92, 0x27, 0xf2, 0x24, 0x92, 0x27, 0xf2, 0x24, 0x92, 0x24, 0xb2, 0x20, 0x2, 0x3f, 0xfe, 0x0, 0x0 },
+{ 0x95, 0xdf, 0x10, 0x24, 0x10, 0x22, 0x17, 0xff, 0x10, 0x20, 0x78, 0x20, 0x13, 0xfe, 0x12, 0x22, 0x12, 0x22, 0x1b, 0xfe, 0x72, 0x22, 0x12, 0x22, 0x13, 0xfe, 0x12, 0x22, 0x12, 0x22, 0x12, 0x22, 0x32, 0x26 },
+{ 0x95, 0xe0, 0x0, 0x80, 0x8, 0x80, 0x8, 0xfc, 0x8, 0x80, 0x8, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x4, 0x90, 0xc, 0x98, 0x18, 0x8c, 0x70, 0x97, 0x3, 0xb0, 0x0, 0x60, 0x0, 0xc0, 0x3, 0x80, 0x1e, 0x0 },
+{ 0x95, 0xe1, 0x0, 0x90, 0x0, 0x88, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x9c },
+{ 0x95, 0xe2, 0x10, 0x14, 0x10, 0x12, 0x11, 0xff, 0x7c, 0x10, 0x4, 0x10, 0xc, 0xfe, 0x8, 0x92, 0x1a, 0x92, 0x14, 0xfe, 0x38, 0x92, 0x54, 0x92, 0x12, 0xfe, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x96 },
+{ 0x95, 0xe3, 0x10, 0x14, 0x10, 0x12, 0x7e, 0xff, 0x10, 0x10, 0x7e, 0x10, 0x52, 0xfe, 0x52, 0x92, 0x7e, 0x92, 0x52, 0xfe, 0x52, 0x92, 0x7e, 0x92, 0x10, 0xfe, 0x7e, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x96 },
+{ 0x95, 0xe4, 0x2, 0x10, 0xe, 0x10, 0x79, 0xff, 0x8, 0x10, 0x8, 0xfe, 0x7e, 0x92, 0x8, 0xfe, 0x8, 0x92, 0x1c, 0x92, 0x1a, 0xfe, 0x2a, 0x0, 0x28, 0x18, 0x48, 0xaa, 0x8, 0xa3, 0x9, 0xa5, 0x9, 0x1c },
+{ 0x95, 0xe5, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x1, 0x0, 0x7f, 0xff, 0x4, 0x10, 0x18, 0x8c, 0x6f, 0xfb, 0x1, 0x8, 0x7, 0x8, 0x3c, 0x38 },
+{ 0x95, 0xe6, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x1, 0x0, 0x7f, 0xff, 0x2, 0x20, 0xc, 0x98, 0x70, 0x87, 0x7, 0xf0, 0x0, 0x80, 0x3f, 0xfe },
+{ 0x95, 0xe7, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x1, 0x0, 0x7f, 0xff, 0x4, 0x10, 0x19, 0xc, 0x65, 0x53, 0xd, 0x78, 0x19, 0x2c, 0x3, 0x0 },
+{ 0x95, 0xe8, 0x0, 0x48, 0x0, 0x4c, 0x0, 0x44, 0x1f, 0xff, 0x10, 0x40, 0x10, 0x40, 0x10, 0x42, 0x10, 0x66, 0x10, 0x24, 0x10, 0x2c, 0x10, 0x38, 0x10, 0x10, 0x10, 0x78, 0x31, 0xcd, 0x27, 0x7, 0x60, 0x2 },
+{ 0x95, 0xe9, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x1, 0x0, 0x7f, 0xff, 0x4, 0x10, 0x1f, 0xfc, 0x68, 0xb, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8 },
+{ 0x95, 0xea, 0x0, 0x0, 0xf, 0xfc, 0x8, 0x4, 0x9, 0x84, 0x8, 0xc4, 0x8, 0x44, 0x8, 0x4, 0x7f, 0xff, 0x10, 0x4, 0x13, 0x4, 0x11, 0x84, 0x10, 0x84, 0x10, 0x4, 0x1f, 0xff, 0x0, 0x8, 0x0, 0x38 },
+{ 0x95, 0xeb, 0x10, 0x20, 0x10, 0x20, 0x3f, 0x7f, 0x68, 0xc8, 0x4, 0x22, 0x33, 0xff, 0x18, 0x20, 0x9, 0xfe, 0x61, 0x22, 0x31, 0xfe, 0x11, 0x22, 0x5, 0xfe, 0xc, 0x4, 0x1b, 0xff, 0x30, 0x84, 0x60, 0x5c },
+{ 0x95, 0xec, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x0, 0x80, 0x3f, 0xfe, 0x4, 0x10, 0x6, 0x30, 0x2, 0x20, 0x7f, 0xff, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8 },
+{ 0x95, 0xed, 0x9, 0x10, 0x9, 0x10, 0x9, 0x10, 0x1f, 0xdf, 0x12, 0x12, 0x32, 0x32, 0x33, 0xa2, 0x52, 0x96, 0x12, 0x94, 0x12, 0x9c, 0x12, 0x88, 0x12, 0x88, 0x12, 0x9c, 0x12, 0x94, 0x12, 0xb6, 0x15, 0xa3 },
+{ 0x95, 0xee, 0x4, 0x20, 0x4, 0x20, 0xf, 0xff, 0x8, 0x20, 0x1b, 0xfe, 0x10, 0x50, 0x37, 0xff, 0x50, 0x88, 0x11, 0x24, 0x16, 0x23, 0x11, 0xfc, 0x10, 0x20, 0x17, 0xff, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20 },
+{ 0x95, 0xef, 0x8, 0x0, 0x8, 0x0, 0xf, 0xfc, 0x18, 0x4, 0x10, 0x4, 0x3f, 0xc4, 0x60, 0x44, 0x0, 0x44, 0x0, 0x44, 0x1f, 0xcc, 0x10, 0x8, 0x10, 0x38, 0x10, 0x0, 0x10, 0x1, 0x18, 0x3, 0xf, 0xfe },
+{ 0x95, 0xf0, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x2, 0xa0, 0x6, 0xb0, 0xc, 0x98, 0x18, 0x8c, 0x70, 0x87, 0x0, 0x80 },
+{ 0x95, 0xf1, 0x8, 0x0, 0x8, 0xfe, 0x3e, 0x82, 0x8, 0x82, 0x8, 0x8e, 0x7f, 0x80, 0x22, 0xfe, 0x36, 0xa2, 0x14, 0xa2, 0x7f, 0xb6, 0x8, 0x94, 0x8, 0x9c, 0x3e, 0x88, 0x8, 0x9c, 0x8, 0x96, 0x8, 0xb3 },
+{ 0x95, 0xf2, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x0, 0x80, 0x1f, 0xfc, 0x1, 0x40, 0x7f, 0xff, 0x2, 0x20, 0x4, 0x90, 0x18, 0x8c, 0x67, 0xf3, 0x0, 0x80, 0x3f, 0xfe, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80 },
+{ 0x95, 0xf3, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x2, 0x20, 0x2, 0x2f, 0xfa, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0xf, 0xf8, 0x0, 0x80, 0x0, 0x90, 0x0, 0x98, 0x0, 0x88, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x95, 0xf4, 0x0, 0x20, 0x10, 0x3e, 0x10, 0x62, 0x54, 0xc6, 0x55, 0xac, 0x54, 0x38, 0x54, 0x6c, 0x55, 0xc7, 0x54, 0x10, 0x54, 0xfe, 0x54, 0x10, 0x7c, 0xfe, 0x0, 0x10, 0x1, 0xff, 0x0, 0x10, 0x0, 0x10 },
+{ 0x95, 0xf5, 0x20, 0x82, 0x20, 0x82, 0x3f, 0xfe, 0x1, 0x0, 0x3, 0xf0, 0xe, 0x10, 0x39, 0x20, 0x0, 0xc0, 0xf, 0x78, 0x78, 0x8f, 0xf, 0xf8, 0x0, 0x80, 0xf, 0xf8, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80 },
+{ 0x95, 0xf6, 0x0, 0x80, 0x20, 0x82, 0x20, 0x82, 0x3f, 0xfe, 0x0, 0x0, 0x1f, 0x3e, 0x11, 0x22, 0x11, 0x22, 0x1f, 0x3e, 0x11, 0x22, 0x11, 0x22, 0x1f, 0x3e, 0x11, 0x22, 0x31, 0x22, 0x21, 0x62, 0x67, 0x4e },
+{ 0x95, 0xf7, 0x0, 0x40, 0x0, 0x40, 0x1f, 0xff, 0x11, 0x0, 0x11, 0x0, 0x13, 0xfc, 0x12, 0x4, 0x17, 0xe4, 0x1c, 0x24, 0x10, 0x24, 0x13, 0xe4, 0x12, 0x1c, 0x32, 0x0, 0x22, 0x1, 0x63, 0x3, 0x1, 0xfe },
+{ 0x95, 0xf8, 0x11, 0x0, 0x11, 0x0, 0x11, 0xfe, 0x13, 0x2, 0x7a, 0x2, 0x13, 0xf2, 0x16, 0x12, 0x10, 0x12, 0x18, 0x12, 0x73, 0xf6, 0x12, 0x4, 0x12, 0x1c, 0x12, 0x0, 0x12, 0x1, 0x13, 0x3, 0x31, 0xfe },
+{ 0x95, 0xf9, 0x10, 0x20, 0x10, 0x20, 0x13, 0xfe, 0x10, 0x20, 0x79, 0xfc, 0x10, 0x50, 0x17, 0xff, 0x10, 0x88, 0x19, 0x24, 0x76, 0x23, 0x11, 0xfc, 0x10, 0x20, 0x13, 0xfe, 0x10, 0x20, 0x10, 0x20, 0x30, 0x20 },
+{ 0x95, 0xfa, 0x8, 0x40, 0x8, 0x40, 0x8, 0x40, 0x7f, 0x7f, 0x8, 0xc4, 0x8, 0xa4, 0xf, 0x24, 0x9, 0x2c, 0x9, 0x28, 0x9, 0x38, 0x19, 0x10, 0x11, 0x38, 0x13, 0x28, 0x32, 0x6c, 0x22, 0x46, 0x66, 0xc3 },
+{ 0x95, 0xfb, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0xf8, 0x3, 0x8, 0x2, 0x8, 0x2, 0x8, 0x6, 0x8, 0x4, 0x18, 0xc, 0x10, 0x18, 0x10, 0x70, 0xf0 },
+{ 0x95, 0xfc, 0x0, 0x0, 0x1f, 0x3e, 0x11, 0x22, 0x11, 0x22, 0x11, 0x22, 0x1f, 0x3e, 0x11, 0x22, 0x11, 0x22, 0x11, 0x22, 0x1f, 0x3e, 0x11, 0x22, 0x11, 0x22, 0x11, 0x22, 0x31, 0x22, 0x21, 0x62, 0x67, 0x4e },
+{ 0x96, 0x40, 0x0, 0x20, 0x30, 0x20, 0x18, 0x20, 0xb, 0xfe, 0x0, 0x20, 0x60, 0x20, 0x30, 0x20, 0x17, 0xff, 0x0, 0x40, 0x8, 0x40, 0x8, 0xc4, 0x18, 0x86, 0x10, 0x82, 0x31, 0x9f, 0x21, 0xf1, 0x67, 0x1 },
+{ 0x96, 0x41, 0x1, 0x0, 0x31, 0x0, 0x19, 0xfe, 0xb, 0x2, 0x2, 0x2, 0x63, 0xf2, 0x36, 0x12, 0x10, 0x12, 0x0, 0x12, 0xb, 0xf6, 0xa, 0x4, 0x1a, 0x1c, 0x12, 0x0, 0x32, 0x1, 0x23, 0x3, 0x61, 0xfe },
+{ 0x96, 0x42, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x0, 0x0, 0x3f, 0xfc, 0x0, 0x30, 0x0, 0xc0, 0x0, 0x80, 0x1, 0x80, 0x12, 0x22, 0x33, 0x33, 0x61, 0x11 },
+{ 0x96, 0x43, 0x0, 0x80, 0x7e, 0x80, 0x10, 0xfe, 0x10, 0x82, 0x10, 0x82, 0x11, 0xf2, 0x3d, 0x12, 0x27, 0x12, 0x64, 0x12, 0x24, 0xf2, 0x24, 0x8e, 0x24, 0x80, 0x24, 0x80, 0x3c, 0x81, 0x0, 0xc3, 0x0, 0x7e },
+{ 0x96, 0x44, 0x8, 0x10, 0x19, 0x1e, 0x11, 0xa2, 0x64, 0xd4, 0x2c, 0x8, 0x18, 0x14, 0x10, 0x63, 0x25, 0x88, 0x7c, 0xbe, 0x14, 0x88, 0x10, 0xbe, 0x54, 0x88, 0x54, 0xff, 0x51, 0x88, 0x11, 0x40, 0x13, 0x3f },
+{ 0x96, 0x45, 0x0, 0x80, 0x3c, 0x80, 0x24, 0xfe, 0x24, 0x82, 0x24, 0x82, 0x3d, 0xf2, 0x25, 0x12, 0x27, 0x12, 0x24, 0x12, 0x3c, 0xf2, 0x24, 0x8e, 0x24, 0x80, 0x24, 0x80, 0x24, 0x81, 0x64, 0xc3, 0x4c, 0x7e },
+{ 0x96, 0x46, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x4, 0x90, 0x0, 0x80, 0x7f, 0xff, 0x2, 0x0, 0x2, 0x0, 0x3, 0xf8, 0x2, 0x8, 0x6, 0x8, 0x4, 0x8, 0xc, 0x18, 0x18, 0x10, 0x70, 0x70 },
+{ 0x96, 0x47, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x0, 0x0, 0x3e, 0x7e, 0x22, 0x42, 0x22, 0x42, 0x3e, 0x7e, 0x22, 0x42, 0x22, 0x42, 0x22, 0x7e, 0x3e, 0xc2, 0x0, 0x82, 0x1, 0x82, 0x7, 0xe },
+{ 0x96, 0x48, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x0, 0x80, 0x21, 0xfe, 0x37, 0xc, 0x10, 0xf8, 0x7, 0x8f, 0x0, 0x20, 0x73, 0xfe, 0x10, 0x20, 0x13, 0xfe, 0x10, 0x20, 0x37, 0xff, 0x68, 0x20, 0x47, 0xff },
+{ 0x96, 0x49, 0x10, 0x20, 0x10, 0x3c, 0x10, 0x64, 0x7c, 0xcc, 0x55, 0xa8, 0x54, 0x30, 0x54, 0x6c, 0x55, 0xc7, 0x54, 0x10, 0x7c, 0xfe, 0x10, 0x10, 0x10, 0xfe, 0x14, 0x10, 0x3d, 0xff, 0x64, 0x10, 0x0, 0x10 },
+{ 0x96, 0x4a, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x4, 0x0, 0xd, 0xfc, 0x19, 0x4, 0x31, 0xfc, 0x50, 0x20, 0x17, 0xff, 0x11, 0x24, 0x16, 0x23, 0x1, 0x8, 0x6, 0x90, 0x7c, 0x60, 0x7, 0x38, 0x1c, 0xf },
+{ 0x96, 0x4b, 0x0, 0x10, 0x3c, 0x10, 0x0, 0x10, 0x7e, 0xff, 0x0, 0x20, 0x3c, 0x20, 0x0, 0x20, 0x0, 0x3e, 0x3c, 0x22, 0x0, 0x22, 0x0, 0x22, 0x3c, 0x62, 0x24, 0x46, 0x24, 0x44, 0x24, 0xc4, 0x3d, 0x9c },
+{ 0x96, 0x4c, 0x2, 0x20, 0x1f, 0xfc, 0x12, 0x24, 0x1f, 0xfc, 0x12, 0x24, 0x1f, 0xfc, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x4, 0x10, 0x2, 0x20, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x96, 0x4d, 0x4, 0x0, 0x4, 0x3f, 0x3f, 0xa1, 0x4, 0x23, 0x4, 0x22, 0x3f, 0xa6, 0x4, 0x24, 0x4, 0x22, 0x4, 0x21, 0x7f, 0xe1, 0x4, 0x21, 0xc, 0x21, 0x8, 0x27, 0x18, 0x20, 0x30, 0x20, 0x60, 0x20 },
+{ 0x96, 0x4e, 0x10, 0x40, 0x38, 0x7c, 0x2c, 0x44, 0x64, 0xcc, 0x41, 0xa8, 0x7c, 0x38, 0x10, 0x6c, 0x11, 0xc7, 0x7c, 0x10, 0x10, 0xfe, 0x54, 0x10, 0x54, 0xfe, 0x50, 0x10, 0x1d, 0xff, 0x30, 0x10, 0x60, 0x10 },
+{ 0x96, 0x4f, 0x8, 0x40, 0x1c, 0x40, 0x16, 0x7e, 0x32, 0x42, 0x28, 0x42, 0x7e, 0xf2, 0x23, 0x92, 0x3e, 0x12, 0x22, 0x12, 0x3e, 0xf2, 0x20, 0x8e, 0x24, 0x80, 0x24, 0x80, 0x2e, 0x81, 0x3a, 0xc3, 0x60, 0x7e },
+{ 0x96, 0x50, 0x1f, 0xfc, 0x10, 0x4, 0x17, 0xf4, 0x10, 0x84, 0x13, 0xe4, 0x12, 0x24, 0x13, 0xe4, 0x12, 0x24, 0x13, 0xe4, 0x12, 0x4, 0x13, 0xfc, 0x12, 0x4, 0x13, 0xf4, 0x30, 0x15, 0x25, 0x57, 0x64, 0x32 },
+{ 0x96, 0x51, 0x0, 0x4, 0x3b, 0x88, 0x2a, 0xbe, 0x2a, 0xa2, 0x2a, 0xbe, 0x3b, 0xa2, 0x2a, 0xbe, 0x2a, 0xa0, 0x2a, 0xbf, 0x3b, 0xa0, 0x2a, 0xbf, 0x2a, 0x81, 0x2a, 0xab, 0x2a, 0xa9, 0x6c, 0xa3, 0x59, 0x86 },
+{ 0x96, 0x52, 0x0, 0x6, 0x0, 0x3c, 0x1f, 0xe0, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x0, 0xc, 0x0, 0x18, 0x0, 0x30, 0x0, 0x60, 0x8, 0xc0, 0xb, 0x80, 0x1e, 0x0, 0x33, 0xc0, 0x60, 0x7f },
+{ 0x96, 0x53, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x8, 0x0, 0x8, 0x0, 0x8, 0x0, 0x8, 0x0, 0x8, 0x0, 0x8, 0x0, 0x8, 0x0, 0x8, 0x0, 0x8, 0x0, 0xc, 0x0, 0x7, 0xfe, 0x0, 0x0 },
+{ 0x96, 0x54, 0x4, 0x20, 0x4, 0x20, 0xf, 0xff, 0x8, 0x84, 0x18, 0x48, 0x13, 0xff, 0x32, 0x1, 0x52, 0x21, 0x10, 0x20, 0x13, 0xff, 0x10, 0x40, 0x10, 0x7e, 0x10, 0x42, 0x10, 0xc2, 0x11, 0x82, 0x13, 0xe },
+{ 0x96, 0x55, 0x4, 0x2, 0x4, 0x12, 0x3f, 0xd2, 0x10, 0x92, 0x19, 0x92, 0x9, 0x12, 0x9, 0x12, 0x7f, 0xf2, 0x0, 0x12, 0x0, 0x12, 0x1f, 0x92, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x1f, 0x8e },
+{ 0x96, 0x56, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x13, 0xff, 0x7c, 0x40, 0x10, 0x40, 0x10, 0x40, 0x10, 0x7e, 0x10, 0x42, 0x10, 0x42, 0x1c, 0x42, 0x70, 0xc2, 0x0, 0x86, 0x1, 0x84, 0x3, 0x4, 0x6, 0x1c },
+{ 0x96, 0x57, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10, 0x9, 0xff, 0x7e, 0x20, 0x12, 0x20, 0x12, 0x20, 0x12, 0x3e, 0x32, 0x22, 0x26, 0x22, 0x24, 0x22, 0x7e, 0x62, 0xb, 0x46, 0x19, 0x44, 0x30, 0xc4, 0x61, 0x9c },
+{ 0x96, 0x58, 0x10, 0x0, 0x11, 0xff, 0x11, 0x1, 0x7d, 0xff, 0x55, 0x1, 0x55, 0xff, 0x54, 0x0, 0x54, 0xfe, 0x54, 0x82, 0x54, 0xfe, 0x5c, 0x82, 0x10, 0x82, 0x10, 0xfe, 0x10, 0x82, 0x10, 0x82, 0x10, 0xfe },
+{ 0x96, 0x59, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x8, 0x0, 0x8, 0x0, 0x8, 0x0, 0xc, 0x0, 0x7, 0xfc, 0x0, 0x0, 0x1, 0x80, 0x4, 0xc0, 0x14, 0x46, 0x14, 0xb, 0x36, 0x19, 0x63, 0xf0 },
+{ 0x96, 0x5a, 0x8, 0x20, 0x8, 0x20, 0x8, 0x20, 0xb, 0xff, 0x28, 0x80, 0x2c, 0x80, 0x2a, 0x80, 0x6a, 0x80, 0x48, 0x80, 0x8, 0x80, 0x8, 0x80, 0x8, 0x80, 0x8, 0x80, 0x8, 0xc0, 0x8, 0x7e, 0x8, 0x0 },
+{ 0x96, 0x5b, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x4, 0x10, 0x4, 0x1f, 0xfc, 0x10, 0x80, 0x10, 0x80, 0x1f, 0xff, 0x11, 0x0, 0x11, 0xfc, 0x31, 0x4, 0x23, 0x4, 0x66, 0x4, 0x1c, 0x1c },
+{ 0x96, 0x5c, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x2, 0x20, 0x1f, 0xfc, 0x2, 0x20, 0x7f, 0xff, 0x4, 0x10, 0x18, 0x8c, 0x66, 0xb3, 0x3, 0xe0, 0xe, 0xb8, 0x38, 0x8e, 0x3, 0x80 },
+{ 0x96, 0x5d, 0x0, 0x0, 0x8, 0x7e, 0x8, 0x42, 0x7f, 0x7e, 0x20, 0x42, 0x20, 0x7e, 0x20, 0x44, 0x1e, 0xc4, 0x1, 0x9c, 0x0, 0x0, 0x3f, 0xfe, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x96, 0x5e, 0x4, 0x10, 0x4, 0x10, 0x3f, 0xfe, 0x4, 0x10, 0x4, 0x10, 0x7, 0xf0, 0x4, 0x10, 0x4, 0x10, 0x7, 0xf0, 0x0, 0x80, 0x7f, 0xff, 0x2, 0xa0, 0x6, 0xb0, 0x1c, 0x9c, 0x70, 0x87, 0x0, 0x80 },
+{ 0x96, 0x5f, 0x10, 0x20, 0x10, 0x20, 0x13, 0xfe, 0x7c, 0x20, 0x11, 0xfc, 0x10, 0x50, 0x3b, 0xff, 0x34, 0x88, 0x31, 0x24, 0x56, 0x23, 0x51, 0xfc, 0x10, 0x20, 0x13, 0xfe, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20 },
+{ 0x96, 0x60, 0x0, 0x0, 0x3f, 0xfe, 0x20, 0x2, 0x3f, 0xfe, 0x20, 0x2, 0x3f, 0xfe, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8 },
+{ 0x96, 0x61, 0x8, 0x10, 0x18, 0x10, 0x10, 0x10, 0x65, 0xff, 0x2c, 0x20, 0x18, 0x20, 0x10, 0x20, 0x24, 0x3e, 0x7e, 0x22, 0xa, 0x22, 0x8, 0x22, 0x2a, 0x62, 0x2a, 0x46, 0x6a, 0x44, 0x48, 0xc4, 0x9, 0x9c },
+{ 0x96, 0x62, 0x0, 0x10, 0x3e, 0x10, 0x22, 0x10, 0x22, 0xff, 0x22, 0x20, 0x3e, 0x20, 0x22, 0x20, 0x22, 0x3e, 0x22, 0x22, 0x3e, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x66, 0x62, 0x44, 0x46, 0xcc },
+{ 0x96, 0x63, 0x0, 0x82, 0x38, 0x86, 0x2b, 0xe4, 0x28, 0x8c, 0x2b, 0xe9, 0x38, 0x3, 0x2b, 0xe2, 0x2a, 0x26, 0x2b, 0xec, 0x38, 0x0, 0x2a, 0x21, 0x2b, 0x63, 0x29, 0x42, 0x28, 0xe6, 0x6b, 0x8c, 0x58, 0x18 },
+{ 0x96, 0x64, 0x0, 0x44, 0x3c, 0x44, 0x1, 0xff, 0x7e, 0x44, 0x0, 0x7c, 0x3c, 0x44, 0x0, 0x44, 0x0, 0x7c, 0x3c, 0x10, 0x1, 0xff, 0x0, 0x54, 0x3c, 0x54, 0x24, 0xd6, 0x24, 0x92, 0x25, 0x93, 0x3c, 0x10 },
+{ 0x96, 0x65, 0x4, 0x10, 0x8, 0x20, 0x14, 0xfe, 0x62, 0x82, 0x14, 0x82, 0x8, 0xfe, 0x14, 0x82, 0x64, 0x82, 0xa, 0xfe, 0x12, 0x48, 0x66, 0x48, 0xa, 0x48, 0x12, 0x48, 0x62, 0x49, 0x6, 0xc9, 0x1d, 0x87 },
+{ 0x96, 0x66, 0x6, 0x0, 0x3c, 0xfe, 0x20, 0x22, 0x24, 0x22, 0x26, 0x62, 0x3a, 0xce, 0x60, 0x0, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x4, 0x10, 0x38, 0xe },
+{ 0x96, 0x67, 0x10, 0x20, 0x38, 0x20, 0x2c, 0x64, 0x66, 0x44, 0x40, 0xfe, 0x7c, 0x2, 0x10, 0x10, 0x10, 0x90, 0x7c, 0xfe, 0x11, 0x10, 0x54, 0x10, 0x55, 0xff, 0x50, 0x10, 0x1c, 0x10, 0x30, 0x10, 0x60, 0x10 },
+{ 0x96, 0x68, 0x0, 0x10, 0x3e, 0x10, 0x22, 0x10, 0x27, 0xff, 0x24, 0x20, 0x2c, 0x20, 0x28, 0x20, 0x24, 0x3e, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x62, 0x2e, 0x46, 0x20, 0x44, 0x20, 0xc4, 0x21, 0x9c },
+{ 0x96, 0x69, 0x0, 0x20, 0x0, 0x2c, 0x3c, 0x26, 0x24, 0x22, 0x24, 0x20, 0x27, 0xff, 0x24, 0x20, 0x24, 0x20, 0x24, 0x70, 0x24, 0x50, 0x24, 0x50, 0x3c, 0xd8, 0x0, 0x88, 0x1, 0x8c, 0x3, 0x6, 0x6, 0x3 },
+{ 0x96, 0x6a, 0x8, 0x0, 0x8, 0xff, 0x7f, 0x10, 0x8, 0x7e, 0x49, 0x42, 0x2b, 0x42, 0x2a, 0x7e, 0x8, 0x42, 0x7f, 0x42, 0x8, 0x7e, 0x8, 0x42, 0x1c, 0x42, 0x14, 0x7e, 0x36, 0x24, 0x23, 0x66, 0x60, 0xc3 },
+{ 0x96, 0x6b, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x23, 0x7e, 0x2e, 0x2, 0x38, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0xe, 0x20, 0x3a, 0x21, 0x62, 0x33, 0x2, 0x1e, 0x2, 0x0 },
+{ 0x96, 0x6c, 0x8, 0x50, 0xa, 0x52, 0x19, 0x54, 0x10, 0x50, 0x33, 0xfe, 0x30, 0x88, 0x50, 0x50, 0x13, 0xfe, 0x10, 0x20, 0x11, 0xfc, 0x10, 0x20, 0x17, 0xff, 0x10, 0x50, 0x10, 0xd8, 0x11, 0x8c, 0x17, 0x7 },
+{ 0x96, 0x6d, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0xc0, 0x1, 0x70, 0x1, 0x18, 0x1, 0xc, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0 },
+{ 0x96, 0x6e, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x84, 0x1f, 0xfc, 0x0, 0x80, 0x3f, 0xfe, 0x0, 0x80, 0x7f, 0xff, 0x12, 0x24, 0x60, 0x83, 0x1f, 0xfc, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x96, 0x6f, 0x10, 0x28, 0x11, 0x29, 0x10, 0xaa, 0x10, 0x28, 0x7d, 0xff, 0x10, 0x44, 0x10, 0x28, 0x11, 0xff, 0x1c, 0x10, 0x70, 0xfe, 0x10, 0x10, 0x11, 0xff, 0x10, 0x28, 0x10, 0x6c, 0x10, 0xc6, 0x31, 0x83 },
+{ 0x96, 0x70, 0x8, 0x20, 0x8, 0x20, 0x8, 0x20, 0x7f, 0x20, 0x8, 0x20, 0x8, 0x30, 0x1c, 0x38, 0x1a, 0x2c, 0x19, 0x26, 0x28, 0x23, 0x28, 0x20, 0x48, 0x20, 0x8, 0x20, 0x8, 0x20, 0x8, 0x20, 0x8, 0x20 },
+{ 0x96, 0x71, 0x8, 0x40, 0x28, 0x40, 0x28, 0x40, 0x28, 0x7f, 0x3e, 0xc4, 0x68, 0x84, 0x49, 0x84, 0x8, 0x4c, 0xe, 0x68, 0x38, 0x28, 0x68, 0x38, 0x8, 0x10, 0x8, 0x38, 0x8, 0x6c, 0x8, 0xc6, 0x9, 0x83 },
+{ 0x96, 0x72, 0x0, 0x20, 0x78, 0x20, 0x4b, 0xfe, 0x48, 0x20, 0x48, 0x20, 0x7f, 0xff, 0x48, 0x88, 0x49, 0x88, 0x4f, 0xf, 0x78, 0x20, 0x48, 0x20, 0x4b, 0xfe, 0x48, 0x20, 0x78, 0x20, 0x0, 0x20, 0x7, 0xff },
+{ 0x96, 0x73, 0x4, 0x10, 0x1c, 0x20, 0x71, 0xfe, 0x11, 0x2, 0x11, 0xfe, 0x7d, 0x2, 0x11, 0xfe, 0x38, 0x20, 0x34, 0xa4, 0x53, 0x2b, 0x50, 0x70, 0x13, 0xc4, 0x10, 0x39, 0x11, 0xc6, 0x10, 0x38, 0x13, 0xe0 },
+{ 0x96, 0x74, 0x8, 0x0, 0x1c, 0x0, 0x16, 0x7f, 0x33, 0x41, 0x20, 0x41, 0x7e, 0x41, 0x48, 0x41, 0x8, 0x41, 0x7f, 0x41, 0x8, 0x41, 0x4a, 0x41, 0x6a, 0x41, 0x28, 0x41, 0xf, 0x41, 0x38, 0x7f, 0x60, 0x0 },
+{ 0x96, 0x75, 0x8, 0x10, 0x8, 0x10, 0x7f, 0x90, 0x8, 0x10, 0x8, 0x7e, 0x7f, 0x92, 0x40, 0x92, 0x5e, 0x92, 0x2, 0x12, 0x4, 0x32, 0xf, 0xa2, 0x78, 0x22, 0x8, 0x66, 0x8, 0x44, 0x8, 0xc4, 0x39, 0x9c },
+{ 0x96, 0x76, 0x0, 0x0, 0x31, 0xf8, 0x19, 0x8, 0x9, 0x8, 0x1, 0x8, 0x63, 0xf, 0x36, 0x0, 0x10, 0x0, 0x3, 0xfc, 0x9, 0x4, 0x9, 0x8c, 0x18, 0xd8, 0x10, 0x70, 0x30, 0xd8, 0x21, 0x8c, 0x67, 0x7 },
+{ 0x96, 0x77, 0x0, 0x10, 0x7f, 0x10, 0x10, 0x30, 0x10, 0x24, 0x1e, 0x26, 0x12, 0x62, 0x12, 0x4f, 0x3a, 0xf9, 0x2e, 0x0, 0x64, 0x7e, 0x4, 0x42, 0xc, 0x42, 0x8, 0x42, 0x18, 0x42, 0x30, 0x42, 0x60, 0x7e },
+{ 0x96, 0x78, 0x10, 0x0, 0x13, 0xfe, 0x12, 0x2, 0x12, 0x2, 0x13, 0xfe, 0x7e, 0x0, 0x12, 0x10, 0x12, 0x92, 0x12, 0x92, 0x12, 0xfe, 0x12, 0x10, 0x1e, 0x10, 0x72, 0x92, 0x6, 0x92, 0x4, 0x92, 0xc, 0xfe },
+{ 0x96, 0x79, 0x10, 0x0, 0x10, 0xfc, 0x10, 0x84, 0x7c, 0xfc, 0x54, 0x84, 0x54, 0xfc, 0x55, 0x22, 0x55, 0xa6, 0x54, 0xa4, 0x57, 0xff, 0x5c, 0x48, 0x10, 0x48, 0x10, 0x48, 0x10, 0xc9, 0x11, 0x89, 0x13, 0x7 },
+{ 0x96, 0x7a, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x2, 0x20, 0x6, 0xb0, 0x1c, 0x9c, 0x77, 0xf7, 0x0, 0x80, 0x4, 0x90, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0xc, 0x10, 0x8, 0x10, 0x18, 0x10, 0x30, 0x10 },
+{ 0x96, 0x7b, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x2, 0xa0, 0x2, 0xa0, 0x6, 0xb0, 0x4, 0x90, 0xc, 0x98, 0x18, 0x8c, 0x30, 0x86, 0x67, 0xf3, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80 },
+{ 0x96, 0x7c, 0x2, 0x0, 0xe, 0xef, 0x38, 0x21, 0x49, 0x21, 0x2a, 0xa9, 0x7f, 0x65, 0x1c, 0x21, 0x2a, 0x21, 0x49, 0x21, 0x0, 0x63, 0x3e, 0xa5, 0x2b, 0x29, 0x3e, 0x21, 0x2a, 0x21, 0x2a, 0x21, 0x3e, 0x67 },
+{ 0x96, 0x7d, 0x0, 0x0, 0x7, 0xf0, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x5, 0x90, 0x4, 0xd0, 0x4, 0x50, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0xc, 0x10, 0x8, 0x11, 0x18, 0x1b, 0x70, 0xe },
+{ 0x96, 0x7e, 0x2, 0x20, 0x6, 0x30, 0xc, 0x18, 0x38, 0xe, 0x6f, 0xfb, 0x1, 0x8, 0x3, 0x8, 0xe, 0x8, 0x38, 0x38, 0x0, 0x0, 0x1f, 0xfc, 0x12, 0x44, 0x12, 0x44, 0x12, 0x44, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x96, 0x80, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xff, 0x22, 0x8, 0x3f, 0xbf, 0x26, 0xc, 0x2b, 0x1a, 0x32, 0xa9, 0x20, 0x1c, 0x27, 0xf0, 0x20, 0x40, 0x2f, 0xfe, 0x60, 0x40, 0x5f, 0xff, 0x40, 0x40, 0x1, 0xc0 },
+{ 0x96, 0x81, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xff, 0x22, 0x8, 0x3f, 0xbf, 0x22, 0x8, 0x27, 0x1c, 0x2a, 0xaa, 0x32, 0x9, 0x20, 0x0, 0x3f, 0xff, 0x21, 0x0, 0x67, 0xfe, 0x5c, 0x2, 0x44, 0x2, 0x7, 0xfe },
+{ 0x96, 0x82, 0x0, 0x80, 0x3f, 0xff, 0x22, 0x8, 0x3f, 0xbf, 0x26, 0xc, 0x2b, 0x1a, 0x32, 0xa9, 0x27, 0xfc, 0x24, 0x44, 0x27, 0xfc, 0x24, 0x44, 0x27, 0xfc, 0x61, 0x2a, 0x43, 0x2e, 0x46, 0x31, 0x1c, 0x1f },
+{ 0x96, 0x83, 0x0, 0x40, 0x0, 0x40, 0x3f, 0xff, 0x20, 0x0, 0x22, 0x8, 0x22, 0x8, 0x3f, 0xbf, 0x22, 0x8, 0x26, 0x1c, 0x27, 0x1c, 0x2a, 0xaa, 0x6a, 0x2a, 0x52, 0x49, 0x42, 0x8, 0x42, 0x8, 0x2, 0x8 },
+{ 0x96, 0x84, 0x10, 0x0, 0x11, 0xfe, 0x11, 0x22, 0x11, 0x22, 0x7d, 0xfe, 0x11, 0x22, 0x11, 0x22, 0x11, 0xfe, 0x10, 0x20, 0x10, 0x20, 0x1d, 0xfe, 0x70, 0x20, 0x0, 0x20, 0x0, 0x20, 0x3, 0xff, 0x0, 0x0 },
+{ 0x96, 0x85, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xfe, 0x7c, 0x10, 0x14, 0x10, 0x14, 0x10, 0x35, 0xff, 0x24, 0x54, 0x2c, 0x54, 0x28, 0x54, 0x78, 0x54, 0x14, 0xd6, 0x34, 0x92, 0x21, 0x93, 0x60, 0x10 },
+{ 0x96, 0x86, 0x0, 0x20, 0x0, 0x20, 0x78, 0x20, 0x4b, 0xfe, 0x48, 0x20, 0x48, 0x20, 0x48, 0x20, 0x7f, 0xff, 0x48, 0xa8, 0x48, 0xa8, 0x48, 0xa8, 0x49, 0xac, 0x79, 0x24, 0x3, 0x26, 0x6, 0x23, 0x0, 0x20 },
+{ 0x96, 0x87, 0x8, 0x40, 0x8, 0x40, 0x8, 0x40, 0x7e, 0xff, 0x8, 0x84, 0x9, 0x84, 0x1c, 0x44, 0x1a, 0x4c, 0x1a, 0x68, 0x28, 0x28, 0x28, 0x38, 0x48, 0x10, 0x8, 0x38, 0x8, 0x6c, 0x8, 0xc6, 0x9, 0x83 },
+{ 0x96, 0x88, 0x8, 0x0, 0x8, 0x0, 0x1f, 0xfe, 0x10, 0x0, 0x30, 0x0, 0x67, 0xf8, 0x4, 0x88, 0x4, 0x88, 0x4, 0x88, 0x7f, 0xff, 0x9, 0x8, 0x9, 0x8, 0x9, 0x8, 0xf, 0xff, 0x0, 0x10, 0x0, 0x70 },
+{ 0x96, 0x89, 0x0, 0x0, 0x3, 0xfe, 0x7a, 0x22, 0x4a, 0x22, 0x4b, 0xfe, 0x4a, 0x22, 0x4a, 0x22, 0x4b, 0xfe, 0x48, 0x20, 0x48, 0x20, 0x7b, 0xfe, 0x0, 0x20, 0x0, 0x20, 0x0, 0x20, 0x7, 0xff, 0x0, 0x0 },
+{ 0x96, 0x8a, 0x8, 0x10, 0x8, 0x10, 0x9, 0xff, 0x7e, 0x10, 0x8, 0xfe, 0x8, 0x82, 0x1c, 0xfe, 0x1a, 0x82, 0x1a, 0xfe, 0x28, 0x82, 0x28, 0xfe, 0x48, 0x0, 0x9, 0xff, 0x8, 0x44, 0x8, 0xc6, 0x9, 0x83 },
+{ 0x96, 0x8b, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x1, 0x0, 0x7f, 0xff, 0x4, 0x90, 0x1f, 0xfc, 0x68, 0x8b, 0x8, 0x88, 0x8, 0xb8, 0x0, 0x80 },
+{ 0x96, 0x8c, 0x0, 0x44, 0x3c, 0x44, 0x25, 0xff, 0x24, 0x44, 0x24, 0x44, 0x3c, 0xfe, 0x24, 0x82, 0x24, 0xfe, 0x24, 0x82, 0x3c, 0xfe, 0x24, 0x10, 0x25, 0xff, 0x24, 0x28, 0x24, 0x6c, 0x64, 0xc6, 0x4d, 0x83 },
+{ 0x96, 0x8d, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x7d, 0xfe, 0x11, 0x22, 0x11, 0x22, 0x38, 0x20, 0x34, 0x20, 0x54, 0x70, 0x50, 0x50, 0x10, 0x50, 0x10, 0x50, 0x10, 0xd0, 0x10, 0x91, 0x11, 0x93, 0x13, 0xe },
+{ 0x96, 0x8e, 0x10, 0x10, 0x1e, 0x10, 0x32, 0xff, 0x24, 0x20, 0x7e, 0x20, 0x2a, 0x7e, 0x2a, 0xc2, 0x3f, 0x42, 0x2a, 0x7e, 0x2a, 0x42, 0x3e, 0x42, 0x0, 0x7e, 0x55, 0x42, 0x55, 0x42, 0x54, 0x42, 0x40, 0x4e },
+{ 0x96, 0x8f, 0x8, 0x0, 0x9, 0xfe, 0x8, 0x10, 0x7e, 0x10, 0x8, 0x10, 0x8, 0x90, 0x1c, 0x90, 0x1a, 0x9e, 0x1a, 0x90, 0x28, 0x90, 0x28, 0x90, 0x48, 0x90, 0x8, 0x90, 0x8, 0x90, 0xb, 0xff, 0x8, 0x0 },
+{ 0x96, 0x90, 0x20, 0x82, 0x3c, 0x44, 0x25, 0xff, 0x48, 0x28, 0x3e, 0xfe, 0x2a, 0xaa, 0x2a, 0xce, 0x3e, 0x82, 0x2a, 0xfe, 0x2a, 0x82, 0x3e, 0xfe, 0x1, 0x4, 0x55, 0xff, 0x55, 0x44, 0x54, 0x24, 0x40, 0xc },
+{ 0x96, 0x91, 0x11, 0x4, 0x11, 0x4, 0x11, 0x4, 0x7d, 0xc4, 0x11, 0x7f, 0x13, 0x54, 0x3a, 0x54, 0x37, 0x54, 0x51, 0xd4, 0x50, 0x94, 0x10, 0xbf, 0x11, 0x84, 0x11, 0x4, 0x13, 0x4, 0x12, 0x4, 0x16, 0x4 },
+{ 0x96, 0x92, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x2, 0x20, 0x2, 0x20, 0x12, 0x24, 0x12, 0x24, 0x32, 0x26, 0x22, 0x22, 0x62, 0x23, 0x6, 0x20, 0x4, 0x20, 0xc, 0x20, 0x18, 0x20, 0x30, 0xe0 },
+{ 0x96, 0x93, 0x4, 0x0, 0x5, 0xfc, 0xd, 0x4, 0x9, 0x4, 0x19, 0x4, 0x11, 0xfc, 0x30, 0x0, 0x53, 0xfe, 0x10, 0x20, 0x10, 0x20, 0x17, 0xff, 0x10, 0x50, 0x10, 0xd8, 0x11, 0x8c, 0x13, 0x6, 0x16, 0x3 },
+{ 0x96, 0x94, 0x0, 0x0, 0x3f, 0xfc, 0x4, 0x4, 0x4, 0x4, 0x6, 0xc, 0x2, 0x8, 0x2, 0x18, 0x3, 0x10, 0x1, 0x30, 0x1, 0xe0, 0x0, 0xc0, 0x1, 0xe0, 0x3, 0x30, 0x6, 0x18, 0x1c, 0xc, 0x70, 0x7 },
+{ 0x96, 0x95, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x17, 0xff, 0x78, 0x20, 0x10, 0x20, 0x10, 0x20, 0x13, 0xfe, 0x18, 0xa8, 0x70, 0xa8, 0x10, 0xa8, 0x11, 0xac, 0x11, 0x24, 0x13, 0x26, 0x16, 0x23, 0x30, 0x20 },
+{ 0x96, 0x96, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x2, 0xa0, 0x6, 0xb0, 0x4, 0x90, 0xc, 0x98, 0x18, 0x8c, 0x30, 0x86, 0x60, 0x83, 0x0, 0x80 },
+{ 0x96, 0x97, 0x0, 0x20, 0x20, 0x20, 0x30, 0x20, 0x17, 0xff, 0x0, 0x20, 0x40, 0x20, 0x60, 0x20, 0x23, 0xfe, 0x0, 0xa8, 0x10, 0xa8, 0x10, 0xa8, 0x11, 0xac, 0x31, 0x24, 0x23, 0x26, 0x26, 0x23, 0x60, 0x20 },
+{ 0x96, 0x98, 0x0, 0x80, 0x30, 0x80, 0x19, 0xff, 0xb, 0x0, 0x6, 0x0, 0x1, 0xfc, 0x0, 0x18, 0x78, 0x30, 0x8, 0x60, 0x8, 0xc0, 0x9, 0x80, 0x9, 0x2, 0x9, 0x86, 0x18, 0xfc, 0x34, 0x0, 0x63, 0xff },
+{ 0x96, 0x99, 0x4, 0x0, 0x5, 0xfc, 0xd, 0x4, 0x9, 0x4, 0x19, 0x4, 0x11, 0xfc, 0x31, 0x10, 0x51, 0x18, 0x13, 0x8, 0x12, 0xcc, 0x16, 0x76, 0x1c, 0x13, 0x11, 0xc0, 0x10, 0x70, 0x10, 0x1c, 0x10, 0x4 },
+{ 0x96, 0x9a, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x0, 0x0, 0x7f, 0xff, 0x49, 0x11, 0x51, 0x11, 0x75, 0x7d, 0x49, 0x55, 0x55, 0x55, 0x7f, 0x7d, 0x49, 0x11, 0x5d, 0x15, 0x6b, 0x1d, 0x49, 0x75, 0x41, 0x3 },
+{ 0x96, 0x9b, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xff, 0x22, 0x8, 0x3f, 0xbf, 0x26, 0xc, 0x2b, 0x1a, 0x32, 0xa9, 0x20, 0x0, 0x27, 0xfc, 0x24, 0x4, 0x27, 0xfc, 0x60, 0x40, 0x4f, 0xfe, 0x48, 0x2, 0xf, 0xfe },
+{ 0x96, 0x9c, 0x0, 0x0, 0x7f, 0xff, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x3, 0xf8, 0x2, 0x8, 0x2, 0x8, 0x6, 0x8, 0x4, 0x8, 0x4, 0x8, 0xc, 0x8, 0x8, 0x8, 0x18, 0x18, 0x30, 0x10, 0x60, 0x70 },
+{ 0x96, 0x9d, 0x10, 0xfc, 0x10, 0x84, 0x10, 0xfc, 0x50, 0x84, 0x58, 0xfc, 0x54, 0x0, 0x53, 0xff, 0x12, 0x49, 0x13, 0xff, 0x10, 0x0, 0x13, 0xff, 0x10, 0x84, 0x10, 0x48, 0x10, 0x30, 0x10, 0xec, 0x13, 0x87 },
+{ 0x96, 0x9e, 0x0, 0x88, 0x30, 0x88, 0x1b, 0xfe, 0x8, 0x88, 0x0, 0x88, 0x67, 0xff, 0x30, 0x20, 0x13, 0xfe, 0x2, 0x22, 0xa, 0xaa, 0xa, 0xaa, 0x1a, 0xaa, 0x12, 0xfa, 0x32, 0x2, 0x22, 0x2, 0x62, 0xe },
+{ 0x96, 0x9f, 0x1, 0xf8, 0x21, 0x8, 0x31, 0xf8, 0x11, 0x8, 0x1, 0xf8, 0x40, 0x0, 0x67, 0xfe, 0x24, 0x92, 0x7, 0xfe, 0x10, 0x0, 0x17, 0xfe, 0x11, 0x4, 0x30, 0x98, 0x20, 0x70, 0x21, 0xdc, 0x67, 0x7 },
+{ 0x96, 0xa0, 0x2, 0x20, 0x7f, 0xff, 0x2, 0x20, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x3f, 0xfe, 0x22, 0x22, 0x3f, 0xfe, 0x0, 0x0, 0x1f, 0xfc, 0x6, 0x38, 0x1, 0xc0, 0xf, 0x78, 0x78, 0xf },
+{ 0x96, 0xa1, 0x0, 0x20, 0x0, 0x20, 0x78, 0x20, 0x4b, 0xfe, 0x48, 0x20, 0x48, 0x20, 0x48, 0x20, 0x4f, 0xff, 0x48, 0xa8, 0x48, 0xa8, 0x49, 0xac, 0x79, 0x24, 0x3, 0x26, 0x6, 0x23, 0x0, 0x20, 0x0, 0x20 },
+{ 0x96, 0xa2, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x2, 0xa0, 0x6, 0xb0, 0x4, 0x90, 0xc, 0x98, 0x18, 0x8c, 0x30, 0x86, 0x60, 0x83, 0x0, 0x80 },
+{ 0x96, 0xa3, 0x4, 0x8, 0x8, 0x8, 0x3f, 0x8, 0x29, 0x3e, 0x29, 0x8, 0x3f, 0x8, 0x29, 0x7f, 0x29, 0x8, 0x3f, 0x1c, 0x14, 0x1c, 0x14, 0xaa, 0x15, 0x9, 0x15, 0x48, 0x35, 0xc8, 0x26, 0x1, 0x63, 0xff },
+{ 0x96, 0xa4, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x1f, 0xfc, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x10, 0x1, 0x18, 0x3, 0xf, 0xfe, 0x0, 0x0 },
+{ 0x96, 0xa5, 0x8, 0x20, 0x8, 0x20, 0x1f, 0xbf, 0x34, 0x48, 0x62, 0x4, 0x4, 0x10, 0x3f, 0xfe, 0x4, 0x10, 0x7, 0xf0, 0x4, 0x10, 0x7, 0xf0, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0xc, 0x18, 0x38, 0xe },
+{ 0x96, 0xa6, 0x10, 0x0, 0x11, 0xfe, 0x11, 0x22, 0x55, 0x22, 0x55, 0x22, 0x55, 0xfe, 0x55, 0x22, 0x55, 0x22, 0x55, 0x22, 0x55, 0x22, 0x55, 0xfe, 0x7c, 0x20, 0x0, 0x20, 0x0, 0x20, 0x0, 0x20, 0x0, 0x20 },
+{ 0x96, 0xa7, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x21, 0x2, 0x21, 0x82, 0x4, 0xa0, 0x14, 0x46, 0x34, 0x8b, 0x67, 0x19, 0x1d, 0xf0, 0x70, 0x0, 0x0, 0x80, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc },
+{ 0x96, 0xa8, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x21, 0x2, 0x24, 0x90, 0x14, 0x66, 0x35, 0x8b, 0xf, 0xf8, 0x78, 0x0, 0x0, 0x80, 0x1f, 0xfc, 0x10, 0x84, 0x1f, 0xfc, 0x0, 0x88, 0x3, 0xfc, 0x3e, 0x6 },
+{ 0x96, 0xa9, 0x0, 0x20, 0x30, 0x20, 0x1b, 0xfe, 0x8, 0x20, 0x1, 0xfc, 0x60, 0x50, 0x37, 0xff, 0x10, 0x88, 0x1, 0x4, 0x6, 0xfb, 0x8, 0x20, 0x1b, 0xfe, 0x10, 0x50, 0x30, 0xd8, 0x21, 0x8c, 0x67, 0x7 },
+{ 0x96, 0xaa, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x0, 0x80, 0x3f, 0xfe, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0x7f, 0xff, 0x8, 0x8, 0xf, 0xf8, 0x1, 0x46, 0x6, 0x6c, 0x7c, 0x30, 0x7, 0x9c, 0x1c, 0x7 },
+{ 0x96, 0xab, 0x4, 0x20, 0x1c, 0x70, 0x70, 0xd8, 0x11, 0x8e, 0x13, 0x3, 0x7c, 0xf8, 0x10, 0x0, 0x11, 0xfe, 0x38, 0x4, 0x34, 0x8, 0x54, 0x20, 0x50, 0x30, 0x11, 0x52, 0x11, 0x43, 0x13, 0x45, 0x12, 0x3c },
+{ 0x96, 0xac, 0x0, 0xc, 0x3c, 0x38, 0x25, 0xe0, 0x25, 0x6, 0x25, 0x3c, 0x3d, 0x20, 0x25, 0x22, 0x25, 0x26, 0x25, 0x2c, 0x3d, 0x30, 0x25, 0x28, 0x25, 0x28, 0x25, 0x2c, 0x25, 0x24, 0x65, 0x26, 0x4e, 0x23 },
+{ 0x96, 0xad, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10, 0x8, 0x54, 0x7e, 0x54, 0x12, 0x56, 0x12, 0xd2, 0x12, 0x93, 0x32, 0x14, 0x26, 0x14, 0x24, 0x34, 0x7e, 0xc, 0xb, 0x8, 0x19, 0x18, 0x30, 0x30, 0x60, 0x60 },
+{ 0x96, 0xae, 0x8, 0xc, 0x4a, 0x38, 0x6a, 0xe0, 0x2a, 0x20, 0x8, 0x20, 0x7e, 0x20, 0x9, 0xfe, 0x8, 0x20, 0x1c, 0x20, 0x1a, 0x20, 0x29, 0xfe, 0x28, 0x20, 0x48, 0x20, 0x8, 0x21, 0x8, 0x33, 0x8, 0x1e },
+{ 0x96, 0xaf, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x1f, 0xfc, 0x10, 0x80, 0x10, 0x80, 0x1f, 0xff, 0x10, 0x40, 0x10, 0x40, 0x10, 0x60, 0x10, 0x20, 0x13, 0xb1, 0x1e, 0x1b, 0x70, 0xe },
+{ 0x96, 0xb0, 0x0, 0x0, 0x3d, 0xfe, 0x25, 0x2, 0x25, 0x2, 0x25, 0x2, 0x3d, 0xfe, 0x25, 0x10, 0x25, 0x10, 0x25, 0xff, 0x3d, 0x10, 0x25, 0x10, 0x25, 0x18, 0x25, 0x8, 0x3d, 0x6d, 0x1, 0xc7, 0x3, 0x2 },
+{ 0x96, 0xb1, 0x0, 0x20, 0x7f, 0x20, 0x2, 0x7f, 0x14, 0x44, 0x18, 0xac, 0x8, 0x28, 0x7f, 0x10, 0x9, 0x6c, 0xa, 0xc7, 0x18, 0x20, 0x18, 0xfe, 0x28, 0x22, 0x28, 0x62, 0x48, 0x46, 0x8, 0xc4, 0x39, 0x8c },
+{ 0x96, 0xb2, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x1f, 0xfc, 0x12, 0x24, 0x1f, 0xfc, 0x0, 0x0, 0x3f, 0xfe, 0x21, 0x2, 0x23, 0xfa, 0x6, 0x30, 0x1d, 0x60, 0x0, 0xc0, 0x3, 0x80, 0x1e, 0x0 },
+{ 0x96, 0xb3, 0x8, 0x0, 0x8, 0x0, 0x1f, 0xfe, 0x39, 0x24, 0x69, 0x24, 0x9, 0x24, 0x7f, 0xff, 0x9, 0x24, 0x9, 0x24, 0x9, 0x24, 0x7f, 0xff, 0x0, 0x0, 0x0, 0x0, 0x12, 0x22, 0x33, 0x33, 0x61, 0x11 },
+{ 0x96, 0xb4, 0x2, 0x0, 0x6, 0x8, 0x4, 0x8, 0x1f, 0xfc, 0x0, 0x4, 0x8, 0x80, 0x8, 0x80, 0x1f, 0xfc, 0x30, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80 },
+{ 0x96, 0xb5, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x18, 0x3, 0x20, 0x1, 0xc0, 0x0, 0x80, 0x7f, 0xff, 0x0, 0xc1, 0x1, 0xc2, 0x1, 0x44, 0x3, 0x40, 0x6, 0x40, 0xc, 0x40, 0x18, 0x40, 0x70, 0x40, 0x1, 0xc0 },
+{ 0x96, 0xb6, 0x3f, 0xfe, 0x0, 0x80, 0x7f, 0xff, 0x40, 0x81, 0x5e, 0xbd, 0x0, 0x80, 0x1e, 0xbc, 0x0, 0x40, 0x3f, 0x7f, 0x2, 0xa4, 0x14, 0x18, 0x7f, 0x67, 0xd, 0x10, 0x14, 0xfe, 0x64, 0x22, 0xc, 0xce },
+{ 0x96, 0xb7, 0x2, 0x88, 0x3a, 0x90, 0x2, 0x7e, 0x2, 0x42, 0x7f, 0x7e, 0x2, 0x42, 0xa, 0x7e, 0x2a, 0x40, 0x2e, 0x7f, 0x2a, 0x40, 0x2a, 0x7f, 0x2a, 0x1, 0x2a, 0xab, 0x3e, 0xa9, 0x62, 0x83, 0x1, 0x6 },
+{ 0x96, 0xb8, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x7d, 0xff, 0x10, 0x0, 0x10, 0xfe, 0x38, 0x82, 0x34, 0x82, 0x34, 0x82, 0x50, 0xfe, 0x50, 0x10, 0x10, 0x92, 0x10, 0x92, 0x11, 0x93, 0x11, 0x11, 0x10, 0x70 },
+{ 0x96, 0xb9, 0x8, 0x0, 0x9, 0xff, 0x8, 0x11, 0x8, 0x9e, 0x7e, 0x90, 0x12, 0xd0, 0x13, 0xbf, 0x12, 0x0, 0x32, 0xfe, 0x26, 0x82, 0x24, 0xfe, 0x7c, 0x82, 0xa, 0xfe, 0x1a, 0x82, 0x30, 0x82, 0x60, 0x86 },
+{ 0x96, 0xba, 0x8, 0x10, 0x8, 0x10, 0x8, 0xfe, 0x8, 0x82, 0x7e, 0x82, 0x12, 0xfe, 0x12, 0x82, 0x12, 0x82, 0x32, 0xfe, 0x26, 0x91, 0x24, 0x93, 0x7c, 0x9a, 0xa, 0x88, 0x1a, 0x8c, 0x30, 0xf6, 0x63, 0x83 },
+{ 0x96, 0xbb, 0x0, 0x0, 0x3f, 0xfe, 0x20, 0x2, 0x27, 0xf2, 0x4, 0x10, 0x4, 0x10, 0x7, 0xf0, 0x4, 0x10, 0x4, 0x10, 0x7, 0xf0, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x0, 0x2, 0x20, 0xe, 0x38, 0x38, 0xe },
+{ 0x96, 0xbc, 0x1, 0x0, 0x1, 0x0, 0x3, 0xf8, 0x6, 0x8, 0xc, 0x18, 0x1b, 0x10, 0x71, 0xb0, 0x0, 0x60, 0x0, 0xc0, 0x3, 0xfe, 0xe, 0x2, 0x7a, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x3, 0xfe },
+{ 0x96, 0xbd, 0x0, 0x80, 0x1, 0xc0, 0x3, 0x60, 0x6, 0x30, 0x1c, 0x1c, 0x73, 0xe7, 0x0, 0x0, 0x0, 0x0, 0x1f, 0x7c, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x1f, 0x5c, 0x0, 0x40, 0x0, 0x40 },
+{ 0x96, 0xbe, 0x0, 0x0, 0x0, 0xfe, 0x7c, 0x82, 0x44, 0x82, 0x44, 0x82, 0x44, 0xfe, 0x7c, 0x82, 0x44, 0x82, 0x44, 0x82, 0x44, 0xfe, 0x44, 0x82, 0x7c, 0x82, 0x1, 0x82, 0x1, 0x2, 0x3, 0x2, 0xe, 0xe },
+{ 0x96, 0xbf, 0x0, 0x0, 0x3e, 0x7e, 0x22, 0x42, 0x22, 0x7e, 0x3e, 0x42, 0x22, 0x7e, 0x22, 0x42, 0x22, 0x42, 0x3e, 0xc2, 0x1, 0x8e, 0x0, 0x0, 0x1f, 0xfc, 0x12, 0x44, 0x12, 0x44, 0x12, 0x44, 0x7f, 0xff },
+{ 0x96, 0xc0, 0x0, 0x20, 0x32, 0x22, 0x1b, 0x26, 0x9, 0x24, 0x0, 0x20, 0x7, 0xff, 0x0, 0xa8, 0x78, 0xa8, 0x9, 0xac, 0x9, 0x24, 0xb, 0x26, 0xe, 0x23, 0x8, 0x20, 0x18, 0x20, 0x34, 0x0, 0x63, 0xff },
+{ 0x96, 0xc1, 0x10, 0x40, 0x38, 0x40, 0x2c, 0x7c, 0x64, 0xc4, 0x40, 0x8c, 0x7d, 0xc8, 0x13, 0x58, 0x10, 0x30, 0x7c, 0x20, 0x10, 0x7e, 0x55, 0xc2, 0x54, 0x42, 0x50, 0x42, 0x1c, 0x42, 0x30, 0x42, 0x60, 0x7e },
+{ 0x96, 0xc2, 0x0, 0x20, 0x0, 0x40, 0x79, 0xfc, 0x49, 0x4, 0x49, 0xfc, 0x49, 0x4, 0x49, 0xfc, 0x49, 0x0, 0x49, 0xff, 0x49, 0x0, 0x79, 0xfe, 0x0, 0x2, 0x5, 0x52, 0xd, 0x52, 0x8, 0x6, 0x0, 0xc },
+{ 0x96, 0xc3, 0x8, 0x0, 0x9, 0xff, 0x8, 0x40, 0x8, 0x44, 0x7e, 0xc4, 0x12, 0x9e, 0x13, 0xf3, 0x12, 0x0, 0x36, 0x10, 0x24, 0x10, 0x24, 0xfe, 0x7e, 0x10, 0xb, 0x10, 0x19, 0x10, 0x30, 0x10, 0x61, 0xff },
+{ 0x96, 0xc4, 0x4, 0x40, 0x14, 0x40, 0x14, 0x40, 0x14, 0x40, 0x3f, 0x46, 0x24, 0x5c, 0x64, 0x70, 0x4, 0x40, 0x7, 0x40, 0x1c, 0x40, 0x74, 0x40, 0x4, 0x40, 0x4, 0x40, 0x4, 0x41, 0x4, 0x63, 0x4, 0x3e },
+{ 0x96, 0xc5, 0x0, 0xa, 0x20, 0x9, 0x30, 0x8, 0x17, 0xff, 0x4, 0x8, 0x47, 0xe8, 0x64, 0x9, 0x24, 0x89, 0x6, 0xab, 0x16, 0xaa, 0x14, 0x8e, 0x15, 0x44, 0x35, 0x44, 0x26, 0x2d, 0x24, 0x17, 0x68, 0x22 },
+{ 0x96, 0xc6, 0x2, 0x0, 0x3, 0xf8, 0x6, 0x10, 0xc, 0x20, 0x38, 0x40, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x2, 0x40, 0x2, 0x40, 0x6, 0x40, 0xc, 0x41, 0x18, 0x63, 0x70, 0x3e },
+{ 0x96, 0xc7, 0x8, 0x10, 0x8, 0x20, 0x8, 0xfe, 0x7e, 0x82, 0x8, 0xfe, 0x8, 0x82, 0x1c, 0x82, 0x1a, 0xfe, 0x1a, 0x10, 0x29, 0xff, 0x29, 0x11, 0x49, 0x11, 0x9, 0x11, 0x9, 0x17, 0x8, 0x10, 0x8, 0x10 },
+{ 0x96, 0xc8, 0x8, 0x10, 0x18, 0x20, 0x10, 0xfe, 0x64, 0x82, 0x2c, 0xfe, 0x18, 0x82, 0x10, 0x82, 0x24, 0xfe, 0x7c, 0x10, 0x15, 0xff, 0x11, 0x11, 0x55, 0x11, 0x55, 0x11, 0x55, 0x17, 0x10, 0x10, 0x10, 0x10 },
+{ 0x96, 0xc9, 0x8, 0x0, 0x1b, 0xff, 0x10, 0x20, 0x64, 0x40, 0x2d, 0xfe, 0x19, 0x4a, 0x11, 0x4a, 0x25, 0x7a, 0x7d, 0x4a, 0x15, 0x4a, 0x11, 0x7a, 0x55, 0x4a, 0x55, 0x4a, 0x55, 0x4a, 0x11, 0xfe, 0x10, 0x0 },
+{ 0x96, 0xca, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x80, 0x1, 0x0, 0x3f, 0xfe, 0x22, 0x22, 0x22, 0x22, 0x23, 0xe2, 0x22, 0x22, 0x22, 0x22, 0x23, 0xe2, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x3f, 0xfe, 0x0, 0x0 },
+{ 0x96, 0xcb, 0x8, 0x0, 0x8, 0xff, 0x7f, 0x10, 0x8, 0x20, 0x3e, 0xfe, 0x8, 0xaa, 0x7f, 0xba, 0x10, 0xaa, 0x1e, 0xaa, 0x22, 0xba, 0x36, 0xaa, 0x5c, 0xaa, 0x8, 0xfe, 0x1c, 0x0, 0x37, 0x0, 0x61, 0xff },
+{ 0x96, 0xcc, 0x10, 0x48, 0x10, 0x48, 0x13, 0xff, 0x10, 0x48, 0x7c, 0x48, 0x11, 0xfe, 0x11, 0x2, 0x11, 0xfe, 0x1d, 0x2, 0x71, 0xfe, 0x10, 0x20, 0x13, 0xff, 0x10, 0x48, 0x10, 0xcc, 0x11, 0x86, 0x33, 0x3 },
+{ 0x96, 0xcd, 0x10, 0x48, 0x10, 0x48, 0x13, 0xff, 0x7c, 0x48, 0x10, 0x48, 0x11, 0xfe, 0x39, 0x2, 0x35, 0xfe, 0x35, 0x2, 0x51, 0xfe, 0x50, 0x20, 0x13, 0xff, 0x10, 0x48, 0x10, 0xcc, 0x11, 0x86, 0x13, 0x3 },
+{ 0x96, 0xce, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x4, 0x54, 0x0, 0x42, 0x1f, 0xff, 0x10, 0x40, 0x10, 0x42, 0x10, 0x62, 0x10, 0x26, 0x10, 0x2c, 0x10, 0x38, 0x30, 0xf1, 0x27, 0x9b, 0x60, 0xe },
+{ 0x96, 0xcf, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x8, 0x0, 0x8, 0x0, 0x8, 0x0, 0x7, 0xfc, 0x1, 0x0, 0x1, 0x0, 0x7f, 0xff, 0x2, 0x10, 0x4, 0x30, 0xf, 0x60, 0x1, 0xc0, 0x7, 0x78, 0x3c, 0xe },
+{ 0x96, 0xd0, 0x0, 0x0, 0x1f, 0xf8, 0x0, 0x30, 0x0, 0x40, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x3, 0x80, 0x0, 0x0, 0x1f, 0xfc, 0x12, 0x44, 0x12, 0x44, 0x12, 0x44, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x96, 0xd1, 0x0, 0x18, 0x0, 0xf0, 0x1f, 0x80, 0x1, 0x0, 0x1, 0x0, 0x3f, 0xfe, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x7f, 0xff, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x1, 0x1, 0x83, 0x0, 0xfe },
+{ 0x96, 0xd2, 0x4, 0x0, 0x45, 0xfe, 0x28, 0x4, 0x10, 0x8, 0x10, 0x10, 0x2b, 0xff, 0x48, 0x10, 0x8, 0x10, 0x18, 0x70, 0x18, 0x0, 0x29, 0xfe, 0x49, 0x52, 0x9, 0x52, 0x9, 0x52, 0x1b, 0xff, 0x70, 0x0 },
+{ 0x96, 0xd3, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0xf, 0xfc, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8 },
+{ 0x96, 0xd4, 0x8, 0x0, 0x19, 0xff, 0x11, 0x1, 0x65, 0x45, 0x2d, 0x29, 0x19, 0xff, 0x11, 0x11, 0x25, 0x11, 0x7d, 0xff, 0x15, 0x21, 0x11, 0x21, 0x55, 0x21, 0x55, 0x3d, 0x55, 0x1, 0x11, 0x1, 0x11, 0x7 },
+{ 0x96, 0xd5, 0x8, 0x6, 0x8, 0x1c, 0x7f, 0x70, 0x8, 0x10, 0x8, 0x10, 0x3e, 0x7e, 0x8, 0x10, 0x8, 0x10, 0x7f, 0x10, 0x8, 0xff, 0x1c, 0x10, 0x1a, 0x10, 0x29, 0x10, 0x48, 0x11, 0x8, 0x1b, 0x8, 0xe },
+{ 0x96, 0xd6, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x3f, 0xfe, 0x20, 0x2, 0x2f, 0xfa, 0x0, 0x0, 0x7f, 0xff, 0x1, 0x0, 0x6, 0x8c, 0x39, 0x58, 0x6, 0xf0, 0x39, 0x58, 0x6, 0x4c, 0x78, 0x47, 0x1, 0xc0 },
+{ 0x96, 0xd7, 0x10, 0x12, 0x17, 0x92, 0x10, 0x3e, 0x1f, 0xd4, 0x30, 0x14, 0x27, 0x98, 0x20, 0x7f, 0x60, 0x10, 0x27, 0xa0, 0x20, 0x7e, 0x20, 0x22, 0x27, 0xa2, 0x24, 0xbe, 0x24, 0xa2, 0x24, 0xa2, 0x27, 0xbe },
+{ 0x96, 0xd8, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x2, 0xa0, 0x2, 0xa0, 0x6, 0xb0, 0x4, 0x90, 0xc, 0x98, 0x8, 0x88, 0x18, 0x8c, 0x30, 0x86, 0x60, 0x83, 0x0, 0x80, 0x0, 0x80 },
+{ 0x96, 0xd9, 0x0, 0x8, 0x3f, 0x8a, 0x24, 0x89, 0x3f, 0x88, 0x24, 0xff, 0x24, 0x88, 0x3f, 0x9c, 0x4, 0x14, 0x3f, 0x94, 0x4, 0x36, 0x7, 0xa2, 0x7c, 0x63, 0x0, 0x0, 0x12, 0x22, 0x33, 0x33, 0x61, 0x11 },
+{ 0x96, 0xda, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x0, 0x0 },
+{ 0x96, 0xdb, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x2, 0xa0, 0x6, 0xb0, 0xc, 0x98, 0x18, 0x8c, 0x70, 0x87, 0x0, 0x80, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x96, 0xdc, 0x8, 0x0, 0x8, 0x0, 0xf, 0xfe, 0x9, 0x22, 0x19, 0x22, 0x11, 0x22, 0x33, 0x22, 0x62, 0x22, 0x6, 0x62, 0xc, 0x42, 0x18, 0xc2, 0x30, 0x82, 0x1, 0x86, 0x3, 0x4, 0xe, 0xc, 0x0, 0x38 },
+{ 0x96, 0xdd, 0x8, 0x42, 0x1c, 0x66, 0x16, 0x24, 0x32, 0x0, 0x28, 0xff, 0x7e, 0x24, 0x22, 0x24, 0x3e, 0x24, 0x22, 0xff, 0x3e, 0x24, 0x20, 0x24, 0x22, 0x24, 0x22, 0x24, 0x2f, 0x64, 0x39, 0x44, 0x60, 0xc4 },
+{ 0x96, 0xde, 0x0, 0x98, 0x0, 0x8c, 0x0, 0x84, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x1, 0xc0, 0x1, 0x40, 0x1, 0x40, 0x3, 0x40, 0x2, 0x40, 0x6, 0x40, 0xc, 0x41, 0x18, 0x63, 0x70, 0x3e },
+{ 0x96, 0xdf, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x4, 0x10, 0x4, 0x1f, 0xfc, 0x10, 0x40, 0x10, 0x40, 0x1f, 0xff, 0x10, 0x40, 0x10, 0xe0, 0x30, 0xb0, 0x21, 0x98, 0x63, 0xc, 0xe, 0x7 },
+{ 0x96, 0xe0, 0x8, 0x0, 0x4a, 0xfe, 0x6a, 0x22, 0x2a, 0x22, 0x8, 0x22, 0x7f, 0x22, 0x8, 0xa2, 0x8, 0xa2, 0x1c, 0xe2, 0x1a, 0x42, 0x2a, 0x42, 0x28, 0xe2, 0x48, 0xa6, 0x8, 0xa4, 0x9, 0x84, 0xb, 0x1c },
+{ 0x96, 0xe1, 0x8, 0x88, 0x7f, 0xff, 0x8, 0x88, 0x8, 0xf8, 0x8, 0x0, 0xf, 0xfc, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x4, 0x10, 0x38, 0xe },
+{ 0x96, 0xe2, 0x0, 0x0, 0x3f, 0x7e, 0x21, 0x42, 0x3f, 0x7e, 0x21, 0x42, 0x3f, 0x7e, 0x20, 0x2, 0x20, 0x2, 0x23, 0xe2, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x23, 0xe2, 0x20, 0x2, 0x20, 0x2, 0x20, 0xe },
+{ 0x96, 0xe3, 0x0, 0x0, 0x3f, 0x7e, 0x21, 0x42, 0x3f, 0x7e, 0x21, 0x42, 0x3f, 0x7e, 0x20, 0x2, 0x20, 0x82, 0x20, 0xc2, 0x21, 0x52, 0x25, 0x1a, 0x25, 0xa, 0x2d, 0x12, 0x28, 0xf2, 0x20, 0x2, 0x20, 0xe },
+{ 0x96, 0xe4, 0x8, 0x10, 0x18, 0x10, 0x10, 0x10, 0x65, 0xff, 0x2c, 0x44, 0x18, 0x44, 0x10, 0x44, 0x22, 0x6c, 0x7e, 0x28, 0xa, 0x38, 0x8, 0x10, 0x2a, 0x38, 0x2a, 0x28, 0x6a, 0x6c, 0x48, 0xc6, 0x9, 0x83 },
+{ 0x96, 0xe5, 0x0, 0x0, 0x3f, 0x7e, 0x21, 0x42, 0x3f, 0x7e, 0x21, 0x42, 0x21, 0x42, 0x3f, 0x7e, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0xe },
+{ 0x96, 0xe6, 0x8, 0x0, 0x8, 0x0, 0xf, 0xfc, 0x8, 0x84, 0x1c, 0x84, 0x14, 0x84, 0x36, 0x84, 0x62, 0x84, 0x3, 0x84, 0x1, 0xc, 0x3, 0x88, 0x6, 0xe8, 0xc, 0x38, 0x18, 0x1f, 0x70, 0x10, 0x0, 0xf0 },
+{ 0x96, 0xe7, 0x0, 0x80, 0x8, 0x80, 0x8, 0x80, 0x8, 0x9c, 0x8, 0xf4, 0xb, 0xc4, 0xe, 0x84, 0x78, 0x84, 0x8, 0x84, 0x8, 0x84, 0x8, 0x9c, 0x8, 0x80, 0x8, 0x1, 0xc, 0x3, 0x7, 0xfe, 0x0, 0x0 },
+{ 0x96, 0xe8, 0x0, 0x40, 0x0, 0x40, 0x30, 0xc4, 0x18, 0x86, 0x9, 0x82, 0x1, 0x3f, 0x7, 0xe1, 0x0, 0x0, 0x8, 0x0, 0x9, 0xfe, 0x19, 0x2, 0x11, 0x2, 0x31, 0x2, 0x21, 0x2, 0x61, 0x2, 0x1, 0xfe },
+{ 0x96, 0xe9, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x4, 0x40, 0x4, 0x40, 0xc, 0xfc, 0x8, 0x84, 0x19, 0xcc, 0x33, 0x28, 0x56, 0x98, 0x10, 0x70, 0x10, 0x20, 0x10, 0x70, 0x11, 0xdc, 0x17, 0x7 },
+{ 0x96, 0xea, 0x2, 0x20, 0xe, 0x38, 0x39, 0x4e, 0x0, 0x80, 0x7, 0x70, 0x7c, 0x1f, 0x0, 0x0, 0x7f, 0xbe, 0x11, 0x22, 0x1f, 0x24, 0x11, 0x28, 0x1f, 0x24, 0x11, 0x22, 0x1f, 0x22, 0x71, 0x2e, 0x1, 0x20 },
+{ 0x96, 0xeb, 0x0, 0x0, 0x7f, 0xbf, 0x11, 0x21, 0x11, 0x23, 0x1f, 0x22, 0x11, 0x26, 0x11, 0x24, 0x11, 0x22, 0x1f, 0x21, 0x11, 0x21, 0x11, 0x21, 0x11, 0x21, 0x1f, 0x27, 0x71, 0x20, 0x1, 0x20, 0x1, 0x20 },
+{ 0x96, 0xec, 0x0, 0x0, 0x7f, 0x7e, 0x49, 0x2, 0x49, 0x4, 0x7f, 0x28, 0x49, 0x10, 0x49, 0xff, 0x7f, 0x11, 0x8, 0x12, 0x8, 0x10, 0x7f, 0x10, 0x8, 0x10, 0x8, 0x10, 0xf, 0x10, 0x78, 0x10, 0x0, 0x70 },
+{ 0x96, 0xed, 0x0, 0x40, 0x7c, 0x40, 0x4, 0x40, 0x4, 0xff, 0x4, 0x90, 0x3d, 0x90, 0x20, 0x10, 0x20, 0x10, 0x20, 0x92, 0x3c, 0x92, 0x4, 0x92, 0x5, 0x93, 0x5, 0x11, 0xc, 0x10, 0x8, 0x10, 0x38, 0x70 },
+{ 0x96, 0xee, 0x4, 0x0, 0x4, 0x0, 0xf, 0xfc, 0x8, 0x80, 0x18, 0x80, 0x30, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x1, 0x40, 0x1, 0x40, 0x3, 0x60, 0x2, 0x20, 0x6, 0x30, 0xc, 0x18, 0x18, 0xc, 0x70, 0x7 },
+{ 0x96, 0xef, 0x0, 0x0, 0x1f, 0xff, 0x10, 0x0, 0x10, 0x0, 0x13, 0xf8, 0x12, 0x8, 0x12, 0x8, 0x12, 0x8, 0x12, 0x8, 0x12, 0x8, 0x12, 0x38, 0x12, 0x0, 0x32, 0x0, 0x22, 0x1, 0x63, 0x3, 0x1, 0xfe },
+{ 0x96, 0xf0, 0x4, 0x0, 0xc, 0xf8, 0x18, 0x88, 0x30, 0x88, 0x64, 0x88, 0xd, 0x8f, 0x1b, 0x0, 0x30, 0x0, 0x71, 0xfc, 0x10, 0x84, 0x10, 0xcc, 0x10, 0x58, 0x10, 0x30, 0x10, 0x78, 0x10, 0xcc, 0x13, 0x87 },
+{ 0x96, 0xf1, 0x8, 0x40, 0x18, 0x40, 0x30, 0x40, 0x62, 0xfe, 0x36, 0x82, 0xd, 0x82, 0x18, 0x2, 0x32, 0x62, 0x7f, 0x32, 0x9, 0x12, 0x8, 0x2, 0x2a, 0x2, 0x2b, 0x2, 0x69, 0x6, 0x48, 0x4, 0x8, 0x1c },
+{ 0x96, 0xf2, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x1, 0x0, 0x33, 0xe6, 0x1a, 0x2c, 0x3, 0xe0, 0x1a, 0x2c, 0x33, 0xe6, 0x0, 0x80, 0x7f, 0xff, 0x2, 0xa0, 0x6, 0xb0, 0x1c, 0x9c, 0x70, 0x87, 0x0, 0x80 },
+{ 0x96, 0xf3, 0x0, 0x0, 0x3c, 0xfe, 0x0, 0x82, 0x7e, 0x82, 0x0, 0x82, 0x3c, 0x82, 0x0, 0xfe, 0x0, 0x90, 0x3c, 0x90, 0x0, 0x98, 0x0, 0x88, 0x3c, 0x88, 0x24, 0x8c, 0x24, 0x84, 0x25, 0x86, 0x3d, 0x3 },
+{ 0x96, 0xf4, 0x0, 0x0, 0x3e, 0xef, 0x22, 0x21, 0x22, 0xef, 0x22, 0x21, 0x3e, 0xef, 0x8, 0x48, 0x8, 0x90, 0x29, 0xff, 0x2e, 0x90, 0x28, 0xfe, 0x28, 0x90, 0x28, 0xfe, 0x2e, 0x90, 0x38, 0x90, 0x60, 0xff },
+{ 0x96, 0xf5, 0x10, 0x10, 0x10, 0x10, 0x11, 0xff, 0x7e, 0x10, 0x0, 0xfe, 0x44, 0x10, 0x45, 0xff, 0x64, 0x0, 0x2c, 0xfe, 0x28, 0x82, 0x8, 0xfe, 0x1e, 0x82, 0x70, 0xfe, 0x0, 0x82, 0x0, 0x82, 0x0, 0x8e },
+{ 0x96, 0xf6, 0x10, 0x20, 0x10, 0x60, 0x11, 0xcf, 0x7d, 0x29, 0x11, 0x29, 0x11, 0x29, 0x39, 0x29, 0x35, 0x29, 0x55, 0x29, 0x51, 0x29, 0x11, 0x29, 0x11, 0xe9, 0x13, 0x2f, 0x10, 0x28, 0x10, 0x68, 0x10, 0xc8 },
+{ 0x96, 0xf7, 0x2, 0x20, 0x7f, 0xff, 0x2, 0x20, 0x4, 0x10, 0x24, 0x90, 0x15, 0x3f, 0x7f, 0xa4, 0xe, 0x64, 0x15, 0x14, 0x64, 0xd4, 0x8, 0x1c, 0x7f, 0xc8, 0x11, 0x1c, 0x3a, 0x14, 0xc, 0x36, 0x73, 0x63 },
+{ 0x96, 0xf8, 0x10, 0x8, 0x39, 0x3e, 0x29, 0xaa, 0x6c, 0xbe, 0x0, 0x8, 0x7c, 0x7f, 0x10, 0x0, 0x13, 0xbe, 0x7c, 0xa2, 0x10, 0xbe, 0x54, 0xa0, 0x54, 0xbe, 0x50, 0xa2, 0x1d, 0xbe, 0x31, 0x40, 0x63, 0x3f },
+{ 0x96, 0xf9, 0x10, 0x20, 0x10, 0x70, 0x10, 0xd8, 0x15, 0x8c, 0x57, 0x7, 0x54, 0xf8, 0x50, 0x0, 0x53, 0xc2, 0x12, 0x52, 0x13, 0xd2, 0x12, 0x52, 0x13, 0xd2, 0x12, 0x52, 0x12, 0x42, 0x12, 0x42, 0x12, 0xce },
+{ 0x96, 0xfa, 0x0, 0x80, 0x3, 0xe0, 0xe, 0x38, 0x79, 0xcf, 0x0, 0x0, 0x1f, 0x4, 0x11, 0x24, 0x1f, 0x24, 0x11, 0x24, 0x1f, 0x24, 0x11, 0x4, 0x13, 0x1c, 0x0, 0xc0, 0x12, 0x66, 0x32, 0xb, 0x61, 0xf9 },
+{ 0x96, 0xfb, 0x0, 0x20, 0x30, 0x20, 0x18, 0x20, 0x8, 0x20, 0x3, 0xfe, 0x62, 0x22, 0x32, 0x22, 0x12, 0x22, 0x2, 0x22, 0xb, 0xfe, 0xa, 0x22, 0x1a, 0x22, 0x12, 0x22, 0x32, 0x22, 0x23, 0xfe, 0x60, 0x0 },
+{ 0x96, 0xfc, 0x0, 0x40, 0x1f, 0xff, 0x10, 0x40, 0x51, 0xb0, 0x3e, 0xef, 0x10, 0x0, 0x17, 0xd2, 0x14, 0x52, 0x37, 0xd2, 0x54, 0x52, 0x17, 0xd2, 0x14, 0x46, 0x30, 0x0, 0x25, 0x42, 0x6d, 0x2b, 0x9, 0xf9 },
+{ 0x97, 0x40, 0x0, 0x10, 0x3c, 0x38, 0x0, 0x6c, 0x7e, 0xc6, 0x1, 0xbb, 0x3c, 0x0, 0x1, 0xe2, 0x1, 0x2a, 0x3d, 0x2a, 0x1, 0xea, 0x1, 0x2a, 0x3d, 0x2a, 0x25, 0xe2, 0x25, 0x22, 0x25, 0x22, 0x3d, 0x6e },
+{ 0x97, 0x41, 0x10, 0x10, 0x10, 0x38, 0x7c, 0x6c, 0x10, 0xc6, 0x7d, 0xbb, 0x54, 0x0, 0x55, 0xe2, 0x7d, 0x2a, 0x55, 0x2a, 0x55, 0xea, 0x7d, 0x2a, 0x11, 0x2a, 0x7d, 0xe2, 0x11, 0x22, 0x11, 0x22, 0x11, 0x6e },
+{ 0x97, 0x42, 0x0, 0x44, 0x0, 0xcc, 0x3c, 0x88, 0x25, 0xff, 0x27, 0x10, 0x25, 0x10, 0x25, 0x10, 0x25, 0xfe, 0x25, 0x10, 0x25, 0x10, 0x25, 0x10, 0x3d, 0xfe, 0x1, 0x10, 0x1, 0x10, 0x1, 0x10, 0x1, 0xff },
+{ 0x97, 0x43, 0x4, 0x20, 0x4, 0x20, 0xc, 0x20, 0xb, 0xff, 0x18, 0x40, 0x10, 0x40, 0x30, 0xc0, 0x50, 0x80, 0x11, 0xfe, 0x13, 0x82, 0x16, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0xfe },
+{ 0x97, 0x44, 0xb, 0xff, 0x8, 0x20, 0x19, 0xfc, 0x11, 0x4, 0x31, 0xfc, 0x31, 0x4, 0x57, 0xff, 0x14, 0x21, 0x12, 0x92, 0x12, 0x85, 0x14, 0x7c, 0x10, 0x80, 0x11, 0xfc, 0x16, 0x84, 0x10, 0x78, 0x17, 0x87 },
+{ 0x97, 0x45, 0x1f, 0xf8, 0x2, 0x30, 0x1, 0x40, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x0, 0x80, 0x7f, 0xfe, 0x1, 0x2, 0x3, 0x2, 0xe, 0x6, 0x38, 0x1c },
+{ 0x97, 0x46, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x7f, 0xff, 0x1, 0x0, 0x1, 0x0, 0x3, 0xf8, 0x2, 0x8, 0x7, 0x18, 0x5, 0x10, 0xd, 0xb0, 0x18, 0xe0, 0x30, 0x70, 0x60, 0xd8, 0x3, 0x8c, 0xe, 0x7 },
+{ 0x97, 0x47, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x2, 0x21, 0x2, 0x7f, 0xff, 0x1, 0x0, 0x2, 0x0, 0x7, 0xfc, 0xe, 0x4, 0x1b, 0xfc, 0x72, 0x4, 0x3, 0xfc, 0x2, 0x4, 0x2, 0x4, 0x2, 0x1c },
+{ 0x97, 0x48, 0x0, 0x80, 0x24, 0x92, 0x24, 0x92, 0x28, 0xa2, 0x28, 0xa2, 0x32, 0xca, 0x2a, 0xaa, 0x24, 0x92, 0x24, 0x92, 0x28, 0xa2, 0x2a, 0xaa, 0x2e, 0xbe, 0x3a, 0xe6, 0x20, 0x82, 0x20, 0x82, 0x3f, 0xfe },
+{ 0x97, 0x49, 0x4, 0x40, 0xc, 0x40, 0x8, 0xff, 0x18, 0x84, 0x15, 0x4c, 0x34, 0x58, 0x54, 0x30, 0x14, 0x38, 0x10, 0x6c, 0x11, 0xc7, 0x0, 0x0, 0x1, 0x80, 0x14, 0xc6, 0x14, 0x4b, 0x36, 0x19, 0x63, 0xf0 },
+{ 0x97, 0x4a, 0x7f, 0xff, 0x0, 0x80, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x7f, 0xff, 0x41, 0x1, 0x54, 0x89, 0x14, 0x14, 0x27, 0xf2, 0x2, 0x0, 0x7, 0xf8, 0x3c, 0x10, 0x3, 0xe0, 0x7c, 0x1f },
+{ 0x97, 0x4b, 0x10, 0x0, 0x11, 0xfc, 0x11, 0x4, 0x11, 0x4, 0x7d, 0xfc, 0x10, 0x0, 0x17, 0xff, 0x11, 0x4, 0x1d, 0xfc, 0x71, 0x4, 0x11, 0xfc, 0x11, 0x7, 0x11, 0xfc, 0x17, 0x4, 0x10, 0x4, 0x30, 0x4 },
+{ 0x97, 0x4c, 0x1, 0x0, 0x1, 0x0, 0x7f, 0xff, 0x1, 0x0, 0x3, 0x0, 0x3, 0xfc, 0x6, 0x4, 0xe, 0x4, 0x1b, 0xfc, 0x32, 0x4, 0x62, 0x4, 0x3, 0xfc, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x1c },
+{ 0x97, 0x4d, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10, 0x7e, 0x10, 0x8, 0xff, 0x8, 0x91, 0x1c, 0x91, 0x1a, 0x91, 0x1a, 0x91, 0x28, 0xff, 0x28, 0x91, 0x48, 0x91, 0x8, 0x91, 0x8, 0x91, 0x8, 0x91, 0x8, 0xff },
+{ 0x97, 0x4e, 0x3, 0xfe, 0x30, 0x84, 0x18, 0x48, 0xb, 0xfe, 0x2, 0x22, 0x62, 0x22, 0x33, 0xfe, 0x12, 0x22, 0x2, 0x22, 0xb, 0xfe, 0x8, 0x20, 0x1b, 0xff, 0x10, 0x41, 0x30, 0xc3, 0x21, 0x82, 0x67, 0xe },
+{ 0x97, 0x4f, 0x0, 0x0, 0x37, 0xfe, 0x18, 0x4, 0x8, 0x88, 0x0, 0x50, 0x63, 0xfe, 0x32, 0x22, 0x12, 0x22, 0x3, 0xfe, 0xa, 0x22, 0xa, 0x22, 0x1b, 0xfe, 0x12, 0x22, 0x32, 0x22, 0x22, 0x22, 0x62, 0x2e },
+{ 0x97, 0x50, 0x5, 0x4, 0x45, 0x8c, 0x28, 0x88, 0x17, 0xff, 0x10, 0x50, 0x28, 0x50, 0x4b, 0xfe, 0xa, 0x52, 0x1a, 0x52, 0x1a, 0x9e, 0x2b, 0x2, 0x4a, 0x2, 0xb, 0xfe, 0xa, 0x2, 0x1a, 0x2, 0x73, 0xfe },
+{ 0x97, 0x51, 0x20, 0x88, 0x31, 0x8c, 0x11, 0xa, 0x7f, 0xca, 0xa, 0x8, 0xa, 0x7f, 0x3f, 0x88, 0x2a, 0x88, 0x2a, 0x88, 0x2b, 0x88, 0x30, 0x9c, 0x20, 0x94, 0x3f, 0x94, 0x20, 0xb6, 0x3f, 0xa2, 0x0, 0x63 },
+{ 0x97, 0x52, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x0, 0x0 },
+{ 0x97, 0x53, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x7d, 0xff, 0x4, 0x20, 0xc, 0x60, 0x8, 0x40, 0x18, 0x40, 0x10, 0xfe, 0x38, 0xc2, 0x55, 0x42, 0x12, 0x42, 0x10, 0x42, 0x10, 0x42, 0x10, 0x42, 0x10, 0x7e },
+{ 0x97, 0x54, 0x10, 0x44, 0x10, 0x44, 0x10, 0xc6, 0x7d, 0x93, 0x4, 0x38, 0xc, 0x6c, 0x8, 0xc6, 0x19, 0x83, 0x14, 0x0, 0x38, 0xfe, 0x54, 0x82, 0x12, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0xfe },
+{ 0x97, 0x55, 0x0, 0x6, 0x3c, 0x1c, 0x0, 0xf0, 0x7e, 0x10, 0x1, 0xff, 0x3c, 0x54, 0x0, 0xd6, 0x1, 0x93, 0x3c, 0x0, 0x0, 0xfc, 0x0, 0x24, 0x3c, 0x27, 0x24, 0x61, 0x24, 0x41, 0x24, 0xc1, 0x3d, 0x87 },
+{ 0x97, 0x56, 0x1, 0x10, 0x21, 0x10, 0x31, 0x10, 0x17, 0xff, 0x1, 0x20, 0x1, 0x1e, 0x1, 0xc2, 0x71, 0x44, 0x11, 0x44, 0x11, 0x5f, 0x13, 0x44, 0x12, 0x44, 0x12, 0x44, 0x36, 0xdc, 0x28, 0x0, 0x67, 0xff },
+{ 0x97, 0x57, 0x7, 0xf0, 0x4, 0x10, 0x4, 0x10, 0x7, 0xf0, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x0, 0x10, 0x0, 0x10, 0x0, 0x10, 0x1, 0x18, 0x3, 0xf, 0xfe },
+{ 0x97, 0x58, 0x1, 0x80, 0x7, 0x1f, 0x3c, 0x11, 0x4, 0x13, 0x3f, 0xd2, 0x14, 0x96, 0x14, 0x94, 0x7f, 0xf2, 0x14, 0x91, 0x14, 0x91, 0x3f, 0xd1, 0x4, 0x11, 0x4, 0x17, 0x5, 0x90, 0xf, 0x10, 0x38, 0x10 },
+{ 0x97, 0x59, 0x10, 0x22, 0x10, 0x26, 0x10, 0x24, 0x10, 0x7f, 0x7f, 0x48, 0x10, 0xc8, 0x11, 0x48, 0x14, 0x7e, 0x14, 0x48, 0x34, 0x48, 0x24, 0x48, 0x2c, 0x7e, 0x28, 0x48, 0x6a, 0x48, 0x1f, 0x48, 0x31, 0x7f },
+{ 0x97, 0x5a, 0x0, 0x8, 0x7f, 0x8, 0x0, 0x8, 0x3e, 0x7f, 0x22, 0x49, 0x3e, 0x49, 0x0, 0x49, 0x7f, 0x49, 0x55, 0x7f, 0x55, 0x8, 0x67, 0x8, 0x41, 0x8, 0x5d, 0xa, 0x49, 0xa, 0x49, 0x1f, 0x4b, 0x71 },
+{ 0x97, 0x5b, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x3, 0xfc, 0x2, 0x4, 0x6, 0x4, 0xc, 0xc, 0x1b, 0x8, 0x31, 0x98, 0x0, 0xd0, 0x0, 0x30, 0x0, 0x60, 0x0, 0xc0, 0x3, 0x80, 0xe, 0x0, 0x78, 0x0 },
+{ 0x97, 0x5c, 0x0, 0x0, 0x1f, 0xf8, 0x0, 0x10, 0x6, 0x20, 0x3, 0x40, 0x1, 0x80, 0x7f, 0xff, 0x0, 0x81, 0x0, 0x82, 0x0, 0x84, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x3, 0x80 },
+{ 0x97, 0x5d, 0x0, 0x80, 0x1, 0xc0, 0x3, 0x60, 0x6, 0x30, 0x1c, 0x1c, 0x70, 0x7, 0xf, 0xf8, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x0, 0x80, 0x8, 0x88, 0x8, 0x88, 0x18, 0x8c, 0x30, 0x86, 0x3, 0x80 },
+{ 0x97, 0x5e, 0x4, 0x0, 0x4, 0x0, 0x7, 0xf0, 0x4, 0x0, 0x4, 0x0, 0x7, 0xe0, 0x0, 0x20, 0x0, 0x20, 0x7f, 0xff, 0x0, 0x20, 0x0, 0x20, 0x0, 0x20, 0x0, 0x60, 0x0, 0x40, 0x0, 0xc0, 0x3, 0x80 },
+{ 0x97, 0x5f, 0x11, 0x4, 0x8, 0x88, 0x7f, 0xff, 0x4, 0x10, 0xd, 0xd8, 0x8, 0x8, 0x3f, 0xfe, 0x60, 0x3, 0x7, 0xf0, 0x0, 0x0, 0x7, 0xf0, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8 },
+{ 0x97, 0x60, 0xc, 0x0, 0x38, 0x9e, 0x23, 0xe2, 0x20, 0x82, 0x3b, 0xee, 0x22, 0xa2, 0x23, 0xe2, 0x22, 0xa2, 0x3b, 0xee, 0x20, 0x82, 0x23, 0xe2, 0x20, 0x82, 0x7f, 0xff, 0x4, 0x10, 0x1c, 0x1c, 0x70, 0x7 },
+{ 0x97, 0x61, 0x0, 0x0, 0x7e, 0xff, 0x2, 0x10, 0x34, 0x7e, 0x18, 0x42, 0x8, 0x42, 0x7f, 0x7e, 0x9, 0x42, 0xb, 0x42, 0xa, 0x7e, 0x8, 0x42, 0x8, 0x42, 0x8, 0x7e, 0x8, 0x24, 0x8, 0x66, 0x38, 0xc3 },
+{ 0x97, 0x62, 0x8, 0x10, 0xb, 0xff, 0x1a, 0x10, 0x12, 0xfe, 0x32, 0x12, 0x33, 0xff, 0x52, 0x12, 0x12, 0xfe, 0x12, 0x10, 0x12, 0xfe, 0x12, 0x92, 0x16, 0xfe, 0x14, 0x92, 0x1c, 0xfe, 0x10, 0x92, 0x10, 0x96 },
+{ 0x97, 0x63, 0x4, 0x20, 0xc, 0x20, 0x8, 0x20, 0x18, 0x20, 0x12, 0xfe, 0x32, 0x22, 0x66, 0x22, 0x34, 0x22, 0x1c, 0x22, 0x8, 0x22, 0x1a, 0x22, 0x12, 0x62, 0x17, 0x42, 0x3d, 0x46, 0x60, 0xc4, 0x1, 0x9c },
+{ 0x97, 0x64, 0x8, 0x6, 0x8, 0x1c, 0x8, 0xf0, 0x8, 0x10, 0x7e, 0x10, 0x12, 0x10, 0x13, 0xff, 0x12, 0x10, 0x36, 0x10, 0x24, 0x38, 0x24, 0x28, 0x7e, 0x28, 0xb, 0x6c, 0x19, 0x44, 0x30, 0xc6, 0x61, 0x83 },
+{ 0x97, 0x65, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x2, 0x24, 0x12, 0xc, 0x98, 0x39, 0xce, 0x3, 0x60, 0x6, 0x30, 0x1c, 0x1c, 0x70, 0x7, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8 },
+{ 0x97, 0x66, 0x0, 0x40, 0x1f, 0xff, 0x10, 0x40, 0x17, 0xfc, 0x10, 0x44, 0x1f, 0xff, 0x10, 0x44, 0x17, 0xfc, 0x10, 0x40, 0x17, 0xfc, 0x14, 0x44, 0x17, 0xfc, 0x34, 0x44, 0x27, 0xfc, 0x64, 0x44, 0x4, 0x4c },
+{ 0x97, 0x67, 0x10, 0x0, 0x10, 0xfc, 0x10, 0x84, 0x10, 0xfc, 0x7c, 0x84, 0x10, 0x84, 0x10, 0xfc, 0x10, 0x0, 0x1b, 0xff, 0x70, 0x80, 0x11, 0xfe, 0x13, 0x2a, 0x10, 0x4a, 0x11, 0x92, 0x10, 0x26, 0x30, 0xcc },
+{ 0x97, 0x68, 0x10, 0x6, 0x10, 0x3c, 0x17, 0xe2, 0x12, 0x46, 0x79, 0x24, 0x10, 0x0, 0x13, 0xfe, 0x10, 0x20, 0x18, 0x20, 0x77, 0xff, 0x10, 0x20, 0x10, 0x20, 0x12, 0x22, 0x12, 0x22, 0x12, 0x22, 0x33, 0xfe },
+{ 0x97, 0x69, 0x10, 0x20, 0x10, 0x20, 0x17, 0xff, 0x10, 0x92, 0x79, 0x94, 0x11, 0x3f, 0x16, 0x64, 0x12, 0xa4, 0x19, 0xbe, 0x73, 0x24, 0x12, 0xa4, 0x17, 0xbe, 0x10, 0xa4, 0x11, 0xa4, 0x13, 0x24, 0x36, 0x3f },
+{ 0x97, 0x6a, 0x0, 0x0, 0x3, 0xdf, 0x78, 0x41, 0x4b, 0xdf, 0x48, 0x41, 0x4b, 0xdf, 0x48, 0x88, 0x79, 0x10, 0x4b, 0xff, 0x4d, 0x10, 0x49, 0xfe, 0x49, 0x10, 0x79, 0xfe, 0x1, 0x10, 0x1, 0x10, 0x1, 0xff },
+{ 0x97, 0x6b, 0x8, 0x0, 0x8, 0xfc, 0x8, 0x84, 0x7e, 0xfc, 0x8, 0x84, 0x8, 0x84, 0x1c, 0xfc, 0x1a, 0x0, 0x1b, 0xff, 0x28, 0x80, 0x29, 0xff, 0x4b, 0x29, 0x8, 0x49, 0x9, 0x93, 0x8, 0x22, 0x8, 0xce },
+{ 0x97, 0x6c, 0x11, 0x4, 0x10, 0x88, 0x13, 0xfe, 0x7c, 0x20, 0x11, 0xfc, 0x10, 0x20, 0x38, 0x20, 0x37, 0xff, 0x30, 0x20, 0x53, 0x23, 0x51, 0xb6, 0x10, 0x38, 0x10, 0xec, 0x13, 0xa6, 0x16, 0x23, 0x10, 0xe0 },
+{ 0x97, 0x6d, 0x1, 0x4, 0x31, 0x8c, 0x18, 0x88, 0xb, 0xfe, 0x0, 0x20, 0x60, 0x20, 0x30, 0x20, 0x11, 0xfc, 0x0, 0x20, 0x8, 0x20, 0x8, 0x20, 0x1b, 0xff, 0x10, 0x20, 0x30, 0x20, 0x20, 0x20, 0x60, 0x20 },
+{ 0x97, 0x6e, 0x0, 0x20, 0x30, 0x20, 0x1b, 0xfe, 0xa, 0x2, 0x2, 0x8a, 0x61, 0x8c, 0x33, 0x26, 0x10, 0x70, 0x0, 0xd8, 0x9, 0x8c, 0xf, 0x7, 0x19, 0xfc, 0x11, 0x4, 0x31, 0x4, 0x21, 0x4, 0x61, 0xfc },
+{ 0x97, 0x6f, 0x8, 0x10, 0x8, 0x10, 0x9, 0xff, 0xb, 0x1, 0x2d, 0x45, 0x28, 0xc6, 0x69, 0x93, 0x48, 0x38, 0x8, 0x6c, 0x9, 0xc7, 0x8, 0x0, 0x1c, 0xfe, 0x14, 0x82, 0x16, 0x82, 0x32, 0x82, 0x60, 0xfe },
+{ 0x97, 0x70, 0x0, 0x0, 0x1f, 0xfe, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x1f, 0xfe, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x1f, 0xfe, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x30, 0x82, 0x20, 0x82, 0x60, 0x8e },
+{ 0x97, 0x71, 0x0, 0x80, 0x3f, 0xfe, 0x22, 0x22, 0x26, 0x22, 0x7c, 0x3f, 0x8, 0x8, 0x4, 0x10, 0x3f, 0xfe, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x0, 0x12, 0x24, 0x33, 0x36, 0x61, 0x13 },
+{ 0x97, 0x72, 0x8, 0x8, 0xc, 0x18, 0x4, 0x10, 0x3f, 0xfe, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80 },
+{ 0x97, 0x73, 0x10, 0x0, 0x11, 0xde, 0x54, 0x42, 0x55, 0xde, 0x54, 0x42, 0x11, 0xde, 0x10, 0x48, 0x7c, 0x90, 0x29, 0xff, 0x2a, 0x90, 0x28, 0xfe, 0x28, 0x90, 0x2a, 0xfe, 0x2c, 0x90, 0x68, 0x90, 0x40, 0xff },
+{ 0x97, 0x74, 0x2, 0x20, 0x7f, 0xff, 0x2, 0x20, 0x8, 0x88, 0x7f, 0xff, 0x8, 0x88, 0x8, 0xf8, 0x8, 0x0, 0xf, 0xfe, 0x0, 0x80, 0x7f, 0xff, 0x2, 0xa0, 0x6, 0xb0, 0x1c, 0x9c, 0x70, 0x87, 0x0, 0x80 },
+{ 0x97, 0x75, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x0, 0x80, 0x3f, 0xfe, 0x24, 0x12, 0xc, 0x98, 0x39, 0xce, 0x7, 0x70, 0x1c, 0x1c, 0x70, 0x7, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8 },
+{ 0x97, 0x76, 0x0, 0x0, 0x7f, 0xff, 0x2, 0x40, 0x1f, 0xfc, 0x12, 0x44, 0x12, 0x44, 0x12, 0x44, 0x1f, 0xfc, 0x1, 0x0, 0x7f, 0xff, 0x2, 0x10, 0x4, 0x30, 0xf, 0x60, 0x1, 0xc0, 0x7, 0x78, 0x3c, 0xe },
+{ 0x97, 0x77, 0x0, 0x6, 0x3c, 0x1c, 0x0, 0xf0, 0x7e, 0x0, 0x1, 0x22, 0x3c, 0x94, 0x0, 0x0, 0x0, 0xfe, 0x3c, 0x10, 0x0, 0x10, 0x1, 0xff, 0x3c, 0x10, 0x24, 0x92, 0x24, 0x92, 0x24, 0x92, 0x3c, 0xfe },
+{ 0x97, 0x78, 0x0, 0x0, 0x3e, 0xfe, 0x22, 0x4, 0x22, 0x68, 0x22, 0x10, 0x3e, 0xff, 0x8, 0x91, 0x28, 0x91, 0x28, 0xff, 0x2e, 0x91, 0x28, 0x91, 0x28, 0xff, 0x28, 0x91, 0x2e, 0x91, 0x38, 0x91, 0x60, 0x93 },
+{ 0x97, 0x79, 0x0, 0xe, 0x33, 0xf8, 0x18, 0x0, 0xa, 0x42, 0x1, 0x24, 0x0, 0x0, 0x3, 0xfe, 0x70, 0x20, 0x10, 0x20, 0x17, 0xff, 0x10, 0x20, 0x12, 0x22, 0x12, 0x22, 0x33, 0xfe, 0x28, 0x0, 0x67, 0xff },
+{ 0x97, 0x7a, 0x0, 0x0, 0x3e, 0xfc, 0x22, 0x84, 0x26, 0xfc, 0x24, 0x84, 0x2c, 0x84, 0x28, 0xfc, 0x28, 0x0, 0x27, 0xff, 0x24, 0x80, 0x24, 0xfe, 0x25, 0x2a, 0x2c, 0x4a, 0x21, 0x92, 0x20, 0x26, 0x20, 0xcc },
+{ 0x97, 0x7b, 0x4, 0x10, 0x2, 0x20, 0x3f, 0xfe, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x7f, 0xff, 0x4, 0x90, 0xf, 0xf8, 0x14, 0x14, 0x67, 0xf3, 0x4, 0x10, 0x7, 0xf4, 0x4, 0x48, 0xf, 0x70, 0x38, 0x1f },
+{ 0x97, 0x7c, 0x12, 0x10, 0x13, 0x10, 0x35, 0xbf, 0x6e, 0x29, 0x1b, 0x6a, 0x31, 0x88, 0x7f, 0x1c, 0x11, 0x14, 0x11, 0x14, 0x11, 0x36, 0x1f, 0x63, 0x0, 0x0, 0x15, 0x86, 0x14, 0xcb, 0x36, 0x19, 0x63, 0xf0 },
+{ 0x97, 0x7d, 0x10, 0x40, 0x10, 0xc0, 0x13, 0xbe, 0x12, 0x22, 0x7e, 0x22, 0x12, 0x22, 0x12, 0x22, 0x12, 0x22, 0x1e, 0x22, 0x72, 0x22, 0x12, 0x22, 0x13, 0xa2, 0x16, 0x2e, 0x10, 0x20, 0x10, 0x20, 0x30, 0x20 },
+{ 0x97, 0x7e, 0x12, 0x10, 0x12, 0x10, 0x33, 0x10, 0x61, 0xbf, 0x8, 0x21, 0x1c, 0x6b, 0x16, 0xa, 0x33, 0x8, 0x61, 0x88, 0x0, 0x1c, 0x3f, 0x14, 0x21, 0x14, 0x21, 0x14, 0x21, 0x36, 0x21, 0x22, 0x3f, 0x63 },
+{ 0x97, 0x80, 0x0, 0xc, 0x30, 0x38, 0x1b, 0xe0, 0x8, 0x20, 0x0, 0x20, 0x60, 0x20, 0x37, 0xff, 0x10, 0x20, 0x0, 0x70, 0x8, 0x50, 0x8, 0x50, 0x18, 0xd8, 0x10, 0x88, 0x31, 0x8c, 0x23, 0x6, 0x66, 0x3 },
+{ 0x97, 0x81, 0x0, 0x88, 0x21, 0x8c, 0x33, 0x6, 0x16, 0x23, 0x0, 0x70, 0x40, 0xd8, 0x61, 0x8c, 0x23, 0x6, 0x6, 0x3, 0x8, 0x0, 0xb, 0xfe, 0x1a, 0x2, 0x12, 0x2, 0x32, 0x2, 0x22, 0x2, 0x63, 0xfe },
+{ 0x97, 0x82, 0x0, 0x0, 0x3f, 0x7e, 0x11, 0x22, 0x9, 0x12, 0x3, 0x6, 0x5, 0xa, 0x19, 0x32, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xfc, 0x4, 0x10, 0x6, 0x30, 0x2, 0x20, 0x2, 0x20, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x97, 0x83, 0x7f, 0x7e, 0x11, 0x22, 0xf, 0x1e, 0x39, 0x72, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x84, 0x1f, 0xfc, 0x2, 0x20, 0x3f, 0xfe, 0x2, 0x20, 0x7f, 0xff, 0x8, 0x8, 0x30, 0x6 },
+{ 0x97, 0x84, 0x0, 0x20, 0x30, 0x20, 0x1b, 0xff, 0xa, 0x1, 0x2, 0x1, 0x61, 0xfe, 0x30, 0x20, 0x10, 0x20, 0x1, 0x20, 0x9, 0x3e, 0x9, 0x20, 0x19, 0x20, 0x11, 0x20, 0x33, 0xa0, 0x22, 0x70, 0x66, 0x1f },
+{ 0x97, 0x85, 0x3f, 0xfe, 0x22, 0x22, 0x22, 0x22, 0x3f, 0xfe, 0x8, 0x12, 0x10, 0x24, 0x62, 0x7f, 0x35, 0xc8, 0x8, 0x48, 0x12, 0x7e, 0x7d, 0x48, 0x8, 0x48, 0x2a, 0x7e, 0x6a, 0x48, 0x4a, 0x48, 0x8, 0x7f },
+{ 0x97, 0x86, 0x10, 0x0, 0x11, 0xff, 0x11, 0x11, 0x7d, 0xff, 0x55, 0x11, 0x55, 0xff, 0x54, 0x20, 0x54, 0x48, 0x54, 0xd0, 0x7c, 0x22, 0x11, 0xff, 0x10, 0x11, 0x14, 0x54, 0x1c, 0xd6, 0x35, 0x93, 0x60, 0x10 },
+{ 0x97, 0x87, 0x8, 0x0, 0x8, 0xfe, 0x8, 0x92, 0x7e, 0x92, 0x2, 0xfe, 0x6, 0x92, 0xc, 0x92, 0x8, 0xfe, 0x1a, 0x10, 0x3d, 0xff, 0x6a, 0x54, 0xa, 0x54, 0x8, 0xd6, 0x8, 0x92, 0x9, 0x93, 0x8, 0x10 },
+{ 0x97, 0x88, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x8, 0x88, 0xc, 0x98, 0x4, 0x90, 0x4, 0x90, 0x7f, 0xff, 0x2, 0xa0, 0x2, 0xa0, 0x6, 0xb0, 0x4, 0x90, 0xc, 0x98, 0x18, 0x8c, 0x70, 0x87, 0x0, 0x80 },
+{ 0x97, 0x89, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x0, 0x80, 0x3f, 0xfe, 0x8, 0x88, 0xc, 0x98, 0x4, 0x90, 0x7f, 0xff, 0x2, 0xa0, 0x6, 0xb0, 0xc, 0x98, 0x18, 0x8c, 0x70, 0x87, 0x0, 0x80 },
+{ 0x97, 0x8a, 0x8, 0x0, 0x8, 0xff, 0x7f, 0x10, 0x8, 0x7e, 0x8, 0x42, 0x7f, 0x42, 0x49, 0x7e, 0x49, 0x42, 0x7f, 0x42, 0x8, 0x7e, 0x1c, 0x42, 0x1a, 0x42, 0x29, 0x7e, 0x28, 0x24, 0x48, 0x66, 0x8, 0xc3 },
+{ 0x97, 0x8b, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x82, 0x2e, 0xba, 0x20, 0x82, 0xe, 0xb8, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc },
+{ 0x97, 0x8c, 0x0, 0x80, 0x30, 0x80, 0x19, 0xfc, 0x9, 0x4, 0x3, 0x8c, 0x66, 0xd8, 0x30, 0x70, 0x11, 0xdc, 0x7, 0x7, 0x8, 0x0, 0x9, 0xfc, 0x19, 0x4, 0x11, 0x4, 0x31, 0x4, 0x21, 0x4, 0x61, 0xfc },
+{ 0x97, 0x8d, 0x8, 0x20, 0x18, 0x20, 0x10, 0x7e, 0x64, 0xc6, 0x2d, 0xac, 0x18, 0x18, 0x10, 0x30, 0x22, 0x6c, 0x7f, 0xc7, 0xa, 0x0, 0x8, 0xfe, 0x2a, 0x82, 0x2a, 0x82, 0x6a, 0x82, 0x48, 0x82, 0x8, 0xfe },
+{ 0x97, 0x8e, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x0, 0x80, 0x30, 0xfc, 0x19, 0x8c, 0x3, 0x58, 0x60, 0x70, 0x31, 0xdc, 0x7, 0x7, 0x0, 0x0, 0xd, 0xfc, 0x19, 0x4, 0x31, 0x4, 0x61, 0xfc },
+{ 0x97, 0x8f, 0x0, 0x20, 0x7f, 0x20, 0x14, 0x3e, 0x14, 0x62, 0x7f, 0x46, 0x55, 0xac, 0x55, 0x18, 0x55, 0x3c, 0x67, 0x66, 0x41, 0xc3, 0x41, 0x0, 0x7f, 0x7e, 0x41, 0x42, 0x41, 0x42, 0x7f, 0x42, 0x0, 0x7e },
+{ 0x97, 0x90, 0x1, 0xa0, 0x7, 0x20, 0x3c, 0x20, 0x4, 0x20, 0x4, 0x20, 0x4, 0x20, 0x7f, 0xe0, 0x4, 0x20, 0x4, 0x20, 0x4, 0x20, 0x3f, 0xa0, 0x20, 0xa0, 0x20, 0xa0, 0x20, 0xa1, 0x20, 0xb3, 0x3f, 0x9e },
+{ 0x97, 0x91, 0x1, 0x80, 0x7, 0x0, 0x3c, 0x7e, 0x22, 0x42, 0x22, 0x42, 0x32, 0x42, 0x3a, 0x52, 0x2a, 0x5a, 0x22, 0x4a, 0x22, 0x42, 0x22, 0x42, 0x3e, 0x42, 0x64, 0x4e, 0xc, 0x40, 0x18, 0x40, 0x30, 0x40 },
+{ 0x97, 0x92, 0x20, 0x82, 0x20, 0x82, 0x3f, 0xfe, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x4, 0x17, 0xf4, 0x10, 0x84, 0x17, 0xf4, 0x14, 0x94, 0x14, 0x94, 0x17, 0xf4, 0x10, 0x84, 0x30, 0xa5, 0x20, 0xf5, 0x6f, 0x93 },
+{ 0x97, 0x93, 0x10, 0x0, 0x13, 0xdf, 0x12, 0x51, 0x7f, 0xdf, 0x12, 0x51, 0x13, 0xdf, 0x32, 0x21, 0x3b, 0xfd, 0x56, 0xa9, 0x52, 0xf9, 0x12, 0xa9, 0x12, 0xf9, 0x12, 0x21, 0x12, 0x71, 0x12, 0xa9, 0x12, 0x23 },
+{ 0x97, 0x94, 0x0, 0x10, 0x27, 0xd0, 0x35, 0x10, 0x15, 0x3f, 0x7, 0xe0, 0x44, 0x40, 0x67, 0xc0, 0x25, 0x1e, 0x5, 0x0, 0x17, 0xc0, 0x10, 0x0, 0x13, 0xfe, 0x32, 0x92, 0x22, 0x92, 0x22, 0x92, 0x67, 0xff },
+{ 0x97, 0x95, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x0, 0x20, 0x3f, 0xa0, 0x24, 0x3f, 0x3f, 0x60, 0x21, 0x40, 0x3f, 0x1e, 0x24, 0x0, 0x3f, 0x80, 0x0, 0x0, 0x1f, 0xfc, 0x12, 0x44, 0x12, 0x44, 0x7f, 0xff },
+{ 0x97, 0x96, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x3f, 0x7e, 0x21, 0x42, 0x3f, 0x7e, 0x21, 0x42, 0x3f, 0x7e, 0x20, 0x82, 0x2f, 0xfa, 0x24, 0x92, 0x27, 0xf2, 0x24, 0x92, 0x27, 0xf2, 0x22, 0xa2, 0x24, 0x96 },
+{ 0x97, 0x97, 0x3f, 0x20, 0x24, 0x3f, 0x3f, 0x40, 0x21, 0x0, 0x3f, 0x3e, 0x24, 0x0, 0x3f, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x2, 0x21, 0xe, 0x23, 0x78, 0x1e },
+{ 0x97, 0x98, 0x1, 0x82, 0x7, 0x2, 0x7c, 0x22, 0x4, 0x22, 0x4, 0x22, 0x7f, 0xa2, 0x4, 0x22, 0xe, 0x22, 0xd, 0x22, 0x14, 0xa2, 0x34, 0x22, 0x64, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0x2, 0x4, 0xe },
+{ 0x97, 0x99, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x0, 0x80, 0x9, 0x80, 0x5, 0x0, 0x3, 0x80, 0x6, 0xe0, 0x1c, 0x38, 0x70, 0xf },
+{ 0x97, 0x9a, 0x3f, 0xfe, 0x20, 0x2, 0x3f, 0xfe, 0x24, 0x80, 0x2c, 0xfe, 0x29, 0x0, 0x30, 0xfc, 0x24, 0x84, 0x2c, 0xfc, 0x28, 0x84, 0x38, 0xfc, 0x28, 0x40, 0x68, 0xfe, 0x4b, 0x44, 0x48, 0x38, 0xb, 0xc7 },
+{ 0x97, 0x9b, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x2, 0xa0, 0x6, 0xb0, 0x1c, 0x9c, 0x70, 0x87, 0x0, 0x0, 0xf, 0xf8, 0x0, 0x30, 0x0, 0xc0, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x3, 0x80 },
+{ 0x97, 0x9c, 0x3, 0x4, 0x3e, 0x24, 0x4, 0x24, 0x7f, 0xa4, 0x4, 0x24, 0xe, 0x24, 0x15, 0x4, 0x64, 0x4, 0x4, 0x1c, 0x0, 0x80, 0x7f, 0xff, 0x2, 0xa0, 0x6, 0xb0, 0x1c, 0x9c, 0x70, 0x87, 0x0, 0x80 },
+{ 0x97, 0x9d, 0x0, 0x0, 0x1, 0xfe, 0x7d, 0x22, 0x11, 0x22, 0x11, 0xfe, 0x11, 0x22, 0x7d, 0x22, 0x11, 0xfe, 0x10, 0x20, 0x10, 0x20, 0x11, 0xfe, 0x1c, 0x20, 0x70, 0x20, 0x0, 0x20, 0x3, 0xff, 0x0, 0x0 },
+{ 0x97, 0x9e, 0x0, 0x20, 0x0, 0x20, 0x7d, 0xff, 0x10, 0x0, 0x11, 0x4a, 0x11, 0x32, 0x7d, 0x4a, 0x11, 0x2, 0x11, 0xfe, 0x10, 0x20, 0x13, 0xff, 0x1e, 0x41, 0x72, 0x49, 0x2, 0xf5, 0x2, 0x1, 0x2, 0x3 },
+{ 0x97, 0x9f, 0x0, 0x40, 0x0, 0x40, 0x1f, 0xff, 0x50, 0x0, 0x30, 0xc2, 0x17, 0x92, 0x11, 0x12, 0x1f, 0xd2, 0x11, 0x12, 0x31, 0x12, 0x53, 0x92, 0x13, 0x52, 0x35, 0x42, 0x29, 0x2, 0x61, 0x2, 0x1, 0xe },
+{ 0x97, 0xa0, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x88, 0xf, 0xf8, 0x8, 0x88, 0xf, 0xf8, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x7f, 0xff, 0x2, 0x42, 0x7c, 0x64, 0x7, 0xb8, 0x1c, 0xf },
+{ 0x97, 0xa1, 0x10, 0x0, 0x10, 0xfe, 0x10, 0x92, 0x7c, 0x92, 0x4, 0xfe, 0xc, 0x92, 0x8, 0x92, 0x1a, 0xfe, 0x14, 0x10, 0x38, 0x10, 0x54, 0xfe, 0x12, 0x10, 0x10, 0x10, 0x10, 0x10, 0x11, 0xff, 0x10, 0x0 },
+{ 0x97, 0xa2, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x97, 0xa3, 0x8, 0x24, 0x8, 0x6c, 0x7f, 0x48, 0x0, 0xff, 0x55, 0xc8, 0x49, 0x48, 0x55, 0x48, 0x7f, 0x7e, 0x8, 0x48, 0x7f, 0x48, 0x51, 0x48, 0x55, 0x7e, 0x7b, 0x48, 0x41, 0x48, 0x41, 0x48, 0x43, 0x7f },
+{ 0x97, 0xa4, 0x0, 0x10, 0x3e, 0x10, 0x22, 0xfe, 0x26, 0x10, 0x24, 0x10, 0x2d, 0xff, 0x28, 0x48, 0x28, 0x48, 0x25, 0x8f, 0x24, 0x10, 0x24, 0x10, 0x24, 0xfe, 0x2c, 0x10, 0x20, 0x10, 0x21, 0xff, 0x20, 0x0 },
+{ 0x97, 0xa5, 0x8, 0x20, 0x1b, 0xfe, 0x10, 0x22, 0x30, 0x22, 0x67, 0xff, 0x8, 0x22, 0x18, 0x22, 0x13, 0xfe, 0x30, 0x20, 0x70, 0x20, 0x13, 0xfe, 0x10, 0x20, 0x10, 0x20, 0x17, 0xff, 0x10, 0x20, 0x10, 0x20 },
+{ 0x97, 0xa6, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x1, 0x0, 0x32, 0xc, 0x19, 0x58, 0x0, 0x80, 0x9, 0x48, 0x1b, 0xac, 0x30, 0x6, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80 },
+{ 0x97, 0xa7, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x0, 0x0, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x6, 0x30, 0x2, 0x20, 0x2, 0x20, 0x2, 0x60, 0x0, 0x40, 0x0, 0x40, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x97, 0xa8, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x8, 0x20, 0x1b, 0xfe, 0x30, 0x22, 0x67, 0xff, 0x8, 0x22, 0x1b, 0xfe, 0x30, 0x20, 0x73, 0xfe, 0x10, 0x20, 0x17, 0xff, 0x10, 0x20, 0x10, 0x20 },
+{ 0x97, 0xa9, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x17, 0xff, 0x78, 0x0, 0x11, 0xfc, 0x11, 0x4, 0x11, 0x4, 0x19, 0xfc, 0x70, 0x20, 0x11, 0x24, 0x11, 0x24, 0x13, 0x26, 0x16, 0x23, 0x10, 0x20, 0x30, 0xe0 },
+{ 0x97, 0xaa, 0x0, 0x40, 0x0, 0x40, 0x7c, 0xfc, 0x55, 0x84, 0x57, 0xc, 0x54, 0xd8, 0x54, 0x70, 0x7d, 0xdc, 0x57, 0x7, 0x54, 0x0, 0x55, 0xfc, 0x55, 0x4, 0x7d, 0x4, 0x1, 0x4, 0x1, 0x4, 0x1, 0xfc },
+{ 0x97, 0xab, 0x8, 0x2, 0x33, 0xc2, 0x21, 0x52, 0x29, 0x52, 0x3a, 0x52, 0x64, 0xd2, 0xe, 0x12, 0x1b, 0x12, 0x71, 0xd2, 0x1f, 0x12, 0x4, 0x12, 0x7f, 0xc2, 0x4, 0x82, 0x25, 0x2, 0x17, 0xc2, 0x7c, 0xe },
+{ 0x97, 0xac, 0x0, 0x20, 0x20, 0x20, 0x37, 0xff, 0x10, 0x80, 0x0, 0x84, 0x41, 0x3e, 0x63, 0xe2, 0x20, 0x0, 0x1, 0x24, 0x9, 0x24, 0x9, 0x24, 0x19, 0x24, 0x11, 0x24, 0x31, 0x25, 0x23, 0x25, 0x66, 0x3 },
+{ 0x97, 0xad, 0x0, 0xc0, 0x27, 0xbf, 0x34, 0x9, 0x14, 0x9, 0x4, 0x99, 0x44, 0x91, 0x67, 0xf7, 0x2c, 0x40, 0x0, 0x0, 0x13, 0xfe, 0x12, 0x22, 0x12, 0x22, 0x33, 0xfe, 0x22, 0x22, 0x22, 0x22, 0x63, 0xfe },
+{ 0x97, 0xae, 0x0, 0x20, 0x7c, 0x20, 0x13, 0xff, 0x10, 0x80, 0x10, 0x84, 0x11, 0x3e, 0x3b, 0xe2, 0x10, 0x0, 0x11, 0x24, 0x11, 0x24, 0x11, 0x24, 0x1d, 0x24, 0x71, 0x24, 0x1, 0x25, 0x3, 0x25, 0x6, 0x3 },
+{ 0x97, 0xaf, 0x7, 0x0, 0x3c, 0x7f, 0x20, 0x11, 0x20, 0x11, 0x22, 0x11, 0x22, 0x33, 0x3f, 0x22, 0x61, 0x66, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc },
+{ 0x97, 0xb0, 0x0, 0x20, 0x7c, 0x20, 0x13, 0xff, 0x10, 0x40, 0x10, 0x44, 0x10, 0x9e, 0x3d, 0xf2, 0x24, 0x0, 0x65, 0x24, 0x25, 0x24, 0x25, 0x24, 0x25, 0x24, 0x3d, 0x24, 0x1, 0x25, 0x3, 0x25, 0x6, 0x3 },
+{ 0x97, 0xb1, 0x8, 0x10, 0x4a, 0x10, 0x6a, 0x10, 0x2a, 0xfe, 0x8, 0x0, 0x7f, 0x44, 0x8, 0x44, 0x1c, 0x44, 0x1a, 0x64, 0x2a, 0x2c, 0x28, 0x28, 0x48, 0x28, 0x8, 0x28, 0x8, 0x8, 0x9, 0xff, 0x8, 0x0 },
+{ 0x97, 0xb2, 0x0, 0x40, 0x3e, 0x40, 0x22, 0xfc, 0x26, 0x8c, 0x25, 0x58, 0x2c, 0x30, 0x28, 0x6c, 0x25, 0xc7, 0x24, 0x50, 0x24, 0xfe, 0x25, 0x10, 0x24, 0x7c, 0x2c, 0x10, 0x20, 0x10, 0x21, 0xff, 0x20, 0x0 },
+{ 0x97, 0xb3, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x4, 0x10, 0x2, 0x20, 0x7f, 0xff, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x88, 0x8, 0x88, 0xf, 0xf8, 0x8, 0x88, 0x8, 0x88, 0xf, 0xf9, 0x0, 0x83, 0x0, 0x7e },
+{ 0x97, 0xb4, 0x4, 0x20, 0x4, 0x20, 0x3f, 0xbf, 0x11, 0x20, 0xa, 0x3e, 0x7f, 0xc2, 0x0, 0x3e, 0x1f, 0x20, 0x11, 0x3e, 0x1f, 0x20, 0x11, 0x3e, 0x1f, 0x20, 0x11, 0x3e, 0x11, 0x21, 0x11, 0x33, 0x13, 0x1e },
+{ 0x97, 0xb5, 0x4, 0x0, 0x5, 0xfc, 0xd, 0x4, 0x9, 0x4, 0x19, 0x4, 0x11, 0x4, 0x31, 0xfc, 0x50, 0x20, 0x10, 0x60, 0x10, 0x40, 0x13, 0xfe, 0x12, 0x2, 0x12, 0x2, 0x12, 0x2, 0x12, 0x2, 0x13, 0xfe },
+{ 0x97, 0xb6, 0x0, 0x80, 0x0, 0xfc, 0x0, 0x80, 0x3f, 0xff, 0x21, 0x1, 0x2f, 0xf8, 0x21, 0x2, 0x27, 0xfe, 0x24, 0x44, 0x27, 0xfc, 0x24, 0x44, 0x27, 0xfc, 0x60, 0x40, 0x45, 0x26, 0x4d, 0xb, 0x18, 0xf9 },
+{ 0x97, 0xb7, 0x10, 0x40, 0x10, 0x40, 0x10, 0x40, 0x7e, 0xff, 0x10, 0x90, 0x11, 0xb0, 0x10, 0x20, 0x1e, 0x72, 0x13, 0xd6, 0x12, 0x54, 0x12, 0x58, 0x12, 0x48, 0x32, 0x4c, 0x26, 0x44, 0x24, 0x46, 0x6c, 0x43 },
+{ 0x97, 0xb8, 0x0, 0x40, 0x0, 0x7e, 0x0, 0x40, 0x1f, 0xff, 0x10, 0x81, 0x17, 0xfc, 0x10, 0x81, 0x17, 0xff, 0x14, 0x44, 0x17, 0xfc, 0x14, 0x44, 0x17, 0xfc, 0x30, 0x80, 0x2f, 0xfe, 0x61, 0x2, 0xe, 0xe },
+{ 0x97, 0xb9, 0x0, 0x0, 0x3f, 0xfe, 0x0, 0xc, 0x0, 0x18, 0x0, 0x30, 0x0, 0xc0, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x3, 0x80 },
+{ 0x97, 0xba, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x0, 0x0, 0x3f, 0xfe, 0x20, 0x2, 0x22, 0x22, 0x2, 0x20, 0x2, 0x20, 0x6, 0x21, 0x1c, 0x33, 0x70, 0x1e },
+{ 0x97, 0xbb, 0x8, 0x40, 0x8, 0x40, 0xf, 0xff, 0x18, 0x88, 0x12, 0x8a, 0x31, 0x4, 0x33, 0xfe, 0x55, 0x5, 0x11, 0xfc, 0x11, 0x4, 0x11, 0xfc, 0x10, 0x20, 0x11, 0x24, 0x13, 0x26, 0x16, 0x23, 0x10, 0xe0 },
+{ 0x97, 0xbc, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x82, 0x20, 0x82, 0x24, 0x92, 0x24, 0x92, 0x24, 0x92, 0x24, 0x92, 0x27, 0xf2, 0x20, 0x2, 0x20, 0x2, 0x20, 0x2, 0x20, 0xe },
+{ 0x97, 0xbd, 0x0, 0x20, 0x30, 0x20, 0x1b, 0xfe, 0x8, 0x20, 0x7, 0xff, 0x0, 0x88, 0x1, 0x88, 0x3, 0xf, 0x8, 0x40, 0x8, 0x7c, 0x18, 0xc4, 0x11, 0x8c, 0x33, 0x58, 0x20, 0x70, 0x60, 0xdc, 0x7, 0x87 },
+{ 0x97, 0xbe, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x2, 0x1, 0x0, 0x7f, 0xff, 0x22, 0x22, 0x14, 0x14, 0xf, 0xf8, 0x78, 0xf, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x4, 0x90, 0x1c, 0x9c, 0x70, 0x87, 0x3, 0x80 },
+{ 0x97, 0xbf, 0x8, 0x4, 0x49, 0x64, 0x6b, 0x34, 0x2a, 0x14, 0x8, 0x4, 0x7e, 0xc4, 0x8, 0x64, 0x1c, 0x24, 0x1a, 0x4, 0x29, 0x7, 0x28, 0x3c, 0x48, 0xe4, 0x8, 0x4, 0x8, 0x4, 0x8, 0x4, 0x8, 0x4 },
+{ 0x97, 0xc0, 0x0, 0x0, 0x33, 0xf8, 0x18, 0x48, 0x61, 0x4a, 0x33, 0x4b, 0xa, 0xc9, 0x18, 0x88, 0x31, 0xb8, 0x60, 0x0, 0x0, 0x80, 0x7f, 0xff, 0x2, 0xa0, 0x6, 0xb0, 0x1c, 0x9c, 0x70, 0x87, 0x0, 0x80 },
+{ 0x97, 0xc1, 0x0, 0x20, 0x20, 0x20, 0x30, 0x20, 0x17, 0xff, 0x0, 0x0, 0x41, 0xfc, 0x61, 0x4, 0x21, 0x4, 0x1, 0x4, 0x9, 0xfc, 0x8, 0x20, 0x19, 0x24, 0x11, 0x24, 0x33, 0x26, 0x26, 0x23, 0x60, 0xe0 },
+{ 0x97, 0xc2, 0x5, 0x22, 0x45, 0xb6, 0x28, 0x94, 0x10, 0x0, 0x11, 0xfc, 0x29, 0x24, 0x49, 0x24, 0x9, 0xfc, 0x19, 0x24, 0x19, 0x24, 0x29, 0xfc, 0x49, 0x24, 0x9, 0x24, 0x9, 0x25, 0x1b, 0x25, 0x76, 0x23 },
+{ 0x97, 0xc3, 0x0, 0x40, 0x0, 0x40, 0x1f, 0xff, 0x10, 0x80, 0x5f, 0xfe, 0x31, 0x10, 0x1a, 0xa, 0x17, 0xfc, 0x1a, 0xa, 0x33, 0xf8, 0x52, 0x8, 0x13, 0xf8, 0x32, 0x48, 0x26, 0x4c, 0x6c, 0x46, 0x1, 0xc0 },
+{ 0x97, 0xc4, 0x0, 0x40, 0x78, 0x40, 0x4f, 0xff, 0x48, 0x88, 0x4a, 0x8a, 0x79, 0x4, 0x4b, 0xfe, 0x4d, 0x5, 0x49, 0xfc, 0x79, 0x4, 0x49, 0xfc, 0x48, 0x20, 0x49, 0x24, 0x7b, 0x26, 0x6, 0x23, 0x0, 0xe0 },
+{ 0x97, 0xc5, 0x4, 0x20, 0x1c, 0x20, 0x71, 0xfe, 0x10, 0x20, 0x13, 0xff, 0x7c, 0x48, 0x10, 0x48, 0x38, 0x8f, 0x35, 0x40, 0x34, 0x7c, 0x50, 0xc4, 0x51, 0x8c, 0x13, 0x58, 0x10, 0x70, 0x10, 0xdc, 0x13, 0x87 },
+{ 0x97, 0xc6, 0x11, 0xfc, 0x55, 0x4, 0x55, 0xfc, 0x55, 0x4, 0x13, 0xff, 0x7c, 0x0, 0x11, 0xfc, 0x11, 0x24, 0x39, 0xfc, 0x35, 0x24, 0x55, 0x24, 0x51, 0xfc, 0x10, 0x20, 0x13, 0xfe, 0x10, 0x20, 0x17, 0xff },
+{ 0x97, 0xc7, 0x0, 0x80, 0x0, 0x80, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x42, 0x8, 0x66, 0x8, 0x2c, 0x8, 0x30, 0x9, 0xd8, 0xf, 0xc, 0x38, 0x7 },
+{ 0x97, 0xc8, 0x0, 0x10, 0x3c, 0x10, 0x0, 0x10, 0x7e, 0xff, 0x0, 0x0, 0x3c, 0x7e, 0x0, 0x42, 0x0, 0x42, 0x3c, 0x42, 0x0, 0x7e, 0x0, 0x10, 0x3c, 0x54, 0x24, 0x54, 0x24, 0xd6, 0x25, 0x93, 0x3c, 0x30 },
+{ 0x97, 0xc9, 0x0, 0x40, 0x60, 0x40, 0x37, 0xff, 0x12, 0x8a, 0x1, 0x4, 0x3, 0xfe, 0x5, 0x5, 0x71, 0xfc, 0x11, 0x4, 0x11, 0xfc, 0x11, 0x24, 0x13, 0x26, 0x16, 0x23, 0x30, 0xe0, 0x28, 0x0, 0x67, 0xff },
+{ 0x97, 0xca, 0xf, 0xf8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x7f, 0xff, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x88, 0xf, 0xf8, 0x8, 0x88, 0x8, 0x88, 0xf, 0xf8, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x80, 0x7f, 0xff },
+{ 0x97, 0xcb, 0x0, 0x20, 0x3c, 0x20, 0x25, 0xfe, 0x24, 0x20, 0x27, 0xff, 0x2c, 0x88, 0x29, 0x88, 0x27, 0x4f, 0x24, 0x40, 0x24, 0xfc, 0x25, 0x84, 0x27, 0xc, 0x2c, 0xd8, 0x20, 0x70, 0x21, 0xdc, 0x27, 0x7 },
+{ 0x97, 0xcc, 0x8, 0x0, 0x1c, 0xff, 0x16, 0x10, 0x33, 0x7e, 0x60, 0x42, 0x1c, 0x42, 0x0, 0x7e, 0x0, 0x42, 0x7e, 0x42, 0x12, 0x7e, 0x12, 0x42, 0x12, 0x42, 0x12, 0x7e, 0x16, 0x24, 0x10, 0x66, 0x10, 0xc3 },
+{ 0x97, 0xcd, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x0, 0x82, 0x0, 0x82, 0x0, 0x82, 0x1, 0x82, 0x1, 0x2, 0x1, 0x2, 0x3, 0x2, 0x2, 0x6, 0x6, 0x4, 0xc, 0x4, 0x38, 0x3c },
+{ 0x97, 0xce, 0x8, 0x0, 0x18, 0xfc, 0x30, 0x4, 0x62, 0xfc, 0x36, 0x4, 0xc, 0x4, 0x19, 0xff, 0x32, 0x10, 0x7e, 0x92, 0xa, 0xd6, 0x8, 0x54, 0x2a, 0x38, 0x2a, 0x5c, 0x6a, 0xd6, 0x49, 0x93, 0x8, 0x30 },
+{ 0x97, 0xcf, 0x4, 0x20, 0x4, 0x70, 0xc, 0xd8, 0x9, 0x8c, 0x1b, 0x6, 0x16, 0xfb, 0x30, 0x0, 0x50, 0x0, 0x13, 0xfe, 0x12, 0x52, 0x12, 0x52, 0x13, 0xfe, 0x12, 0x52, 0x12, 0x52, 0x12, 0x52, 0x12, 0x56 },
+{ 0x97, 0xd0, 0x0, 0x0, 0x1f, 0xff, 0x10, 0x0, 0x17, 0xfc, 0x14, 0x44, 0x14, 0x44, 0x17, 0xfc, 0x14, 0x44, 0x14, 0x44, 0x17, 0xfc, 0x10, 0x40, 0x10, 0x40, 0x37, 0xfc, 0x20, 0x40, 0x60, 0x40, 0xf, 0xfe },
+{ 0x97, 0xd1, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10, 0x7e, 0xff, 0x8, 0x10, 0x8, 0x10, 0x1c, 0x38, 0x1a, 0x38, 0x19, 0x54, 0x28, 0x54, 0x28, 0x92, 0x49, 0x11, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10 },
+{ 0x97, 0xd2, 0x1, 0x8, 0x21, 0x8, 0x31, 0x8, 0x17, 0xbf, 0x1, 0x8, 0x41, 0x8, 0x63, 0x9c, 0x23, 0x5c, 0x5, 0x2a, 0x15, 0x2a, 0x19, 0x49, 0x11, 0x8, 0x31, 0x8, 0x21, 0x8, 0x21, 0x8, 0x61, 0x8 },
+{ 0x97, 0xd3, 0x11, 0x22, 0x10, 0xa4, 0x14, 0x20, 0x55, 0xfe, 0x54, 0xa8, 0x59, 0xac, 0x53, 0x26, 0x16, 0x23, 0x11, 0xc4, 0x11, 0x7e, 0x12, 0x54, 0x35, 0x54, 0x28, 0xbf, 0x29, 0x84, 0x63, 0x4, 0x46, 0x4 },
+{ 0x97, 0xd4, 0x0, 0x88, 0x7c, 0x88, 0x10, 0x88, 0x13, 0xde, 0x10, 0x88, 0x10, 0x88, 0x7d, 0xdc, 0x11, 0xdc, 0x12, 0xaa, 0x12, 0xaa, 0x14, 0x89, 0x10, 0x88, 0x1c, 0x88, 0x70, 0x88, 0x0, 0x88, 0x0, 0x88 },
+{ 0x97, 0xd5, 0x0, 0x40, 0x7e, 0x40, 0x48, 0xff, 0x49, 0x80, 0x48, 0x7c, 0x7e, 0x44, 0x42, 0x44, 0x42, 0x44, 0x7e, 0x7c, 0x48, 0x0, 0x49, 0xef, 0x49, 0x29, 0x49, 0x29, 0x7f, 0x29, 0x1, 0x29, 0x1, 0xef },
+{ 0x97, 0xd6, 0x10, 0x20, 0x10, 0x70, 0x7c, 0xd8, 0x11, 0x8c, 0x7f, 0x7, 0x54, 0xf8, 0x54, 0x0, 0x7d, 0xfe, 0x55, 0x52, 0x55, 0x52, 0x7d, 0xfe, 0x11, 0x52, 0x7d, 0x52, 0x11, 0x52, 0x11, 0x52, 0x11, 0x56 },
+{ 0x97, 0xd7, 0x0, 0x92, 0x3c, 0x54, 0x24, 0x10, 0x25, 0xff, 0x2c, 0x54, 0x28, 0xd6, 0x29, 0x93, 0x24, 0x90, 0x24, 0xe2, 0x25, 0xbf, 0x27, 0x2a, 0x24, 0xea, 0x2c, 0x7f, 0x20, 0xc2, 0x21, 0x82, 0x23, 0x2 },
+{ 0x97, 0xd8, 0x20, 0x92, 0x3c, 0x54, 0x24, 0x10, 0x49, 0xff, 0x7c, 0x54, 0x54, 0xd6, 0x55, 0x93, 0x7c, 0x90, 0x54, 0xe2, 0x55, 0xbf, 0x7f, 0x2a, 0x0, 0xea, 0x54, 0x7f, 0x54, 0xc2, 0x55, 0x82, 0x43, 0x2 },
+{ 0x97, 0xd9, 0x8, 0x92, 0x8, 0x54, 0x7f, 0x10, 0x54, 0xff, 0x7f, 0x54, 0x55, 0x56, 0x55, 0xd3, 0x7f, 0x90, 0x54, 0xe2, 0x55, 0xbf, 0x5f, 0x2a, 0x54, 0xaa, 0x54, 0x6a, 0x5d, 0x5f, 0x77, 0x42, 0x40, 0xc2 },
+{ 0x97, 0xda, 0x0, 0x60, 0x7d, 0xdf, 0x11, 0x5, 0x11, 0x5, 0x11, 0x45, 0x11, 0x6d, 0x7d, 0xa9, 0x13, 0x1b, 0x10, 0x0, 0x11, 0xfe, 0x11, 0x22, 0x11, 0x22, 0x1d, 0xfe, 0x71, 0x22, 0x1, 0x22, 0x1, 0xfe },
+{ 0x97, 0xdb, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x88, 0xf, 0xf8, 0x8, 0x88, 0x8, 0x88, 0xf, 0xf8, 0x30, 0x6, 0x1e, 0x3c, 0x0, 0x0, 0xe, 0x38, 0x38, 0xe, 0x0, 0x80, 0xf, 0xf8, 0x0, 0x80, 0x7f, 0xff },
+{ 0x97, 0xdc, 0x0, 0x0, 0x27, 0xff, 0x30, 0x0, 0x13, 0xfe, 0x2, 0x2, 0x42, 0x2, 0x63, 0xfe, 0x22, 0x20, 0x2, 0x20, 0x13, 0xff, 0x12, 0x20, 0x16, 0x70, 0x34, 0x50, 0x2c, 0xd8, 0x21, 0x8c, 0x67, 0x7 },
+{ 0x97, 0xdd, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x84, 0x10, 0x84, 0x1f, 0xfc, 0x1, 0x10, 0x6, 0x22, 0x1, 0x42, 0x7f, 0xff, 0x0, 0x81, 0x4, 0x90, 0x1c, 0x9c, 0x70, 0x87, 0x0, 0x80 },
+{ 0x97, 0xde, 0x8, 0x0, 0x4a, 0xff, 0x2a, 0x10, 0x7f, 0x7e, 0x8, 0x42, 0x1c, 0x42, 0x2a, 0x7e, 0x49, 0x42, 0x0, 0x42, 0x8, 0x7e, 0x7f, 0x42, 0x8, 0x42, 0x1c, 0x7e, 0x16, 0x24, 0x33, 0x66, 0x60, 0xc3 },
+{ 0x97, 0xdf, 0x0, 0x80, 0x1, 0xc0, 0x3, 0x60, 0x6, 0x30, 0xc, 0x18, 0x18, 0xc, 0x77, 0xf7, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xfe, 0x0, 0x82, 0x0, 0x82, 0x0, 0x82, 0x0, 0x8e, 0x0, 0x80, 0x0, 0x80 },
+{ 0x97, 0xe0, 0x4, 0x20, 0x4, 0x70, 0xc, 0xd8, 0x9, 0x8c, 0x1b, 0x6, 0x16, 0xfb, 0x30, 0x0, 0x50, 0x0, 0x13, 0xfe, 0x10, 0x42, 0x10, 0x42, 0x10, 0x42, 0x10, 0x42, 0x10, 0x4e, 0x10, 0x40, 0x10, 0x40 },
+{ 0x97, 0xe1, 0x8, 0x1, 0xf, 0xe9, 0x8, 0x89, 0x18, 0x89, 0x10, 0x89, 0x11, 0xe9, 0x31, 0x29, 0x31, 0x29, 0x53, 0xa9, 0x16, 0xe9, 0x10, 0x49, 0x10, 0xc1, 0x10, 0x81, 0x11, 0x81, 0x13, 0x1, 0x16, 0x7 },
+{ 0x97, 0xe2, 0x0, 0x20, 0x30, 0x70, 0x18, 0xd8, 0x9, 0x8c, 0x3, 0x6, 0x6, 0xfb, 0x0, 0x0, 0x0, 0x0, 0xb, 0xfe, 0x8, 0x42, 0x18, 0x42, 0x10, 0x42, 0x30, 0x42, 0x20, 0x4e, 0x60, 0x40, 0x0, 0x40 },
+{ 0x97, 0xe3, 0x0, 0x10, 0x3f, 0xd0, 0x20, 0x10, 0x20, 0x10, 0x3f, 0xbe, 0x24, 0x12, 0x24, 0x12, 0x27, 0x92, 0x24, 0x92, 0x24, 0x92, 0x24, 0x92, 0x24, 0x92, 0x64, 0xb2, 0x4d, 0xa6, 0x49, 0x24, 0x1b, 0x6c },
+{ 0x97, 0xe4, 0x20, 0x82, 0x20, 0x82, 0x3f, 0xfe, 0x8, 0x0, 0x1c, 0xff, 0x36, 0x10, 0x63, 0x7e, 0x1c, 0x42, 0x0, 0x7e, 0x7e, 0x42, 0x12, 0x7e, 0x12, 0x42, 0x12, 0x7e, 0x16, 0x24, 0x10, 0x66, 0x10, 0xc3 },
+{ 0x97, 0xe5, 0x10, 0x20, 0x10, 0x70, 0x10, 0xd8, 0x51, 0x8c, 0x5b, 0x6, 0x54, 0xfb, 0x54, 0x0, 0x50, 0x0, 0x13, 0xfe, 0x10, 0x42, 0x10, 0x42, 0x10, 0x42, 0x10, 0x42, 0x10, 0x4e, 0x10, 0x40, 0x10, 0x40 },
+{ 0x97, 0xe6, 0x0, 0x20, 0x7c, 0x70, 0x10, 0xd8, 0x11, 0x8c, 0x13, 0x6, 0x16, 0xfb, 0x38, 0x0, 0x10, 0x0, 0x13, 0xfe, 0x10, 0x42, 0x10, 0x42, 0x1c, 0x42, 0x70, 0x42, 0x0, 0x4e, 0x0, 0x40, 0x0, 0x40 },
+{ 0x97, 0xe7, 0x8, 0x40, 0x8, 0x40, 0x8, 0x40, 0x7e, 0x40, 0x2, 0x40, 0x6, 0x40, 0x4, 0x40, 0xc, 0x40, 0x18, 0x40, 0x3e, 0x40, 0x6b, 0x40, 0x8, 0x40, 0x8, 0x40, 0x8, 0x41, 0x8, 0x63, 0x8, 0x3e },
+{ 0x97, 0xe8, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x4, 0x90, 0x1, 0xc0, 0x7, 0x70, 0x1c, 0x1c, 0x77, 0xf7, 0x0, 0x0, 0x1f, 0xfc, 0x1, 0x4, 0x1, 0x4, 0x1, 0x4, 0x1, 0x1c, 0x1, 0x0 },
+{ 0x97, 0xe9, 0x8, 0x10, 0x1c, 0x38, 0x16, 0x6c, 0x32, 0xc6, 0x21, 0x83, 0x7e, 0x7c, 0x8, 0x0, 0x8, 0x0, 0x7e, 0xfe, 0x8, 0x22, 0x4a, 0x22, 0x6a, 0x22, 0x28, 0x22, 0xe, 0x2e, 0x38, 0x20, 0x60, 0x20 },
+{ 0x97, 0xea, 0x8, 0x10, 0x8, 0x10, 0x7f, 0x7e, 0x8, 0x12, 0x3e, 0xff, 0x0, 0x12, 0x3e, 0x7e, 0x0, 0x10, 0x3e, 0x92, 0x8, 0xd6, 0x2a, 0x54, 0x2b, 0x18, 0x69, 0x34, 0x48, 0x56, 0x9, 0x93, 0x18, 0x30 },
+{ 0x97, 0xeb, 0x1f, 0xfc, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x82, 0x2e, 0xba, 0x20, 0x82, 0xe, 0xb8, 0x1, 0xc0, 0x7, 0x70, 0x1c, 0x1c, 0x73, 0xf7, 0x0, 0x0, 0xf, 0xfc, 0x0, 0x84, 0x0, 0x8c, 0x0, 0x80 },
+{ 0x97, 0xec, 0x1f, 0xfc, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x82, 0x2e, 0xba, 0x20, 0x82, 0xe, 0xb8, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x0, 0x3f, 0xfe, 0x1, 0x40, 0x9, 0x48, 0x5, 0x50, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x97, 0xed, 0x7f, 0x7f, 0x0, 0x0, 0x3e, 0x3e, 0x22, 0x22, 0x2a, 0x2a, 0x0, 0x80, 0x3f, 0xff, 0x22, 0x20, 0x3f, 0xfe, 0x22, 0x22, 0x3f, 0xfe, 0x24, 0x20, 0x27, 0xbc, 0x64, 0x21, 0x47, 0xb3, 0x1c, 0x1e },
+{ 0x97, 0xee, 0x4, 0x8, 0x14, 0x1c, 0x17, 0x94, 0x14, 0x36, 0x14, 0x63, 0x7f, 0xdd, 0x20, 0x80, 0x35, 0x80, 0x2e, 0xbe, 0x24, 0x92, 0x3f, 0x92, 0x24, 0x92, 0x2e, 0x96, 0x35, 0x90, 0x20, 0x90, 0x3f, 0x90 },
+{ 0x97, 0xef, 0x0, 0x0, 0x3f, 0xff, 0x22, 0x8, 0x22, 0x8, 0x3f, 0xbf, 0x22, 0x8, 0x27, 0x1c, 0x3a, 0xab, 0x22, 0x8, 0x20, 0x0, 0x2f, 0xfe, 0x28, 0x2, 0x6f, 0xfe, 0x48, 0x2, 0x48, 0x2, 0xf, 0xfe },
+{ 0x97, 0xf0, 0x0, 0x0, 0x3f, 0xff, 0x22, 0x8, 0x22, 0x8, 0x3f, 0xbf, 0x22, 0x8, 0x27, 0x1c, 0x3a, 0xab, 0x22, 0x8, 0x20, 0x40, 0x24, 0x40, 0x64, 0x7e, 0x44, 0x40, 0x44, 0x40, 0x1f, 0xff, 0x0, 0x0 },
+{ 0x97, 0xf1, 0x0, 0x2, 0x3f, 0xd2, 0x4, 0x12, 0x4, 0x12, 0xc, 0x12, 0xf, 0x92, 0x18, 0x92, 0x10, 0x92, 0x39, 0x92, 0x6d, 0x12, 0x7, 0x12, 0x2, 0x2, 0x6, 0x2, 0xc, 0x2, 0x18, 0x2, 0x70, 0xe },
+{ 0x97, 0xf2, 0x0, 0x80, 0x4, 0x90, 0xc, 0x98, 0x18, 0x8c, 0x70, 0x97, 0x3, 0xb0, 0x0, 0xe0, 0x7, 0x80, 0x7c, 0x0, 0x0, 0x80, 0x3f, 0xfc, 0x1, 0x4, 0x3, 0x4, 0x6, 0xc, 0x1c, 0x8, 0x70, 0x38 },
+{ 0x97, 0xf3, 0x0, 0x2, 0x3f, 0xd2, 0x4, 0x12, 0x4, 0x12, 0xf, 0x92, 0x8, 0x92, 0x19, 0x92, 0x35, 0x12, 0x3, 0x2, 0x6, 0x2, 0xc, 0x2, 0x38, 0xe, 0x0, 0x0, 0x12, 0x22, 0x33, 0x33, 0x61, 0x11 },
+{ 0x97, 0xf4, 0x0, 0x2, 0x3f, 0xd2, 0x4, 0x12, 0xf, 0x92, 0x18, 0x92, 0x35, 0x92, 0x3, 0x2, 0xe, 0x2, 0x38, 0x8e, 0x0, 0x80, 0x7f, 0xff, 0x1, 0x44, 0x7, 0x68, 0x7c, 0x30, 0x7, 0x9c, 0x1c, 0x7 },
+{ 0x97, 0xf5, 0x0, 0x80, 0x3f, 0xff, 0x24, 0x8, 0x22, 0x10, 0x3f, 0xfe, 0x21, 0x20, 0x2f, 0xfc, 0x21, 0x24, 0x3f, 0xff, 0x21, 0x24, 0x2f, 0xfc, 0x25, 0x28, 0x65, 0x2c, 0x4d, 0x26, 0x59, 0x23, 0x1, 0x20 },
+{ 0x97, 0xf6, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x2, 0x20, 0xa, 0x28, 0xa, 0x28, 0x1a, 0x2c, 0x32, 0x26, 0x66, 0x23, 0xc, 0x20, 0x0, 0x0, 0x5, 0x80, 0x14, 0xc6, 0x14, 0x4b, 0x36, 0x19, 0x63, 0xf0 },
+{ 0x97, 0xf7, 0x11, 0x22, 0x10, 0xa4, 0x10, 0x20, 0x13, 0xff, 0x58, 0xa8, 0x55, 0xac, 0x53, 0x27, 0x51, 0x20, 0x11, 0xc4, 0x12, 0x7f, 0x13, 0x54, 0x15, 0xd4, 0x10, 0xbf, 0x11, 0x84, 0x13, 0x4, 0x16, 0x4 },
+{ 0x97, 0xf8, 0x0, 0x10, 0x24, 0x10, 0x36, 0xfe, 0x12, 0x10, 0x0, 0xfe, 0x40, 0x92, 0x60, 0x92, 0x2e, 0xfe, 0x2, 0x92, 0x2, 0x92, 0x12, 0xfe, 0x12, 0x10, 0x33, 0xff, 0x26, 0x10, 0x25, 0x10, 0x6c, 0xff },
+{ 0x97, 0xf9, 0x8, 0x10, 0x8, 0x10, 0x9, 0xff, 0xa, 0x10, 0x2a, 0xfe, 0x2c, 0x92, 0x68, 0xfe, 0x48, 0x92, 0x8, 0x92, 0x8, 0xfe, 0x8, 0x54, 0x1c, 0x54, 0x16, 0x54, 0x12, 0xd6, 0x31, 0x93, 0x60, 0x10 },
+{ 0x97, 0xfa, 0x10, 0x20, 0x3f, 0xbf, 0x64, 0x48, 0x0, 0x80, 0x3f, 0xff, 0x22, 0x10, 0x3f, 0xfe, 0x21, 0x20, 0x2f, 0xfc, 0x21, 0x24, 0x3f, 0xff, 0x21, 0x24, 0x2f, 0xfc, 0x65, 0x28, 0x4d, 0x2c, 0x19, 0x27 },
+{ 0x97, 0xfb, 0x8, 0x10, 0x18, 0x10, 0x31, 0xff, 0x62, 0x10, 0x36, 0xfe, 0xc, 0x92, 0x18, 0xfe, 0x34, 0x92, 0x7e, 0x92, 0xa, 0xfe, 0x8, 0x54, 0x2a, 0x54, 0x2a, 0xd6, 0x6a, 0x92, 0x49, 0x93, 0x8, 0x10 },
+{ 0x97, 0xfc, 0x0, 0x42, 0x7e, 0x84, 0x25, 0x8, 0x24, 0xa5, 0x3c, 0x42, 0x24, 0x84, 0x25, 0x29, 0x25, 0xef, 0x3c, 0x0, 0x25, 0x29, 0x25, 0x29, 0x25, 0x29, 0x3d, 0xef, 0x64, 0x28, 0x4, 0x68, 0x5, 0xc8 },
+{ 0x98, 0x40, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x0, 0x20, 0x33, 0xff, 0x18, 0x20, 0x9, 0xfe, 0x1, 0x22, 0x1, 0xfe, 0x79, 0x22, 0x9, 0xfe, 0x8, 0x20, 0xb, 0xff, 0x18, 0x20, 0x34, 0x20, 0x63, 0xff },
+{ 0x98, 0x41, 0x0, 0x20, 0x30, 0x20, 0x1b, 0xff, 0x8, 0x20, 0x1, 0xfe, 0x1, 0x22, 0x1, 0x22, 0x79, 0xfe, 0x9, 0x22, 0x9, 0x22, 0x9, 0xfe, 0x8, 0x20, 0xb, 0xff, 0x18, 0x20, 0x34, 0x20, 0x63, 0xff },
+{ 0x98, 0x42, 0x8, 0x10, 0x1c, 0x10, 0x16, 0xff, 0x32, 0x10, 0x20, 0xfe, 0x7e, 0x92, 0x8, 0xfe, 0x8, 0x92, 0x7e, 0x92, 0x8, 0xfe, 0x4a, 0x54, 0x6a, 0x54, 0x28, 0xd6, 0xe, 0x92, 0x39, 0x93, 0x60, 0x10 },
+{ 0x98, 0x43, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x0, 0x80, 0x1, 0x80, 0x1, 0x0, 0x1f, 0xfc, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x1f, 0xfc },
+{ 0x98, 0x44, 0x4, 0x0, 0xf, 0xe0, 0x10, 0x40, 0x7f, 0xfc, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x84, 0x1f, 0xfc, 0x12, 0x24, 0x33, 0x36, 0x61, 0x13, 0x1f, 0xfc, 0x10, 0x4, 0x1f, 0xfc, 0x10, 0x4, 0x1f, 0xfc },
+{ 0x98, 0x45, 0x10, 0x80, 0x11, 0xf8, 0x13, 0x10, 0x7d, 0xfe, 0x11, 0x22, 0x11, 0xfe, 0x39, 0x22, 0x35, 0xfe, 0x31, 0x4a, 0x52, 0x25, 0x50, 0x0, 0x11, 0xfe, 0x11, 0x2, 0x11, 0xfe, 0x11, 0x2, 0x11, 0xfe },
+{ 0x98, 0x46, 0x8, 0x0, 0x9, 0xff, 0x8, 0x0, 0xa, 0x0, 0x2a, 0xfe, 0x2c, 0x82, 0x68, 0x82, 0x48, 0xfe, 0x8, 0x80, 0x8, 0x80, 0x1c, 0x80, 0x16, 0x80, 0x12, 0x80, 0x31, 0x80, 0x21, 0x0, 0x63, 0x0 },
+{ 0x98, 0x47, 0x0, 0x40, 0x3c, 0x40, 0x24, 0x7c, 0x24, 0xc4, 0x3d, 0x8c, 0x24, 0x68, 0x24, 0x38, 0x24, 0x6c, 0x3d, 0xc7, 0x24, 0x0, 0x24, 0xfe, 0x24, 0x82, 0x3c, 0x82, 0x14, 0x82, 0x36, 0x82, 0x62, 0xfe },
+{ 0x98, 0x48, 0x0, 0x40, 0x3e, 0x40, 0x22, 0x7c, 0x22, 0xc4, 0x23, 0x8c, 0x3e, 0x68, 0x8, 0x38, 0x8, 0x6c, 0x29, 0xc7, 0x2e, 0x0, 0x28, 0xfe, 0x28, 0x82, 0x28, 0x82, 0x2e, 0x82, 0x38, 0x82, 0x60, 0xfe },
+{ 0x98, 0x49, 0x3f, 0xfe, 0x0, 0x80, 0x7f, 0xff, 0x40, 0x81, 0x5e, 0xbd, 0x40, 0x81, 0x1e, 0xbc, 0x0, 0x20, 0x3e, 0x7c, 0x22, 0xc4, 0x3e, 0x2c, 0x8, 0x38, 0x2e, 0xc7, 0x28, 0x7e, 0x2e, 0x42, 0x78, 0x7e },
+{ 0x98, 0x4a, 0x11, 0x2, 0x19, 0x86, 0x8, 0x8c, 0x0, 0x8, 0x3f, 0xfe, 0x20, 0x2, 0x20, 0x82, 0x0, 0x80, 0x1f, 0xfc, 0x0, 0x84, 0x1, 0x84, 0x1, 0x4, 0x3, 0x4, 0x6, 0xc, 0xc, 0x8, 0x38, 0x38 },
+{ 0x98, 0x4b, 0x0, 0x80, 0x1f, 0xfc, 0x10, 0x84, 0x7f, 0xff, 0x10, 0x84, 0x1f, 0xfc, 0x0, 0x80, 0x1f, 0xfc, 0x10, 0x84, 0x1f, 0xfc, 0x1, 0x0, 0x7f, 0xff, 0x4, 0x10, 0x1f, 0xe0, 0x1, 0x38, 0x3e, 0xe },
+{ 0x98, 0x4c, 0x0, 0x40, 0x0, 0x40, 0x1f, 0xff, 0x10, 0x0, 0x11, 0x0, 0x17, 0xde, 0x14, 0x52, 0x17, 0xd2, 0x14, 0x56, 0x17, 0xd4, 0x14, 0x12, 0x14, 0x92, 0x34, 0x92, 0x27, 0xd6, 0x6c, 0x50, 0x0, 0x10 },
+{ 0x98, 0x4d, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x80, 0x0, 0x80, 0xf, 0xf8, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x4, 0x10, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0xc, 0x10, 0x8, 0x10, 0x18, 0x10, 0x30, 0x10 },
+{ 0x98, 0x4e, 0x8, 0x0, 0x8, 0x3e, 0x3f, 0x22, 0x21, 0x22, 0x21, 0x22, 0x3f, 0x3e, 0x21, 0x22, 0x21, 0x22, 0x3f, 0x22, 0x20, 0x3e, 0x20, 0x22, 0x22, 0x22, 0x22, 0x22, 0x2f, 0x62, 0x39, 0x42, 0x60, 0xce },
+{ 0x98, 0x4f, 0x8, 0x91, 0x8, 0x52, 0x8, 0x10, 0x7e, 0xff, 0x8, 0x54, 0x8, 0x54, 0x18, 0xd6, 0x1d, 0x93, 0x1a, 0x0, 0x2a, 0x20, 0x29, 0xff, 0x48, 0x44, 0x8, 0x8c, 0x8, 0xf8, 0x8, 0x2e, 0x9, 0xc3 },
+{ 0x98, 0x50, 0x11, 0x0, 0x11, 0x1f, 0x13, 0xd1, 0x7e, 0x53, 0x12, 0x52, 0x13, 0xd6, 0x3a, 0x54, 0x36, 0x52, 0x53, 0xd1, 0x52, 0x11, 0x12, 0x91, 0x12, 0x91, 0x12, 0xd7, 0x13, 0x50, 0x16, 0x10, 0x10, 0x10 },
+{ 0x98, 0x51, 0x0, 0x40, 0x30, 0x40, 0x1b, 0xfc, 0xa, 0x4, 0x2, 0x4, 0x63, 0xfc, 0x32, 0x4, 0x12, 0x4, 0x3, 0xfc, 0xa, 0x21, 0xa, 0x33, 0x1a, 0x16, 0x12, 0x18, 0x32, 0xcc, 0x23, 0x86, 0x6e, 0x3 },
+{ 0x98, 0x52, 0x0, 0x0, 0x27, 0xff, 0x34, 0x1, 0x17, 0xff, 0x4, 0x0, 0x45, 0xff, 0x64, 0x10, 0x25, 0xff, 0x5, 0x11, 0x15, 0x99, 0x15, 0x55, 0x15, 0x11, 0x35, 0x99, 0x2d, 0x55, 0x29, 0x11, 0x61, 0x13 },
+{ 0x98, 0x53, 0x0, 0x80, 0x0, 0x80, 0x3f, 0xfe, 0x20, 0x2, 0x20, 0x2, 0x4, 0x80, 0x4, 0x80, 0xf, 0xfc, 0x18, 0x80, 0x30, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80 },
+{ 0x98, 0x54, 0x4, 0x20, 0x44, 0x20, 0x29, 0xfc, 0x19, 0x4, 0x11, 0x4, 0x29, 0xfc, 0x49, 0x4, 0x9, 0x4, 0x19, 0xfd, 0x19, 0x13, 0x29, 0x16, 0x49, 0x18, 0x9, 0x8, 0x9, 0xc, 0x19, 0xe6, 0x77, 0x3 },
+{ 0x98, 0x55, 0x10, 0x20, 0x1f, 0xbf, 0x34, 0x48, 0x62, 0x4, 0x0, 0x80, 0x1f, 0xfc, 0x4, 0x10, 0x7f, 0xff, 0x0, 0x0, 0x1f, 0xfc, 0x10, 0x84, 0x1f, 0xfc, 0x10, 0x84, 0x1f, 0xfc, 0x0, 0x81, 0x0, 0x7f },
+{ 0x98, 0x56, 0x0, 0x84, 0x0, 0x84, 0x1f, 0xfc, 0x0, 0x88, 0x0, 0x98, 0x0, 0xb0, 0x7f, 0xff, 0x0, 0xc0, 0x1, 0x80, 0x7, 0xc, 0x1c, 0x78, 0x77, 0xc0, 0x4, 0x0, 0x4, 0x1, 0x6, 0x3, 0x3, 0xfe },
+{ 0x98, 0x57, 0x8, 0x20, 0x7f, 0xbf, 0x12, 0x20, 0x7f, 0xbe, 0x21, 0x2, 0x3f, 0x3e, 0x21, 0x20, 0x3f, 0x3e, 0x21, 0x20, 0x23, 0x21, 0x7f, 0xff, 0x8, 0x8, 0xf, 0xf8, 0x8, 0xf, 0x7f, 0xf8, 0x0, 0x8 },
+{ 0x98, 0x58, 0x11, 0x22, 0x11, 0xb6, 0x10, 0x94, 0x7c, 0x0, 0x55, 0xfc, 0x55, 0x24, 0x55, 0x24, 0x55, 0xfc, 0x55, 0x24, 0x7d, 0x24, 0x11, 0xfc, 0x11, 0x24, 0x15, 0x24, 0x15, 0x25, 0x3d, 0x25, 0x66, 0x23 },
+{ 0x98, 0x59, 0x4, 0x0, 0x4, 0x3f, 0x3f, 0xa1, 0x20, 0xa3, 0x20, 0xa2, 0x3f, 0xa6, 0x20, 0xa4, 0x20, 0xa2, 0x3f, 0xa1, 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x27, 0xa1, 0x3c, 0xa7, 0x60, 0x20, 0x0, 0x20 },
+{ 0x98, 0x5a, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x7f, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x10, 0x4, 0x10, 0xc, 0x18, 0x8, 0x8, 0x18, 0xc, 0x10, 0x4, 0x30, 0x6, 0x60, 0x3 },
+{ 0x98, 0x5b, 0x4, 0x10, 0x7f, 0xff, 0x14, 0x54, 0x36, 0x96, 0x65, 0x13, 0x0, 0x40, 0x1f, 0xff, 0x11, 0x20, 0x1f, 0xfe, 0x11, 0x22, 0x1f, 0xfe, 0x14, 0x20, 0x37, 0xbc, 0x24, 0x21, 0x67, 0xa3, 0x1c, 0x1e },
+{ 0x98, 0x5c, 0x10, 0x0, 0x11, 0xfc, 0x10, 0x4, 0x7d, 0xfc, 0x4, 0x4, 0xc, 0x4, 0xb, 0xff, 0x18, 0x20, 0x11, 0x22, 0x3d, 0xa6, 0x56, 0xb4, 0x10, 0x78, 0x10, 0xac, 0x11, 0xa6, 0x13, 0x23, 0x10, 0xe0 },
+{ 0x98, 0x5d, 0x0, 0x20, 0x3c, 0x20, 0x24, 0x20, 0x24, 0x20, 0x25, 0xfe, 0x3c, 0x22, 0x24, 0x22, 0x24, 0x22, 0x24, 0x22, 0x3c, 0x22, 0x24, 0x22, 0x24, 0x62, 0x24, 0x46, 0x24, 0x44, 0x64, 0xc4, 0x4d, 0x9c },
+{ 0x98, 0x5e, 0x8, 0x0, 0x1c, 0xfc, 0x16, 0x4, 0x32, 0xfc, 0x20, 0x4, 0x7e, 0x4, 0x9, 0xff, 0x8, 0x10, 0x7e, 0x92, 0x8, 0xd6, 0x4a, 0x54, 0x2a, 0x38, 0x28, 0x5c, 0xe, 0xd6, 0x39, 0x93, 0x60, 0x70 },
+{ 0x98, 0x5f, 0x0, 0x10, 0x3c, 0x38, 0x0, 0x6c, 0x7e, 0xc6, 0x1, 0x83, 0x3c, 0x7c, 0x0, 0x0, 0x0, 0x0, 0x3c, 0xfe, 0x0, 0xaa, 0x0, 0xaa, 0x3c, 0xfe, 0x24, 0xaa, 0x24, 0xaa, 0x24, 0xaa, 0x3c, 0x86 },
+{ 0x98, 0x60, 0x8, 0xc, 0x8, 0x38, 0xb, 0xe0, 0x18, 0x20, 0x17, 0xff, 0x30, 0xa8, 0x31, 0xac, 0x57, 0x27, 0x10, 0x40, 0x10, 0x40, 0x17, 0xff, 0x10, 0x84, 0x11, 0x8, 0x13, 0xf0, 0x10, 0x5c, 0x17, 0x86 },
+{ 0x98, 0x61, 0x1, 0x80, 0x7, 0x0, 0x7c, 0x7e, 0x4, 0x42, 0x4, 0x42, 0x7f, 0xc2, 0x4, 0x42, 0xe, 0x42, 0xd, 0x42, 0x15, 0x42, 0x34, 0x42, 0x64, 0x42, 0x4, 0x42, 0x4, 0x7e, 0x4, 0x0, 0x4, 0x0 },
+{ 0x98, 0x62, 0x0, 0x6, 0x3c, 0x1c, 0x0, 0xf0, 0x7e, 0x10, 0x0, 0x10, 0x3d, 0xff, 0x0, 0x10, 0x0, 0x10, 0x3c, 0x10, 0x0, 0x10, 0x0, 0xfe, 0x3c, 0x82, 0x24, 0x82, 0x24, 0x82, 0x24, 0x82, 0x3c, 0xfe },
+{ 0x98, 0x63, 0x0, 0x0, 0x3f, 0xfe, 0x0, 0x80, 0x1, 0xa0, 0x3, 0xb0, 0xe, 0x9c, 0x78, 0x87, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x80, 0x8, 0x80, 0x8, 0xf8, 0x8, 0x80, 0x8, 0x80, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x98, 0x64, 0x0, 0x20, 0x3e, 0x20, 0x23, 0xff, 0x22, 0x20, 0x3e, 0x20, 0x22, 0x7e, 0x22, 0x42, 0x22, 0xc2, 0x3f, 0x7e, 0x22, 0x42, 0x22, 0x42, 0x22, 0x7e, 0x3e, 0x42, 0x14, 0x42, 0x36, 0x42, 0x63, 0x4e },
+{ 0x98, 0x65, 0x0, 0x20, 0x3c, 0x20, 0x24, 0xfe, 0x24, 0x22, 0x24, 0x22, 0x3c, 0x62, 0x24, 0xce, 0x24, 0x0, 0x24, 0x84, 0x3d, 0xef, 0x24, 0xa5, 0x24, 0xa5, 0x24, 0xa5, 0x24, 0xa5, 0x64, 0xa5, 0x4d, 0x6b },
+{ 0x98, 0x66, 0x0, 0x48, 0x0, 0x44, 0x7f, 0xff, 0x0, 0x40, 0x1f, 0x62, 0x11, 0x26, 0x1f, 0x34, 0x0, 0x18, 0xf, 0xbd, 0x78, 0x67, 0x1, 0xc2, 0x0, 0x0, 0x14, 0xc6, 0x14, 0x6b, 0x36, 0x19, 0x63, 0xf0 },
+{ 0x98, 0x67, 0x8, 0x20, 0x8, 0x20, 0x8, 0xfc, 0x7e, 0x24, 0x8, 0x64, 0xc, 0x45, 0x1a, 0xc5, 0x19, 0x83, 0x18, 0x10, 0x28, 0x10, 0x29, 0xff, 0x48, 0x10, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10, 0x8, 0x10 },
+{ 0x98, 0x68, 0x4, 0x12, 0x7f, 0xbf, 0x11, 0x14, 0x1f, 0x14, 0x24, 0xb5, 0x4c, 0x67, 0x1, 0x0, 0xf, 0xf0, 0x8, 0x10, 0xf, 0xf0, 0x8, 0x10, 0xf, 0xff, 0x8, 0x0, 0x2f, 0xfe, 0x64, 0x92, 0x42, 0x4e },
+{ 0x98, 0x69, 0x0, 0x0, 0x3f, 0xfe, 0x2, 0x0, 0x2, 0x0, 0x3, 0xf0, 0x2, 0x10, 0x6, 0x90, 0x4, 0xd0, 0x4, 0x50, 0x5, 0x10, 0xd, 0xb0, 0x8, 0xa0, 0x0, 0x20, 0x0, 0x20, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x98, 0x6a, 0x0, 0x0, 0x3f, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xf, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x0 },
+{ 0x98, 0x6b, 0x10, 0x0, 0x1e, 0xee, 0x32, 0xaa, 0x24, 0xaa, 0x7e, 0xee, 0x2a, 0x0, 0x2a, 0xfe, 0x3e, 0x0, 0x2b, 0xff, 0x2a, 0x20, 0x3e, 0x40, 0x0, 0xfe, 0x55, 0x2, 0x55, 0x2, 0x54, 0x6, 0x40, 0x1c },
+{ 0x98, 0x6c, 0x0, 0x10, 0x3c, 0x10, 0x1, 0xff, 0x7f, 0x1, 0x1, 0xd, 0x3c, 0x38, 0x0, 0xe0, 0x0, 0x20, 0x3c, 0x20, 0x1, 0xff, 0x0, 0x20, 0x3c, 0x20, 0x24, 0x20, 0x24, 0x21, 0x24, 0x33, 0x3c, 0x1e },
+{ 0x98, 0x6d, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x0, 0x80, 0x3f, 0xfe, 0x4, 0x10, 0x7, 0xf0, 0x0, 0x0, 0x3f, 0xfe, 0x24, 0x12, 0x27, 0xf6, 0x0, 0x80, 0x7f, 0xff, 0x2, 0xa0, 0xe, 0xb8, 0x78, 0x8f },
+{ 0x98, 0x6e, 0x4, 0x10, 0x7f, 0xff, 0x4, 0x10, 0x0, 0x0, 0x3f, 0xff, 0x28, 0x90, 0x25, 0x10, 0x2f, 0xbf, 0x22, 0x29, 0x2a, 0xaa, 0x2a, 0x88, 0x2a, 0x9c, 0x2f, 0x94, 0x62, 0x14, 0x46, 0x36, 0xc, 0x63 },
+{ 0x98, 0x6f, 0x10, 0x20, 0x10, 0x20, 0x13, 0xfe, 0x7e, 0x2, 0x12, 0x2, 0x11, 0x0, 0x39, 0xde, 0x35, 0x52, 0x33, 0x52, 0x52, 0x52, 0x57, 0xd2, 0x10, 0x96, 0x11, 0x90, 0x11, 0x11, 0x13, 0x13, 0x16, 0xe },
+{ 0x98, 0x70, 0x0, 0x20, 0x20, 0x20, 0x37, 0xff, 0x10, 0x88, 0x2, 0x8a, 0x44, 0x89, 0x61, 0x8, 0x20, 0x0, 0x7, 0xfe, 0x10, 0x2, 0x13, 0xfe, 0x12, 0x0, 0x33, 0xff, 0x20, 0x1, 0x20, 0x3, 0x60, 0xe },
+{ 0x98, 0x71, 0x0, 0x20, 0x7c, 0x20, 0x13, 0xfe, 0x12, 0x2, 0x12, 0x2, 0x11, 0x0, 0x39, 0xde, 0x29, 0x52, 0x6b, 0x52, 0x2a, 0x52, 0x2d, 0xd2, 0x28, 0x96, 0x29, 0x90, 0x39, 0x11, 0x3, 0x13, 0x6, 0xe },
+{ 0x98, 0x72, 0x0, 0x20, 0x38, 0x20, 0x2b, 0xfe, 0x2a, 0x2, 0x2a, 0x2, 0x39, 0x0, 0x29, 0xde, 0x29, 0x52, 0x2b, 0x52, 0x3a, 0x52, 0x29, 0x52, 0x28, 0xd6, 0x28, 0x90, 0x28, 0x91, 0x69, 0x93, 0x5b, 0xe },
+};
+
diff --git a/private/ntos/boot/bootfont/jpn/genfont.c b/private/ntos/boot/bootfont/jpn/genfont.c
new file mode 100644
index 000000000..dae6282eb
--- /dev/null
+++ b/private/ntos/boot/bootfont/jpn/genfont.c
@@ -0,0 +1,110 @@
+#include <windows.h>
+#include <stdio.h>
+
+#include "..\..\lib\i386\bootfont.h"
+#include "fntjapan.h"
+
+
+int
+_CRTAPI1
+main(
+ IN int argc,
+ IN char *argv[]
+ )
+{
+ HANDLE hFile;
+ DWORD BytesWritten;
+ BOOL b;
+ BOOTFONTBIN_HEADER Header;
+ unsigned u;
+
+ if(argc != 2) {
+ fprintf(stderr,"Usage: %s <outputfile>\n",argv[0]);
+ return(1);
+ }
+
+ //
+ // Fill in the header.
+ //
+ Header.Signature = BOOTFONTBIN_SIGNATURE;
+ Header.LanguageId = 0x411;
+
+ Header.NumSbcsChars = MAX_SBCS_NUM;
+ Header.NumDbcsChars = MAX_DBCS_NUM;
+
+ Header.SbcsEntriesTotalSize = MAX_SBCS_BYTES * MAX_SBCS_NUM;
+ Header.DbcsEntriesTotalSize = MAX_DBCS_BYTES * MAX_DBCS_NUM;
+
+ ZeroMemory(Header.DbcsLeadTable,sizeof(Header.DbcsLeadTable));
+ MoveMemory(Header.DbcsLeadTable,LeadByteTable,sizeof(LeadByteTable));
+
+ Header.CharacterImageHeight = 16;
+ Header.CharacterTopPad = 1;
+ Header.CharacterBottomPad = 2;
+
+ Header.CharacterImageSbcsWidth = 8;
+ Header.CharacterImageDbcsWidth = 16;
+
+ Header.SbcsOffset = sizeof(BOOTFONTBIN_HEADER);
+ Header.DbcsOffset = Header.SbcsOffset + Header.SbcsEntriesTotalSize;
+
+ //
+ // Create the output file.
+ //
+ hFile = CreateFile(
+ argv[1],
+ FILE_GENERIC_WRITE,
+ 0,
+ NULL,
+ CREATE_ALWAYS,
+ 0,
+ NULL
+ );
+
+ if(hFile == INVALID_HANDLE_VALUE) {
+ printf("Unable to create output file (%u)\n",GetLastError());
+ return(1);
+ }
+
+ //
+ // Write the header.
+ //
+ b = WriteFile(hFile,&Header,sizeof(BOOTFONTBIN_HEADER),&BytesWritten,NULL);
+ if(!b) {
+ printf("Error writing output file (%u)\n",GetLastError());
+ CloseHandle(hFile);
+ return(1);
+ }
+
+ //
+ // Write the sbcs images.
+ //
+ for(u=0; u<MAX_SBCS_NUM; u++) {
+ b = WriteFile(hFile,SBCSImage[u],MAX_SBCS_BYTES,&BytesWritten,NULL);
+ if(!b) {
+ printf("Error writing output file (%u)\n",GetLastError());
+ CloseHandle(hFile);
+ return(1);
+ }
+ }
+
+ //
+ // Write the dbcs images.
+ //
+ for(u=0; u<MAX_DBCS_NUM; u++) {
+ b = WriteFile(hFile,DBCSImage[u],MAX_DBCS_BYTES,&BytesWritten,NULL);
+ if(!b) {
+ printf("Error writing output file (%u)\n",GetLastError());
+ CloseHandle(hFile);
+ return(1);
+ }
+ }
+
+ //
+ // Done.
+ //
+ CloseHandle(hFile);
+ printf("Output file sucessfully generated\n");
+ return(0);
+}
+
diff --git a/private/ntos/boot/bootfont/jpn/makefile b/private/ntos/boot/bootfont/jpn/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/boot/bootfont/jpn/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/boot/bootfont/jpn/sources b/private/ntos/boot/bootfont/jpn/sources
new file mode 100644
index 000000000..53bfd458f
--- /dev/null
+++ b/private/ntos/boot/bootfont/jpn/sources
@@ -0,0 +1,29 @@
+!IF 0
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=boot
+MINORCOMP=genfont
+
+TARGETNAME=genfont
+TARGETPATH=obj
+TARGETTYPE=PROGRAM
+
+SOURCES=
+UMTYPE=console
+UMAPPL=genfont
diff --git a/private/ntos/boot/bootfont/readme.txt b/private/ntos/boot/bootfont/readme.txt
new file mode 100644
index 000000000..5aa6b8610
--- /dev/null
+++ b/private/ntos/boot/bootfont/readme.txt
@@ -0,0 +1,6 @@
+The jpn directory contains the original fntjapan.h that was once
+compiled into the x86 boot loaders, and a program I wrote to generate
+bootfont.bin for Japan from it.
+
+- tedm, 7/11/95, Tokyo
+ \ No newline at end of file
diff --git a/private/ntos/boot/dbcs.txt b/private/ntos/boot/dbcs.txt
new file mode 100644
index 000000000..c55c48ee8
--- /dev/null
+++ b/private/ntos/boot/dbcs.txt
@@ -0,0 +1,48 @@
+This file describes the nature of DBCS support in ntldr/setupldr.bin for x86.
+
+On non-x86 machines we do nothing for now. The firmware is in control of the video
+and thus the firmware is supposed to support displaying characters deemed necessary
+by the system designer.
+
+The x86 loaders operate using either standard 80x25 vga text mode or standard
+640x480 graphics mode. In the latter case the loader display system paints
+characters to simulate a console-type environment. Text mode is the default.
+
+Early in initialization, the loader attempts to open a file called BOOTFONT.BIN
+on the root of the drive from which boot is occurring (ie, in the same place where
+it later expects to find ntdetect.com, boot.ini, etc). If that file is found and
+is deemed valid, the display subsystem switches to graphics mode and is thus able
+to display arbitrary glyphs. The font file gives such details as the dbcs lead byte
+ranges, and so support in the loader display system is not dependent on any
+particular codepage.
+
+Thus we achieve single-binary and the ability to fully localize ntldr and
+setupldr.bin for any locale.
+
+See boot\lib\i386\bootfont.h for the format of the bootfont.bin file.
+
+Note that Setup will install bootfont.bin. If this file becomes corrupt or the
+user deletes it, the ntldr will fall back to sbcs support via vga text mode.
+For this reason, it may be desirable to include English message resources
+(as well as the ones for the particular localization) in ntldr so at least
+the boot selection screens will be readable in English and not just display
+as garbage.
+
+Still to do some day, issues, problems, etc:
+
+ - If non-x86 machines' firmware starts to support DBCS we should be able to
+ extend support to these machines orthoganally since the x86 implementation
+ is entirely 'hidden' in the ARC emulation layer. The only thing we would need
+ is a mechanism to 'trigger' dbcs mode, which is performed by the presence of
+ bootfont.bin on x86 machines.
+
+ - The ARC console is driven by control sequences that are introduced with 0x9b.
+ Unfortunately this is a valid lead byte char in several Far East code pages.
+ In Japan this doesn't bite us because we don't actually use any characters that
+ lead with 0x9b. The fix is to replace use of 0x9b with ESC[ (escape-left bracket)
+ which is a synonym. However we don't know if all ARC firmware out there
+ supports that as a synonym, so #ifdef _X86_ would probably be necessary
+ (that would be ok since we are not enabling dbcs for non-x86 machines anyway).
+
+- tedm, 7/11/95, Tokyo
+ \ No newline at end of file
diff --git a/private/ntos/boot/detect/chk/16bitbld.cmd b/private/ntos/boot/detect/chk/16bitbld.cmd
new file mode 100644
index 000000000..259f2b1a3
--- /dev/null
+++ b/private/ntos/boot/detect/chk/16bitbld.cmd
@@ -0,0 +1,5 @@
+setlocal
+path %SystemRoot%\mstools;\\kernel\razzle3\os2sup\oak\bin;\\kernel\razzle3\os2sup\sdk\bin;%path%
+set NTVERSION=
+nmake
+endlocal
diff --git a/private/ntos/boot/detect/chk/makefile b/private/ntos/boot/detect/chk/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/boot/detect/chk/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/boot/detect/chk/makefile.inc b/private/ntos/boot/detect/chk/makefile.inc
new file mode 100644
index 000000000..06a97ebe7
--- /dev/null
+++ b/private/ntos/boot/detect/chk/makefile.inc
@@ -0,0 +1,119 @@
+# Copyright (C) by Microsoft Corporation.
+#
+# MAKEFILE for NT ntdetect.chk
+#
+# Created:
+# 14-Feb-1992
+#
+# Author:
+# Shie-Lin Tzong
+#
+
+.SUFFIXES: .com .exe .obj .lst .c .asm .def .lnk .inc
+
+OD= obj\i386
+DETECT_DEBUG= -DDBG=1
+
+#
+# C Compiler Definitions
+# ~~~~~~~~~~~~~~~~~~~~~~
+
+!IFNDEF BASEDIR
+BASEDIR=$(_NTDRIVE)\nt
+!ENDIF
+
+CC= cl16
+CFLAGS= -W3 -G2s -Zelp $(DETECT_DEBUG) $(BLFLAGS)
+CINC= -I. -I..\..\..\inc -I$(BASEDIR)\public\sdk\inc -I..\i386
+
+
+#
+# Assembler Definitions
+# ~~~~~~~~~~~~~~~~~~~~~
+
+ASM= masm386
+AFLAGS= -Mx -z $(DETECT_DEBUG) $(GAFLAGS)
+AINC= -I$(BASEDIR)\public\sdk\inc -I..\i386
+
+
+#
+# Linker Definitions
+# ~~~~~~~~~~~~~~~~~~
+
+LINK=link_60
+LIBS=..\i386\long.lib ..\i386\slibce.lib ..\i386\llibce.lib
+DEF=
+
+
+#
+# Rules for generating objects
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+
+{..\i386\}.asm{$(OD)}.obj:
+ $(ASM) $(AFLAGS) $(AINC) $<, $@;
+
+{..\i386\}.asm{$(OD)}.lst:
+ $(ASM) -l -n $(AFLAGS) $(AINC) $<, $*.obj, $@;
+
+{..\i386\}.c{$(OD)}.obj:
+ $(CC) $(CFLAGS) $(CINC) -c -Fo$@ $<
+
+{..\i386\}.c{$(OD)}.cod:
+ $(CC) $(CFLAGS) $(CINC) -c -Fc$@ $<
+
+
+#
+# List of object files required
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+OBJ= $(OD)\main.obj $(OD)\comlptc.obj $(OD)\diska.obj \
+ $(OD)\display.obj $(OD)\diskc.obj $(OD)\hwdetect.obj $(OD)\hweisaa.obj \
+ $(OD)\hweisac.obj $(OD)\hwheap.obj $(OD)\hwmacha.obj $(OD)\hwmcaa.obj \
+ $(OD)\hwmcac.obj $(OD)\hwmisca.obj $(OD)\hwvbiosc.obj $(OD)\keybda.obj \
+ $(OD)\keybdc.obj $(OD)\mousea.obj $(OD)\mousec.obj $(OD)\videoa.obj \
+ $(OD)\backend.obj $(OD)\hwpcia.obj $(OD)\hwapm.obj $(OD)\hwpbiosc.obj
+
+#
+# Dependencies
+# ~~~~~~~~~~~~
+
+$(OD)\ntdetect.chk: $(OBJ)
+
+$(OD)\backend.obj $(OD)\backend.lst: ..\i386\backend.asm
+$(OD)\hweisaa.obj $(OD)\hweisaa.cod: ..\i386\hweisa.inc ..\i386\hweisaa.asm
+$(OD)\hwpcia.obj $(OD)\hwpcia.cod: ..\i386\hwpci.inc ..\i386\hwpcia.asm
+$(OD)\hwapm.obj $(OD)\hwapm.cod: ..\i386\hwapm.c
+$(OD)\main.obj $(OD)\main.lst: ..\i386\main.asm ..\i386\main.inc
+$(OD)\display.obj $(OD)\display.cod: ..\i386\display.c ..\i386\types.h
+$(OD)\diska.obj $(OD)\diska.lst: ..\i386\diska.asm
+$(OD)\hwheap.obj $(OD)\hwheap.cod: ..\i386\hwheap.c ..\i386\hwdetect.h
+$(OD)\hwdetect.obj $(OD)\hwdetect.cod: ..\i386\hwdetect.c ..\i386\hwdetect.h
+$(OD)\hwmisca.obj $(OD)\hwmisca.lst: ..\i386\hwmisca.asm
+$(OD)\videoa.obj $(OD)\videoa.lst: ..\i386\videoa.asm
+$(OD)\keybdc.obj $(OD)\keybdc.cod: ..\i386\keybdc.c ..\i386\hwdetect.h
+$(OD)\keybda.obj $(OD)\keybda.lst: ..\i386\keybda.asm
+$(OD)\comlptc.obj $(OD)\comlptc.cod: ..\i386\comlptc.c ..\i386\hwdetect.h
+$(OD)\mousea.obj $(OD)\mousea.lst: ..\i386\mousea.asm ..\i386\mouse.inc
+$(OD)\mousec.obj $(OD)\mousec.cod: ..\i386\mousec.c ..\i386\hwdetect.h
+$(OD)\diskc.obj $(OD)\diskc.cod: ..\i386\diskc.c ..\i386\hwdetect.h ..\i386\disk.h
+$(OD)\hweisac.obj $(OD)\hweisac.cod: ..\i386\hweisac.c ..\i386\hwdetect.h
+$(OD)\hwmcac.obj $(OD)\hwmcac.cod: ..\i386\hwmcac.c ..\i386\hwdetect.h
+$(OD)\hwmcaa.obj $(OD)\hwmcaa.lst: ..\i386\hwmcaa.asm
+$(OD)\hwmacha.obj $(OD)\hwmacha.lst: ..\i386\hwmacha.asm
+$(OD)\hwvbiosc.obj $(OD)\hwvbiosc.cod: ..\i386\hwvbiosc.c ..\i386\hwdetect.h ..\i386\hwvbios.h
+$(OD)\hwpbiosc.obj $(OD)\hwpbiosc.cod: ..\i386\hwpbiosc.c ..\i386\hwdetect.h ..\i386\pnpbios.h
+
+$(OD)\ntdetect.chk: $(OBJ) $(DOBJ) $(LIBS)
+ $(LINK) @<<
+ /tiny /nod /noi /map $(OD)\main $(OD)\hweisaa $(OD)\display +
+ $(OD)\hwheap $(OD)\hwdetect $(OD)\hwmisca $(OD)\videoa +
+ $(OD)\keybda $(OD)\keybdc $(OD)\comlptc $(OD)\mousea $(OD)\mousec +
+ $(OD)\diskc $(OD)\diska $(OD)\hweisac $(OD)\hwmcac $(OD)\hwmcaa +
+ $(OD)\hwmacha $(OD)\hwvbiosc $(OD)\backend $(OD)\hwpcia $(OD)\hwapm +
+ $(OD)\hwpbiosc
+ $(OD)\ntdetect.chk,
+ $(OD)\ntdetect.map,
+ $(LIBS);
+<<
+ binplace $(OD)\ntdetect.chk
diff --git a/private/ntos/boot/detect/chk/sources b/private/ntos/boot/detect/chk/sources
new file mode 100644
index 000000000..fec8dfb26
--- /dev/null
+++ b/private/ntos/boot/detect/chk/sources
@@ -0,0 +1,67 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=detect
+
+TARGETNAME=ntdetect.chk
+TARGETPATH=obj
+TARGETTYPE=UMAPPL_NOLIB
+
+INCLUDES=$(BASEDIR)\public\sdk\inc;..\..\..\inc
+
+SOURCES=
+
+i386_SOURCES=..\i386\backend.asm \
+ ..\i386\hweisaa.asm \
+ ..\i386\hweisac.c \
+ ..\i386\hwpcia.asm \
+ ..\i386\main.asm \
+ ..\i386\display.c \
+ ..\i386\diska.asm \
+ ..\i386\diskc.c \
+ ..\i386\hwheap.c \
+ ..\i386\hwdetect.c \
+ ..\i386\hwmisca.asm \
+ ..\i386\videoa.asm \
+ ..\i386\keybdc.c \
+ ..\i386\keybda.asm \
+ ..\i386\comlptc.c \
+ ..\i386\mousea.asm \
+ ..\i386\mousec.c \
+ ..\i386\hwmcac.c \
+ ..\i386\hwmcaa.asm \
+ ..\i386\hwmacha.asm \
+ ..\i386\hwvbiosc.c \
+ ..\i386\hwpbiosc.c
+
+!IF $(386)
+
+NTTARGETFILES=obj\i386\ntdetect.chk
+
+!ENDIF
+
+
+
+
diff --git a/private/ntos/boot/detect/dirs b/private/ntos/boot/detect/dirs
new file mode 100644
index 000000000..a48018ee8
--- /dev/null
+++ b/private/ntos/boot/detect/dirs
@@ -0,0 +1,25 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+
+Author:
+
+ Steve Wood (stevewo) 17-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\dirs.tpl
+
+!ENDIF
+
+DIRS=fre
+
+OPTIONAL_DIRS=chk
diff --git a/private/ntos/boot/detect/fre/16bitbld.cmd b/private/ntos/boot/detect/fre/16bitbld.cmd
new file mode 100644
index 000000000..259f2b1a3
--- /dev/null
+++ b/private/ntos/boot/detect/fre/16bitbld.cmd
@@ -0,0 +1,5 @@
+setlocal
+path %SystemRoot%\mstools;\\kernel\razzle3\os2sup\oak\bin;\\kernel\razzle3\os2sup\sdk\bin;%path%
+set NTVERSION=
+nmake
+endlocal
diff --git a/private/ntos/boot/detect/fre/makefile b/private/ntos/boot/detect/fre/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/boot/detect/fre/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/boot/detect/fre/makefile.inc b/private/ntos/boot/detect/fre/makefile.inc
new file mode 100644
index 000000000..a94b63b0a
--- /dev/null
+++ b/private/ntos/boot/detect/fre/makefile.inc
@@ -0,0 +1,121 @@
+# Copyright (C) by Microsoft Corporation.
+#
+# MAKEFILE for NT ntdetect.com
+#
+# Created:
+# 14-Feb-1992
+#
+# Author:
+# Shie-Lin Tzong
+#
+
+.SUFFIXES: .com .exe .obj .lst .c .asm .def .lnk .inc
+
+PATH= $(_NTBINDIR)\private\mvdm\tools16;$(PATH)
+
+OD= obj\i386
+DETECT_DEBUG= -DDBG=0
+
+#
+# C Compiler Definitions
+# ~~~~~~~~~~~~~~~~~~~~~~
+
+!IFNDEF BASEDIR
+BASEDIR=$(_NTDRIVE)\nt
+!ENDIF
+
+CC= cl16
+CFLAGS= -W3 -G2s -Zelp $(DETECT_DEBUG) $(BLFLAGS)
+CINC= -I. -I..\..\..\inc -I$(BASEDIR)\public\sdk\inc -I..\i386
+
+
+#
+# Assembler Definitions
+# ~~~~~~~~~~~~~~~~~~~~~
+
+ASM= masm386
+AFLAGS= -Mx -z $(DETECT_DEBUG) $(GAFLAGS)
+AINC= -I$(BASEDIR)\public\sdk\inc -I..\i386
+
+
+#
+# Linker Definitions
+# ~~~~~~~~~~~~~~~~~~
+
+LINK=link_60
+LIBS=..\i386\long.lib ..\i386\slibce.lib ..\i386\llibce.lib
+DEF=
+
+
+#
+# Rules for generating objects
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+
+{..\i386\}.asm{$(OD)}.obj:
+ $(ASM) $(AFLAGS) $(AINC) $<, $@;
+
+{..\i386\}.asm{$(OD)}.lst:
+ $(ASM) -l -n $(AFLAGS) $(AINC) $<, $*.obj, $@;
+
+{..\i386\}.c{$(OD)}.obj:
+ $(CC) $(CFLAGS) $(CINC) -c -Fo$@ $<
+
+{..\i386\}.c{$(OD)}.cod:
+ $(CC) $(CFLAGS) $(CINC) -c -Fc$@ $<
+
+
+#
+# List of object files required
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+OBJ= $(OD)\main.obj $(OD)\comlptc.obj $(OD)\diska.obj \
+ $(OD)\display.obj $(OD)\diskc.obj $(OD)\hwdetect.obj $(OD)\hweisaa.obj \
+ $(OD)\hweisac.obj $(OD)\hwheap.obj $(OD)\hwmacha.obj $(OD)\hwmcaa.obj \
+ $(OD)\hwmcac.obj $(OD)\hwmisca.obj $(OD)\hwvbiosc.obj $(OD)\keybda.obj \
+ $(OD)\keybdc.obj $(OD)\mousea.obj $(OD)\mousec.obj $(OD)\videoa.obj \
+ $(OD)\backend.obj $(OD)\hwpcia.obj $(OD)\hwapm.obj $(OD)\hwpbiosc.obj
+
+#
+# Dependencies
+# ~~~~~~~~~~~~
+
+$(OD)\ntdetect.com: $(OBJ)
+
+$(OD)\backend.obj $(OD)\backend.lst: ..\i386\backend.asm
+$(OD)\hweisaa.obj $(OD)\hweisaa.cod: ..\i386\hweisa.inc ..\i386\hweisaa.asm
+$(OD)\hwpcia.obj $(OD)\hwpcia.cod: ..\i386\hwpci.inc ..\i386\hwpcia.asm
+$(OD)\hwapm.obj $(OD)\hwapm.cod: ..\i386\hwapm.c
+$(OD)\main.obj $(OD)\main.lst: ..\i386\main.asm ..\i386\main.inc
+$(OD)\display.obj $(OD)\display.cod: ..\i386\display.c ..\i386\types.h
+$(OD)\diska.obj $(OD)\diska.lst: ..\i386\diska.asm
+$(OD)\hwheap.obj $(OD)\hwheap.cod: ..\i386\hwheap.c ..\i386\hwdetect.h
+$(OD)\hwdetect.obj $(OD)\hwdetect.cod: ..\i386\hwdetect.c ..\i386\hwdetect.h
+$(OD)\hwmisca.obj $(OD)\hwmisca.lst: ..\i386\hwmisca.asm
+$(OD)\videoa.obj $(OD)\videoa.lst: ..\i386\videoa.asm
+$(OD)\keybdc.obj $(OD)\keybdc.cod: ..\i386\keybdc.c ..\i386\hwdetect.h
+$(OD)\keybda.obj $(OD)\keybda.lst: ..\i386\keybda.asm
+$(OD)\comlptc.obj $(OD)\comlptc.cod: ..\i386\comlptc.c ..\i386\hwdetect.h
+$(OD)\mousea.obj $(OD)\mousea.lst: ..\i386\mousea.asm ..\i386\mouse.inc
+$(OD)\mousec.obj $(OD)\mousec.cod: ..\i386\mousec.c ..\i386\hwdetect.h
+$(OD)\diskc.obj $(OD)\diskc.cod: ..\i386\diskc.c ..\i386\hwdetect.h ..\i386\disk.h
+$(OD)\hweisac.obj $(OD)\hweisac.cod: ..\i386\hweisac.c ..\i386\hwdetect.h
+$(OD)\hwmcac.obj $(OD)\hwmcac.cod: ..\i386\hwmcac.c ..\i386\hwdetect.h
+$(OD)\hwmcaa.obj $(OD)\hwmcaa.lst: ..\i386\hwmcaa.asm
+$(OD)\hwmacha.obj $(OD)\hwmacha.lst: ..\i386\hwmacha.asm
+$(OD)\hwpbiosc.obj $(OD)\hwpbiosc.cod: ..\i386\hwpbiosc.c ..\i386\hwdetect.h ..\i386\pnpbios.h
+$(OD)\hwvbiosc.obj $(OD)\hwvbiosc.cod: ..\i386\hwvbiosc.c ..\i386\hwdetect.h ..\i386\hwvbios.h
+
+$(OD)\ntdetect.com: $(OBJ) $(DOBJ) $(LIBS)
+ $(LINK) @<<
+ /tiny /nod /noi /map $(OD)\main $(OD)\hweisaa $(OD)\display +
+ $(OD)\hwheap $(OD)\hwdetect $(OD)\hwmisca $(OD)\videoa +
+ $(OD)\keybda $(OD)\keybdc $(OD)\comlptc $(OD)\mousea $(OD)\mousec +
+ $(OD)\diskc $(OD)\diska $(OD)\hweisac $(OD)\hwmcac $(OD)\hwmcaa +
+ $(OD)\hwmacha $(OD)\hwvbiosc $(OD)\backend $(OD)\hwpcia $(OD)\hwapm +
+ $(OD)\hwpbiosc
+ $(OD)\ntdetect.com,
+ $(OD)\ntdetect.map,
+ $(LIBS);
+<<
+ binplace $(OD)\ntdetect.com
diff --git a/private/ntos/boot/detect/fre/sources b/private/ntos/boot/detect/fre/sources
new file mode 100644
index 000000000..0b93f4ebf
--- /dev/null
+++ b/private/ntos/boot/detect/fre/sources
@@ -0,0 +1,67 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=detect
+
+TARGETNAME=ntdetect.com
+TARGETPATH=obj
+TARGETTYPE=UMAPPL_NOLIB
+
+INCLUDES=$(BASEDIR)\public\sdk\inc;..\..\..\inc
+
+SOURCES=
+
+i386_SOURCES=..\i386\backend.asm \
+ ..\i386\hweisaa.asm \
+ ..\i386\hweisac.c \
+ ..\i386\hwpcia.asm \
+ ..\i386\main.asm \
+ ..\i386\display.c \
+ ..\i386\diska.asm \
+ ..\i386\diskc.c \
+ ..\i386\hwheap.c \
+ ..\i386\hwdetect.c \
+ ..\i386\hwmisca.asm \
+ ..\i386\videoa.asm \
+ ..\i386\keybdc.c \
+ ..\i386\keybda.asm \
+ ..\i386\comlptc.c \
+ ..\i386\mousea.asm \
+ ..\i386\mousec.c \
+ ..\i386\hwmcac.c \
+ ..\i386\hwmcaa.asm \
+ ..\i386\hwmacha.asm \
+ ..\i386\hwpbiosc.c \
+ ..\i386\hwvbiosc.c
+
+!IF $(386)
+
+NTTARGETFILES=obj\i386\ntdetect.com
+
+!ENDIF
+
+
+
+
diff --git a/private/ntos/boot/detect/i386/backend.asm b/private/ntos/boot/detect/i386/backend.asm
new file mode 100644
index 000000000..ea1fa61b0
--- /dev/null
+++ b/private/ntos/boot/detect/i386/backend.asm
@@ -0,0 +1,28 @@
+;++
+;
+; Module Name:
+;
+; backend.asm
+;
+; Module Description:
+;
+; This module is needed only to get around a linker quirk we
+; run into because we're linking an app compiled as a "small"
+; model app as a "tiny" model app.
+;
+; BUGBUG
+; This is how we find the end of the com file and the beginning of the
+; OS loader coff header. This could probably be moved into the last file
+; on the link line. I will do that when time permits.
+;--
+
+
+.386p
+
+_DATA segment para use16 public 'DATA'
+
+public _BackEnd
+_BackEnd equ $
+
+_DATA ends
+ end
diff --git a/private/ntos/boot/detect/i386/bios.h b/private/ntos/boot/detect/i386/bios.h
new file mode 100644
index 000000000..2fa15138f
--- /dev/null
+++ b/private/ntos/boot/detect/i386/bios.h
@@ -0,0 +1,175 @@
+/***
+*bios.h - declarations for bios interface functions and supporting definitions
+*
+* Copyright (c) 1987-1990, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* This file declares the constants, structures, and functions
+* used for accessing and using various BIOS interfaces.
+*
+****/
+
+#ifndef _MT
+
+/* manifest constants for BIOS serial communications (RS-232) support */
+
+/* serial port services */
+
+#define _COM_INIT 0 /* init serial port */
+#define _COM_SEND 1 /* send character */
+#define _COM_RECEIVE 2 /* receive character */
+#define _COM_STATUS 3 /* get serial port status */
+
+/* serial port initializers. One and only one constant from each of the
+ * following four groups - character size, stop bit, parity, and baud rate -
+ * must be specified in the initialization byte.
+ */
+
+/* character size initializers */
+
+#define _COM_CHR7 2 /* 7 bits characters */
+#define _COM_CHR8 3 /* 8 bits characters */
+
+/* stop bit values - on or off */
+
+#define _COM_STOP1 0 /* 1 stop bit */
+#define _COM_STOP2 4 /* 2 stop bits */
+
+/* parity initializers */
+
+#define _COM_NOPARITY 0 /* no parity */
+#define _COM_ODDPARITY 8 /* odd parity */
+#define _COM_EVENPARITY 24 /* even parity */
+
+/* baud rate initializers */
+
+#define _COM_110 0 /* 110 baud */
+#define _COM_150 32 /* 150 baud */
+#define _COM_300 64 /* 300 baud */
+#define _COM_600 96 /* 600 baud */
+#define _COM_1200 128 /* 1200 baud */
+#define _COM_2400 160 /* 2400 baud */
+#define _COM_4800 192 /* 4800 baud */
+#define _COM_9600 224 /* 9600 baud */
+
+
+/* manifest constants for BIOS disk support */
+
+/* disk services */
+
+#define _DISK_RESET 0 /* reset disk controller */
+#define _DISK_STATUS 1 /* get disk status */
+#define _DISK_READ 2 /* read disk sectors */
+#define _DISK_WRITE 3 /* write disk sectors */
+#define _DISK_VERIFY 4 /* verify disk sectors */
+#define _DISK_FORMAT 5 /* format disk track */
+
+/* struct used to send/receive information to/from the BIOS disk services */
+
+#ifndef _DISKINFO_T_DEFINED
+
+struct diskinfo_t {
+ unsigned drive;
+ unsigned head;
+ unsigned track;
+ unsigned sector;
+ unsigned nsectors;
+ void _far *buffer;
+ };
+
+#define _DISKINFO_T_DEFINED
+
+#endif
+
+
+/* manifest constants for BIOS keyboard support */
+
+/* keyboard services */
+
+#define _KEYBRD_READ 0 /* read next character from keyboard */
+#define _KEYBRD_READY 1 /* check for keystroke */
+#define _KEYBRD_SHIFTSTATUS 2 /* get current shift key status */
+
+/* services for enhanced keyboards */
+
+#define _NKEYBRD_READ 0x10 /* read next character from keyboard */
+#define _NKEYBRD_READY 0x11 /* check for keystroke */
+#define _NKEYBRD_SHIFTSTATUS 0x12 /* get current shift key status */
+
+
+/* manifest constants for BIOS printer support */
+
+/* printer services */
+
+#define _PRINTER_WRITE 0 /* write character to printer */
+#define _PRINTER_INIT 1 /* intialize printer */
+#define _PRINTER_STATUS 2 /* get printer status */
+
+
+/* manifest constants for BIOS time of day support */
+
+/* time of day services */
+
+#define _TIME_GETCLOCK 0 /* get current clock count */
+#define _TIME_SETCLOCK 1 /* set current clock count */
+
+
+#ifndef _REGS_DEFINED
+
+/* word registers */
+
+struct WORDREGS {
+ unsigned int ax;
+ unsigned int bx;
+ unsigned int cx;
+ unsigned int dx;
+ unsigned int si;
+ unsigned int di;
+ unsigned int cflag;
+ };
+
+/* byte registers */
+
+struct BYTEREGS {
+ unsigned char al, ah;
+ unsigned char bl, bh;
+ unsigned char cl, ch;
+ unsigned char dl, dh;
+ };
+
+/* general purpose registers union -
+ * overlays the corresponding word and byte registers.
+ */
+
+union REGS {
+ struct WORDREGS x;
+ struct BYTEREGS h;
+ };
+
+/* segment registers */
+
+struct SREGS {
+ unsigned int es;
+ unsigned int cs;
+ unsigned int ss;
+ unsigned int ds;
+ };
+
+#define _REGS_DEFINED
+
+#endif /* _REGS_DEFINED */
+
+
+/* function prototypes */
+
+unsigned _bios_disk(unsigned, struct diskinfo_t *);
+unsigned _bios_equiplist(void);
+unsigned _bios_keybrd(unsigned);
+unsigned _bios_memsize(void);
+unsigned _bios_printer(unsigned, unsigned, unsigned);
+unsigned _bios_serialcom(unsigned, unsigned, unsigned);
+unsigned _bios_timeofday(unsigned, long *);
+int int86(int, union REGS *, union REGS *);
+int int86x(int, union REGS *, union REGS *, struct SREGS *);
+
+#endif /* _MT */
diff --git a/private/ntos/boot/detect/i386/comlpt.h b/private/ntos/boot/detect/i386/comlpt.h
new file mode 100644
index 000000000..dcd4aec2e
--- /dev/null
+++ b/private/ntos/boot/detect/i386/comlpt.h
@@ -0,0 +1,123 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ ixkdcom.h
+
+Abstract:
+
+ This module contains the header file for comport detection code.
+ The code is extracted from NT Hal for kernel debugger.
+
+Author:
+
+ Shie-Lin Tzong (shielint) Dec-23-1991.
+
+Revision History:
+
+--*/
+
+#define MAX_COM_PORTS 4 // Max. number of comports detectable
+#define MAX_LPT_PORTS 3 // Max. number of LPT ports detectable
+
+#define COM1_PORT 0x03f8
+#define COM2_PORT 0x02f8
+#define COM3_PORT
+#define COM4_PORT
+
+#define BAUD_RATE_9600_MSB 0x0
+#define BAUD_RATE_9600_LSB 0xC
+#define IER_TEST_VALUE 0xF
+
+//
+// Offsets from the base register address of the
+// various registers for the 8250 family of UARTS.
+//
+#define RECEIVE_BUFFER_REGISTER (0x00u)
+#define TRANSMIT_HOLDING_REGISTER (0x00u)
+#define INTERRUPT_ENABLE_REGISTER (0x01u)
+#define INTERRUPT_IDENT_REGISTER (0x02u)
+#define FIFO_CONTROL_REGISTER (0x02u)
+#define LINE_CONTROL_REGISTER (0x03u)
+#define MODEM_CONTROL_REGISTER (0x04u)
+#define LINE_STATUS_REGISTER (0x05u)
+#define MODEM_STATUS_REGISTER (0x06u)
+#define DIVISOR_LATCH_LSB (0x00u)
+#define DIVISOR_LATCH_MSB (0x01u)
+#define SERIAL_REGISTER_LENGTH (7)
+
+//
+// These masks define access to the line control register.
+//
+
+//
+// This defines the bit used to control the definition of the "first"
+// two registers for the 8250. These registers are the input/output
+// register and the interrupt enable register. When the DLAB bit is
+// enabled these registers become the least significant and most
+// significant bytes of the divisor value.
+//
+#define SERIAL_LCR_DLAB 0x80
+
+//
+// This defines the bit used to control whether the device is sending
+// a break. When this bit is set the device is sending a space (logic 0).
+//
+// Most protocols will assume that this is a hangup.
+//
+#define SERIAL_LCR_BREAK 0x40
+
+
+//
+// This macro writes to the modem control register
+//
+// Arguments:
+//
+// BaseAddress - A pointer to the address from which the hardware
+// device registers are located.
+//
+// ModemControl - The control bits to send to the modem control.
+//
+//
+
+#define WRITE_MODEM_CONTROL(BaseAddress,ModemControl) \
+do \
+{ \
+ WRITE_PORT_UCHAR( \
+ (BaseAddress)+MODEM_CONTROL_REGISTER, \
+ (ModemControl) \
+ ); \
+} while (0)
+
+//
+// This macro reads the modem control register
+//
+// Arguments:
+//
+// BaseAddress - A pointer to the address from which the hardware
+// device registers are located.
+//
+//
+#define READ_MODEM_CONTROL(BaseAddress) \
+ (READ_PORT_UCHAR((BaseAddress)+MODEM_CONTROL_REGISTER))
+
+//
+// This macro reads the interrupt identification register
+//
+// Arguments:
+//
+// BaseAddress - A pointer to the address from which the hardware
+// device registers are located.
+//
+// Note that this routine potententially quites a transmitter
+// empty interrupt. This is because one way that the transmitter
+// empty interrupt is cleared is to simply read the interrupt id
+// register.
+//
+//
+#define READ_INTERRUPT_ID_REG(BaseAddress) \
+ (READ_PORT_UCHAR((BaseAddress)+INTERRUPT_IDENT_REGISTER))
+
+
diff --git a/private/ntos/boot/detect/i386/comlptc.c b/private/ntos/boot/detect/i386/comlptc.c
new file mode 100644
index 000000000..20d8875fd
--- /dev/null
+++ b/private/ntos/boot/detect/i386/comlptc.c
@@ -0,0 +1,983 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ comport.c
+
+Abstract:
+
+ This module contains C code to determine comport and LPT configuration in
+ syste.
+
+Author:
+
+ Shie-Lin Tzong (shielint) Dec-23-1991
+
+Revision History:
+
+--*/
+
+#include "hwdetect.h"
+#include "comlpt.h"
+#include "bios.h"
+#include "string.h"
+
+#define LOWEST_IRQ 3
+#define MASTER_IRQ_MASK_BITS 0xf8
+#define SLAVE_IRQ_MASK_BITS 0xfe
+
+//
+// ComPortAddress[] is a global array to remember which comports have
+// been detected and their I/O port addresses.
+//
+
+USHORT ComPortAddress[MAX_COM_PORTS] = {0, 0, 0, 0};
+
+VOID
+SerialInterruptRequest (
+ PUCHAR PortAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine generates an interrupt on the interrupt line for
+ com port.
+
+Arguments:
+
+ PortAddress - the port address of the desired com port.
+
+Return Value:
+
+ None.
+--*/
+
+{
+
+ USHORT i;
+ UCHAR Temp;
+
+ WRITE_PORT_UCHAR(
+ PortAddress + MODEM_CONTROL_REGISTER,
+ 8
+ );
+
+ WRITE_PORT_UCHAR(
+ PortAddress + INTERRUPT_ENABLE_REGISTER,
+ 0
+ );
+
+ WRITE_PORT_UCHAR(
+ PortAddress + INTERRUPT_ENABLE_REGISTER,
+ 0xf
+ );
+
+ //
+ // Add some delay
+ //
+
+ for (i = 0; i < 5 ; i++ ) {
+ Temp = READ_PORT_UCHAR((PUCHAR) PIC1_PORT1);
+ Temp = READ_PORT_UCHAR((PUCHAR) PIC2_PORT1);
+ }
+}
+VOID
+SerialInterruptDismiss (
+ PUCHAR PortAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dismisses an interrupt on the interrupt line for
+ com port.
+
+Arguments:
+
+ PortAddress - the port address of the desired com port.
+
+Return Value:
+
+ None.
+--*/
+
+{
+ USHORT i;
+ UCHAR Temp;
+
+ Temp = READ_PORT_UCHAR(
+ PortAddress + INTERRUPT_IDENT_REGISTER
+ );
+
+ WRITE_PORT_UCHAR(
+ PortAddress + INTERRUPT_ENABLE_REGISTER,
+ 0
+ );
+
+ //
+ // Add some delay
+ //
+
+ for (i = 0; i < 5 ; i++ ) {
+ Temp = READ_PORT_UCHAR((PUCHAR) PIC1_PORT1);
+ Temp = READ_PORT_UCHAR((PUCHAR) PIC2_PORT1);
+ }
+}
+
+BOOLEAN
+DoesPortExist(
+ IN PUCHAR Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine examines several of what might be the serial device
+ registers. It ensures that the bits that should be zero are zero.
+ It will then attempt to set the device to 19200 baud. If the
+ will then attempt to read that baud. If it is still 19200 then
+ we can feel pretty safe that this is a serial device.
+
+ NOTE: If there is indeed a serial port at the address specified
+ it will absolutely have interrupts inhibited upon return
+ from this routine.
+
+Arguments:
+
+ Address - address of hw port.
+
+Return Value:
+
+ TRUE - Port exists. Party on.
+
+ FALSE - Port doesn't exist. Don't use it.
+
+--*/
+
+{
+
+ UCHAR IerContents;
+ UCHAR BaudRateMsb, BaudRateLsb;
+ BOOLEAN ReturnValue = FALSE;
+ UCHAR LineControl, Temp;
+
+
+ LineControl = READ_PORT_UCHAR(Address+LINE_CONTROL_REGISTER);
+
+ //
+ // Read original baud rate divisor and save it.
+ //
+
+ WRITE_PORT_UCHAR(
+ Address+LINE_CONTROL_REGISTER,
+ (UCHAR)(LineControl | SERIAL_LCR_DLAB)
+ );
+ BaudRateMsb = READ_PORT_UCHAR(Address+DIVISOR_LATCH_MSB);
+ BaudRateLsb = READ_PORT_UCHAR(Address+DIVISOR_LATCH_LSB);
+
+ //
+ // Change baud rate to 9600.
+ //
+
+ WRITE_PORT_UCHAR(Address+DIVISOR_LATCH_MSB, BAUD_RATE_9600_MSB);
+ WRITE_PORT_UCHAR(Address+DIVISOR_LATCH_LSB, BAUD_RATE_9600_LSB);
+
+ //
+ // Read IER and save it away.
+ //
+
+ WRITE_PORT_UCHAR(
+ Address+LINE_CONTROL_REGISTER,
+ (UCHAR)(LineControl & ~SERIAL_LCR_DLAB)
+ );
+ IerContents = READ_PORT_UCHAR(
+ Address + INTERRUPT_ENABLE_REGISTER
+ );
+
+ WRITE_PORT_UCHAR(
+ Address + INTERRUPT_ENABLE_REGISTER,
+ IER_TEST_VALUE
+ );
+
+ //
+ // Read baud rate divisor. The values we read should be equal to the
+ // values we set earlier.
+ //
+
+ WRITE_PORT_UCHAR(
+ Address+LINE_CONTROL_REGISTER,
+ (UCHAR)(LineControl | SERIAL_LCR_DLAB)
+ );
+ Temp = READ_PORT_UCHAR(Address+DIVISOR_LATCH_MSB);
+ if (Temp != BAUD_RATE_9600_MSB) {
+ goto AllDone;
+ }
+ Temp = READ_PORT_UCHAR(Address+DIVISOR_LATCH_LSB);
+ if (Temp != BAUD_RATE_9600_LSB) {
+ goto AllDone;
+ }
+
+ //
+ // Read IER and it should be equal to the value we set earlier.
+ //
+
+ WRITE_PORT_UCHAR(
+ Address+LINE_CONTROL_REGISTER,
+ (UCHAR)(LineControl & ~SERIAL_LCR_DLAB)
+ );
+ Temp = READ_PORT_UCHAR(
+ Address + INTERRUPT_ENABLE_REGISTER
+ );
+ if (Temp != IER_TEST_VALUE) {
+ goto AllDone;
+ }
+ ReturnValue = TRUE;
+
+AllDone:
+
+ //
+ // Restore registers which we destroyed .
+ //
+
+ WRITE_PORT_UCHAR(
+ Address+LINE_CONTROL_REGISTER,
+ (UCHAR)(LineControl & ~SERIAL_LCR_DLAB)
+ );
+
+ WRITE_PORT_UCHAR(
+ Address + INTERRUPT_ENABLE_REGISTER,
+ IerContents
+ );
+
+ WRITE_PORT_UCHAR(
+ Address+LINE_CONTROL_REGISTER,
+ (UCHAR)(LineControl | SERIAL_LCR_DLAB)
+ );
+
+ WRITE_PORT_UCHAR(Address+DIVISOR_LATCH_MSB, BaudRateMsb);
+ WRITE_PORT_UCHAR(Address+DIVISOR_LATCH_LSB, BaudRateLsb);
+
+ WRITE_PORT_UCHAR(
+ Address+LINE_CONTROL_REGISTER,
+ LineControl
+ );
+
+ return ReturnValue;
+}
+
+BOOLEAN
+HwInterruptDetection(
+ IN PUCHAR BasePort,
+ IN VOID (*InterruptRequestRoutine)(),
+ IN VOID (*InterruptDismissRoutine)(),
+ OUT PUSHORT Vector
+ )
+
+/*++
+
+Routine Description:
+
+ This routine attempts to locate the interrupt vector for which
+ the device is configured. The allowable vectors are
+ 3 - 7, and 9 - 15. If no interrupt vector is found, or more than
+ one is found, the routine returns FALSE. Otherwise, TRUE is returned.
+
+ Note that we diddle the i8259 interrupt controllers here.
+
+Arguments:
+
+ BasePort - the I/O port base for the device.
+
+ InterruptRequestRoutine - A pointer to a routine to generate
+ desired interrupt.
+
+ InterruptDismissRoutine - A pointer to a routine to dismiss the interrupt
+ generated by InterruptRequestRoutine.
+
+ Vector - Pointer to the location to store the mouse interrupt vector.
+
+Return Value:
+
+ Returns TRUE if the Inport interrupt vector was located; otherwise,
+ FALSE is returned.
+
+--*/
+
+{
+ UCHAR OldMasterMask, OldSlaveMask;
+ UCHAR MasterMask, SlaveMask;
+ UCHAR InterruptBits;
+ UCHAR PossibleInterruptBits;
+ int i;
+ int NumberOfIRQs;
+ BOOLEAN VectorFound = FALSE;
+
+ //
+ // Get the i8259 interrupt masks.
+ //
+
+ OldMasterMask = READ_PORT_UCHAR((PUCHAR) PIC1_PORT1);
+ OldSlaveMask = READ_PORT_UCHAR((PUCHAR) PIC2_PORT1);
+
+ //
+ // Raise IRQL to the highest priority IRQL the inport would use.
+ //
+
+ WRITE_PORT_UCHAR(
+ (PUCHAR) PIC1_PORT1,
+ (UCHAR) 0xff ^ ((UCHAR)(1 << LOWEST_IRQ) - 1)
+ );
+
+ WRITE_PORT_UCHAR(
+ (PUCHAR) PIC2_PORT1,
+ (UCHAR) 0xfe
+ );
+
+ //
+ // Get the master i8259 interrupt mask.
+ //
+
+ MasterMask = READ_PORT_UCHAR((PUCHAR) PIC1_PORT1);
+
+ //
+ // Disable potential device interrupts.
+ //
+
+ WRITE_PORT_UCHAR(
+ (PUCHAR) PIC1_PORT1,
+ (UCHAR) (MasterMask | MASTER_IRQ_MASK_BITS)
+ );
+
+ //
+ // Attempt to locate the interrupt line on the master i8259.
+ // Why try this 10 times? It's magic...
+ //
+
+ PossibleInterruptBits = MASTER_IRQ_MASK_BITS;
+ for (i = 0; i < 10; i++) {
+
+
+ //
+ // Generate a 0 on the master 8259 interrupt line
+ //
+
+ (*InterruptDismissRoutine)(BasePort);
+
+ //
+ // Read the interrupt bits off the master i8259. Only bits
+ // 3 - 7 are of interest. Eliminate non-functional
+ // IRQs. Only continue looking at the master i8259 if there
+ // is at least one functional IRQ.
+ //
+
+ _asm {cli}
+ WRITE_PORT_UCHAR((PUCHAR) PIC1_PORT0, OCW3_READ_IRR);
+ InterruptBits = READ_PORT_UCHAR((PUCHAR) PIC1_PORT0);
+ _asm {sti}
+ InterruptBits &= MASTER_IRQ_MASK_BITS;
+ InterruptBits ^= MASTER_IRQ_MASK_BITS;
+ PossibleInterruptBits &= InterruptBits;
+ if (!PossibleInterruptBits) {
+ break;
+ }
+
+ //
+ // Generate an interrupt from the desired device.
+ //
+
+ (*InterruptRequestRoutine)(BasePort);
+
+ //
+ // Read the interrupt bits off the master i8259. Only bits
+ // 3 - 7 are of interest. Eliminate non-functional
+ // IRQs. Only continue looking at the master i8259 if there
+ // is at least one functional IRQ.
+ //
+
+ _asm {cli}
+ WRITE_PORT_UCHAR((PUCHAR) PIC1_PORT0, OCW3_READ_IRR);
+ InterruptBits = READ_PORT_UCHAR((PUCHAR) PIC1_PORT0);
+ _asm {sti}
+ InterruptBits &= MASTER_IRQ_MASK_BITS;
+ PossibleInterruptBits &= InterruptBits;
+
+ if (!PossibleInterruptBits) {
+ break;
+ }
+ }
+
+ if (PossibleInterruptBits) {
+
+ //
+ // We found at least one IRQ on the master i8259 that could belong
+ // to the Inport mouse. Count how many we found. If there is
+ // more than one, we haven't found the vector. Otherwise, we've
+ // successfully located the Inport interrupt vector on the master
+ // i8259 (provided the interrupt vector is 3, 4, 5, or 7).
+ //
+
+ PossibleInterruptBits >>= 3;
+ NumberOfIRQs = 0;
+ for (i = 3; i <= 7; i++) {
+ if (PossibleInterruptBits & 1) {
+ NumberOfIRQs += 1;
+ *Vector = (CCHAR) i;
+ }
+ PossibleInterruptBits >>= 1;
+ }
+ if (NumberOfIRQs == 1) {
+ VectorFound = TRUE;
+ }
+ }
+
+ //
+ // If we didn't locate the interrupt vector on the master i8259, attempt
+ // to locate it on the slave i8259.
+ //
+
+ if (!VectorFound) {
+
+ //
+ // Get the slave i8259 interrupt mask.
+ //
+
+ SlaveMask = READ_PORT_UCHAR((PUCHAR) PIC2_PORT1);
+
+ //
+ // Attempt to locate the interupt line on the slave i8259.
+ // Why try this 20 times? It's magic...
+ //
+
+ PossibleInterruptBits = SLAVE_IRQ_MASK_BITS;
+ for (i = 0; i < 20; i++) {
+
+ //
+ // Generate a 0 on the Inport IRQ on the slave i8259.
+ //
+
+ (*InterruptDismissRoutine)(BasePort);
+
+ //
+ // Read the interrupt bits off the slave i8259.
+ // Eliminate non-functional IRQs. Only continue
+ // looking at the slave i8259 if there is at least one
+ // functional IRQ.
+ //
+
+ _asm {cli}
+ WRITE_PORT_UCHAR((PUCHAR) PIC2_PORT0, OCW3_READ_IRR);
+ InterruptBits = READ_PORT_UCHAR((PUCHAR) PIC2_PORT0);
+ _asm {sti}
+ InterruptBits &= SLAVE_IRQ_MASK_BITS;
+ InterruptBits ^= SLAVE_IRQ_MASK_BITS;
+ PossibleInterruptBits &= InterruptBits;
+ if (!PossibleInterruptBits) {
+ break;
+ }
+
+ //
+ // Generate a 1 on the Inport IRQ on the slave i8259.
+ //
+
+ (*InterruptRequestRoutine)(BasePort);
+
+ //
+ // Read the interrupt bits off the slave i8259.
+ // Eliminate non-functional IRQs. Only continue
+ // looking at the slave i8259 if there is at least one
+ // functional IRQ.
+ //
+
+ _asm {cli}
+ WRITE_PORT_UCHAR((PUCHAR) PIC2_PORT0, OCW3_READ_IRR);
+ InterruptBits = READ_PORT_UCHAR((PUCHAR) PIC2_PORT0);
+ _asm {sti}
+ InterruptBits &= SLAVE_IRQ_MASK_BITS;
+ PossibleInterruptBits &= InterruptBits;
+
+ if (!PossibleInterruptBits) {
+ break;
+ }
+
+ }
+
+ if (PossibleInterruptBits) {
+
+ //
+ // We found at least one IRQ on the slave i8259 that could belong
+ // to the device. Count how many we found. If there is
+ // more than one, we haven't found the vector. Otherwise, we've
+ // successfully located the device interrupt vector on the slave
+ // i8259.
+ //
+
+ PossibleInterruptBits >>= 1;
+ NumberOfIRQs = 0;
+ for (i = 9; i <= 15; i++) {
+ if (PossibleInterruptBits & 1) {
+ NumberOfIRQs += 1;
+ *Vector = (CCHAR) i;
+ }
+ PossibleInterruptBits >>= 1;
+ }
+ if (NumberOfIRQs == 1) {
+ VectorFound = TRUE;
+ }
+ }
+
+ //
+ // Restore the i8259 slave.
+ //
+
+ WRITE_PORT_UCHAR((PUCHAR) PIC2_PORT0, OCW3_READ_ISR);
+
+ //
+ // Restore the i8259 slave interrupt mask.
+ //
+
+ WRITE_PORT_UCHAR((PUCHAR) PIC2_PORT1, SlaveMask);
+ }
+
+ //
+ // Dismiss interrupt on the device
+ //
+
+ (*InterruptDismissRoutine)(BasePort);
+
+ //
+ // Restore the i8259 master.
+ //
+
+ WRITE_PORT_UCHAR((PUCHAR) PIC1_PORT0, OCW3_READ_ISR);
+
+ //
+ // Restore the i8259 master interrupt mask.
+ //
+
+ WRITE_PORT_UCHAR((PUCHAR) PIC1_PORT1, MasterMask);
+
+ //
+ // Restore the previous IRQL.
+ //
+
+ WRITE_PORT_UCHAR(
+ (PUCHAR) PIC1_PORT1,
+ OldMasterMask
+ );
+
+ WRITE_PORT_UCHAR(
+ (PUCHAR) PIC2_PORT1,
+ OldSlaveMask
+ );
+
+ return(VectorFound);
+}
+
+FPFWCONFIGURATION_COMPONENT_DATA
+GetComportInformation (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine will attempt to detect the comports information
+ for the system. The information includes port address, irq
+ level.
+
+ Note that this routine can only detect up to 4 comports and
+ it assumes that if MCA, COM3 and COM4 use irq 4. Otherwise,
+ COM3 uses irq 4 and COM4 uses irq 3. Also, the number of ports
+ for COMPORT is set to 8 (for example, COM2 uses ports 2F8 - 2FF)
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A pointer to a stucture of type FWCONFIGURATION_COMPONENT_DATA
+ which is the root of comport component list.
+ If no comport exists, a value of NULL is returned.
+
+--*/
+
+{
+
+ FPFWCONFIGURATION_COMPONENT_DATA CurrentEntry, PreviousEntry = NULL;
+ FPFWCONFIGURATION_COMPONENT_DATA FirstComport = NULL;
+ FPFWCONFIGURATION_COMPONENT Component;
+ HWCONTROLLER_DATA ControlData;
+ UCHAR i, j, z;
+ SHORT Port;
+ UCHAR ComportName[] = "COM?";
+ CM_SERIAL_DEVICE_DATA SerialData;
+ ULONG BaudClock = 1843200;
+ USHORT Vector;
+ BOOLEAN PortExist;
+ USHORT IoPorts[MAX_COM_PORTS] = {0x3f8, 0x2f8, 0x3e8, 0x2e8};
+
+
+ //
+ // BIOS DATA area 40:0 is the port address of the first valid COM port
+ //
+
+ USHORT far *pPortAddress = (USHORT far *)0x00400000;
+
+ //
+ // Initialize serial device specific data
+ //
+
+ SerialData.Version = 0;
+ SerialData.Revision = 0;
+ SerialData.BaudClock = 1843200;
+
+ //
+ // Initialize default COM port address.
+ // Some BIOS puts incorrect comport address to the 40:0 area.
+ // To cope with this problem, we test the port address supplied
+ // by BIOS first. If it fail, we try our default port.
+ //
+
+ for (i = 0; i < MAX_COM_PORTS; i++) {
+ for (j = 0; j < MAX_COM_PORTS; j++) {
+ if (IoPorts[i] == *(pPortAddress + j)) {
+ IoPorts[i] = 0;
+ break;
+ }
+ }
+ }
+
+ for (i = 0; i < MAX_COM_PORTS; i++) {
+
+ PortExist = FALSE;
+
+ //
+ // Initialize Controller data
+ //
+
+ ControlData.NumberPortEntries = 0;
+ ControlData.NumberIrqEntries = 0;
+ ControlData.NumberMemoryEntries = 0;
+ ControlData.NumberDmaEntries = 0;
+ z = 0;
+
+ //
+ // Load the port address from the BIOS data area, if it exists
+ //
+
+ Port = *(pPortAddress + i);
+
+ //
+ // Determine if the port exists
+ //
+
+ if (Port != 0) {
+ if (DoesPortExist((PUCHAR)Port)) {
+ PortExist = TRUE;
+ }
+ }
+ if (!PortExist && (Port = IoPorts[i])) {
+ if (PortExist = DoesPortExist((PUCHAR)Port)) {
+ IoPorts[i] = 0;
+ *(pPortAddress+i) = (USHORT)Port;
+ }
+ }
+ if (PortExist) {
+
+ //
+ // Remember the port address in our global variable
+ // such that other detection code (e.g. Serial Mouse) can
+ // get the information.
+ //
+
+ ComPortAddress[i] = Port;
+
+ CurrentEntry = (FPFWCONFIGURATION_COMPONENT_DATA)HwAllocateHeap (
+ sizeof(FWCONFIGURATION_COMPONENT_DATA), TRUE);
+ if (!FirstComport) {
+ FirstComport = CurrentEntry;
+ }
+ Component = &CurrentEntry->ComponentEntry;
+
+ Component->Class = ControllerClass;
+ Component->Type = SerialController;
+ Component->Flags.ConsoleOut = 1;
+ Component->Flags.ConsoleIn = 1;
+ Component->Flags.Output = 1;
+ Component->Flags.Input = 1;
+ Component->Version = 0;
+ Component->Key = i;
+ Component->AffinityMask = 0xffffffff;
+
+ //
+ // Set up type string.
+ //
+
+ ComportName[3] = i + (UCHAR)'1';
+
+ //
+ // Set up Port information
+ //
+
+ ControlData.NumberPortEntries = 1;
+ ControlData.DescriptorList[z].Type = RESOURCE_PORT;
+ ControlData.DescriptorList[z].ShareDisposition =
+ CmResourceShareDeviceExclusive;
+ ControlData.DescriptorList[z].Flags = CM_RESOURCE_PORT_IO;
+ ControlData.DescriptorList[z].u.Port.Start.LowPart = (ULONG)Port;
+ ControlData.DescriptorList[z].u.Port.Start.HighPart = 0;
+ ControlData.DescriptorList[z].u.Port.Length = 7;
+ z++;
+
+ //
+ // Set up Irq information
+ //
+
+ ControlData.NumberIrqEntries = 1;
+ ControlData.DescriptorList[z].Type = RESOURCE_INTERRUPT;
+ ControlData.DescriptorList[z].ShareDisposition =
+ CmResourceShareUndetermined;
+ if (HwBusType == MACHINE_TYPE_MCA) {
+ ControlData.DescriptorList[z].Flags = LEVEL_SENSITIVE;
+ if (i == 0) { // COM1 - irql4; COM2 - COM3 - irq3
+ ControlData.DescriptorList[z].u.Interrupt.Level = 4;
+ ControlData.DescriptorList[z].u.Interrupt.Vector = 4;
+ } else {
+ ControlData.DescriptorList[z].u.Interrupt.Level = 3;
+ ControlData.DescriptorList[z].u.Interrupt.Vector = 3;
+ }
+ } else {
+
+ //
+ // For EISA the LevelTriggered is temporarily set to FALSE.
+ // COM1 and COM3 use irq 4; COM2 and COM4 use irq3
+ //
+
+ ControlData.DescriptorList[z].Flags = EDGE_TRIGGERED;
+ if (Port == 0x3f8 || Port == 0x3e8) {
+ ControlData.DescriptorList[z].u.Interrupt.Level = 4;
+ ControlData.DescriptorList[z].u.Interrupt.Vector = 4;
+ } else if (Port == 0x2f8 || Port == 0x2e8) {
+ ControlData.DescriptorList[z].u.Interrupt.Level = 3;
+ ControlData.DescriptorList[z].u.Interrupt.Vector = 3;
+ } else if (i == 0 || i == 2) {
+ ControlData.DescriptorList[z].u.Interrupt.Level = 4;
+ ControlData.DescriptorList[z].u.Interrupt.Vector = 4;
+ } else {
+ ControlData.DescriptorList[z].u.Interrupt.Level = 3;
+ ControlData.DescriptorList[z].u.Interrupt.Vector = 3;
+ }
+ }
+
+ ControlData.DescriptorList[z].u.Interrupt.Affinity = ALL_PROCESSORS;
+
+ //
+ // Try to determine the interrupt vector. If we success, the
+ // new vector will be used to replace the default value.
+ //
+
+ if (HwInterruptDetection((PUCHAR)Port,
+ SerialInterruptRequest,
+ SerialInterruptDismiss,
+ &Vector)) {
+
+ ControlData.DescriptorList[z].u.Interrupt.Level =
+ (ULONG)Vector;
+ ControlData.DescriptorList[z].u.Interrupt.Vector =
+ (ULONG)Vector;
+ }
+
+ //
+ // Since the com port interrupt detection destryed some
+ // of the com port registers, here we do the clean up.
+ //
+
+ WRITE_PORT_UCHAR ((PUCHAR)(Port + INTERRUPT_ENABLE_REGISTER), 0);
+ WRITE_PORT_UCHAR ((PUCHAR)(Port + MODEM_CONTROL_REGISTER), 0);
+
+ CurrentEntry->ConfigurationData =
+ HwSetUpResourceDescriptor(Component,
+ ComportName,
+ &ControlData,
+ sizeof(SerialData),
+ (PUCHAR)&SerialData
+ );
+ if (PreviousEntry) {
+ PreviousEntry->Sibling = CurrentEntry;
+ }
+ PreviousEntry = CurrentEntry;
+ }
+ }
+ return(FirstComport);
+}
+
+FPFWCONFIGURATION_COMPONENT_DATA
+GetLptInformation (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine will attempt to detect the parallel printer port
+ information for the system. The information includes port address,
+ irq level.
+
+ Note if this code is run after user established NETWORK LPT
+ connection. The Network LPT will be counted as regular parallel
+ port.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A pointer to a stucture of type PONENT_DATA
+ which is the root of Parallel component list.
+ If no comport exists, a value of NULL is returned.
+
+--*/
+
+{
+
+ FPFWCONFIGURATION_COMPONENT_DATA CurrentEntry, PreviousEntry = NULL;
+ FPFWCONFIGURATION_COMPONENT_DATA FirstLptPort = NULL;
+ FPFWCONFIGURATION_COMPONENT Component;
+ HWCONTROLLER_DATA ControlData;
+ UCHAR LptPortName[] = "PARALLEL?";
+ USHORT i, z;
+ USHORT LptStatus;
+ ULONG Port;
+
+ //
+ // BIOS DATA area 40:8 is the port address of the first valid COM port
+ //
+
+ USHORT far *pPortAddress = (USHORT far *)0x00400008;
+
+ for (i = 0; i < MAX_LPT_PORTS; i++) {
+
+ Port = (ULONG)*(pPortAddress + i);
+ if (Port == 0) {
+ continue;
+ } else {
+
+ //
+ // If we think we have a lpt, we will initialize it to
+ // a known state. In order to make printing work under
+ // nt, the arbitration level must be disabled. The BIOS
+ // init function seems to do the trick.
+ //
+
+ _asm {
+ mov ah, 1
+ mov dx, i
+ int 17h
+ }
+ }
+
+ //
+ // Initialize Controller data
+ //
+
+ ControlData.NumberPortEntries = 0;
+ ControlData.NumberIrqEntries = 0;
+ ControlData.NumberMemoryEntries = 0;
+ ControlData.NumberDmaEntries = 0;
+ z = 0;
+
+ //
+ // Determine if the port exists
+ //
+
+ LptStatus = _bios_printer(_PRINTER_STATUS, i , 0);
+ if (!(LptStatus & 6)){
+ CurrentEntry = (FPFWCONFIGURATION_COMPONENT_DATA)HwAllocateHeap (
+ sizeof(FWCONFIGURATION_COMPONENT_DATA), TRUE);
+ if (!FirstLptPort) {
+ FirstLptPort = CurrentEntry;
+ }
+ Component = &CurrentEntry->ComponentEntry;
+
+ Component->Class = ControllerClass;
+ Component->Type = ParallelController;
+ Component->Flags.Output = 1;
+ Component->Version = 0;
+ Component->Key = i;
+ Component->AffinityMask = 0xffffffff;
+
+ //
+ // Set up type string.
+ //
+
+ LptPortName[8] = (UCHAR)i + (UCHAR)'1';
+
+ //
+ // Set up Port information
+ //
+
+ Port = (ULONG)*(pPortAddress + i);
+ ControlData.NumberPortEntries = 1;
+ ControlData.DescriptorList[z].Type = RESOURCE_PORT;
+ ControlData.DescriptorList[z].ShareDisposition =
+ CmResourceShareDeviceExclusive;
+ ControlData.DescriptorList[z].Flags = CM_RESOURCE_PORT_IO;
+ ControlData.DescriptorList[z].u.Port.Start.LowPart = Port;
+ ControlData.DescriptorList[z].u.Port.Start.HighPart = 0;
+ ControlData.DescriptorList[z].u.Port.Length = 3;
+ z++;
+
+ //
+ // Set up Irq information
+ //
+
+ ControlData.NumberIrqEntries = 1;
+ ControlData.DescriptorList[z].Type = RESOURCE_INTERRUPT;
+ ControlData.DescriptorList[z].ShareDisposition =
+ CmResourceShareUndetermined;
+ ControlData.DescriptorList[z].u.Interrupt.Affinity = ALL_PROCESSORS;
+ if (i ==0) {
+ ControlData.DescriptorList[z].u.Interrupt.Level = 7;
+ ControlData.DescriptorList[z].u.Interrupt.Vector = 7;
+ } else {
+ ControlData.DescriptorList[z].u.Interrupt.Level = 5;
+ ControlData.DescriptorList[z].u.Interrupt.Vector = 5;
+ }
+
+ if (HwBusType == MACHINE_TYPE_MCA) {
+ ControlData.DescriptorList[z].Flags = LEVEL_SENSITIVE;
+ } else {
+
+ //
+ // For EISA the LevelTriggered is temporarily set to FALSE.
+ //
+
+ ControlData.DescriptorList[z].Flags = EDGE_TRIGGERED;
+ }
+
+ CurrentEntry->ConfigurationData =
+ HwSetUpResourceDescriptor(Component,
+ LptPortName,
+ &ControlData,
+ 0,
+ NULL
+ );
+
+ if (PreviousEntry) {
+ PreviousEntry->Sibling = CurrentEntry;
+ }
+ PreviousEntry = CurrentEntry;
+ }
+ }
+ return(FirstLptPort);
+}
diff --git a/private/ntos/boot/detect/i386/cpu.asm b/private/ntos/boot/detect/i386/cpu.asm
new file mode 100644
index 000000000..acca632cd
--- /dev/null
+++ b/private/ntos/boot/detect/i386/cpu.asm
@@ -0,0 +1,902 @@
+ title "Processor type and stepping detection"
+;++
+;
+; Copyright (c) 1989 Microsoft Corporation
+;
+; Module Name:
+;
+; cpu.asm
+;
+; Abstract:
+;
+; This module implements the assembley code necessary to determine
+; cpu type and stepping information.
+;
+; Author:
+;
+; Shie-Lin Tzong (shielint) 28-Oct-1991.
+; Some of the code is extracted from Cruiser (mainly,
+; the code to determine 386 stepping.)
+;
+; Environment:
+;
+; 80x86 Real Mode.
+;
+; Revision History:
+;
+;
+;--
+
+ .xlist
+include cpu.inc
+ .list
+
+;
+; constant for i386 32-bit multiplication test
+;
+
+MULTIPLIER equ 00000081h
+MULTIPLICAND equ 0417a000h
+RESULT_HIGH equ 00000002h
+RESULT_LOW equ 0fe7a000h
+
+;
+; Constants for Floating Point test
+;
+
+REALLONG_LOW equ 00000000
+REALLONG_HIGH equ 3FE00000h
+PSEUDO_DENORMAL_LOW equ 00000000h
+PSEUDO_DENORMAL_MID equ 80000000h
+PSEUDO_DENORMAL_HIGH equ 0000h
+
+.386p
+
+_TEXT SEGMENT PARA USE16 PUBLIC 'CODE'
+ ASSUME CS: _TEXT, DS:NOTHING, SS:NOTHING
+
+
+;++
+;
+; USHORT
+; HwGetProcessorType (
+; VOID
+; )
+;
+; Routine Description:
+;
+; This function determines type of processor (80486, 80386, 80286,
+; and even 8086/8088). it relies on Intel-approved code that takes
+; advantage of the documented behavior of the high nibble of the flag
+; word in the REAL MODE of the various processors.
+;
+; For completeness, the code also checks for 8088/8086. But, it won't
+; work.
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; (ax) = x86h or 0 if unrecongnized processor.
+;
+;--
+
+.8086
+
+ public _HwGetProcessorType
+_HwGetProcessorType proc near
+
+ pushf ; save entry flags
+
+;
+; The MSB (bit 15) is always a one on the 8086 and 8088 and a zero on
+; the 286, 386 and 486.
+;
+
+ pushf
+ pop ax
+ and ax, NOT 08000h ; clear bit 15 of flags
+ push ax
+ popf ; try to put that in the flags
+ pushf
+ pop ax ; look at what really went into flags
+
+ test ax,08000h ; Was high bit set ?
+ jnz short x_86 ; if nz, still set, goto x_86
+
+;
+; Bit 14 (NT flag) and bits 13/12 (IOPL bit field) are always zero on
+; the 286, but can be set on the 386 and 486.
+;
+
+ or ax,07000h ; Try to set the NT/IOPL bits
+ push ax
+ popf ; Put in to the flags
+ sti ; (for VDMM/IOPL0)
+ pushf
+ pop ax ; look at actual flags
+ test ax,07000h ; Any high bits set ?
+ jz short x_286 ; if z, no, goto x_286
+
+.386p
+
+;
+; The Alignment Check bit in flag can be set on 486 and is always zero
+; on 386.
+;
+
+ mov eax,cr0 ; test for 486 processor
+ push eax ; save CR0 value
+ and eax,not CR0_AM ; disable alignment check
+ mov cr0,eax
+ db ADDRESS_OVERRIDE
+ pushfd ; save original EFLAGS
+ db ADDRESS_OVERRIDE
+ pushfd ; try to set alignment check
+ or dword ptr [esp],EFLAGS_AC ; bit in EFLAGS
+ db ADDRESS_OVERRIDE
+ popfd
+ db ADDRESS_OVERRIDE
+ pushfd ; copy new flags into ECX
+ pop ecx ; [ecx] = new flags word
+ db ADDRESS_OVERRIDE
+ popfd ; restore original EFLAGS
+ pop eax ; restore original CR0 value
+ mov cr0,eax
+ and ecx, EFLAGS_AC ; did AC bit get set?
+ jz short x_386 ; if z, no, goto x_386
+
+ mov eax, 4h ; if nz, we have a 486 processor
+
+.286p
+
+ jmp short hpt99
+
+x_286:
+ mov ax, 2h ; Return 286 processor type.
+ jmp short hpt99
+
+x_86:
+ mov ax, 0h ; Return 86h for 8088/8086 CPU type.
+ jmp short hpt99
+
+x_386:
+ mov ax, 3h ; Return 386 processor type.
+hpt99:
+ popf ; restore flags
+ ret
+
+_HwGetProcessorType endp
+
+.386p
+
+;++
+;
+; USHORT
+; HwGetCpuStepping (
+; UHSORT CpuType
+; )
+;
+; Routine Description:
+;
+; This function determines cpu stepping for the specified CPU type.
+;
+; Currently, this routine only determine stepping for 386 and 486.
+;
+; Arguments:
+;
+; CpuType - The Cpu type which its stepping information will be returned.
+; The input value MUST be either 386 or 486.
+;
+; Return Value:
+;
+; [ax] - Cpu stepping. For example, [ax] = D0h for D0 stepping.
+;
+;--
+
+HgcsCpuType equ [esp + 2]
+
+ public _HwGetCpuStepping
+_HwGetCpuStepping proc
+
+ mov ax, HgcsCpuType ; [ax] = CpuType
+ cmp ax, 3h ; Is cpu = 386?
+ jz short Hgcs00 ; if z, yes, go Hgcs00
+
+ call Get486Stepping ; else, check for 486 stepping
+ jmp short Hgcs90 ; [ax] = Stepping information
+
+Hgcs00:
+ call Get386Stepping ; [ax] = Stepping information
+
+Hgcs90:
+ ret
+
+_HwGetCpuStepping endp
+
+;++
+;
+; USHORT
+; Get386Stepping (
+; VOID
+; )
+;
+; Routine Description:
+;
+; This function determines cpu stepping for i386 CPU stepping.
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; [ax] - Cpu stepping. For example, [ax] = D0h for D0 stepping.
+; [ax] = 0 means bad CPU and stepping is not important.
+;
+;--
+
+ public Get386Stepping
+Get386Stepping proc
+
+ call MultiplyTest ; Perform mutiplication test
+ jnc short G3s00 ; if nc, muttest is ok
+ mov ax, 0
+ ret
+G3s00:
+ call Check386B0 ; Check for B0 stepping
+ jnc short G3s05 ; if nc, it's B1/later
+ mov ax, 0B0h ; It is B0/earlier stepping
+ ret
+
+G3s05:
+ call Check386D1 ; Check for D1 stepping
+ jc short G3s10 ; if c, it is NOT D1
+ mov ax, 0D1h ; It is D1/later stepping
+ ret
+
+G3s10:
+ mov ax, 0B1h ; assume it is B1 stepping
+ ret
+
+Get386Stepping endp
+
+;++
+;
+; USHORT
+; Get486Stepping (
+; VOID
+; )
+;
+; Routine Description:
+;
+; This function determines cpu stepping for i486 CPU type.
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; [ax] - Cpu stepping. For example, [ax] = D0h for D0 stepping.
+;
+;--
+
+ public Get486Stepping
+Get486Stepping proc
+
+ call Check486AStepping ; Check for A stepping
+ jnc short G4s00 ; if nc, it is NOT A stepping
+
+ mov ax, 0A0h ; set to A stepping
+ ret
+
+G4s00: call Check486BStepping ; Check for B stepping
+ jnc short G4s10 ; if nc, it is NOT a B stepping
+
+ mov ax, 0B0h ; set to B stepping
+ ret
+
+;
+; Before we test for 486 C/D step, we need to make sure NPX is present.
+; Because the test uses FP instruction to do the detection.
+;
+
+G4s10: call _IsNpxPresent ; Check if cpu has coprocessor support?
+ cmp ax, 0
+ jz short G4s15 ; it is actually 486sx
+
+ call Check486CStepping ; Check for C stepping
+ jnc short G4s20 ; if nc, it is NOT a C stepping
+G4s15:
+ mov ax, 0C0h ; set to C stepping
+ ret
+
+G4s20: mov ax, 0D0h ; Set to D stepping
+ ret
+
+Get486Stepping endp
+
+;++
+;
+; BOOLEAN
+; Check486AStepping (
+; VOID
+; )
+;
+; Routine Description:
+;
+; This routine checks for 486 A Stepping.
+;
+; It takes advantage of the fact that on the A-step of the i486
+; processor, the ET bit in CR0 could be set or cleared by software,
+; but was not used by the hardware. On B or C -step, ET bit in CR0
+; is now hardwired to a "1" to force usage of the 386 math coprocessor
+; protocol.
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; Carry Flag clear if B or later stepping.
+; Carry Flag set if A or earlier stepping.
+;
+;--
+ public Check486AStepping
+Check486AStepping proc near
+.386p
+ mov eax, cr0 ; reset ET bit in cr0
+ and eax, NOT CR0_ET
+ mov cr0, eax
+
+ mov eax, cr0 ; get cr0 back
+ test eax, CR0_ET ; if ET bit still set?
+ jnz short cas10 ; if nz, yes, still set, it's NOT A step
+ stc
+ ret
+
+cas10: clc
+ ret
+
+ ret
+Check486AStepping endp
+
+;++
+;
+; BOOLEAN
+; Check486BStepping (
+; VOID
+; )
+;
+; Routine Description:
+;
+; This routine checks for 486 B Stepping.
+;
+; On the i486 processor, the "mov to/from DR4/5" instructions were
+; aliased to "mov to/from DR6/7" instructions. However, the i486
+; B or earlier steps generate an Invalid opcode exception when DR4/5
+; are used with "mov to/from special register" instruction.
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; Carry Flag clear if C or later stepping.
+; Carry Flag set if B stepping.
+;
+;--
+ public Check486BStepping
+Check486BStepping proc
+
+ push ds
+ push bx
+
+ xor ax,ax
+ mov ds,ax ; (DS) = 0 (real mode IDT)
+ mov bx,6*4
+ push dword ptr [bx] ; save old int 6 vector
+
+ mov word ptr [bx].VectorOffset,offset Temporary486Int6
+ mov [bx].VectorSegment,cs ; set vector to new int 6 handler
+
+c4bs50: db 0fh, 21h, 0e0h ; mov eax, DR4
+ nop
+ nop
+ nop
+ nop
+ nop
+ clc ; it is C step
+ jmp short c4bs70
+c4bs60: stc ; it's B step
+c4bs70: pop dword ptr [bx] ; restore old int 6 vector
+
+ pop bx
+ pop ds
+ ret
+
+ ret
+
+Check486BStepping endp
+
+;++
+;
+; BOOLEAN
+; Temporary486Int6 (
+; VOID
+; )
+;
+; Routine Description:
+;
+; Temporary int 6 handler - assumes the cause of the exception was the
+; attempted execution of an mov to/from DR4/5 instruction.
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; none.
+;
+;--
+
+Temporary486Int6 proc
+
+ mov word ptr [esp].IretIp,offset c4bs60 ; set IP to stc instruction
+ iret
+
+Temporary486Int6 endp
+
+;++
+;
+; BOOLEAN
+; Check486CStepping (
+; VOID
+; )
+;
+; Routine Description:
+;
+; This routine checks for 486 C Stepping.
+;
+; This routine takes advantage of the fact that FSCALE produces
+; wrong result with Denormal or Pseudo-denormal operand on 486
+; C and earlier steps.
+;
+; If the value contained in ST(1), second location in the floating
+; point stack, is between 1 and 11, and the value in ST, top of the
+; floating point stack, is either a pseudo-denormal number or a
+; denormal number with the underflow exception unmasked, the FSCALE
+; instruction produces an incorrect result.
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; Carry Flag clear if D or later stepping.
+; Carry Flag set if C stepping.
+;
+;--
+
+FpControl equ [ebp - 2]
+RealLongSt1 equ [ebp - 10]
+PseudoDenormal equ [ebp - 20]
+FscaleResult equ [ebp - 30]
+
+ public Check486CStepping
+Check486CStepping proc
+
+ push ebp
+ mov ebp, esp
+ sub esp, 30 ; Allocate space for temp real variables
+
+;
+; Initialize the local FP variables to predefined values.
+; RealLongSt1 = 1.0 * (2 ** -1) = 0.5 in normalized double precision FP form
+; PseudoDenormal = a unsupported format by IEEE.
+; Sign bit = 0
+; Exponent = 000000000000000B
+; Significand = 100000...0B
+; FscaleResult = The result of FSCALE instruction. Depending on 486 step,
+; the value will be different:
+; Under C and earlier steps, 486 returns the original value
+; in ST as the result. The correct returned value should be
+; original significand and an exponent of 0...01.
+;
+
+ mov dword ptr RealLongSt1, REALLONG_LOW
+ mov dword ptr RealLongSt1 + 4, REALLONG_HIGH
+ mov dword ptr PseudoDenormal, PSEUDO_DENORMAL_LOW
+ mov dword ptr PseudoDenormal + 4, PSEUDO_DENORMAL_MID
+ mov word ptr PseudoDenormal + 8, PSEUDO_DENORMAL_HIGH
+
+.387
+ fnstcw FpControl ; Get FP control word
+ fwait
+ or word ptr FpControl, 0FFh ; Mask all the FP exceptions
+ fldcw FpControl ; Set FP control
+
+ fld qword ptr RealLongSt1 ; 0 < ST(1) = RealLongSt1 < 1
+ fld tbyte ptr PseudoDenormal; Denormalized operand. Note, i486
+ ; won't report denormal exception
+ ; on 'FLD' instruction.
+ ; ST(0) = Extended Denormalized operand
+ fscale ; try to trigger 486Cx errata
+ fstp tbyte ptr FscaleResult ; Store ST(0) in FscaleResult
+ cmp word ptr FscaleResult + 8, PSEUDO_DENORMAL_HIGH
+ ; Is Exponent changed?
+ jz short c4ds00 ; if z, no, it is C step
+ clc
+ jmp short c4ds10
+c4ds00: stc
+c4ds10: mov esp, ebp
+ pop ebp
+ ret
+
+Check486CStepping endp
+
+;++
+;
+; BOOLEAN
+; Check386B0 (
+; VOID
+; )
+;
+; Routine Description:
+;
+; This routine checks for 386 B0 or earlier stepping.
+;
+; It takes advantage of the fact that the bit INSERT and
+; EXTRACT instructions that existed in B0 and earlier versions of the
+; 386 were removed in the B1 stepping. When executed on the B1, INSERT
+; and EXTRACT cause an int 6 (invalid opcode) exception. This routine
+; can therefore discriminate between B1/later 386s and B0/earlier 386s.
+; It is intended to be used in sequence with other checks to determine
+; processor stepping by exercising specific bugs found in specific
+; steppings of the 386.
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; Carry Flag clear if B1 or later stepping
+; Carry Flag set if B0 or prior
+;
+;--
+
+
+ ASSUME ds:nothing, es:nothing, fs:nothing, gs:nothing, ss:nothing
+
+Check386B0 proc
+
+ push ds
+ push bx
+
+ xor ax,ax
+ mov ds,ax ; (DS) = 0 (real mode IDT)
+ mov bx,6*4
+ push dword ptr [bx] ; save old int 6 vector
+
+ mov word ptr [bx].VectorOffset,offset TemporaryInt6
+ mov [bx].VectorSegment,cs ; set vector to new int 6 handler
+
+;
+; Attempt execution of Extract Bit String instruction. Execution on
+; B0 or earlier with length (CL) = 0 will return 0 into the destination
+; (CX in this case). Execution on B1 or later will fail either due to
+; taking the invalid opcode trap, or if the opcode is valid, we don't
+; expect CX will be zeroed by any new instruction supported by newer
+; steppings. The dummy int 6 handler will clears the Carry Flag and
+; returns execution to the appropriate label. If the instruction
+; actually executes, CX will *probably* remain unchanged in any new
+; stepping that uses the opcode for something else. The nops are meant
+; to handle newer steppings with an unknown instruction length.
+;
+
+ xor ax,ax
+ mov dx,ax
+ mov cx,0ff00h ; Extract length (CL) == 0, (CX) != 0
+
+b1c50: db 0fh, 0a6h, 0cah ; xbts cx,dx,ax,cl
+ nop
+ nop
+ nop
+ nop
+ nop
+ stc ; assume B0
+ jcxz short b1c70 ; jmp if B0
+b1c60: clc
+b1c70: pop dword ptr [bx] ; restore old int 6 vector
+
+ pop bx
+ pop ds
+ ret
+
+Check386B0 endp
+
+;++
+;
+; BOOLEAN
+; TemporaryInt6 (
+; VOID
+; )
+;
+; Routine Description:
+;
+; Temporary int 6 handler - assumes the cause of the exception was the
+; attempted execution of an XTBS instruction.
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; none.
+;
+;--
+
+TemporaryInt6 proc
+
+ mov word ptr [esp].IretIp,offset b1c60 ; set IP to clc instruction
+ iret
+
+TemporaryInt6 endp
+
+;++
+;
+; BOOLEAN
+; Check386D1 (
+; VOID
+; )
+;
+; Routine Description:
+;
+; This routine checks for 386 D1 Stepping.
+;
+; It takes advantage of the fact that on pre-D1 386, if a REPeated
+; MOVS instruction is executed when single-stepping is enabled,
+; a single step trap is taken every TWO moves steps, but should
+; occuu each move step.
+;
+; NOTE: This routine cannot distinguish between a D0 stepping and a D1
+; stepping. If a need arises to make this distinction, this routine
+; will need modification. D0 steppings will be recognized as D1.
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; Carry Flag clear if D1 or later stepping
+; Carry Flag set if B1 or prior
+;
+;--
+
+ assume ds:nothing, es:nothing, fs:nothing, gs:nothing, ss:nothing
+
+Check386D1 proc
+
+ push ds
+ push bx
+
+ xor ax,ax
+ mov ds,ax ; (DS) = 0 (real mode IDT)
+ mov bx,1*4
+ push dword ptr [bx] ; save old int 1 vector
+
+ mov word ptr [bx].VectorOffset,offset TemporaryInt1
+ mov word ptr [bx].VectorSegment,cs ; set vector to new int 1 handler
+
+;
+; Attempt execution of rep movsb instruction with the Trace Flag set.
+; Execution on B1 or earlier with length (CX) > 1 will trace over two
+; iterations before accepting the trace trap. Execution on D1 or later
+; will accept the trace trap after a single iteration. The dummy int 1
+; handler will return execution to the instruction following the movsb
+; instruction. Examination of (CX) will reveal the stepping.
+;
+
+ sub sp,4 ; make room for target of movsb
+ xor si,si ; (ds:si) = 0:0
+ push ss ; (es:di) = ss:sp-4
+ pop es
+ mov di,sp
+ mov cx,2 ; 2 iterations
+ pushf
+ or word ptr [esp], EFLAGS_TF
+ popf ; cause a single step trap
+ rep movsb
+
+d1c60: add sp,4 ; clean off stack
+ pop dword ptr [bx] ; restore old int 1 vector
+ stc ; assume B1
+ jcxz short d1cx ; jmp if <= B1
+ clc ; else clear carry to indicate >= D1
+d1cx:
+ pop bx
+ pop ds
+ ret
+
+Check386D1 endp
+
+;++
+;
+; BOOLEAN
+; TemporaryInt1 (
+; VOID
+; )
+;
+; Routine Description:
+;
+; Temporary int 1 handler - assumes the cause of the exception was
+; trace trap at the above rep movs instruction.
+;
+; Arguments:
+;
+; (esp)->eip of trapped instruction
+; cs of trapped instruction
+; eflags of trapped instruction
+;
+;--
+
+TemporaryInt1 proc
+
+ and word ptr [esp].IretFlags,not EFLAGS_TF ; clear caller's Trace Flag
+ mov word ptr [esp].IretIp,offset d1c60 ; set IP to next instruction
+ iret
+
+TemporaryInt1 endp
+
+;++
+;
+; BOOLEAN
+; MultiplyTest (
+; VOID
+; )
+;
+; Routine Description:
+;
+; This routine checks the 386 32-bit multiply instruction.
+; The reason for this check is because some of the i386 fail to
+; perform this instruction.
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; Carry Flag clear on success
+; Carry Flag set on failure
+;
+;--
+;
+
+ assume ds:nothing, es:nothing, fs:nothing, gs:nothing, ss:nothing
+
+MultiplyTest proc
+
+ xor cx,cx ; 64K times is a nice round number
+mlt00: push cx
+ call Multiply ; does this chip's multiply work?
+ pop cx
+ jc short mltx ; if c, No, exit
+ loop mlt00 ; if nc, YEs, loop to try again
+ clc
+mltx:
+ ret
+
+MultiplyTest endp
+
+;++
+;
+; BOOLEAN
+; Multiply (
+; VOID
+; )
+;
+; Routine Description:
+;
+; This routine performs 32-bit multiplication test which is known to
+; fail on bad 386s.
+;
+; Note, the supplied pattern values must be used for consistent results.
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; Carry Flag clear on success.
+; Carry Flag set on failure.
+;
+;--
+
+Multiply proc
+
+ mov ecx, MULTIPLIER
+ mov eax, MULTIPLICAND
+ mul ecx
+
+ cmp edx, RESULT_HIGH ; Q: high order answer OK ?
+ stc ; assume failure
+ jnz short mlpx ; N: exit with error
+
+ cmp eax, RESULT_LOW ; Q: low order answer OK ?
+ stc ; assume failure
+ jnz short mlpx ; N: exit with error
+
+ clc ; indicate success
+mlpx:
+ ret
+
+Multiply endp
+
+;++
+;
+; BOOLEAN
+; IsNpxPresent(
+; VOID
+; );
+;
+; Routine Description:
+;
+; This routine determines if there is any Numeric coprocessor
+; present. If yes, the ET bit in CR0 will be set; otherwise
+; it will be reset.
+;
+; Note that we do NOT determine its type (287, 387).
+; This code is extracted from Intel book.
+;
+; Arguments:
+;
+; None.
+;
+; Return:
+;
+; TRUE - If NPX is present. Else a value of FALSE is returned.
+;
+;--
+
+ public _IsNpxPresent
+_IsNpxPresent proc near
+
+ push bp ; Save caller's bp
+.386p
+ mov eax, cr0
+ and eax, NOT CR0_ET ; Assume no NPX
+ mov edx, 0
+.287
+ fninit ; Initialize NPX
+ mov cx, 5A5Ah ; Put non-zero value
+ push cx ; into the memory we are going to use
+ mov bp, sp
+ fnstsw word ptr [bp] ; Retrieve status - must use non-wait
+ cmp byte ptr [bp], 0 ; All bits cleared by fninit?
+ jne Inp10
+
+ or eax, CR0_ET
+ mov edx, 1
+Inp10:
+ mov cr0, eax
+ pop ax ; clear scratch value
+ pop bp ; Restore caller's bp
+ mov eax, edx
+ ret
+
+_IsNpxPresent endp
+
+_TEXT ENDS
+ END
diff --git a/private/ntos/boot/detect/i386/cpu.inc b/private/ntos/boot/detect/i386/cpu.inc
new file mode 100644
index 000000000..55b02c8b0
--- /dev/null
+++ b/private/ntos/boot/detect/i386/cpu.inc
@@ -0,0 +1,72 @@
+;++
+;
+; Copyright (c) 1989 Microsoft Corporation
+;
+; Module Name:
+;
+; cpu.inc
+;
+; Abstract:
+;
+; This module contains the assembly structures and definitions
+; for INTEL 80x86 CPU specifiec information. This include file
+; is mainly used by CPU.ASM to determine CPU type and stepping
+; number.
+;
+; Author:
+;
+; Shie-Lin (shielint) 1-Oct-1991
+;
+; Revision History:
+;
+;--
+
+;
+; The following equates define the control bits of CR0 register
+;
+
+CR0_AM equ 40000h
+CR0_ET equ 00010h
+
+;
+; The following equates define the control bits of EFALGS register
+;
+
+EFLAGS_AC equ 40000h
+EFLAGS_VM equ 20000h
+EFLAGS_RF equ 10000h
+EFLAGS_NF equ 4000h
+EFLAGS_IOPL equ 3000h
+EFLAGS_IF equ 200h
+EFLAGS_TF equ 100h
+
+
+;
+; define the structure type for real mode interrupt vectore
+;
+
+RealModeVector struc
+
+VectorOffset dw 0
+VectorSegment dw 0
+
+RealModeVector ends
+
+;
+; Define the iret frame
+;
+
+IretFrame struc
+
+IretIp dw 0
+IretCs dw 0
+IretFlags dw 0
+
+IretFrame ends
+
+;
+; Misc. definitions
+;
+
+ADDRESS_OVERRIDE equ 67h
+OPERAND_OVERRIDE equ 66h
diff --git a/private/ntos/boot/detect/i386/disk.h b/private/ntos/boot/detect/i386/disk.h
new file mode 100644
index 000000000..a64b12f77
--- /dev/null
+++ b/private/ntos/boot/detect/i386/disk.h
@@ -0,0 +1,87 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ flo_data.h
+
+Abstract:
+
+ This file includes data and hardware declarations for the BIOS
+ disk and floppy.
+
+Author:
+
+ Shie-Lin Tzong (shielint) Dec-26-1991.
+
+Environment:
+
+ x86 real mode.
+
+Notes:
+
+--*/
+
+
+
+//
+// CMOS related definitions and macros
+//
+
+#define CMOS_CONTROL_PORT 0x70 // cmos command port
+#define CMOS_DATA_PORT 0x71 // cmos data port
+#define CMOS_FLOPPY_CONFIG_BYTE 0x10
+
+//
+// The length of CBIOS floppy parameter table
+//
+
+#define FLOPPY_PARAMETER_TABLE_LENGTH 28
+
+//
+// The CM_FLOPPY_DEVICE_DATA we use here is the newly updated one.
+// To distinguish this, we set the version number in the CM_FLOPPY_DEVICE_DATA
+// to 2. (Otherwise, it should be < 2)
+//
+
+#define CURRENT_FLOPPY_DATA_VERSION 2
+
+extern USHORT NumberBiosDisks;
+
+//
+// External References
+//
+
+extern
+BOOLEAN
+IsExtendedInt13Available (
+ IN USHORT DriveNumber
+ );
+
+extern
+USHORT
+GetExtendedDriveParameters (
+ IN USHORT DriveNumber,
+ IN CM_DISK_GEOMETRY_DEVICE_DATA far *DeviceData
+ );
+
+//
+// Partition table record and boot signature offsets in 16-bit words.
+//
+
+#define PARTITION_TABLE_OFFSET (0x1be / 2)
+#define BOOT_SIGNATURE_OFFSET ((0x200 / 2) - 1)
+
+//
+// Boot record signature value.
+//
+
+#define BOOT_RECORD_SIGNATURE (0xaa55)
+
+VOID
+GetDiskId(
+ USHORT Drive,
+ PUCHAR Identifier
+ );
+
diff --git a/private/ntos/boot/detect/i386/diska.asm b/private/ntos/boot/detect/i386/diska.asm
new file mode 100644
index 000000000..65ce0ad0d
--- /dev/null
+++ b/private/ntos/boot/detect/i386/diska.asm
@@ -0,0 +1,332 @@
+ title "Int13 Drive parameter information detection"
+;++
+;
+; Copyright (c) 1989 Microsoft Corporation
+;
+; Module Name:
+;
+; diska.asm
+;
+; Abstract:
+;
+; This module implements the assembley code necessary to detect/collect
+; harddisk paramter information.
+;
+; Author:
+;
+; Shie-Lin Tzong (shielint) 22-Feb-1992
+;
+; Environment:
+;
+; Real Mode 16-bit code.
+;
+; Revision History:
+;
+;
+;--
+
+
+.386p
+
+;
+; Standard int 13 drive parameters.
+; The parameters returned from int 13 function 8
+;
+
+Int13DriveParameters struc
+
+ DriveSelect dw 0
+ MaxCylinders dd 0
+ SectorsPerTrack dw 0
+ MaxHeads dw 0
+ NumberDrives dw 0
+
+Int13DriveParameters ends
+
+SIZE_OF_PARAMETERS equ 12
+
+;
+; Extended int 13 drive parameters
+; The Drive Parameters returned from int 13 function 48h
+;
+
+ExInt13DriveParameters struc
+
+ ExBufferSize dw 0
+ ExFlags dw 0
+ ExCylinders dd 0
+ ExHeads dd 0
+ ExSectorsPerTrack dd 0
+ ExSectorsPerDrive dd 0
+ dd 0
+ ExSectorSize dw 0
+ ExReserved dw 0
+
+ExInt13DriveParameters ends
+
+SIZE_OF_EXTENDED_PARAMETERS equ 28
+
+;
+; Structure used by nt kernel Configuration Manager
+;
+
+CmDiskGeometryDeviceData struc
+
+ CmBytesPerSector dd 0
+ CmNumberOfCylinders dd 0
+ CmSectorsPerTrack dd 0
+ CmNumberOfHeads dd 0
+
+CmDiskGeometryDeviceData ends
+
+SIZE_OF_CM_DISK_DATA EQU 16
+
+_DATA SEGMENT PARA USE16 PUBLIC 'DATA'
+
+ public _NumberBiosDisks
+_NumberBiosDisks dw 0
+
+RomChain db 8 * SIZE_OF_PARAMETERS dup(?)
+
+_DATA ends
+
+_TEXT SEGMENT PARA USE16 PUBLIC 'CODE'
+ ASSUME CS: _TEXT, DS:_DATA, SS:NOTHING
+
+;++
+;
+; VOID
+; GetInt13DriveParamters (
+; OUT PUCHAR Buffer,
+; OUT PUSHORT Size
+; )
+;
+; Routine Description:
+;
+; This function calls real mode int 13h function 8 to get drive
+; parameters for drive 80h - 87h.
+;
+; Arguments:
+;
+; Buffer - Supplies a pointer to a buffer to receive the drive paramter
+; information.
+;
+; Size - Supplies a pointer to a USHORT to receive the size of the drive
+; parameter information returned.
+;
+; Return Value:
+;
+; None.
+;
+;--
+
+ Public _GetInt13DriveParameters
+_GetInt13DriveParameters proc
+
+ push bp
+ mov bp, sp
+ push si
+ push bx
+
+ mov dx, 80h ; Starting from drive 80h
+ mov cx, 0 ; count
+ mov si, offset RomChain ; [si]->Buffer
+gidp00:
+ push cx ; save count
+ push dx ; save drive select
+
+;
+; First check if drive is present. It turns out function returns drive
+; parameters even when the drive is not present.
+;
+
+ mov ah, 15h
+ int 13h ; Get type of drive
+ jc short gidp99
+
+ cmp ah, 0 ; if ah=0 drive is not present
+ jz gidp99
+
+ pop dx
+ pop cx
+ push cx
+ push dx
+
+ mov ah, 8 ; int 13 function 8
+ int 13h ; call int 13
+ jc short gidp99 ; if c, fail, go exit
+
+ inc _NumberBiosDisks
+ mov al, cl
+ and al, 3fh ; Only want bit 0 - 5
+ mov ah, 0
+ mov [si].SectorsPerTrack, ax
+ shr cl, 6
+ xchg cl, ch
+ mov word ptr [si].MaxCylinders, cx
+ mov word ptr [si + 2].MaxCylinders, 0
+ mov byte ptr [si].MaxHeads, dh
+ mov byte ptr [si + 1].MaxHeads, 0
+ mov byte ptr [si].NumberDrives, dl
+ mov byte ptr [si + 1].NumberDrives, 0
+ pop dx ; get back current drive number
+ mov [si].DriveSelect, dx
+ inc dx
+ pop cx ; get back count
+ inc cx ; increase table count
+ cmp dx, 88h ; Are we done? (dx == 88h)
+ je short gidp100
+
+ add si, SIZE_OF_PARAMETERS
+ jmp gidp00
+
+gidp99: pop dx
+ pop cx
+gidp100:
+ mov ax, offset RomChain
+ mov si, [bp + 4] ; [si]-> variable to receive buffer addr
+ mov [si], ax ; return buffer address
+ mov si, [bp + 6] ; [si]-> variable to receive buffer size
+ mov ax, cx
+ mov cl, SIZE_OF_PARAMETERS
+ mul cl
+ mov [si], ax ; return buffer size
+
+ pop bx
+ pop si
+ pop bp
+ ret
+
+_GetInt13DriveParameters endp
+
+;++
+;
+; BOOLEAN
+; IsExtendedInt13Available
+; USHORT DriveNumber
+; )
+;
+; Routine Description:
+;
+; This function checks if extended int13 functions available.
+;
+; Arguments:
+;
+; DriveNumber - the drive number to check for.
+;
+; Return Value:
+;
+; TRUE if extended int 13 service is available. Otherwise a value of
+; FALSE is returned.
+;
+;--
+
+ Public _IsExtendedInt13Available
+_IsExtendedInt13Available proc
+
+ push bp
+ mov bp, sp
+ push bx
+
+ mov dl, [bp+4] ; get DriveNumber parameter
+ mov ah, 41h
+ mov bx, 55aah
+ int 13h
+ jc short Ieda90
+
+ cmp bx, 0AA55h
+ jne short Ieda90
+
+ test cx, 1 ; bit 0 = Extended disk access is supported
+ jz short Ieda90
+
+ mov ax, 1
+ jmp short IedaExit
+Ieda90:
+ xor eax, eax
+IedaExit:
+ pop bx
+ pop bp
+ ret
+
+_IsExtendedInt13Available endp
+
+;++
+;
+; USHORT
+; GetExtendedDriveParameters
+; USHORT DriveNumber,
+; FPCM_DISK_GEOMETRY_DEVICE_DATA DeviceData
+; )
+;
+; Routine Description:
+;
+; This function use extended int13 service function 48h to get
+; drive parameters.
+;
+; Arguments:
+;
+; DriveNumber - the drive number to get the drive parameters.
+;
+; DeviceData - supplies a far pointer to a buffer to receive the parameters.
+;
+;
+; Return Value:
+;
+; Size of DeviceData. If the extended int 13 service is not available,
+; a zero value will be returned.
+;
+;--
+
+ Public _GetExtendedDriveParameters
+_GetExtendedDriveParameters proc
+
+ push bp
+ mov bp, sp
+ push si
+ push bx
+ sub sp, SIZE_OF_EXTENDED_PARAMETERS
+
+ mov dl, [bp+4] ; get DriveNumber parameter
+ mov si, sp ; [si]-> Local buffer
+ mov word ptr [si].ExBufferSize, SIZE_OF_EXTENDED_PARAMETERS
+ mov ah, 48h
+ int 13h
+ jc short Gedp90
+
+ or ah, ah ; Make sure there is no error
+ jnz short Gedp90 ; if error, exit
+
+ cmp [si].ExBufferSize, ExReserved
+ jl short Gedp90 ; the retruned data is too small to be useful
+
+ mov bx, [bp+6]
+ mov ax, [bp+8]
+ mov es, ax ; (es:bx)->Caller's buffer
+ ASSUME es:NOTHING
+
+ mov eax, [si].ExCylinders
+ mov es:[bx].CmNumberOfCylinders, eax
+ mov eax, [si].ExHeads
+ mov es:[bx].CmNumberOfHeads, eax
+ mov eax, [si].ExSectorsPerTrack
+ mov es:[bx].CmSectorsPerTrack, eax
+ xor eax, eax
+ mov ax, [si].ExSectorSize
+ mov es:[bx].CmBytesPerSector, eax
+ mov ax, SIZE_OF_CM_DISK_DATA
+ jmp short GedpExit
+Gedp90:
+ xor eax, eax
+GedpExit:
+ add sp, SIZE_OF_EXTENDED_PARAMETERS
+ pop bx
+ pop si
+ pop bp
+ ret
+
+_GetExtendedDriveParameters endp
+_TEXT ends
+ end
+
+ \ No newline at end of file
diff --git a/private/ntos/boot/detect/i386/diskc.c b/private/ntos/boot/detect/i386/diskc.c
new file mode 100644
index 000000000..317431000
--- /dev/null
+++ b/private/ntos/boot/detect/i386/diskc.c
@@ -0,0 +1,540 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ diskc.c
+
+Abstract:
+
+ This is the NEC PD756 (aka AT, aka ISA, aka ix86) and Intel 82077
+ (aka MIPS) floppy diskette detection code for NT. This file also
+ collect BIOS disk drive parameters.
+
+Author:
+
+ Shie-Lin Tzong (shielint) Dec-26-1991.
+
+Environment:
+
+ x86 real mode.
+
+Revision History:
+
+
+Notes:
+
+--*/
+
+//
+// Include files.
+//
+
+#include "hwdetect.h"
+#include "disk.h"
+#include <string.h>
+
+
+FPFWCONFIGURATION_COMPONENT_DATA
+GetFloppyInformation(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine tries to get floppy configuration information.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A pointer to a FPCONFIGURATION_COMPONENT_DATA is returned. It is
+ the head of floppy component tree root.
+
+--*/
+
+{
+ UCHAR DriveType;
+ FPUCHAR ParameterTable;
+ FPFWCONFIGURATION_COMPONENT_DATA CurrentEntry, PreviousEntry = NULL;
+ FPFWCONFIGURATION_COMPONENT_DATA FirstController = NULL;
+ FPFWCONFIGURATION_COMPONENT Component;
+ HWCONTROLLER_DATA ControlData;
+ UCHAR FloppyNumber = 0;
+ UCHAR DiskName[30];
+ UCHAR FloppyParmTable[FLOPPY_PARAMETER_TABLE_LENGTH];
+ FPUCHAR fpString;
+ USHORT Length, z;
+ ULONG MaxDensity = 0;
+ CM_FLOPPY_DEVICE_DATA far *FloppyData;
+ FPHWRESOURCE_DESCRIPTOR_LIST DescriptorList;
+ USHORT FloppyDataVersion;
+
+ for (z = 0; z < FLOPPY_PARAMETER_TABLE_LENGTH; z++ ) {
+ FloppyParmTable[z] = 0;
+ }
+
+ //
+ // Initialize Controller data
+ //
+
+ ControlData.NumberPortEntries = 0;
+ ControlData.NumberIrqEntries = 0;
+ ControlData.NumberMemoryEntries = 0;
+ ControlData.NumberDmaEntries = 0;
+ z = 0;
+
+ //
+ // Allocate space for Controller component and initialize it.
+ //
+
+ CurrentEntry = (FPFWCONFIGURATION_COMPONENT_DATA)HwAllocateHeap (
+ sizeof(FWCONFIGURATION_COMPONENT_DATA), TRUE);
+ FirstController = CurrentEntry;
+ Component = &CurrentEntry->ComponentEntry;
+
+ Component->Class = ControllerClass;
+ Component->Type = DiskController;
+ Component->Flags.Removable = 1;
+ Component->Flags.Input = 1;
+ Component->Flags.Output = 1;
+ Component->Version = 0;
+ Component->Key = 0;
+ Component->AffinityMask = 0xffffffff;
+
+ //
+ // Set up Port information
+ //
+
+ ControlData.NumberPortEntries = 1;
+ ControlData.DescriptorList[z].Type = RESOURCE_PORT;
+ ControlData.DescriptorList[z].ShareDisposition =
+ CmResourceShareDeviceExclusive;
+ ControlData.DescriptorList[z].Flags = CM_RESOURCE_PORT_IO;
+ ControlData.DescriptorList[z].u.Port.Start.LowPart = (ULONG)0x3f0;
+ ControlData.DescriptorList[z].u.Port.Start.HighPart = (ULONG)0;
+ ControlData.DescriptorList[z].u.Port.Length = 8;
+ z++;
+
+ //
+ // Set up Irq information
+ //
+
+ ControlData.NumberIrqEntries = 1;
+ ControlData.DescriptorList[z].Type = RESOURCE_INTERRUPT;
+ ControlData.DescriptorList[z].ShareDisposition =
+ CmResourceShareUndetermined;
+ if (HwBusType == MACHINE_TYPE_MCA) {
+ ControlData.DescriptorList[z].Flags = LEVEL_SENSITIVE;
+ } else {
+ ControlData.DescriptorList[z].Flags = EDGE_TRIGGERED;
+ }
+ ControlData.DescriptorList[z].u.Interrupt.Level = 6;
+ ControlData.DescriptorList[z].u.Interrupt.Vector = 6;
+ ControlData.DescriptorList[z].u.Interrupt.Affinity = ALL_PROCESSORS;
+ z++;
+
+ //
+ // Set up DMA information. Only set channel number. Timming and
+ // transferSize are defaulted - 8 bits and ISA compatible.
+ //
+
+ ControlData.NumberDmaEntries = 1;
+ ControlData.DescriptorList[z].Type = RESOURCE_DMA;
+ ControlData.DescriptorList[z].ShareDisposition =
+ CmResourceShareUndetermined;
+ ControlData.DescriptorList[z].Flags = 0;
+ ControlData.DescriptorList[z].u.Dma.Channel = (ULONG)2;
+ ControlData.DescriptorList[z].u.Dma.Port = 0;
+ z++;
+
+ CurrentEntry->ConfigurationData =
+ HwSetUpResourceDescriptor(Component,
+ NULL,
+ &ControlData,
+ 0,
+ NULL
+ );
+
+ //
+ // Collect disk peripheral data
+ //
+
+ while (1) {
+ _asm {
+ push es
+
+ mov DriveType, 0
+ mov FloppyDataVersion, CURRENT_FLOPPY_DATA_VERSION
+
+ mov ah, 15h
+ mov dl, FloppyNumber
+ int 13h
+ jc short CmosTest
+
+ cmp ah, 0
+ je short Exit
+
+ cmp ah, 2 ; make sure this is floppy
+ ja short Exit
+
+ mov ah, 8
+ mov dl, FloppyNumber
+ lea di, word ptr FloppyParmTable ; use 'word ptr' to quiet compiler
+ push ds
+ pop es ; (es:di)->dummy FloppyParmTable
+ int 13h
+ jc short CmosTest
+
+ mov DriveType, bl
+ mov ax, es
+ mov word ptr ParameterTable + 2, ax
+ mov word ptr ParameterTable, di
+ jmp short Exit
+
+ CmosTest:
+
+ ;
+ ; if int 13 fails, we know that floppy drive is present.
+ ; So, we try to get the Drive Type from CMOS.
+ ;
+
+ mov al, CMOS_FLOPPY_CONFIG_BYTE
+ mov dx, CMOS_CONTROL_PORT ; address port
+ out dx, al
+ jmp $ + 2 ; I/O DELAY
+ mov dx, CMOS_DATA_PORT ; READ IN REQUESTED CMOS DATA
+ in al, dx
+ jmp $ + 2 ; I/O DELAY
+
+ cmp FloppyNumber, 0
+ jne short CmosTest1
+
+ and al, 0xf0
+ shr al, 4
+ jmp short CmosTest2
+
+ CmosTest1:
+ cmp FloppyNumber, 1
+ jne short Exit
+
+ and al, 0xf
+ CmosTest2:
+ mov DriveType, al
+ mov FloppyDataVersion, 0
+ Exit:
+ pop es
+ }
+
+ if (DriveType) {
+
+ //
+ // Allocate space for first pripheral component and initialize it.
+ //
+
+ CurrentEntry = (FPFWCONFIGURATION_COMPONENT_DATA)HwAllocateHeap (
+ sizeof(FWCONFIGURATION_COMPONENT_DATA), TRUE);
+
+ Component = &CurrentEntry->ComponentEntry;
+
+ Component->Class = PeripheralClass;
+ Component->Type = FloppyDiskPeripheral;
+ Component->Version = 0;
+ Component->Key = FloppyNumber;
+ Component->AffinityMask = 0xffffffff;
+ Component->ConfigurationDataLength = 0;
+
+ //
+ // Set up type string.
+ //
+
+ strcpy(DiskName, "FLOPPYx");
+ DiskName[6] = FloppyNumber + (UCHAR)'1';
+ Length = strlen(DiskName) + 1;
+ fpString = (FPUCHAR)HwAllocateHeap(Length, FALSE);
+ _fstrcpy(fpString, DiskName);
+ Component->IdentifierLength = Length;
+ Component->Identifier = fpString;
+
+ //
+ // Set up floppy device specific data
+ //
+
+ switch (DriveType) {
+ case 1:
+ MaxDensity = 360;
+ break;
+ case 2:
+ MaxDensity = 1200;
+ break;
+ case 3:
+ MaxDensity = 720;
+ break;
+ case 4:
+ MaxDensity = 1440;
+ break;
+ case 5:
+ case 6:
+ MaxDensity = 2880;
+ break;
+ default:
+ MaxDensity = 0;
+ break;
+ }
+ if (FloppyDataVersion == CURRENT_FLOPPY_DATA_VERSION) {
+ Length = sizeof(CM_FLOPPY_DEVICE_DATA);
+ } else {
+ Length = (SHORT)&(((CM_FLOPPY_DEVICE_DATA*)0)->StepRateHeadUnloadTime);
+ }
+ DescriptorList = (FPHWRESOURCE_DESCRIPTOR_LIST)HwAllocateHeap(
+ Length + sizeof(HWRESOURCE_DESCRIPTOR_LIST),
+ TRUE);
+ CurrentEntry->ConfigurationData = DescriptorList;
+ Component->ConfigurationDataLength =
+ Length + sizeof(HWRESOURCE_DESCRIPTOR_LIST);
+ DescriptorList->Count = 1;
+ DescriptorList->PartialDescriptors[0].Type = RESOURCE_DEVICE_DATA;
+ DescriptorList->PartialDescriptors[0].u.DeviceSpecificData.DataSize =
+ Length;
+ FloppyData = (CM_FLOPPY_DEVICE_DATA far *)(DescriptorList + 1);
+ FloppyData->MaxDensity = MaxDensity;
+ FloppyData->Version = FloppyDataVersion;
+ if (FloppyDataVersion == CURRENT_FLOPPY_DATA_VERSION) {
+ _fmemcpy((FPCHAR)&FloppyData->StepRateHeadUnloadTime,
+ ParameterTable,
+ sizeof(CM_FLOPPY_DEVICE_DATA) -
+ (SHORT)&(((CM_FLOPPY_DEVICE_DATA*)0)->StepRateHeadUnloadTime)
+ );
+ }
+ if (FloppyNumber == 0) {
+ FirstController->Child = CurrentEntry;
+ } else {
+ PreviousEntry->Sibling = CurrentEntry;
+ }
+ CurrentEntry->Parent = FirstController;
+ PreviousEntry = CurrentEntry;
+ FloppyNumber++;
+ } else {
+
+ //
+ // This is a *hack* for ntldr. Here we create a arc name for
+ // each bios disks such that ntldr can open them.
+ //
+
+ if (NumberBiosDisks != 0) {
+
+ for (z = 0; z < NumberBiosDisks; z++) {
+
+ //
+ // Allocate space for disk peripheral component
+ //
+
+ CurrentEntry = (FPFWCONFIGURATION_COMPONENT_DATA)HwAllocateHeap (
+ sizeof(FWCONFIGURATION_COMPONENT_DATA), TRUE);
+
+ Component = &CurrentEntry->ComponentEntry;
+
+ Component->Class = PeripheralClass;
+ Component->Type = DiskPeripheral;
+ Component->Flags.Input = 1;
+ Component->Flags.Output = 1;
+ Component->Version = 0;
+ Component->Key = z;
+ Component->AffinityMask = 0xffffffff;
+
+ //
+ // Set up identifier string = 8 digit signature - 8 digit checksum
+ // for example: 00fe964d-005467dd
+ //
+
+ GetDiskId(0x80 + z, DiskName);
+ if (DiskName == NULL) {
+ strcpy(DiskName, "BIOSDISKx");
+ DiskName[8] = (UCHAR)z + (UCHAR)'1';
+ }
+ Length = strlen(DiskName) + 1;
+ fpString = (FPUCHAR)HwAllocateHeap(Length, FALSE);
+ _fstrcpy(fpString, DiskName);
+ Component->IdentifierLength = Length;
+ Component->Identifier = fpString;
+
+ //
+ // Set up BIOS disk device specific data.
+ // (If extended int 13 drive parameters are supported by
+ // BIOS, we will collect them and store them here.)
+ //
+
+ if (IsExtendedInt13Available(0x80+z)) {
+ DescriptorList = (FPHWRESOURCE_DESCRIPTOR_LIST)HwAllocateHeap(
+ sizeof(HWRESOURCE_DESCRIPTOR_LIST) +
+ sizeof(CM_DISK_GEOMETRY_DEVICE_DATA),
+ TRUE);
+ Length = GetExtendedDriveParameters(
+ 0x80 + z,
+ (CM_DISK_GEOMETRY_DEVICE_DATA far *)(DescriptorList + 1)
+ );
+ if (Length) {
+ CurrentEntry->ConfigurationData = DescriptorList;
+ Component->ConfigurationDataLength =
+ Length + sizeof(HWRESOURCE_DESCRIPTOR_LIST);
+ DescriptorList->Count = 1;
+ DescriptorList->PartialDescriptors[0].Type = RESOURCE_DEVICE_DATA;
+ DescriptorList->PartialDescriptors[0].u.DeviceSpecificData.DataSize =
+ Length;
+ } else {
+ HwFreeHeap(sizeof(HWRESOURCE_DESCRIPTOR_LIST) +
+ sizeof(CM_DISK_GEOMETRY_DEVICE_DATA));
+ }
+ }
+
+ if (PreviousEntry == NULL) {
+ FirstController->Child = CurrentEntry;
+ } else {
+ PreviousEntry->Sibling = CurrentEntry;
+ }
+ CurrentEntry->Parent = FirstController;
+ PreviousEntry = CurrentEntry;
+ }
+ }
+ return(FirstController);
+ }
+ }
+}
+
+VOID
+GetDiskId(
+ USHORT Disk,
+ PUCHAR Identifier
+ )
+
+/*++
+
+Routine Description:
+
+ This routine reads the master boot sector of the specified harddisk drive,
+ compute the checksum of the sector to form a drive identifier.
+
+ The identifier will be set to "8-digit-checksum"+"-"+"8-digit-signature"
+ For example: 00ff6396-6549071f
+
+Arguments:
+
+ Disk - supplies the BIOS drive number, i.e. 80h - 87h
+
+ Identifier - Supplies a buffer to receive the disk id.
+
+Return Value:
+
+ None. In the worst case, the Identifier will be empty.
+
+--*/
+
+{
+ UCHAR Sector[512];
+ ULONG Signature, Checksum;
+ USHORT i, Length;
+ PUCHAR BufferAddress;
+ BOOLEAN Fail;
+
+ Identifier[0] = 0;
+ BufferAddress = &Sector[0];
+ Fail = FALSE;
+
+ //
+ // Read in the first sector
+ //
+
+ _asm {
+ push es
+ mov ax, 0x201
+ mov cx, 1
+ mov dx, Disk
+ push ss
+ pop es
+ mov bx, BufferAddress
+ int 0x13
+ pop es
+ jnc Gdixxx
+
+ mov Fail, 1
+ Gdixxx:
+ }
+
+ if (!Fail) {
+ Signature = ((PULONG)Sector)[PARTITION_TABLE_OFFSET/2-1];
+
+ //
+ // compute the checksum
+ //
+
+ Checksum = 0;
+ for (i = 0; i < 128; i++) {
+ Checksum += ((PULONG)Sector)[i];
+ }
+ Checksum = -Checksum;
+
+ //
+ // Zero the identifier
+ //
+
+ for (i=0; i < 30; i++) {
+ Identifier[i]='0';
+ }
+
+ //
+ // Put the dashes in the right places.
+ //
+
+ Identifier[8] = '-';
+ Identifier[17] = '-';
+
+ //
+ // If the boot sector has a valid partition table signature,
+ // attach an 'A.' Otherwise we use 'X.'
+ //
+
+ if (((PUSHORT)Sector)[BOOT_SIGNATURE_OFFSET] != BOOT_RECORD_SIGNATURE) {
+ Identifier[18]='X';
+ } else {
+ Identifier[18]='A';
+ }
+
+ //
+ // Reuse sector buffer to build checksum string.
+ //
+
+ ultoa(Checksum, Sector, 16);
+ Length = strlen(Sector);
+
+ for (i=0; i<Length; i++) {
+ Identifier[7-i] = Sector[Length-i-1];
+ }
+
+ //
+ // Reuse sector buffer to build signature string.
+ //
+
+ ultoa(Signature, Sector, 16);
+ Length = strlen(Sector);
+
+ for (i=0; i<Length; i++) {
+ Identifier[16-i] = Sector[Length-i-1];
+ }
+
+ //
+ // Terminate string.
+ //
+
+ Identifier[19] = 0;
+#if DBG
+ BlPrint("%s\n", Identifier);
+#endif
+ }
+}
+
+
diff --git a/private/ntos/boot/detect/i386/display.c b/private/ntos/boot/detect/i386/display.c
new file mode 100644
index 000000000..56af09ec1
--- /dev/null
+++ b/private/ntos/boot/detect/i386/display.c
@@ -0,0 +1,632 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ display.c
+
+Author:
+
+ Thomas Parslow (tomp) Mar-01-90
+
+Abstract:
+
+ Video support routines.
+
+ The SU module only need to be able to write to the video display
+ in order to report errors, traps, etc.
+
+ The routines in this file all write to a video buffer assumed to be
+ at realmode address b800:0000, and 4k bytes in length. The segment
+ portion of the far pointers used to access the video buffer are stamped
+ with a protmode selector value when we switch to protect mode. This is
+ done in the routine "ProtMode" in "misc386.asm".
+
+
+--*/
+
+#include "hwdetect.h"
+
+#if DBG
+
+#define ZLEN_SHORT(x) ((x < 0x10) + (x < 0x100) + (x < 0x1000))
+#define ZLEN_LONG(x) ((x < 0x10) + (x < 0x100) + (x < 0x1000) + (x < 0x10000) + (x < 0x100000)+(x < 0x1000000)+(x < 0x10000000))
+
+
+#define ROWS 25
+#define COLUMNS 80
+#define SCREEN_WIDTH COLUMNS
+#define SCREEN_SIZE ROWS * COLUMNS
+#define NORMAL_ATTRIB 0x07
+#define REVERSE_ATTRIB 0x70
+#define SCREEN_START 0xb8000000
+
+
+//
+// Internal routines
+//
+
+VOID
+putc(
+ IN CHAR
+ );
+VOID
+putu(
+ IN ULONG
+ );
+
+VOID
+BlPuts(
+ IN PCHAR
+ );
+
+VOID
+puti(
+ IN LONG
+ );
+
+VOID
+putx(
+ IN ULONG
+ );
+
+VOID
+scroll(
+ VOID
+ );
+
+static
+VOID
+tab(
+ VOID
+ );
+
+static
+VOID
+newline(
+ VOID
+ );
+
+static
+VOID
+putzeros(
+ USHORT,
+ USHORT
+ );
+
+
+USHORT
+Redirect = 0;
+
+
+
+//
+// Used by all BlPrint subordinate routines for padding computations.
+//
+
+CHAR sc=0;
+ULONG fw=0;
+
+
+
+VOID
+BlPrint(
+ PCHAR cp,
+ ...
+ )
+
+/*++
+
+Routine Description:
+
+ Standard printf function with a subset of formating features supported.
+
+ Currently handles
+
+ %d, %ld - signed short, signed long
+ %u, %lu - unsigned short, unsigned long
+ %c, %s - character, string
+ %x, %lx - unsigned print in hex, unsigned long print in hex
+
+ Does not do:
+
+ - field width specification
+ - floating point.
+
+Arguments:
+
+ cp - pointer to the format string, text string.
+
+
+Returns:
+
+ Nothing
+
+
+--*/
+
+{
+ USHORT b,c,w,len;
+ PUCHAR ap;
+ ULONG l;
+
+ //
+ // Cast a pointer to the first word on the stack
+ //
+
+ ap = (PUCHAR)&cp + sizeof(PCHAR);
+ sc = ' '; // default padding char is space
+
+ //
+ // Process the arguments using the descriptor string
+ //
+
+
+ while (b = *cp++)
+ {
+ if (b == '%')
+ {
+ c = *cp++;
+
+ switch (c)
+ {
+ case 'd':
+ puti((long)*((int *)ap));
+ ap += sizeof(int);
+ break;
+
+ case 's':
+ BlPuts(*((PCHAR *)ap));
+ ap += sizeof (char *);
+ break;
+
+ case 'c':
+ putc(*((char *)ap));
+ ap += sizeof(int);
+ break;
+
+ case 'x':
+ w = *((USHORT *)ap);
+ len = ZLEN_SHORT(w);
+ while(len--) putc('0');
+ putx((ULONG)*((USHORT *)ap));
+ ap += sizeof(int);
+ break;
+
+ case 'u':
+ putu((ULONG)*((USHORT *)ap));
+ ap += sizeof(int);
+ break;
+
+ case 'l':
+ c = *cp++;
+
+ switch(c) {
+
+ case 'u':
+ putu(*((ULONG *)ap));
+ ap += sizeof(long);
+ break;
+
+ case 'x':
+ l = *((ULONG *)ap);
+ len = ZLEN_LONG(l);
+ while(len--) putc('0');
+ putx(*((ULONG *)ap));
+ ap += sizeof(long);
+ break;
+
+ case 'd':
+ puti(*((ULONG *)ap));
+ ap += sizeof(long);
+ break;
+
+ }
+ break;
+
+ default :
+ putc((char)b);
+ putc((char)c);
+ }
+ }
+ else
+ putc((char)b);
+ }
+
+}
+
+FPUCHAR vp = (FPUCHAR)SCREEN_START;
+FPUCHAR ScreenStart = (FPUCHAR)SCREEN_START;
+
+static int lcnt = 0;
+static int row = 0;
+
+
+VOID BlPuts(
+ PCHAR cp
+ )
+/*++
+
+Routine Description:
+
+ Writes a string on the display at the current cursor position
+
+Arguments:
+
+ cp - pointer to ASCIIZ string to display.
+
+
+Returns:
+
+ Nothing
+
+
+
+--*/
+
+
+{
+ char c;
+
+ while(c = *cp++)
+ putc(c);
+}
+
+
+//
+// Write a hex short to display
+//
+
+
+VOID putx(
+ ULONG x
+ )
+/*++
+
+Routine Description:
+
+ Writes hex long to the display at the current cursor position.
+
+Arguments:
+
+ x - ulong to write.
+
+Returns:
+
+ Nothing
+
+
+--*/
+
+{
+ ULONG j;
+
+ if (x/16)
+ putx(x/16);
+
+ if((j=x%16) > 9) {
+ putc((char)(j+'A'- 10));
+ } else {
+ putc((char)(j+'0'));
+ }
+}
+
+
+VOID puti(
+ LONG i
+ )
+/*++
+
+Routine Description:
+
+ Writes a long integer on the display at the current cursor position.
+
+Arguments:
+
+ i - the integer to write to the display.
+
+Returns:
+
+ Nothing
+
+
+--*/
+
+
+{
+ if (i<0)
+ {
+ i = -i;
+ putc((char)'-');
+ }
+
+ if (i/10)
+ puti(i/10);
+
+ putc((char)((i%10)+'0'));
+}
+
+
+
+VOID putu(
+ ULONG u
+ )
+/*++
+
+Routine Description:
+
+ Write an unsigned long to display
+
+Arguments:
+
+ u - unsigned
+
+
+--*/
+
+{
+ if (u/10)
+ putu(u/10);
+
+ putc((char)((u%10)+'0'));
+
+}
+
+
+VOID putc(
+ CHAR c
+ )
+/*++
+
+Routine Description:
+
+ Writes a character on the display at the current position.
+
+Arguments:
+
+ c - character to write
+
+
+Returns:
+
+ Nothing
+
+
+--*/
+
+{
+ switch (c)
+ {
+ case '\n':
+ newline();
+ break;
+
+ case '\t':
+ tab();
+ break;
+
+ default :
+ if (FP_OFF(vp) >= (SCREEN_SIZE * 2)) {
+ vp = (FPUCHAR)((ScreenStart + (2*SCREEN_WIDTH*(ROWS-1))));
+ scroll();
+ }
+ *vp = c;
+ vp += 2;
+ ++lcnt;
+ }
+}
+
+
+VOID newline(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Moves the cursor to the beginning of the next line. If the bottom
+ of the display has been reached, the screen is scrolled one line up.
+
+Arguments:
+
+ None
+
+
+Returns:
+
+ Nothing
+
+
+--*/
+
+{
+ vp += (SCREEN_WIDTH - lcnt)<<1;
+
+ if (++row > ROWS-1) {
+
+ vp = (FPUCHAR)((ScreenStart + (2*SCREEN_WIDTH*(ROWS-1))));
+ scroll();
+
+ }
+
+ lcnt = 0;
+
+}
+
+
+VOID scroll(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Scrolls the display UP one line.
+
+Arguments:
+
+ None
+
+Returns:
+
+ Nothing
+
+Notes:
+
+ Currently we scroll the display by reading and writing directly from
+ and to the video display buffer. We optionally switch to real mode
+ and to int 10s
+
+--*/
+
+{
+ USHORT i,j;
+ USHORT far *p1 = (USHORT far *)ScreenStart;
+ USHORT far *p2 = (USHORT far *)(ScreenStart + 2*SCREEN_WIDTH) ;
+
+ for (i=0; i < ROWS - 1; i++)
+ for (j=0; j < SCREEN_WIDTH; j++)
+ *p1++ = *p2++;
+
+ for (i=0; i < SCREEN_WIDTH; i++)
+ *p1++ = REVERSE_ATTRIB*256 + ' ';
+
+}
+
+
+static
+VOID tab(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+
+ Computes the next tab stop and moves the cursor to that location.
+
+
+Arguments:
+
+
+ None
+
+
+Returns:
+
+ Nothing
+
+--*/
+
+{
+ int inc;
+
+ inc = 8 - (lcnt % 8);
+ vp += inc<<1;
+ lcnt += inc;
+}
+
+
+VOID clrscrn(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Clears the video display by writing blanks with the current
+ video attribute over the entire display.
+
+
+Arguments:
+
+ None
+
+Returns:
+
+ Nothing
+
+
+--*/
+
+{
+ int i,a;
+ unsigned far *vwp = (unsigned far *)SCREEN_START;
+ a = REVERSE_ATTRIB*256 + ' ';
+
+ for (i = SCREEN_SIZE ; i ; i--)
+ *vwp++ = a;
+
+ row = 0;
+ lcnt = 0;
+ vp = (FPUCHAR)ScreenStart;
+
+}
+
+#else
+
+VOID
+BlPrint(
+ PCHAR cp,
+ ...
+ )
+
+/*++
+
+Routine Description:
+
+ Standard printf function with a subset of formating features supported.
+
+ Currently handles
+
+ %d, %ld - signed short, signed long
+ %u, %lu - unsigned short, unsigned long
+ %c, %s - character, string
+ %x, %lx - unsigned print in hex, unsigned long print in hex
+
+ Does not do:
+
+ - field width specification
+ - floating point.
+
+Arguments:
+
+ cp - pointer to the format string, text string.
+
+
+Returns:
+
+ Nothing
+
+
+--*/
+
+{
+}
+
+VOID clrscrn(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Clears the video display by writing blanks with the current
+ video attribute over the entire display.
+
+
+Arguments:
+
+ None
+
+Returns:
+
+ Nothing
+
+
+--*/
+
+{
+}
+#endif
diff --git a/private/ntos/boot/detect/i386/eisa.h b/private/ntos/boot/detect/i386/eisa.h
new file mode 100644
index 000000000..29f643a91
--- /dev/null
+++ b/private/ntos/boot/detect/i386/eisa.h
@@ -0,0 +1,215 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ eisa.h
+
+Abstract:
+
+ This module contains the i386 EISA bus specific header file.
+
+Author:
+
+ Shie-Lin Tzong (shielint) 6-June-1991
+
+Revision History:
+
+--*/
+
+//
+// SU module's version of the memory descriptor
+//
+typedef struct _MEMORY_LIST_ENTRY {
+ ULONG BlockBase;
+ ULONG BlockSize;
+} MEMORY_LIST_ENTRY, *PMEMORY_LIST_ENTRY;
+
+//
+// Memory configuration of eisa data block structure
+//
+
+typedef struct _EISA_MEMORY_TYPE {
+ UCHAR ReadWrite: 1;
+ UCHAR Cached : 1;
+ UCHAR Reserved0 :1;
+ UCHAR Type:2;
+ UCHAR Shared:1;
+ UCHAR Reserved1 :1;
+ UCHAR MoreEntries : 1;
+} EISA_MEMORY_TYPE, *PEISA_MEMORY_TYPE;
+
+typedef struct _BTEISA_MEMORY_CONFIGURATION {
+ EISA_MEMORY_TYPE ConfigurationByte;
+ UCHAR DataSize;
+ USHORT PhysicalAddress_LSW;
+ UCHAR PhysicalAddress_MSB;
+ USHORT MemorySize;
+} BTEISA_MEMORY_CONFIGURATION, *PBTEISA_MEMORY_CONFIGURATION;
+
+//
+// Interrupt configurationn of eisa data block structure
+//
+
+typedef struct _EISA_IRQ_DESCRIPTOR {
+ UCHAR Interrupt : 4;
+ UCHAR Reserved :1;
+ UCHAR LevelTriggered :1;
+ UCHAR Shared : 1;
+ UCHAR MoreEntries : 1;
+} EISA_IRQ_DESCRIPTOR, *PEISA_IRQ_DESCRIPTOR;
+
+typedef struct _BTEISA_IRQ_CONFIGURATION {
+ EISA_IRQ_DESCRIPTOR ConfigurationByte;
+ UCHAR Reserved;
+} BTEISA_IRQ_CONFIGURATION, *PBTEISA_IRQ_CONFIGURATION;
+
+//
+// DMA description of eisa data block structure
+//
+
+typedef struct _DMA_CONFIG_BYTE0 {
+ UCHAR Channel : 3;
+ UCHAR Reserved : 3;
+ UCHAR Shared :1;
+ UCHAR MoreEntries :1;
+} DMA_CONFIG_BYTE0;
+
+typedef struct _DMA_CONFIG_BYTE1 {
+ UCHAR Reserved0 : 2;
+ UCHAR TransferSize : 2;
+ UCHAR Timing : 2;
+ UCHAR Reserved1 : 2;
+} DMA_CONFIG_BYTE1;
+
+typedef struct _BTEISA_DMA_CONFIGURATION {
+ DMA_CONFIG_BYTE0 ConfigurationByte0;
+ DMA_CONFIG_BYTE1 ConfigurationByte1;
+} BTEISA_DMA_CONFIGURATION, *PBTEISA_DMA_CONFIGURATION;
+
+typedef struct _EISA_PORT_DESCRIPTOR {
+ UCHAR NumberPorts : 5;
+ UCHAR Reserved :1;
+ UCHAR Shared :1;
+ UCHAR MoreEntries : 1;
+} EISA_PORT_DESCRIPTOR, *TEISA_PORT_DESCRIPTOR;
+
+typedef struct _BTEISA_PORT_CONFIGURATION {
+ EISA_PORT_DESCRIPTOR Configuration;
+ USHORT PortAddress;
+} BTEISA_PORT_CONFIGURATION, *PBTEISA_PORT_CONFIGURATION;
+
+typedef struct _BTEISA_SLOT_INFORMATION {
+ UCHAR ReturnCode;
+ UCHAR ReturnFlags;
+ UCHAR MajorRevision;
+ UCHAR MinorRevision;
+ USHORT Checksum;
+ UCHAR NumberFunctions;
+ UCHAR FunctionInformation;
+ ULONG CompressedId;
+} BTEISA_SLOT_INFORMATION, *PBTEISA_SLOT_INFORMATION,
+ far *FPBTEISA_SLOT_INFORMATION;
+
+typedef struct _BTEISA_FUNCTION_INFORMATION {
+ ULONG CompressedId;
+ UCHAR IdSlotFlags1;
+ UCHAR IdSlotFlags2;
+ UCHAR MinorRevision;
+ UCHAR MajorRevision;
+ UCHAR Selections[26];
+ UCHAR FunctionFlags;
+ UCHAR TypeString[80];
+ BTEISA_MEMORY_CONFIGURATION EisaMemory[9];
+ BTEISA_IRQ_CONFIGURATION EisaIrq[7];
+ BTEISA_DMA_CONFIGURATION EisaDma[4];
+ BTEISA_PORT_CONFIGURATION EisaPort[20];
+ UCHAR InitializationData[60];
+} BTEISA_FUNCTION_INFORMATION, *PBTEISA_FUNCTION_INFORMATION,
+ far *FPBTEISA_FUNCTION_INFORMATION;
+
+//
+// Masks for EISA function information
+//
+
+#define EISA_FUNCTION_ENABLED 0x80
+#define EISA_FREE_FORM_DATA 0x40
+#define EISA_HAS_PORT_INIT_ENTRY 0x20
+#define EISA_HAS_PORT_RANGE 0x10
+#define EISA_HAS_DMA_ENTRY 0x08
+#define EISA_HAS_IRQ_ENTRY 0x04
+#define EISA_HAS_MEMORY_ENTRY 0x02
+#define EISA_HAS_TYPE_ENTRY 0x01
+#define EISA_HAS_INFORMATION EISA_HAS_PORT_RANGE + \
+ EISA_HAS_DMA_ENTRY + \
+ EISA_HAS_IRQ_ENTRY + \
+ EISA_HAS_MEMORY_ENTRY + \
+ EISA_HAS_TYPE_ENTRY
+
+//
+// Masks for EISA memory configuration
+//
+
+#define EISA_MORE_ENTRIES 0x80
+#define EISA_SYSTEM_MEMORY 0x00
+#define EISA_MEMORY_TYPE_RAM 0x01
+
+//
+// Returned error code for EISA bios call
+//
+
+#define EISA_INVALID_SLOT 0x80
+#define EISA_INVALID_FUNCTION 0x81
+#define EISA_INVALID_CONFIGURATION 0x82
+#define EISA_EMPTY_SLOT 0x83
+#define EISA_INVALID_BIOS_CALL 0x86
+
+//
+// Misc. definitions
+//
+
+#define _16MEGB ((ULONG)16 * 1024 * 1024)
+#define _64MEGB ((ULONG)64 * 1024 * 1024)
+
+BOOLEAN
+FindFunctionInformation (
+ IN UCHAR SlotFlags,
+ IN UCHAR FunctionFlags,
+ OUT PBTEISA_FUNCTION_INFORMATION Buffer,
+ IN BOOLEAN FromBeginning
+ );
+
+USHORT
+CountMemoryBlocks (
+ VOID
+ );
+
+ULONG
+EisaConstructMemoryDescriptors (
+ VOID
+ );
+
+UCHAR
+BtGetEisaSlotInformation (
+ PBTEISA_SLOT_INFORMATION SlotInformation,
+ UCHAR Slot
+ );
+
+UCHAR
+BtGetEisaFunctionInformation (
+ PBTEISA_FUNCTION_INFORMATION FunctionInformation,
+ UCHAR Slot,
+ UCHAR Function
+ );
+
+BOOLEAN
+BtIsEisaSystem (
+ VOID
+ );
+
+//
+// External References
+//
+
+extern MEMORY_LIST_ENTRY _far *MemoryDescriptorList;
diff --git a/private/ntos/boot/detect/i386/hwapm.c b/private/ntos/boot/detect/i386/hwapm.c
new file mode 100644
index 000000000..0511a5dae
--- /dev/null
+++ b/private/ntos/boot/detect/i386/hwapm.c
@@ -0,0 +1,79 @@
+
+/*++
+
+Copyright (c) 1990, 1991 Microsoft Corporation
+
+
+Module Name:
+
+ hwapm.c
+
+Abstract:
+
+Author:
+
+
+Environment:
+
+ Real mode.
+
+Revision History:
+
+--*/
+
+
+#include "hwdetect.h"
+#include <string.h>
+
+#if _PNP_POWER_
+
+#include "apm.h"
+
+VOID Int15 (PULONG, PULONG, PULONG, PULONG, PULONG);
+
+BOOLEAN
+HwGetApmSystemData(
+ IN PAPM_REGISTRY_INFO ApmEntry
+ )
+{
+ ULONG RegEax, RegEbx, RegEcx, RegEdx, CyFlag;
+
+ //
+ // Perform APM installation check
+ //
+
+ RegEax = APM_INSTALLATION_CHECK;
+ RegEbx = APM_DEVICE_BIOS;
+ Int15 (&RegEax, &RegEbx, &RegEcx, &RegEdx, &CyFlag);
+
+ if (CyFlag ||
+ (RegEbx & 0xff) != 'M' ||
+ ((RegEbx >> 8) & 0xff) != 'P') {
+
+ return FALSE;
+ }
+
+ ApmEntry->ApmRevMajor = (UCHAR) (RegEax >> 8) & 0xff;
+ ApmEntry->ApmRevMinor = (UCHAR) RegEax & 0xff;
+ ApmEntry->ApmInstallFlags = (USHORT) RegEcx;
+
+ //
+ // Connect to 32 bit interface
+ //
+
+ RegEax = APM_PROTECT_MODE_16bit_CONNECT;
+ RegEbx = APM_DEVICE_BIOS;
+ Int15 (&RegEax, &RegEbx, &RegEcx, &RegEdx, &CyFlag);
+
+ if (CyFlag) {
+ return FALSE;
+ }
+
+ ApmEntry->Code16BitSegmentBase = (USHORT) RegEax;
+ ApmEntry->Code16BitOffset = (USHORT) RegEbx;
+ ApmEntry->Data16BitSegment = (USHORT) RegEcx;
+
+ return TRUE;
+}
+
+#endif // _PNP_POWER_
diff --git a/private/ntos/boot/detect/i386/hwdetect.c b/private/ntos/boot/detect/i386/hwdetect.c
new file mode 100644
index 000000000..9a73fbc25
--- /dev/null
+++ b/private/ntos/boot/detect/i386/hwdetect.c
@@ -0,0 +1,1393 @@
+/*++
+
+Copyright (c) 1990, 1991 Microsoft Corporation
+
+
+Module Name:
+
+ hwdetect.c
+
+Abstract:
+
+ This is the main hardware detection module. Its main function is
+ to detect various system hardware and build a configuration tree.
+
+ N.B. The configuration built in the detection module will needs to
+ be adjusted later before we switch to FLAT mode. The is because
+ all the "POINTER" is a far pointer instead of a flat pointer.
+
+Author:
+
+ Shie-Lin Tzong (shielint) 16-Jan-92
+
+
+Environment:
+
+ Real mode.
+
+Revision History:
+
+--*/
+
+#include "hwdetect.h"
+#include "pci.h"
+#include <string.h>
+#include "apm.h"
+
+
+#if DBG
+
+PUCHAR TypeName[] = {
+ "ArcSystem",
+ "CentralProcessor",
+ "FloatingPointProcessor",
+ "PrimaryICache",
+ "PrimaryDCache",
+ "SecondaryICache",
+ "SecondaryDCache",
+ "SecondaryCache",
+ "EisaAdapter",
+ "TcaAdapter",
+ "ScsiAdapter",
+ "DtiAdapter",
+ "MultifunctionAapter",
+ "DiskController",
+ "TapeController",
+ "CdRomController",
+ "WormController",
+ "SerialController",
+ "NetworkController",
+ "DisplayController",
+ "ParallelController",
+ "PointerController",
+ "KeyboardController",
+ "AudioController",
+ "OtherController",
+ "DiskPeripheral",
+ "FloppyDiskPeripheral",
+ "TapePeripheral",
+ "ModemPeripheral",
+ "MonitorPeripheral",
+ "PrinterPeraipheral",
+ "PointerPeripheral",
+ "KeyboardPeripheral",
+ "TerminalPeripheral",
+ "OtherPeripheral",
+ "LinePeripheral",
+ "NetworkPeripheral",
+ "SystemMemory",
+ "MaximumType"
+ };
+
+VOID
+CheckConfigurationTree(
+ FPFWCONFIGURATION_COMPONENT_DATA CurrentEntry
+ );
+
+extern
+USHORT
+HwGetKey(
+ VOID
+ );
+#endif
+
+VOID
+GetIrqFromEisaData(
+ FPFWCONFIGURATION_COMPONENT_DATA ControllerList,
+ CONFIGURATION_TYPE ControllerType
+ );
+
+//
+// HwBusType - defines the BUS type of the machine.
+// This variable is used by detection code only.
+//
+
+USHORT HwBusType = 0;
+
+//
+// AdapterEntry is the Configuration_Component_data for the bus adapter
+//
+
+FPFWCONFIGURATION_COMPONENT_DATA AdapterEntry = NULL;
+
+//
+// FpRomBlock - A far pointer to our Rom Block
+//
+
+FPUCHAR FpRomBlock = NULL;
+USHORT RomBlockLength = 0;
+
+//
+// HwMcaPosData - A far pointer to the POS data block of MCA machine
+//
+
+FPMCA_POS_DATA HwMcaPosData;
+
+//
+// HwEisaConfigurationData - A far pointer to the EISA configuration
+// data on EISA machine.
+//
+
+FPUCHAR HwEisaConfigurationData = NULL;
+ULONG HwEisaConfigurationSize = 0L;
+
+//
+// DisableSerialMice - A bit flags to indicate the comports whose serial
+// mouse detection should be skipped.
+//
+
+USHORT DisableSerialMice = 0x0;
+
+//
+// Internal references and definitions.
+//
+
+typedef enum _RELATIONSHIP_FLAGS {
+ Child,
+ Sibling,
+ Parent
+} RELATIONSHIP_FLAGS;
+
+
+VOID
+HardwareDetection(
+ ULONG HeapStart,
+ ULONG HeapSize,
+ ULONG ConfigurationTree,
+ ULONG HeapUsed,
+ ULONG OptionString,
+ ULONG OptionStringLength
+ )
+/*++
+
+Routine Description:
+
+ Main entrypoint of the HW recognizer test. The routine builds
+ a configuration tree and leaves it in the hardware heap.
+
+Arguments:
+
+ HeapStart - Supplies the starting address of the configuaration heap.
+
+ HeapSize - Supplies the size of the heap in byte.
+
+ ConfigurationTree - Supplies a 32 bit FLAT address of the variable to
+ receive the hardware configuration tree.
+
+ HeapUsed - Supplies a 32 bit FLAT address of the variable to receive
+ the actual heap size in used.
+
+ OptionString - Supplies a 32 bit FLAT address of load option string.
+
+ OptionStringLength - Supplies the length of the OptionString
+
+Returns:
+
+ None.
+
+--*/
+{
+ FPFWCONFIGURATION_COMPONENT_DATA ConfigurationRoot;
+ FPFWCONFIGURATION_COMPONENT_DATA FirstCom = NULL, FirstLpt = NULL;
+ FPFWCONFIGURATION_COMPONENT_DATA CurrentEntry, PreviousEntry;
+ FPFWCONFIGURATION_COMPONENT Component;
+ RELATIONSHIP_FLAGS NextRelationship;
+ CHAR Identifier[256];
+ USHORT BiosYear, BiosMonth, BiosDay;
+ PUCHAR MachineId;
+ USHORT Length, InitialLength, i, Count = 0;
+ FPCHAR IdentifierString;
+ PMOUSE_INFORMATION MouseInfo = 0;
+ USHORT KeyboardId = 0;
+ ULONG VideoAdapterType = 0;
+ FPULONG BlConfigurationTree = NULL;
+ FPULONG BlHeapUsed = NULL;
+ FPCHAR BlOptions, EndOptions;
+ PUCHAR RomChain;
+ FPUCHAR FpRomChain = NULL, ConfigurationData, EndConfigurationData;
+ SHORT FreeSize;
+ FPHWPARTIAL_RESOURCE_DESCRIPTOR Descriptor;
+ FPHWRESOURCE_DESCRIPTOR_LIST DescriptorList;
+ PCI_REGISTRY_INFO PciEntry;
+ APM_REGISTRY_INFO ApmEntry;
+
+
+ //
+ // First initialize our hardware heap.
+ //
+
+ HwInitializeHeap(HeapStart, HeapSize);
+
+ MAKE_FP(BlConfigurationTree, ConfigurationTree);
+ MAKE_FP(BlHeapUsed, HeapUsed);
+ MAKE_FP(BlOptions, OptionString);
+
+ //
+ // Parse OptionString and see if we need to disable serial mice detection.
+ //
+
+ if (BlOptions && OptionStringLength <= 0x1000L && OptionStringLength > 0L) {
+ EndOptions = BlOptions + OptionStringLength;
+ if (*EndOptions == '\0') {
+ do {
+ if (BlOptions = _fstrstr(BlOptions, "NOSERIALMICE")) {
+ BlOptions += strlen("NOSERIALMICE");
+ while ((*BlOptions == ' ') || (*BlOptions == ':') ||
+ (*BlOptions == '=')) {
+ BlOptions++;
+ }
+ if (*BlOptions == 'C' && BlOptions[1] == 'O' &&
+ BlOptions[2] == 'M') {
+ BlOptions += 3;
+ while (TRUE) {
+ while (*BlOptions != '\0' && (*BlOptions == ' ' ||
+ *BlOptions == ',' || *BlOptions == ';' ||
+ *BlOptions == '0')) {
+ BlOptions++;
+ }
+ if (*BlOptions >= '0' && *BlOptions <= '9') {
+ if (BlOptions[1] < '0' || BlOptions[1] > '9') {
+ DisableSerialMice |= 1 << (*BlOptions - '0');
+ BlOptions++;
+ } else {
+ BlOptions++;
+ while (*BlOptions && *BlOptions <= '9' &&
+ *BlOptions >= '0') {
+ BlOptions++;
+ }
+ }
+ }else {
+ break;
+ }
+ }
+ } else {
+ DisableSerialMice = 0xffff;
+ break;
+ }
+ }
+ } while (BlOptions && *BlOptions && (BlOptions < EndOptions)); // double checking
+ }
+ }
+
+ //
+ // Determine bus type
+ //
+
+ if (HwIsEisaSystem()) {
+ HwBusType = MACHINE_TYPE_EISA;
+ } else if (HwIsMcaSystem()) {
+ HwBusType = MACHINE_TYPE_MCA;
+ } else {
+ HwBusType = MACHINE_TYPE_ISA;
+ }
+
+ //
+ // Allocate heap space for System component and initialize it.
+ // Also make the System component the root of configuration tree.
+ //
+
+#if DBG
+ clrscrn ();
+ BlPrint("Detecting System Component ...\n");
+#endif
+
+ ConfigurationRoot = (FPFWCONFIGURATION_COMPONENT_DATA)HwAllocateHeap (
+ sizeof(FWCONFIGURATION_COMPONENT_DATA), TRUE);
+ Component = &ConfigurationRoot->ComponentEntry;
+
+ Component->Class = SystemClass;
+ Component->Type = MaximumType; // NOTE should be IsaCompatible
+ Component->Version = 0;
+ Component->Key = 0;
+ Component->AffinityMask = 0;
+ Component->ConfigurationDataLength = 0;
+ MachineId = GetMachineId();
+ if (MachineId) {
+ Length = strlen(MachineId) + 1;
+ IdentifierString = (FPCHAR)HwAllocateHeap(Length, FALSE);
+ _fstrcpy(IdentifierString, MachineId);
+ Component->Identifier = IdentifierString;
+ Component->IdentifierLength = Length;
+ } else {
+ Component->Identifier = 0;
+ Component->IdentifierLength = 0;
+ }
+ NextRelationship = Child;
+ PreviousEntry = ConfigurationRoot;
+
+#if DBG
+ BlPrint("Reading BIOS date ...\n");
+#endif
+
+ HwGetBiosDate (0xF0000, 0xFFFF, &BiosYear, &BiosMonth, &BiosDay);
+
+#if DBG
+ BlPrint("Done reading BIOS date (%d/%d/%d)\n",
+ BiosMonth, BiosDay, BiosYear);
+#endif
+
+
+#if DBG
+ BlPrint("Detecting PCI Bus Component ...\n");
+#endif
+
+ if (BiosYear > 1992 || (BiosYear == 1992 && BiosMonth >= 11) ) {
+
+ // Bios date valid for pci presence check..
+ HwGetPciSystemData((PVOID) &PciEntry, TRUE);
+
+ } else {
+
+ // Bios date not confirmed...
+ HwGetPciSystemData((PVOID) &PciEntry, FALSE);
+ }
+
+ //
+ // Add a registry entry for each PCI bus
+ //
+
+ for (i=0; i < PciEntry.NoBuses; i++) {
+
+ AdapterEntry = (FPFWCONFIGURATION_COMPONENT_DATA)HwAllocateHeap (
+ sizeof(FWCONFIGURATION_COMPONENT_DATA), TRUE);
+
+ Component = &AdapterEntry->ComponentEntry;
+ Component->Class = AdapterClass;
+ Component->Type = MultiFunctionAdapter;
+
+ strcpy (Identifier, "PCI");
+ Length = strlen(Identifier) + 1;
+ IdentifierString = (FPCHAR)HwAllocateHeap(Length, FALSE);
+ _fstrcpy(IdentifierString, Identifier);
+
+ Component->Version = 0;
+ Component->Key = 0;
+ Component->AffinityMask = 0xffffffff;
+ Component->IdentifierLength = Length;
+ Component->Identifier = IdentifierString;
+
+ AdapterEntry->ConfigurationData = NULL;
+ Component->ConfigurationDataLength = 0;
+
+ if (i == 0) {
+ //
+ // For the first PCI bus include the PCI_REGISTRY_INFO
+ //
+
+ Length = sizeof(PCI_REGISTRY_INFO) + DATA_HEADER_SIZE;
+ ConfigurationData = (FPUCHAR) HwAllocateHeap(Length, TRUE);
+
+ Component->ConfigurationDataLength = Length;
+ AdapterEntry->ConfigurationData = ConfigurationData;
+
+ _fmemcpy ( ((FPUCHAR) ConfigurationData+DATA_HEADER_SIZE),
+ (FPVOID) &PciEntry, sizeof (PCI_REGISTRY_INFO));
+
+ HwSetUpFreeFormDataHeader(
+ (FPHWRESOURCE_DESCRIPTOR_LIST) ConfigurationData,
+ 0,
+ 0,
+ 0,
+ Length - DATA_HEADER_SIZE
+ );
+ }
+
+ //
+ // Add it to tree
+ //
+
+ if (NextRelationship == Sibling) {
+ PreviousEntry->Sibling = AdapterEntry;
+ AdapterEntry->Parent = PreviousEntry->Parent;
+ } else {
+ PreviousEntry->Child = AdapterEntry;
+ AdapterEntry->Parent = PreviousEntry;
+ }
+
+ NextRelationship = Sibling;
+ PreviousEntry = AdapterEntry;
+ }
+
+#if DBG
+ BlPrint("Detecting PCI Bus Component completes ...\n");
+#endif
+
+#if _PNP_POWER_
+
+#if DBG
+ BlPrint("Detecting APM Bus Component ...\n");
+#endif
+
+ if (HwGetApmSystemData((PVOID) &ApmEntry)) {
+ AdapterEntry = (FPFWCONFIGURATION_COMPONENT_DATA)HwAllocateHeap (
+ sizeof(FWCONFIGURATION_COMPONENT_DATA), TRUE);
+
+ Component = &AdapterEntry->ComponentEntry;
+ Component->Class = AdapterClass;
+ Component->Type = MultiFunctionAdapter;
+
+ strcpy (Identifier, "APM");
+ Length = strlen(Identifier) + 1;
+ IdentifierString = (FPCHAR)HwAllocateHeap(Length, FALSE);
+ _fstrcpy(IdentifierString, Identifier);
+
+ Component->Version = 0;
+ Component->Key = 0;
+ Component->AffinityMask = 0xffffffff;
+ Component->IdentifierLength = Length;
+ Component->Identifier = IdentifierString;
+
+ AdapterEntry->ConfigurationData = NULL;
+ Component->ConfigurationDataLength = 0;
+
+ //
+
+ Length = sizeof(APM_REGISTRY_INFO) + DATA_HEADER_SIZE;
+ ConfigurationData = (FPUCHAR) HwAllocateHeap(Length, TRUE);
+
+ Component->ConfigurationDataLength = Length;
+ AdapterEntry->ConfigurationData = ConfigurationData;
+
+ _fmemcpy ( ((FPUCHAR) ConfigurationData+DATA_HEADER_SIZE),
+ (FPVOID) &ApmEntry, sizeof (APM_REGISTRY_INFO));
+
+ HwSetUpFreeFormDataHeader(
+ (FPHWRESOURCE_DESCRIPTOR_LIST) ConfigurationData,
+ 0,
+ 0,
+ 0,
+ Length - DATA_HEADER_SIZE
+ );
+
+ //
+ // Add it to tree
+ //
+
+ if (NextRelationship == Sibling) {
+ PreviousEntry->Sibling = AdapterEntry;
+ AdapterEntry->Parent = PreviousEntry->Parent;
+ } else {
+ PreviousEntry->Child = AdapterEntry;
+ AdapterEntry->Parent = PreviousEntry;
+ }
+
+ NextRelationship = Sibling;
+ PreviousEntry = AdapterEntry;
+ }
+
+#if DBG
+ BlPrint("APM Data collection complete...\n");
+#endif // DBG
+
+#endif // _PNP_POWER_
+
+#if DBG
+ BlPrint("Detecting PnP BIOS Bus Component ...\n");
+#endif
+
+ if (HwGetPnpBiosSystemData(&ConfigurationData, &Length)) {
+ AdapterEntry = (FPFWCONFIGURATION_COMPONENT_DATA)HwAllocateHeap (
+ sizeof(FWCONFIGURATION_COMPONENT_DATA), TRUE);
+
+ AdapterEntry->ConfigurationData = ConfigurationData;
+ Component = &AdapterEntry->ComponentEntry;
+ Component->ConfigurationDataLength = Length;
+
+ Component->Class = AdapterClass;
+ Component->Type = MultiFunctionAdapter;
+
+ strcpy (Identifier, "PNP BIOS");
+ i = strlen(Identifier) + 1;
+ IdentifierString = (FPCHAR)HwAllocateHeap(i, FALSE);
+ _fstrcpy(IdentifierString, Identifier);
+
+ Component->Version = 0;
+ Component->Key = 0;
+ Component->AffinityMask = 0xffffffff;
+ Component->IdentifierLength = i;
+ Component->Identifier = IdentifierString;
+
+ HwSetUpFreeFormDataHeader(
+ (FPHWRESOURCE_DESCRIPTOR_LIST) ConfigurationData,
+ 0,
+ 0,
+ 0,
+ Length - DATA_HEADER_SIZE
+ );
+
+ //
+ // Add it to tree
+ //
+
+ if (NextRelationship == Sibling) {
+ PreviousEntry->Sibling = AdapterEntry;
+ AdapterEntry->Parent = PreviousEntry->Parent;
+ } else {
+ PreviousEntry->Child = AdapterEntry;
+ AdapterEntry->Parent = PreviousEntry;
+ }
+
+ NextRelationship = Sibling;
+ PreviousEntry = AdapterEntry;
+ }
+
+#if DBG
+ BlPrint("PnP BIOS Data collection complete...\n");
+#endif // DBG
+
+ //
+ // Allocate heap space for Bus component and initialize it.
+ //
+
+#if DBG
+ BlPrint("Detecting Bus/Adapter Component ...\n");
+#endif
+
+ AdapterEntry = (FPFWCONFIGURATION_COMPONENT_DATA)HwAllocateHeap (
+ sizeof(FWCONFIGURATION_COMPONENT_DATA), TRUE);
+
+ Component = &AdapterEntry->ComponentEntry;
+
+ Component->Class = AdapterClass;
+
+ //
+ // The assumption here is that the machine has only one
+ // type of IO bus. If a machine has more than one types of
+ // IO buses, it will not use this detection code anyway.
+ //
+
+ if (HwBusType == MACHINE_TYPE_EISA) {
+
+ //
+ // Note We don't collect EISA config data here. Because we may
+ // exhaust the heap space. We will collect the data after all
+ // the other components are detected.
+ //
+
+ Component->Type = EisaAdapter;
+ strcpy(Identifier, "EISA");
+ AdapterEntry->ConfigurationData = NULL;
+ Component->ConfigurationDataLength = 0;
+
+ } else if (HwBusType == MACHINE_TYPE_MCA) {
+
+ Component->Type = MultiFunctionAdapter;
+ strcpy(Identifier, "MCA");
+ GetMcaPosData(&AdapterEntry->ConfigurationData,
+ &Component->ConfigurationDataLength);
+ HwMcaPosData = (FPMCA_POS_DATA)
+ ((FPUCHAR)AdapterEntry->ConfigurationData + DATA_HEADER_SIZE);
+
+ } else {
+
+ //
+ // If not EISA or MCA, it must be ISA
+ //
+
+ Component->Type = MultiFunctionAdapter;
+ strcpy(Identifier, "ISA");
+ }
+ Length = strlen(Identifier) + 1;
+ IdentifierString = (FPCHAR)HwAllocateHeap(Length, FALSE);
+ _fstrcpy(IdentifierString, Identifier);
+ Component->Version = 0;
+ Component->Key = 0;
+ Component->AffinityMask = 0xffffffff;
+ Component->IdentifierLength = Length;
+ Component->Identifier = IdentifierString;
+
+ //
+ // Make Adapter component System's child
+ //
+
+ if (NextRelationship == Sibling) {
+ PreviousEntry->Sibling = AdapterEntry;
+ AdapterEntry->Parent = PreviousEntry->Parent;
+ } else {
+ PreviousEntry->Child = AdapterEntry;
+ AdapterEntry->Parent = PreviousEntry;
+ }
+ NextRelationship = Child;
+ PreviousEntry = AdapterEntry;
+
+ //
+ // Collect BIOS information for ConfigurationRoot component.
+ // This step is done here because we need data collected in
+ // adapter component. The ConfigurationData is:
+ // HWRESOURCE_DESCRIPTOR_LIST header
+ // HWPARTIAL_RESOURCE_DESCRIPTOR for Parameter Table
+ // HWPARTIAL_RESOURCE_DESCRIPTOR for Rom Blocks.
+ // (Note DATA_HEADER_SIZE contains the size of the first partial
+ // descriptor already.)
+ //
+
+#if DBG
+ BlPrint("Collecting Disk Geometry...\n");
+#endif
+
+ GetInt13DriveParameters((PVOID)&RomChain, &Length);
+ InitialLength = (USHORT)(Length + RESERVED_ROM_BLOCK_LIST_SIZE + DATA_HEADER_SIZE +
+ sizeof(HWPARTIAL_RESOURCE_DESCRIPTOR));
+ ConfigurationData = (FPUCHAR)HwAllocateHeap(InitialLength, FALSE);
+ EndConfigurationData = ConfigurationData + DATA_HEADER_SIZE;
+ if (Length != 0) {
+ FpRomChain = EndConfigurationData;
+ _fmemcpy(FpRomChain, (FPVOID)RomChain, Length);
+ }
+ EndConfigurationData += (sizeof(HWPARTIAL_RESOURCE_DESCRIPTOR) +
+ Length);
+ HwSetUpFreeFormDataHeader((FPHWRESOURCE_DESCRIPTOR_LIST)ConfigurationData,
+ 0,
+ 0,
+ 0,
+ Length
+ );
+
+ //
+ // Scan ROM to collect all the ROM blocks, if possible.
+ //
+
+#if DBG
+ BlPrint("Detecting ROM Blocks...\n");
+#endif
+
+ FpRomBlock = EndConfigurationData;
+ GetRomBlocks(FpRomBlock, &Length);
+ RomBlockLength = Length;
+ if (Length != 0) {
+ EndConfigurationData += Length;
+ } else {
+ FpRomBlock = NULL;
+ }
+
+ //
+ // We have both RomChain and RomBlock information/Headers.
+ //
+
+ DescriptorList = (FPHWRESOURCE_DESCRIPTOR_LIST)ConfigurationData;
+ DescriptorList->Count = 2;
+ Descriptor = (FPHWPARTIAL_RESOURCE_DESCRIPTOR)(
+ EndConfigurationData - Length -
+ sizeof(HWPARTIAL_RESOURCE_DESCRIPTOR));
+ Descriptor->Type = RESOURCE_DEVICE_DATA;
+ Descriptor->ShareDisposition = 0;
+ Descriptor->Flags = 0;
+ Descriptor->u.DeviceSpecificData.DataSize = (ULONG)Length;
+ Descriptor->u.DeviceSpecificData.Reserved1 = 0;
+ Descriptor->u.DeviceSpecificData.Reserved2 = 0;
+
+ Length = (USHORT)(MAKE_FLAT_ADDRESS(EndConfigurationData) -
+ MAKE_FLAT_ADDRESS(ConfigurationData));
+ ConfigurationRoot->ComponentEntry.ConfigurationDataLength = Length;
+ ConfigurationRoot->ConfigurationData = ConfigurationData;
+ FreeSize = InitialLength - Length;
+
+ HwFreeHeap((ULONG)FreeSize);
+
+ //
+ // Set up device information structure for Keyboard.
+ //
+
+#if DBG
+ BlPrint("Detecting Keyboard Component ...\n");
+#endif
+
+ KeyboardId = GetKeyboardId();
+
+ CurrentEntry = SetKeyboardConfigurationData(KeyboardId);
+
+ //
+ // Make display component the child of Adapter component.
+ //
+
+ if (NextRelationship == Sibling) {
+ PreviousEntry->Sibling = CurrentEntry;
+ CurrentEntry->Parent = PreviousEntry->Parent;
+ } else {
+ PreviousEntry->Child = CurrentEntry;
+ CurrentEntry->Parent = PreviousEntry;
+ }
+ NextRelationship = Sibling;
+ PreviousEntry = CurrentEntry;
+
+ //
+ // Set up device information for com port (Each COM component
+ // is treated as a controller class.)
+ //
+
+#if DBG
+ BlPrint("Detecting ComPort Component ...\n");
+#endif
+
+ if (CurrentEntry = GetComportInformation()) {
+
+ FirstCom = CurrentEntry;
+
+ //
+ // Make current component the child of Adapter component.
+ //
+
+ if (NextRelationship == Sibling) {
+ PreviousEntry->Sibling = CurrentEntry;
+ } else {
+ PreviousEntry->Child = CurrentEntry;
+ }
+ while (CurrentEntry) {
+ CurrentEntry->Parent = AdapterEntry;
+ PreviousEntry = CurrentEntry;
+ CurrentEntry = CurrentEntry->Sibling;
+ }
+ NextRelationship = Sibling;
+ }
+
+ //
+ // Set up device information for parallel port. (Each parallel
+ // is treated as a controller class.)
+ //
+
+#if DBG
+ BlPrint("Detecting Parallel Component ...\n");
+#endif
+
+ if (CurrentEntry = GetLptInformation()) {
+
+ FirstLpt = CurrentEntry;
+
+ //
+ // Make current component the child of Adapter component.
+ //
+
+ if (NextRelationship == Sibling) {
+ PreviousEntry->Sibling = CurrentEntry;
+ CurrentEntry->Parent = PreviousEntry->Parent;
+ } else {
+ PreviousEntry->Child = CurrentEntry;
+ CurrentEntry->Parent = PreviousEntry;
+ }
+ PreviousEntry = CurrentEntry;
+ CurrentEntry = CurrentEntry->Sibling;
+ while (CurrentEntry) {
+ CurrentEntry->Parent = PreviousEntry->Parent;
+ PreviousEntry = CurrentEntry;
+ CurrentEntry = CurrentEntry->Sibling;
+ }
+ NextRelationship = Sibling;
+ }
+
+ //
+ // Set up device information structure for Mouse.
+ //
+
+#if DBG
+ BlPrint("Detecting Mouse Component ...\n");
+#endif
+
+ if (CurrentEntry = GetMouseInformation()) {
+
+ //
+ // Make current component the child of Adapter component.
+ //
+
+ if (NextRelationship == Sibling) {
+ PreviousEntry->Sibling = CurrentEntry;
+ CurrentEntry->Parent = PreviousEntry->Parent;
+ } else {
+ PreviousEntry->Child = CurrentEntry;
+ CurrentEntry->Parent = PreviousEntry;
+ }
+ PreviousEntry = CurrentEntry;
+ CurrentEntry = CurrentEntry->Sibling;
+ while (CurrentEntry) {
+ CurrentEntry->Parent = PreviousEntry->Parent;
+ PreviousEntry = CurrentEntry;
+ CurrentEntry = CurrentEntry->Sibling;
+ }
+ NextRelationship = Sibling;
+ }
+
+ //
+ // Set up device information for floppy drives. (The returned information
+ // is a tree structure.)
+ //
+
+#if DBG
+ BlPrint("Detecting Floppy Component ...\n");
+#endif
+
+ if (CurrentEntry = GetFloppyInformation()) {
+
+ //
+ // Make current component the child of Adapter component.
+ //
+
+ if (NextRelationship == Sibling) {
+ PreviousEntry->Sibling = CurrentEntry;
+ } else {
+ PreviousEntry->Child = CurrentEntry;
+ }
+ while (CurrentEntry) {
+ CurrentEntry->Parent = AdapterEntry;
+ PreviousEntry = CurrentEntry;
+ CurrentEntry = CurrentEntry->Sibling;
+ }
+ NextRelationship = Sibling;
+ }
+
+ //
+ // Set up device information structure for Video Display Adapter.
+ //
+
+#if DBG
+ BlPrint("Detection done. Press a key to display hardware info ...\n");
+ while ( ! HwGetKey ());
+ clrscrn ();
+// BlPrint("Detecting Video Component ...\n");
+#endif
+
+#if 0 // Remove video detection
+ if (VideoAdapterType = GetVideoAdapterType()) {
+
+ CurrentEntry = SetVideoConfigurationData(VideoAdapterType);
+
+ //
+ // Make display component the child of Adapter component.
+ //
+
+ if (NextRelationship == Sibling) {
+ PreviousEntry->Sibling = CurrentEntry;
+ CurrentEntry->Parent = PreviousEntry->Parent;
+ } else {
+ PreviousEntry->Child = CurrentEntry;
+ CurrentEntry->Parent = PreviousEntry;
+ }
+ NextRelationship = Sibling;
+ PreviousEntry = CurrentEntry;
+ }
+#endif
+
+ //
+ // Misc. supports. Note, the information collected here will NOT be
+ // written to hardware registry.
+ //
+ // 1. Collect video font information for vdm
+ //
+
+ GetVideoFontInformation();
+
+ //
+ // After all the components are detected, we collect EISA config data.
+ //
+
+ if (HwBusType == MACHINE_TYPE_EISA) {
+
+ Component = &AdapterEntry->ComponentEntry;
+ GetEisaConfigurationData(&AdapterEntry->ConfigurationData,
+ &Component->ConfigurationDataLength);
+ if (Component->ConfigurationDataLength) {
+ HwEisaConfigurationData = (FPUCHAR)AdapterEntry->ConfigurationData +
+ DATA_HEADER_SIZE;
+ HwEisaConfigurationSize = Component->ConfigurationDataLength -
+ DATA_HEADER_SIZE;
+
+ //
+ // Misc. detections based on Eisa config data
+ //
+ // Update Lpt and com controllers' irq information by examining
+ // the EISA configuration data.
+ //
+
+ GetIrqFromEisaData(FirstLpt, ParallelController);
+ GetIrqFromEisaData(FirstCom, SerialController);
+ }
+ }
+
+
+#if DBG
+ CheckConfigurationTree(ConfigurationRoot);
+#endif
+
+ //
+ // Update all the far pointers in the tree to flat 32 bit pointers
+ //
+
+ UpdateConfigurationTree(ConfigurationRoot);
+
+ //
+ // Set up returned values:
+ // Size of Heap space which should be preserved for configuration tree
+ // Pointer to the root of the configuration tree.
+ //
+
+ CurrentEntry = (FPFWCONFIGURATION_COMPONENT_DATA)HwAllocateHeap(0, FALSE);
+ *BlHeapUsed = MAKE_FLAT_ADDRESS(CurrentEntry) -
+ MAKE_FLAT_ADDRESS(ConfigurationRoot);
+ *BlConfigurationTree = (ULONG)MAKE_FLAT_ADDRESS(ConfigurationRoot);
+}
+
+VOID
+GetIrqFromEisaData(
+ FPFWCONFIGURATION_COMPONENT_DATA ControllerList,
+ CONFIGURATION_TYPE ControllerType
+ )
+/*++
+
+Routine Description:
+
+ This routine updates all irq information for ControllerType components
+ in the controllerList by examinine the eisa configuration data.
+
+Arguments:
+
+ ControllerList - Supplies a pointer to a component entry whoes irq will
+ be updated.
+
+ ControllerType - Supplies the controller type whoes irq will be searched
+ for.
+
+Returns:
+
+ None.
+
+--*/
+{
+
+ FPFWCONFIGURATION_COMPONENT_DATA CurrentEntry;
+ FPHWPARTIAL_RESOURCE_DESCRIPTOR Descriptor;
+ FPHWRESOURCE_DESCRIPTOR_LIST DescriptorList;
+ USHORT i, Port;
+ UCHAR Irq, Trigger;
+
+ CurrentEntry = ControllerList;
+ while (CurrentEntry &&
+ CurrentEntry->ComponentEntry.Type == ControllerType) {
+ if (CurrentEntry->ConfigurationData) {
+ DescriptorList = (FPHWRESOURCE_DESCRIPTOR_LIST)
+ CurrentEntry->ConfigurationData;
+ Port = 0;
+ for (i = 0; i < (USHORT)DescriptorList->Count; i++) {
+ Descriptor = &DescriptorList->PartialDescriptors[i];
+ if (Descriptor->Type == CmResourceTypePort) {
+ Port = (USHORT)Descriptor->u.Port.Start.LowPart;
+ break;
+ }
+ }
+ if (Port != 0) {
+ for (i = 0; i < (USHORT)DescriptorList->Count; i++) {
+ Descriptor = &DescriptorList->PartialDescriptors[i];
+ if (Descriptor->Type == CmResourceTypeInterrupt) {
+ if (HwEisaGetIrqFromPort(Port, &Irq, &Trigger)) {
+ if (Trigger == 0) { // EISA EDGE_TRIGGER
+ Descriptor->Flags = EDGE_TRIGGERED;
+ } else {
+ Descriptor->Flags = LEVEL_SENSITIVE;
+ }
+ Descriptor->u.Interrupt.Level = Irq;
+ Descriptor->u.Interrupt.Vector = Irq;
+ break;
+ }
+ }
+ }
+ }
+ }
+ CurrentEntry = CurrentEntry->Sibling;
+ }
+}
+
+VOID
+UpdateComponentPointers(
+ FPFWCONFIGURATION_COMPONENT_DATA CurrentEntry
+ )
+/*++
+
+Routine Description:
+
+ This routine updates all the "far" pointer to 32 bit flat addresses
+ for a component entry.
+
+Arguments:
+
+ CurrentEntry - Supplies a pointer to a component entry which will
+ be updated.
+
+Returns:
+
+ None.
+
+--*/
+{
+ FPULONG UpdatePointer;
+ FPVOID NextEntry;
+ ULONG FlatAddress;
+
+ //
+ // Update the child, parent, sibling and ConfigurationData
+ // far pointers to 32 bit flat addresses.
+ // N.B. After we update the pointers to flat addresses, they
+ // can no longer be accessed in real mode.
+ //
+
+ UpdatePointer = (FPULONG)&CurrentEntry->Child;
+ NextEntry = (FPVOID)CurrentEntry->Child;
+ FlatAddress = MAKE_FLAT_ADDRESS(NextEntry);
+ *UpdatePointer = FlatAddress;
+
+ UpdatePointer = (FPULONG)&CurrentEntry->Parent;
+ NextEntry = (FPVOID)CurrentEntry->Parent;
+ FlatAddress = MAKE_FLAT_ADDRESS(NextEntry);
+ *UpdatePointer = FlatAddress;
+
+ UpdatePointer = (FPULONG)&CurrentEntry->Sibling;
+ NextEntry = (FPVOID)CurrentEntry->Sibling;
+ FlatAddress = MAKE_FLAT_ADDRESS(NextEntry);
+ *UpdatePointer = FlatAddress;
+
+ UpdatePointer = (FPULONG)&CurrentEntry->ComponentEntry.Identifier;
+ NextEntry = (FPVOID)CurrentEntry->ComponentEntry.Identifier;
+ FlatAddress = MAKE_FLAT_ADDRESS(NextEntry);
+ *UpdatePointer = FlatAddress;
+
+ UpdatePointer = (FPULONG)&CurrentEntry->ConfigurationData;
+ NextEntry = (FPVOID)CurrentEntry->ConfigurationData;
+ FlatAddress = MAKE_FLAT_ADDRESS(NextEntry);
+ *UpdatePointer = FlatAddress;
+
+}
+
+
+
+VOID
+UpdateConfigurationTree(
+ FPFWCONFIGURATION_COMPONENT_DATA CurrentEntry
+ )
+/*++
+
+Routine Description:
+
+ This routine traverses loader configuration tree and changes
+ all the "far" pointer to 32 bit flat addresses.
+
+Arguments:
+
+ CurrentEntry - Supplies a pointer to a loader configuration
+ tree or subtree.
+
+Returns:
+
+ None.
+
+--*/
+{
+ if (CurrentEntry) {
+ UpdateConfigurationTree(CurrentEntry->Child);
+ UpdateConfigurationTree(CurrentEntry->Sibling);
+ UpdateComponentPointers(CurrentEntry);
+ }
+}
+
+FPVOID
+HwSetUpResourceDescriptor (
+ FPFWCONFIGURATION_COMPONENT Component,
+ PUCHAR Identifier,
+ PHWCONTROLLER_DATA ControlData,
+ USHORT SpecificDataLength,
+ PUCHAR SpecificData
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates space from far heap , puts the caller's controller
+ information to the space and sets up CONFIGURATION_COMPONENT
+ structure for the caller.
+
+Arguments:
+
+ Component - Supplies the address the component whose configuration data
+ should be set up.
+
+ Identifier - Suppies a pointer to the identifier to identify the controller
+
+ ControlData - Supplies a point to a structure which describes
+ controller information.
+
+ SpecificDataLength - size of the device specific data. Device specific
+ data is the information not defined in the standard format.
+
+ SpecificData - Supplies a pointer to the device specific data.
+
+
+Return Value:
+
+ Returns a far pointer to the Configuration data.
+
+--*/
+
+{
+ FPCHAR fpIdentifier;
+ FPHWRESOURCE_DESCRIPTOR_LIST fpDescriptor = NULL;
+ USHORT Length;
+ SHORT Count, i;
+ FPUCHAR fpSpecificData;
+
+ //
+ // Set up Identifier string for hardware component, if necessary.
+ //
+
+ if (Identifier) {
+ Length = strlen(Identifier) + 1;
+ Component->IdentifierLength = Length;
+ fpIdentifier = (FPUCHAR)HwAllocateHeap(Length, FALSE);
+ Component->Identifier = fpIdentifier;
+ _fstrcpy(fpIdentifier, Identifier);
+ } else {
+ Component->IdentifierLength = 0;
+ Component->Identifier = NULL;
+ }
+
+ //
+ // Set up configuration data for hardware component, if necessary
+ //
+
+ Count = ControlData->NumberPortEntries + ControlData->NumberIrqEntries +
+ ControlData->NumberMemoryEntries + ControlData->NumberDmaEntries;
+
+ if (SpecificDataLength) {
+
+ //
+ // if we have device specific data, we need to increment the count
+ // by one.
+ //
+
+ Count++;
+ }
+
+ if (Count >0) {
+ Length = (USHORT)(Count * sizeof(HWPARTIAL_RESOURCE_DESCRIPTOR) +
+ FIELD_OFFSET(HWRESOURCE_DESCRIPTOR_LIST, PartialDescriptors) +
+ SpecificDataLength);
+ fpDescriptor = (FPHWRESOURCE_DESCRIPTOR_LIST)HwAllocateHeap(Length, TRUE);
+ fpDescriptor->Count = Count;
+
+ //
+ // Copy all the partial descriptors to the destination descriptors
+ // except the last one. (The last partial descriptor may be a device
+ // specific data. It requires special handling.)
+ //
+
+ for (i = 0; i < (Count - 1); i++) {
+ fpDescriptor->PartialDescriptors[i] =
+ ControlData->DescriptorList[i];
+ }
+
+ //
+ // Set up the last partial descriptor. If it is a port, memory, irq or
+ // dma entry, we simply copy it. If the last one is for device specific
+ // data, we set up the length and copy the device spcific data to the end
+ // of the decriptor.
+ //
+
+ if (SpecificData) {
+ fpDescriptor->PartialDescriptors[Count - 1].Type =
+ RESOURCE_DEVICE_DATA;
+ fpDescriptor->PartialDescriptors[Count - 1].Flags = 0;
+ fpDescriptor->PartialDescriptors[Count - 1].u.DeviceSpecificData.DataSize =
+ SpecificDataLength;
+ fpSpecificData = (FPUCHAR)&(fpDescriptor->PartialDescriptors[Count]);
+ _fmemcpy(fpSpecificData, SpecificData, SpecificDataLength);
+ } else {
+ fpDescriptor->PartialDescriptors[Count - 1] =
+ ControlData->DescriptorList[Count - 1];
+ }
+ Component->ConfigurationDataLength = Length;
+ }
+ return(fpDescriptor);
+}
+VOID
+HwSetUpFreeFormDataHeader (
+ FPHWRESOURCE_DESCRIPTOR_LIST Header,
+ USHORT Version,
+ USHORT Revision,
+ USHORT Flags,
+ ULONG DataSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initialize free formed data header. Note this routine
+ sets the the Header and initialize the FIRST PartialDescriptor only.
+ If the header contains more than one descriptor, the caller must handle
+ it itself.
+
+Arguments:
+
+ Header - Supplies a pointer to the header to be initialized.
+
+ Version - Version number for the header.
+
+ Revision - Revision number for the header.
+
+ Flags - Free formed data flags. (Currently, it is undefined and
+ should be zero.)
+
+ DataSize - Size of the free formed data.
+
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ Header->Version = Version;
+ Header->Revision = Revision;
+ Header->Count = 1;
+ Header->PartialDescriptors[0].Type = RESOURCE_DEVICE_DATA;
+ Header->PartialDescriptors[0].ShareDisposition = 0;
+ Header->PartialDescriptors[0].Flags = Flags;
+ Header->PartialDescriptors[0].u.DeviceSpecificData.DataSize = DataSize;
+ Header->PartialDescriptors[0].u.DeviceSpecificData.Reserved1 = 0;
+ Header->PartialDescriptors[0].u.DeviceSpecificData.Reserved2 = 0;
+}
+#if DBG
+
+VOID
+CheckComponentNode(
+ FPFWCONFIGURATION_COMPONENT_DATA CurrentEntry
+ )
+{
+ FPUCHAR NextEntry, DataPointer;
+ ULONG FlatAddress;
+ ULONG Length;
+ UCHAR IdString[40];
+ USHORT Count, i;
+ UCHAR Type;
+ FPHWRESOURCE_DESCRIPTOR_LIST DescriptorList;
+ FPHWPARTIAL_RESOURCE_DESCRIPTOR Descriptor;
+
+ FlatAddress = MAKE_FLAT_ADDRESS(CurrentEntry);
+ clrscrn ();
+ BlPrint("\n");
+ BlPrint("Current Node: %lx\n", FlatAddress);
+ BlPrint(" Type = %s\n", TypeName[CurrentEntry->ComponentEntry.Type]);
+
+ //
+ // Update the child, parent, sibling and ConfigurationData
+ // far pointers to 32 bit flat addresses.
+ // N.B. After we update the pointers to flat addresses, they
+ // can no longer be accessed in real mode.
+ //
+
+ NextEntry = (FPUCHAR)CurrentEntry->Child;
+ FlatAddress = MAKE_FLAT_ADDRESS(NextEntry);
+ if (FlatAddress > 0x60000 || (FlatAddress < 0x50000 && FlatAddress != 0)) {
+ BlPrint("Invalid address: Child = %lx\n", FlatAddress);
+ } else {
+ BlPrint("\tChild = %lx\n", FlatAddress);
+ }
+
+ NextEntry = (FPUCHAR)CurrentEntry->Parent;
+ FlatAddress = MAKE_FLAT_ADDRESS(NextEntry);
+ if (FlatAddress > 0x60000 || (FlatAddress < 0x50000 && FlatAddress != 0)) {
+ BlPrint("Invalid address: Parent = %lx\n", FlatAddress);
+ } else {
+ BlPrint("\tParent = %lx\n", FlatAddress);
+ }
+
+ NextEntry = (FPUCHAR)CurrentEntry->Sibling;
+ FlatAddress = MAKE_FLAT_ADDRESS(NextEntry);
+ if (FlatAddress > 0x60000 || (FlatAddress < 0x50000 && FlatAddress != 0)) {
+ BlPrint("Invalid address: Sibling = %lx\n", FlatAddress);
+ } else {
+ BlPrint("\tSibling = %lx\n", FlatAddress);
+ }
+
+ NextEntry = (FPUCHAR)CurrentEntry->ConfigurationData;
+ FlatAddress = MAKE_FLAT_ADDRESS(NextEntry);
+ if (FlatAddress > 0x60000 || (FlatAddress < 0x50000 && FlatAddress != 0)) {
+ BlPrint("Invalid address: ConfigurationData = %lx\n", FlatAddress);
+ } else {
+ BlPrint("\tConfigurationData = %lx\n", FlatAddress);
+ }
+
+ Length = CurrentEntry->ComponentEntry.IdentifierLength;
+ BlPrint("IdentifierLength = %lx\n", CurrentEntry->ComponentEntry.IdentifierLength);
+ if (Length > 0) {
+ _fstrcpy(IdString, CurrentEntry->ComponentEntry.Identifier);
+ BlPrint("Identifier = %s\n", IdString);
+ }
+
+ Length = CurrentEntry->ComponentEntry.ConfigurationDataLength;
+ BlPrint("ConfigdataLength = %lx\n", Length);
+
+ if (Length > 0) {
+
+ DescriptorList = (FPHWRESOURCE_DESCRIPTOR_LIST)CurrentEntry->ConfigurationData;
+ BlPrint("Version = %x, Revision = %x\n", DescriptorList->Version,
+ DescriptorList->Revision);
+ Count = (USHORT)DescriptorList->Count;
+ Descriptor = &DescriptorList->PartialDescriptors[0];
+ BlPrint("Count = %x\n", Count);
+ while (Count > 0) {
+ Type = Descriptor->Type;
+ if (Type == RESOURCE_PORT) {
+ BlPrint("Type = Port");
+ BlPrint("\tShareDisposition = %x\n", Descriptor->ShareDisposition);
+ BlPrint("PortFlags = %x\n", Descriptor->Flags);
+ BlPrint("PortStart = %x", Descriptor->u.Port.Start);
+ BlPrint("\tPortLength = %x\n", Descriptor->u.Port.Length);
+ } else if (Type == RESOURCE_DMA) {
+ BlPrint("Type = Dma");
+ BlPrint("\tShareDisposition = %x\n", Descriptor->ShareDisposition);
+ BlPrint("DmaFlags = %x\n", Descriptor->Flags);
+ BlPrint("DmaChannel = %x", Descriptor->u.Dma.Channel);
+ BlPrint("\tDmaPort = %lx\n", Descriptor->u.Dma.Port);
+ } else if (Type == RESOURCE_INTERRUPT) {
+ BlPrint("Type = Interrupt");
+ BlPrint("\tShareDisposition = %x\n", Descriptor->ShareDisposition);
+ BlPrint("InterruptFlags = %x\n", Descriptor->Flags);
+ BlPrint("Level = %x", Descriptor->u.Interrupt.Level);
+ BlPrint("\tVector = %x\n", Descriptor->u.Interrupt.Vector);
+ } else if (Type == RESOURCE_MEMORY) {
+ BlPrint("Type = Memory");
+ BlPrint("\tShareDisposition = %x\n", Descriptor->ShareDisposition);
+ BlPrint("MemoryFlags = %x\n", Descriptor->Flags);
+ BlPrint("Start1 = %lx", (ULONG)Descriptor->u.Memory.Start.LowPart);
+ BlPrint("\tStart2 = %lx", (ULONG)Descriptor->u.Memory.Start.HighPart);
+ BlPrint("\tLength = %lx\n", Descriptor->u.Memory.Length);
+ } else {
+ BlPrint("Type = Device Data\n");
+ Length = Descriptor->u.DeviceSpecificData.DataSize;
+ BlPrint("Size = %lx\n", Length);
+ DataPointer = (FPUCHAR)(Descriptor+1);
+ for (i = 0; i < Length && i < 64; i++) {
+ BlPrint("%x ", *DataPointer);
+ DataPointer++;
+ }
+ break;
+ }
+ Count--;
+ Descriptor++;
+ }
+ }
+ while (HwGetKey() == 0) {
+ }
+}
+
+VOID
+CheckConfigurationTree(
+ FPFWCONFIGURATION_COMPONENT_DATA CurrentEntry
+ )
+{
+ if (CurrentEntry) {
+ CheckComponentNode(CurrentEntry);
+ CheckConfigurationTree(CurrentEntry->Sibling);
+ CheckConfigurationTree(CurrentEntry->Child);
+ }
+}
+
+#endif
diff --git a/private/ntos/boot/detect/i386/hwdetect.h b/private/ntos/boot/detect/i386/hwdetect.h
new file mode 100644
index 000000000..94c637676
--- /dev/null
+++ b/private/ntos/boot/detect/i386/hwdetect.h
@@ -0,0 +1,542 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ detect.h
+
+Abstract:
+
+ This module is a global C include file for all the detection
+ modules.
+
+Author:
+
+ Shie-Lin Tzong (shielint) 27-Dec-1991
+
+Revision History:
+
+--*/
+
+#define i386
+#define _X86_
+#define __stdcall
+#include "types.h"
+#include "ntmisc.h"
+#include <ntconfig.h>
+#include <arc.h>
+
+//
+// Machine type definitions.
+//
+
+#define MACHINE_TYPE_ISA 0
+#define MACHINE_TYPE_EISA 1
+#define MACHINE_TYPE_MCA 2
+
+//
+// Interrupt controller register addresses.
+//
+
+#define PIC1_PORT0 0x20 // master PIC
+#define PIC1_PORT1 0x21
+#define PIC2_PORT0 0x0A0 // slave PIC
+#define PIC2_PORT1 0x0A1
+
+//
+// Commands for interrupt controller
+//
+
+#define OCW3_READ_ISR 0xb
+#define OCW3_READ_IRR 0xa
+
+//
+// Definitions for the data stored in the first page 0x700 area
+// The 0x700 is the place vdm loads MS-DOS. It should be very safe
+// to pass the data required by vdm.
+//
+
+#define DOS_BEGIN_SEGMENT 0x70 // DOS loaded segment address
+
+#define VIDEO_FONT_OFFSET 0 // Video font ptrs stored at 0x700
+#define VIDEO_FONT_DATA_SIZE 0x40
+
+#define EBIOS_INFO_OFFSET 0x40 // Extended bios infor:
+ // EBIOS data area address 4 bytes
+ // EBIOS data area size 4 byte
+#define EBIOS_INFO_SIZE 0x8
+
+//
+// Mouse information structure
+// N.B. This *must* match the one defined in mouse.inc
+//
+
+typedef struct _MOUSE_INFORMATION {
+ UCHAR MouseType;
+ UCHAR MouseSubtype;
+ USHORT MousePort; // if serial mouse, 1 for com1, 2 for com2 ...
+ USHORT MouseIrq;
+ USHORT DeviceIdLength;
+ UCHAR DeviceId[10];
+} MOUSE_INFORMATION, *PMOUSE_INFORMATION;
+
+//
+// Mouse Type definitions
+//
+
+#define UNKNOWN_MOUSE 0
+#define NO_MOUSE 0x100 // YES! it is 0x100 *NOT* 0x10000
+
+#define MS_MOUSE 0x200 // MS regular mouses
+#define MS_BALLPOINT 0x300 // MS ballpoint mouse
+#define LT_MOUSE 0x400 // Logitec Mouse
+
+//
+// note last 4 bits of the subtype are reserved subtype specific use
+//
+
+#define PS_MOUSE 0x1
+#define SERIAL_MOUSE 0x2
+#define INPORT_MOUSE 0x3
+#define BUS_MOUSE 0x4
+#define PS_MOUSE_WITH_WHEEL 0x5
+#define SERIAL_MOUSE_WITH_WHEEL 0x6
+
+//#define MOUSE_RESERVE_MASK 0xfffffff
+
+//
+// Definitions for the keyboard type returned from
+// the detect keyboard function.
+//
+
+#define UNKNOWN_KEYBOARD 0
+#define OLI_83KEY 1
+#define OLI_102KEY 2
+#define OLI_86KEY 3
+#define OLI_A101_102KEY 4
+#define XT_83KEY 5
+#define ATT_302 6
+#define PCAT_ENHANCED 7
+#define PCAT_86KEY 8
+#define PCXT_84KEY 9
+
+//
+// Redefine the configuration component structures to use FAR pointer type.
+//
+// Since ntdetect.com running at 16 bit real mode, it has to use FAR pointers
+// to access loader heap. Before returning to ntldr, ntdetect must convert
+// these far pointers to 32 bit flat addresses such that kernel can acess the
+// configuration tree.
+//
+
+typedef struct _FWCONFIGURATION_COMPONENT {
+ CONFIGURATION_CLASS Class;
+ USHORT Reserved0;
+ CONFIGURATION_TYPE Type;
+ USHORT Reserverd1;
+ DEVICE_FLAGS Flags;
+ ULONG Version;
+ ULONG Key;
+ ULONG AffinityMask;
+ ULONG ConfigurationDataLength;
+ ULONG IdentifierLength;
+ FPCHAR Identifier;
+} FWCONFIGURATION_COMPONENT, far *FPFWCONFIGURATION_COMPONENT;
+
+typedef struct _FWCONFIGURATION_COMPONENT_DATA {
+ struct _FWCONFIGURATION_COMPONENT_DATA far *Parent;
+ struct _FWCONFIGURATION_COMPONENT_DATA far *Child;
+ struct _FWCONFIGURATION_COMPONENT_DATA far *Sibling;
+ FWCONFIGURATION_COMPONENT ComponentEntry;
+ FPVOID ConfigurationData;
+} FWCONFIGURATION_COMPONENT_DATA, far *FPFWCONFIGURATION_COMPONENT_DATA;
+
+//
+// defined the MicroChannel POS data structure
+//
+
+typedef CM_MCA_POS_DATA MCA_POS_DATA, far *FPMCA_POS_DATA;
+
+//
+// Rom Block Definition
+//
+
+typedef CM_ROM_BLOCK ROM_BLOCK, far *FPROM_BLOCK;
+#define RESERVED_ROM_BLOCK_LIST_SIZE (((0xf0000 - 0xc0000)/512) * sizeof(ROM_BLOCK))
+
+//
+// Other type redefinitions
+//
+
+typedef CM_PARTIAL_RESOURCE_DESCRIPTOR HWPARTIAL_RESOURCE_DESCRIPTOR;
+typedef HWPARTIAL_RESOURCE_DESCRIPTOR *PHWPARTIAL_RESOURCE_DESCRIPTOR;
+typedef HWPARTIAL_RESOURCE_DESCRIPTOR far *FPHWPARTIAL_RESOURCE_DESCRIPTOR;
+
+typedef CM_PARTIAL_RESOURCE_LIST HWRESOURCE_DESCRIPTOR_LIST;
+typedef HWRESOURCE_DESCRIPTOR_LIST *PHWRESOURCE_DESCRIPTOR_LIST;
+typedef HWRESOURCE_DESCRIPTOR_LIST far *FPHWRESOURCE_DESCRIPTOR_LIST;
+
+typedef CM_EISA_SLOT_INFORMATION EISA_SLOT_INFORMATION, *PEISA_SLOT_INFORMATION;
+typedef CM_EISA_SLOT_INFORMATION far *FPEISA_SLOT_INFORMATION;
+typedef CM_EISA_FUNCTION_INFORMATION EISA_FUNCTION_INFORMATION, *PEISA_FUNCTION_INFORMATION;
+typedef CM_EISA_FUNCTION_INFORMATION far *FPEISA_FUNCTION_INFORMATION;
+
+#define LEVEL_SENSITIVE CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE
+#define EDGE_TRIGGERED CM_RESOURCE_INTERRUPT_LATCHED
+#define RESOURCE_PORT 1
+#define RESOURCE_INTERRUPT 2
+#define RESOURCE_MEMORY 3
+#define RESOURCE_DMA 4
+#define RESOURCE_DEVICE_DATA 5
+#define ALL_PROCESSORS 0xffffffff
+
+//
+// Note the DATA_HEADER_SIZE counts ONE partial descriptor only.
+// if the resource list has more than one descriptors, you must add
+// the size of extra descriptors to this value.
+//
+
+#define DATA_HEADER_SIZE sizeof(CM_PARTIAL_RESOURCE_LIST)
+
+//
+// Defines the structure to store controller information
+// (used by ntdetect internally)
+//
+
+#define MAXIMUM_DESCRIPTORS 10
+
+typedef struct _HWCONTROLLER_DATA {
+ UCHAR NumberPortEntries;
+ UCHAR NumberIrqEntries;
+ UCHAR NumberMemoryEntries;
+ UCHAR NumberDmaEntries;
+ HWPARTIAL_RESOURCE_DESCRIPTOR DescriptorList[MAXIMUM_DESCRIPTORS];
+} HWCONTROLLER_DATA, *PHWCONTROLLER_DATA;
+
+//
+// Macro definitions for conversion between far and fat pointers
+//
+
+#define MAKE_FP(p,a) FP_SEG(p) = (USHORT)((a) >> 4) & 0xffff; FP_OFF(p) = (USHORT)((a) & 0x0f)
+#define MAKE_FLAT_ADDRESS(fp) ( ((ULONG)FP_SEG(fp) * 16 ) + (ULONG)FP_OFF(fp) )
+
+//
+// Calculate the byte offset of a field in a structure of type type.
+//
+
+#define FIELD_OFFSET(type, field) ((LONG)&(((type *)0)->field))
+
+//
+// I/O Port read and write routines.
+//
+
+extern
+VOID
+WRITE_PORT_UCHAR (
+ PUCHAR PortAddress,
+ UCHAR Value
+ );
+
+extern
+UCHAR
+READ_PORT_UCHAR(
+ PUCHAR Port
+ );
+
+extern
+VOID
+WRITE_PORT_USHORT (
+ PUSHORT PortAddress,
+ USHORT Value
+ );
+
+extern
+USHORT
+READ_PORT_USHORT(
+ PUSHORT Port
+ );
+
+//
+// prototype definitions for Heap management routines
+//
+
+extern
+BOOLEAN
+HwInitializeHeap (
+ ULONG HeapStart,
+ ULONG HeapSize
+ );
+
+extern
+FPVOID
+HwAllocateHeap(
+ ULONG RequestSize,
+ BOOLEAN ZeroInitialized
+ );
+
+extern
+VOID
+HwFreeHeap(
+ ULONG Size
+ );
+
+//
+// Misc. prototype definitions
+//
+
+extern
+FPVOID
+HwSetUpResourceDescriptor (
+ FPFWCONFIGURATION_COMPONENT Component,
+ PUCHAR Identifier,
+ PHWCONTROLLER_DATA ControlData,
+ USHORT SpecificDataLength,
+ PUCHAR SpecificData
+ );
+
+extern
+VOID
+HwSetUpFreeFormDataHeader (
+ FPHWRESOURCE_DESCRIPTOR_LIST Header,
+ USHORT Version,
+ USHORT Revision,
+ USHORT Flags,
+ ULONG DataSize
+ );
+
+extern
+BOOLEAN
+IsEnhancedKeyboard (
+ VOID
+ );
+
+extern
+SHORT
+GetKeyboardIdBytes (
+ PCHAR IdBuffer,
+ SHORT Length
+ );
+
+extern
+USHORT
+GetKeyboardId(
+ VOID
+ );
+
+extern
+FPFWCONFIGURATION_COMPONENT_DATA
+SetKeyboardConfigurationData (
+ IN USHORT KeyboardId
+ );
+
+#if 0 // Remove video detection
+extern
+ULONG
+GetVideoAdapterType (
+ VOID
+ );
+
+extern
+FPFWCONFIGURATION_COMPONENT_DATA
+SetVideoConfigurationData (
+ IN ULONG VideoType
+ );
+#endif // Remove video detection
+
+extern
+FPFWCONFIGURATION_COMPONENT_DATA
+GetComportInformation (
+ VOID
+ );
+
+extern
+FPFWCONFIGURATION_COMPONENT_DATA
+GetLptInformation (
+ VOID
+ );
+
+extern
+PMOUSE_INFORMATION
+GetMouseId (
+ VOID
+ );
+
+extern
+FPFWCONFIGURATION_COMPONENT_DATA
+GetMouseInformation (
+ VOID
+ );
+
+extern
+FPFWCONFIGURATION_COMPONENT_DATA
+GetFloppyInformation(
+ VOID
+ );
+
+extern
+FPFWCONFIGURATION_COMPONENT_DATA
+GetAtDiskInformation(
+ VOID
+ );
+
+extern
+BOOLEAN
+HwIsMcaSystem(
+ VOID
+ );
+
+extern
+BOOLEAN
+HwIsEisaSystem(
+ VOID
+ );
+
+extern
+BOOLEAN
+IsNpxPresent(
+ VOID
+ );
+
+extern
+USHORT
+HwGetProcessorType(
+ VOID
+ );
+
+extern
+USHORT
+HwGetCpuStepping(
+ USHORT
+ );
+
+extern
+VOID
+GetMcaPosData(
+ FPVOID Entry,
+ FPULONG DataLength
+ );
+
+extern
+VOID
+GetEisaConfigurationData(
+ FPVOID Entry,
+ FPULONG DataLength
+ );
+
+extern
+VOID
+UpdateConfigurationTree(
+ FPFWCONFIGURATION_COMPONENT_DATA CurrentEntry
+ );
+
+extern
+PUCHAR
+GetMachineId(
+ VOID
+ );
+
+extern
+VOID
+HwGetEisaSlotInformation (
+ PEISA_SLOT_INFORMATION SlotInformation,
+ UCHAR Slot
+ );
+
+extern
+UCHAR
+HwGetEisaFunctionInformation (
+ PEISA_FUNCTION_INFORMATION FunctionInformation,
+ UCHAR Slot,
+ UCHAR Function
+ );
+
+extern
+VOID
+GetBiosSystemEnvironment (
+ PUCHAR Buffer
+ );
+
+extern
+VOID
+GetInt13DriveParameters (
+ PUCHAR Buffer,
+ PUSHORT Size
+ );
+
+extern
+VOID
+GetRomBlocks(
+ FPUCHAR ReservedBuff,
+ PUSHORT Size
+ );
+
+extern
+VOID
+GetVideoFontInformation(
+ VOID
+ );
+
+extern
+BOOLEAN
+HwEisaGetIrqFromPort (
+ USHORT Port,
+ PUCHAR Irq,
+ PUCHAR TriggerMethod
+ );
+
+VOID
+HwGetPciSystemData(
+ PVOID,
+ BOOLEAN
+ );
+
+VOID
+HwGetBiosDate(
+ ULONG source,
+ USHORT Length,
+ PUSHORT BiosYear,
+ PUSHORT BiosMonth,
+ PUSHORT BiosDay
+ );
+
+BOOLEAN
+HwGetPnpBiosSystemData(
+ IN FPUCHAR *Configuration,
+ IN PUSHORT Length
+ );
+
+#if DBG
+extern
+VOID
+BlPrint(
+ IN PCHAR,
+ ...
+ );
+
+extern
+VOID
+clrscrn (
+ VOID
+ );
+
+#endif // DBG
+
+//
+// External declarations for global variables
+//
+
+extern USHORT HwBusType;
+
+extern FPFWCONFIGURATION_COMPONENT_DATA AdapterEntry;
+
+extern FPMCA_POS_DATA HwMcaPosData;
+
+extern FPUCHAR FpRomBlock;
+
+extern USHORT RomBlockLength;
+
+extern FPUCHAR HwEisaConfigurationData;
+
+extern ULONG HwEisaConfigurationSize;
+
diff --git a/private/ntos/boot/detect/i386/hweisa.inc b/private/ntos/boot/detect/i386/hweisa.inc
new file mode 100644
index 000000000..05aa94ade
--- /dev/null
+++ b/private/ntos/boot/detect/i386/hweisa.inc
@@ -0,0 +1,61 @@
+;++
+;
+; Copyright (c) 1989 Microsoft Corporation
+;
+; Module Name:
+;
+; eisa.inc
+;
+; Abstract:
+;
+; This module contains the assembly structures and definitions
+; for making 16-bit real mode EISA BIOS calls.
+;
+; Author:
+;
+; Shie-Lin (shielint) 7-June-1991
+;
+; Revision History:
+;
+;--
+
+;
+; EISA BIOS call function number.
+;
+
+GET_EISA_SLOT_INFORMATION equ 0D800h
+GET_EISA_FUNCTION_INFORMATION equ 0D801h
+
+;
+; Length of EISA information block
+;
+
+EISA_INFORMATION_BLOCK_LENGTH equ 320
+
+;
+; Structure for EISA slot information block
+;
+
+EISA_SLOT_INFORMATION struc
+
+ SlotReturn db 0
+ SlotFlags db 0
+ SlotMajorRevision db 0
+ SlotMinorRevision db 0
+ SlotChecksum dw 0
+ SlotNumberFunctions db 0
+ SlotFunctionInformation db 0
+ SlotCompressedId dd 0
+
+EISA_SLOT_INFORMATION ends
+
+;
+; Structure for EISA function information block
+;
+
+EISA_FUNCTION_INFORMATION struc
+
+ FunctionReturn db 0
+ FunctionInformation db EISA_INFORMATION_BLOCK_LENGTH dup (0)
+
+EISA_FUNCTION_INFORMATION ends
diff --git a/private/ntos/boot/detect/i386/hweisaa.asm b/private/ntos/boot/detect/i386/hweisaa.asm
new file mode 100644
index 000000000..6b7043f7d
--- /dev/null
+++ b/private/ntos/boot/detect/i386/hweisaa.asm
@@ -0,0 +1,279 @@
+ title "EISA bus Support Assembley Code"
+;++
+;
+; Copyright (c) 1989 Microsoft Corporation
+;
+; Module Name:
+;
+; eisaa.asm
+;
+; Abstract:
+;
+; This module implements the assembley code necessary to get configuration
+; information on EISA machines.
+;
+; Author:
+;
+; Shie-Lin Tzong (shielint) 7-June-1991
+;
+; Environment:
+;
+; Real Mode 16-bit code.
+;
+; Revision History:
+;
+;
+;--
+
+
+.386p
+ .xlist
+include hweisa.inc
+ .list
+
+_DATA SEGMENT PARA USE16 PUBLIC 'DATA'
+
+ public _FunctionInformation
+_FunctionInformation db 0
+ db EISA_INFORMATION_BLOCK_LENGTH dup (0)
+
+_DATA ends
+
+_TEXT SEGMENT PARA USE16 PUBLIC 'CODE'
+ ASSUME CS: _TEXT
+
+;++
+;
+; VOID
+; HwGetEisaSlotInformation (
+; PBTEISA_SLOT_INFORMATION SlotInformation,
+; UCHAR Slot
+; )
+;
+; Routine Description:
+;
+; This function retrieves the slot information for the specified slot.
+;
+; Arguments:
+;
+; SlotInformation - Supplies a pointer to the structure which will
+; receive the slot information.
+;
+; Slot - Specifies the slot to retrieve the information.
+;
+; Return Value:
+;
+; None.
+;
+;--
+
+HgesSlotInformation equ [bp + 4]
+HgesSlot equ [bp + 6]
+
+ public _HwGetEisaSlotInformation
+_HwGetEisaSlotInformation proc
+
+ push bp ; The following INT 15H destroies
+ mov bp, sp ; ALL the general registers.
+ push si
+ push di
+ push bx
+
+ mov cl, HgesSlot
+ mov ax, GET_EISA_SLOT_INFORMATION
+ int 15h
+
+ push bx ; Save revision level
+ mov bx, HgesSlotInformation
+
+ ;
+ ; fill values into eisa slot info structure.
+ ;
+
+ mov [bx].SlotReturn, ah
+ mov [bx].SlotFlags, al
+ pop ax ; [ax] = revision level
+ mov [bx].SlotMajorRevision, ah
+ mov [bx].SlotMinorRevision, al
+ mov [bx].SlotChecksum, cx
+ mov [bx].SlotNumberFunctions, dh
+ mov [bx].SlotFunctionInformation, dl
+ mov word ptr [bx].SlotCompressedId, di
+ mov word ptr [bx+2].SlotCompressedId, si
+
+ pop bx
+ pop di
+ pop si
+ pop bp
+ ret
+
+_HwGetEisaSlotInformation endp
+
+;++
+;
+; UCHAR
+; HwGetEisaFunctionInformation (
+; PBTEISA_FUNCTION_INFORMATION FunctionInformation,
+; UCHAR Slot,
+; UCHAR Function
+; )
+;
+; Routine Description:
+;
+; This function retrieves function information for the specified slot
+; and function.
+;
+; Arguments:
+;
+; FunctionInformation - Supplies a pointer to the structure which will
+; receive the slot information.
+;
+; Slot - Specifies the slot to retrieve the information.
+;
+; Function - Supplies the function number of the desired slot.
+;
+; Return Value:
+;
+; Return code of the EISA function call.
+;
+;--
+
+HgefFunctionInformation equ [bp + 4]
+HgefSlot equ [bp + 6]
+HgefFunction equ [bp + 8]
+
+ public _HwGetEisaFunctionInformation
+_HwGetEisaFunctionInformation proc
+
+ push bp
+ mov bp, sp
+ push si
+
+ mov ax, GET_EISA_FUNCTION_INFORMATION
+ mov cl, HgefSlot ; [cl] = slot, [ch]=function
+ mov ch, HgefFunction
+ mov si, HgefFunctionInformation
+ ; (ds:si)->Function information
+ int 15h
+
+ mov al, ah ; move the return code to AL
+
+ pop si
+ pop bp
+ ret
+_HwGetEisaFunctionInformation endp
+
+;++
+;
+; BOOLEAN
+; HwIsEisaSystem (
+; VOID
+; )
+;
+; Routine Description:
+;
+; This function determines if the target machines is EISA based machines.
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; TRUE - if this is EISA machine. Otherwise, a value of FALSE is returned.
+;--
+
+ public _HwIsEisaSystem
+_HwIsEisaSystem proc
+
+ push es
+ push bx
+
+;
+; Check for an EISA system. If "EISA" is at F000:FFD9h then it
+; is an EISA system.
+;
+
+ mov ax,0f000h ; segment
+ mov es,ax
+ mov bx,0ffd9h ; offset in the ROM
+ mov eax, "ASIE"
+ cmp eax, es:[bx]
+ jne short hies00 ; if ne, Not EISA system, go bies00
+
+ mov ax, 1 ; set return value to TRUE
+ jmp short hies10
+
+hies00:
+ mov ax, 0
+hies10:
+ pop bx
+ pop es
+ ret
+_HwIsEisaSystem endp
+
+;++
+;
+; VOID
+; Int15 (
+; PULONG eax,
+; PULONG ebx,
+; PULONG ecx,
+; PULONG edx,
+; PULONG CyFlag
+; )
+;
+; Routine Description:
+;
+; Calls Int15 with the requesed registers and returns the result
+;
+;--
+
+ public _Int15
+_Int15 proc
+ push bp
+ mov bp, sp
+ push esi
+ push edi
+ push ebx
+
+ mov si, [bp+4] ; pointer to eax
+ mov eax, [si]
+
+ mov si, [bp+6] ; pointer to ebx
+ mov ebx, [si]
+
+ mov si, [bp+8] ; pointer to ecx
+ mov ecx, [si]
+
+ mov si, [bp+10] ; pointer to edx
+ mov edx, [si]
+
+ int 15h ; do it
+
+ mov si, [bp+4] ; pointer to eax
+ mov [si], eax
+
+ mov si, [bp+6] ; pointer to ebx
+ mov [si], ebx
+
+ mov si, [bp+8] ; pointer to ecx
+ mov [si], ecx
+
+ mov si, [bp+10] ; pointer to edx
+ mov [si], edx
+
+ sbb eax, eax
+ mov si, [bp+12] ; pointer CyFlag
+ mov [si], eax
+
+ pop ebx
+ pop edi
+ pop esi
+ pop bp
+ ret
+_Int15 endp
+
+
+_TEXT ends
+ end
diff --git a/private/ntos/boot/detect/i386/hweisac.c b/private/ntos/boot/detect/i386/hweisac.c
new file mode 100644
index 000000000..6bb6f5642
--- /dev/null
+++ b/private/ntos/boot/detect/i386/hweisac.c
@@ -0,0 +1,308 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ eisac.c
+
+Abstract:
+
+ This module implements routines to get EISA configuration information.
+
+Author:
+
+ Shie-Lin Tzong (shielint) 18-Jan-1992
+
+Environment:
+
+ 16-bit real mode.
+
+
+Revision History:
+
+
+--*/
+
+#include "hwdetect.h"
+#include "string.h"
+
+typedef EISA_PORT_CONFIGURATION far *FPEISA_PORT_CONFIGURATION;
+
+extern CM_EISA_FUNCTION_INFORMATION FunctionInformation;
+
+
+VOID
+GetEisaConfigurationData (
+ FPVOID Buffer,
+ FPULONG Size
+ )
+
+/*++
+
+Routine Description:
+
+ This routine collects all the eisa slot information, function
+ information and stores it in the caller supplied Buffer and
+ returns the size of the data.
+
+Arguments:
+
+
+ Buffer - A pointer to a PVOID to recieve the address of configuration
+ data.
+
+ Size - a pointer to a ULONG to receive the size of the configuration
+ data.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UCHAR Slot=0;
+ UCHAR Function=0, SlotFunctions = 0, ReturnCode;
+ EISA_SLOT_INFORMATION SlotInformation;
+ FPUCHAR ConfigurationData, CurrentData;
+ FPEISA_SLOT_INFORMATION FarSlotInformation;
+ ULONG TotalSize = DATA_HEADER_SIZE;
+ BOOLEAN Overflowed = FALSE;
+
+ HwGetEisaSlotInformation(&SlotInformation, Slot);
+
+ TotalSize += sizeof(EISA_SLOT_INFORMATION);
+ ConfigurationData = (FPVOID)HwAllocateHeap(TotalSize, FALSE);
+ CurrentData = ConfigurationData + DATA_HEADER_SIZE;
+
+ _fmemcpy(CurrentData, (FPVOID)&SlotInformation, sizeof(EISA_SLOT_INFORMATION));
+ FarSlotInformation = (FPEISA_SLOT_INFORMATION)CurrentData;
+
+ while (SlotInformation.ReturnCode != EISA_INVALID_SLOT) {
+
+ //
+ // Ensure that the slot is not empty and collect all the function
+ // information for the slot.
+ //
+
+ if (SlotInformation.ReturnCode != EISA_EMPTY_SLOT) {
+
+ while (SlotInformation.NumberFunctions > Function) {
+ ReturnCode = HwGetEisaFunctionInformation(
+ &FunctionInformation, Slot, Function);
+ Function++;
+
+ //
+ // if function call succeeds and the function contains usefull
+ // information or this is the last function for the slot and
+ // there is no function information collected for the slot, we
+ // will save this function information to our heap.
+ //
+
+ if (!ReturnCode) {
+ if (((FunctionInformation.FunctionFlags & 0x7f) != 0) ||
+ (SlotInformation.NumberFunctions == Function &&
+ SlotFunctions == 0)) {
+ CurrentData = (FPVOID)HwAllocateHeap(
+ sizeof(EISA_FUNCTION_INFORMATION), FALSE);
+ if (CurrentData == NULL) {
+ Overflowed = TRUE;
+ break;
+ }
+ SlotFunctions++;
+ TotalSize += sizeof(EISA_FUNCTION_INFORMATION);
+ _fmemcpy(CurrentData,
+ (FPVOID)&FunctionInformation,
+ sizeof(EISA_FUNCTION_INFORMATION));
+ }
+ }
+ }
+ FarSlotInformation->NumberFunctions = SlotFunctions;
+ }
+ if (Overflowed) {
+ break;
+ }
+ Slot++;
+ Function = 0;
+ HwGetEisaSlotInformation(&SlotInformation, Slot);
+ CurrentData = (FPVOID)HwAllocateHeap(
+ sizeof(EISA_SLOT_INFORMATION), FALSE);
+ if (CurrentData == NULL) {
+ Overflowed = TRUE;
+ break;
+ }
+ TotalSize += sizeof(EISA_SLOT_INFORMATION);
+ _fmemcpy(CurrentData,
+ (FPVOID)&SlotInformation,
+ sizeof(EISA_SLOT_INFORMATION));
+ FarSlotInformation = (FPEISA_SLOT_INFORMATION)CurrentData;
+ SlotFunctions = 0;
+ }
+
+ //
+ // Free the last EISA_SLOT_INFORMATION space which contains the slot
+ // information for IVALID SLOT
+ //
+
+ if (Overflowed != TRUE) {
+ HwFreeHeap(sizeof(EISA_SLOT_INFORMATION));
+ TotalSize -= sizeof(EISA_SLOT_INFORMATION);
+ }
+
+ //
+ // Check if we got any EISA information. If nothing, we release
+ // the space for data header and return.
+ //
+
+ if (TotalSize == DATA_HEADER_SIZE) {
+ HwFreeHeap(DATA_HEADER_SIZE);
+ *(FPULONG)Buffer = (ULONG)0;
+ *Size = (ULONG)0;
+ } else {
+ HwSetUpFreeFormDataHeader((FPHWRESOURCE_DESCRIPTOR_LIST)ConfigurationData,
+ 0,
+ 0,
+ 0,
+ TotalSize - DATA_HEADER_SIZE
+ );
+ *(FPULONG)Buffer = (ULONG)ConfigurationData;
+ *Size = TotalSize;
+ }
+}
+
+BOOLEAN
+HwEisaGetIrqFromPort (
+ USHORT Port,
+ PUCHAR Irq,
+ PUCHAR TriggerMethod
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans EISA configuration data to match the I/O port address.
+ The IRQ information is returned from the matched EISA function information.
+
+Arguments:
+
+ Port - The I/O port address to scan for.
+
+ Irq - Supplies a pointer to a variable to receive the irq information.
+
+ TriggerMethod - Supplies a pointer to a variable to receive the
+ EISA interrupt trigger method.
+
+Return Value:
+
+ TRUE - if the Irq information is found. Otherwise a value of FALSE is
+ returned.
+
+--*/
+
+{
+ UCHAR Function, i, j;
+ FPEISA_SLOT_INFORMATION SlotInformation;
+ FPEISA_FUNCTION_INFORMATION Buffer;
+ UCHAR FunctionFlags;
+ ULONG SizeToScan = 0L;
+ EISA_PORT_CONFIGURATION PortConfig;
+ EISA_IRQ_DESCRIPTOR IrqConfig;
+ SlotInformation = (FPEISA_SLOT_INFORMATION)HwEisaConfigurationData;
+
+ //
+ // Scan through all the EISA configuration data.
+ //
+
+ while (SizeToScan < HwEisaConfigurationSize) {
+ if (SlotInformation->ReturnCode != EISA_EMPTY_SLOT) {
+
+ //
+ // Make sure this slot contains PORT_RANGE and IRQ information.
+ //
+
+ if ((SlotInformation->FunctionInformation & EISA_HAS_PORT_RANGE) &&
+ (SlotInformation->FunctionInformation & EISA_HAS_IRQ_ENTRY)) {
+
+ Buffer = (FPEISA_FUNCTION_INFORMATION)(SlotInformation + 1);
+
+ //
+ // For each function of the slot, if it contains both the IRQ
+ // and PORT information, we then check for its PORT address.
+ //
+
+ for (Function = 0; Function < SlotInformation->NumberFunctions; Function++) {
+ FunctionFlags = Buffer->FunctionFlags;
+ if ((FunctionFlags & EISA_HAS_IRQ_ENTRY) &&
+ (FunctionFlags & EISA_HAS_PORT_RANGE)) {
+ for (i = 0; i < 20 ; i++ ) {
+ PortConfig = Buffer->EisaPort[i];
+ if ((Port >= PortConfig.PortAddress) &&
+ (Port <= (PortConfig.PortAddress +
+ PortConfig.Configuration.NumberPorts))) {
+
+ //
+ // If there is only one IRQ entry, that's the
+ // one we want. (This is the normal case and
+ // correct usage of EISA function data.) Otherwise,
+ // we try to get the irq from the same index
+ // number as port entry. (This is ALR's incorrect
+ // way of packing functions into one function
+ // data.)
+ //
+
+ IrqConfig = Buffer->EisaIrq[0].ConfigurationByte;
+ if (IrqConfig.MoreEntries == 0) {
+ *Irq = IrqConfig.Interrupt;
+ *TriggerMethod = IrqConfig.LevelTriggered;
+ return(TRUE);
+ } else if (i >= 7) {
+ return(FALSE);
+ }
+
+ for (j = 0; j <= i; j++) {
+ if (j == i) {
+ *Irq = IrqConfig.Interrupt;
+ *TriggerMethod = IrqConfig.LevelTriggered;
+ return(TRUE);
+ }
+ if (!IrqConfig.MoreEntries) {
+ return(FALSE);
+ }
+ IrqConfig =
+ Buffer->EisaIrq[j+1].ConfigurationByte;
+ }
+ return(FALSE);
+ }
+ if (!PortConfig.Configuration.MoreEntries) {
+ break;
+ }
+ }
+ }
+ Buffer++;
+ }
+ }
+
+ //
+ // Move on to next slot
+ //
+
+ SizeToScan += sizeof(EISA_SLOT_INFORMATION) +
+ sizeof(EISA_FUNCTION_INFORMATION) *
+ SlotInformation->NumberFunctions;
+ SlotInformation = (FPEISA_SLOT_INFORMATION)(HwEisaConfigurationData +
+ SizeToScan);
+ } else {
+
+ //
+ // This is a empty slot. We simply skip it.
+ //
+
+ SizeToScan += sizeof(EISA_SLOT_INFORMATION);
+ SlotInformation++;
+ }
+ }
+ return(FALSE);
+}
+
diff --git a/private/ntos/boot/detect/i386/hwheap.c b/private/ntos/boot/detect/i386/hwheap.c
new file mode 100644
index 000000000..90a09b903
--- /dev/null
+++ b/private/ntos/boot/detect/i386/hwheap.c
@@ -0,0 +1,229 @@
+/*++
+
+Copyright (c) 1990, 1991 Microsoft Corporation
+
+
+Module Name:
+
+ hwheap.c
+
+Abstract:
+
+ This is a very simple Heap Manager for NT OS Hardware recognizer.
+ This module provides functions to allocate memory in byte-unit
+ from a permanent heap.
+
+Author:
+
+ Shie-Lin Tzong (shielint) 18-Oct-91
+
+
+Environment:
+
+ Kernel Mode
+
+
+Revision History:
+
+
+--*/
+
+#include "hwdetect.h"
+#include "string.h"
+
+VOID
+GrowHeapSpace(
+ ULONG
+ );
+
+VOID
+HeapCheck(
+ PVOID
+ );
+
+//
+// Heap management variables.
+//
+
+ULONG HwHeapBase = 0; // Current virtual address of base of heap
+ULONG HwHeapPointer = 0; // Pointer to the end of available heap
+ULONG HwHeapSize = 0; // Size of Heap
+ULONG HwAvailableHeap = 0; // Currently available heap space
+
+#if DBG
+ULONG HwPreviousAllocSize = 0;
+#endif
+
+BOOLEAN
+HwResizeHeap (
+ ULONG NewHeapSize
+ )
+
+/*++
+
+Routine Description:
+
+ The routine grows current heap to the specified size.
+ It reallocates the heap, copies the data in current heap to
+ the new heap, updates heap variables, updates heap pointers
+ in hardware data structures and finally frees the old heap.
+
+Arguments:
+
+ NewHeapSize - Specifies the size of the new heap.
+
+Returns:
+
+ TRUE - if operation is done sucessfully. Else it returns FALSE.
+
+--*/
+
+{
+ //
+ // Not implemented yet.
+ //
+
+ return(FALSE);
+}
+
+BOOLEAN
+HwInitializeHeap(
+ ULONG HeapStart,
+ ULONG HeapSize
+ )
+
+/*++
+
+Routine Description:
+
+ The routine allocates heap and initializes some vital heap
+ variables.
+
+Arguments:
+
+ None
+
+Returns:
+
+ FALSE - if unable to allocate initial heap. Else it returns TRUE.
+
+--*/
+
+{
+
+ HwHeapBase = HeapStart;
+ HwHeapPointer = HwHeapBase;
+ HwHeapSize = HeapSize;
+ HwAvailableHeap = HwHeapSize;
+ return(TRUE);
+
+}
+
+FPVOID
+HwAllocateHeap(
+ ULONG RequestSize,
+ BOOLEAN ZeroInitialized
+ )
+
+/**
+
+Routine Description:
+
+ Allocates memory from the hardware recognizer's heap.
+
+ The heap begins with a default size. If a request exhausts heap space,
+ the heap will be grown to accomodate the request. The heap can grow
+ up to any size limited by NTLDR. If we run out of heap space and are
+ unable to allocate more memory, a value of NULL will be returned.
+
+Arguments:
+
+ RequestSize - Size of block to allocate.
+
+ ZeroInitialized - Specifies if the heap should be zero initialized.
+
+Returns:
+
+ Returns a pointer to the allocated block of memory. A NULL pointer
+ will be returned if we run out of heap and are unable to resize
+ current heap.
+
+--*/
+
+{
+ FPVOID ReturnPointer;
+
+ if (RequestSize > HwAvailableHeap) {
+
+ //
+ // We're out of heap. Try to grow current heap to satisfy the
+ // request.
+ //
+
+ if (!HwResizeHeap(HwHeapSize + RequestSize)) {
+#if DBG
+ BlPrint("Unable to grow heap\n");
+#endif
+ return(NULL);
+ }
+ }
+
+ //
+ // Set our return value to the new Heap pointer then
+ // update the remaining space and heap pointer.
+ //
+
+ MAKE_FP(ReturnPointer, HwHeapPointer);
+ HwHeapPointer += RequestSize;
+#if DBG
+ HwPreviousAllocSize = RequestSize;
+#endif
+ HwAvailableHeap -= RequestSize;
+ if (ZeroInitialized) {
+ _fmemset(ReturnPointer, 0, (USHORT)RequestSize);
+ }
+ return (ReturnPointer);
+}
+
+VOID
+HwFreeHeap(
+ ULONG Size
+ )
+
+/**
+
+Routine Description:
+
+ Unallocates memory from the hardware recognizer's heap.
+
+ The unallocation is very basic. It simply moves heap pointer
+ back by the size specified and increases the heap size by the
+ specified size. The routine should be used only when previous
+ allocateHeap allocated too much memory.
+
+Arguments:
+
+ RequestSize - Size of block to allocate.
+
+Returns:
+
+ Returns a pointer to the allocated block of memory. A NULL pointer
+ will be returned if we run out of heap and are unable to resize
+ current heap.
+
+--*/
+
+{
+
+#if DBG
+ if (Size > HwPreviousAllocSize) {
+ BlPrint("Invalid heap deallocation ...\n");
+ } else {
+ HwPreviousAllocSize -= Size;
+ }
+#endif
+
+ HwHeapPointer -= Size;
+ HwAvailableHeap += Size;
+}
+
diff --git a/private/ntos/boot/detect/i386/hwmacha.asm b/private/ntos/boot/detect/i386/hwmacha.asm
new file mode 100644
index 000000000..bdce7554b
--- /dev/null
+++ b/private/ntos/boot/detect/i386/hwmacha.asm
@@ -0,0 +1,1346 @@
+ title "Machine Id detection"
+;++
+;
+; Copyright (c) 1989 Microsoft Corporation
+;
+; Module Name:
+;
+; machine.asm
+;
+; Abstract:
+;
+; This module implements the assembley code necessary to detect
+; certain special machines.
+;
+; Author:
+;
+; Shie-Lin Tzong (shielint) 28-Oct-1991.
+; Most of the code is extracted from Win 3.1 setup program.
+;
+; Environment:
+;
+; 80x86 Real Mode.
+;
+; Revision History:
+;
+;
+;--
+
+.386
+extrn _HwBusType: WORD
+
+;
+; Machine detection: Test ID equates (different tests must have different
+; ID's, all tests in CompTypeTable must be given one of
+; the following labels)
+;
+
+INT15_C0 equ 1
+STR_CMP equ 2
+STR_ICMP equ 3
+NEC_PS_TEST equ 4
+AST_TEST equ 5
+
+;
+; STANDARD ROM BIOS MACHINE TYPES used in ROM_BIOS_Machine_ID
+;
+
+IBM_PCAT equ 0FCh
+IBM_PCAT_SUB1 equ 000h
+IBM_PCAT_SUB2 equ 001h
+IBM_PS2_50_SUB equ 004h
+IBM_PS2_60_SUB equ 005h
+IBM_PS2_30 equ 0FAh
+IBM_PS2_80 equ 0F8h
+IBM_PS2_30_SUB equ 000h
+IBM_PS2_80_SUB equ 000h
+IBM_PS2_80_SUB2 equ 001h
+IBM_PS2_25 equ 0FAh
+IBM_PS2_25_SUB equ 001h
+IBM_PS2_70 equ 0f8h
+IBM_PS2_70_SUB equ 004h
+IBM_PS2_70_SUB2 equ 009h
+IBM_PS2_70_SUBP equ 00Bh
+IBM_PS2_L40SX_M equ 0F8h
+IBM_PS2_L40SX_SM equ 023h
+
+;
+; IBM ThinkPad 750 and PS2 E model and submodel byte
+; We need to identify these two machine because of their weird FDC
+;
+
+IBM_THINKPAD_750_MODEL equ 0F8h
+IBM_THINKPAD_750_SUBMODEL_L equ 061h
+IBM_THINKPAD_750_SUBMODEL_H equ 067h
+IBM_THINKPAD_750_SUBMODEL1 equ 0A9h
+
+
+IBM_PS2_E_MODEL equ 024F8h
+
+;
+; Special equates
+;
+
+AST_STR_LEN equ 12
+
+;
+; CMOS related definitions and macros
+;
+
+CMOS_CONTROL_PORT EQU 70h ; command port for cmos
+CMOS_DATA_PORT EQU 71h ; cmos data port
+
+;
+; CMOS_READ
+;
+; Description: This macro read a byte from the CMOS register specified
+; in (AL).
+;
+; Parameter: (AL) = address/register to read
+; Return: (AL) = data
+;
+
+CMOS_READ MACRO
+ OUT CMOS_CONTROL_PORT,al ; ADDRESS LOCATION AND DISABLE NMI
+ jmp $ + 2 ; I/O DELAY
+ IN AL,CMOS_DATA_PORT ; READ IN REQUESTED CMOS DATA
+ jmp $ + 2 ; I/O DELAY
+ENDM
+
+;
+; CMOS_WRITE
+;
+; Description: This macro read a byte from the CMOS register specified
+; in (AL).
+;
+; Parameter: (AL) = address/register to read
+; (AH) = data to be written
+;
+; Return: None
+;
+
+CMOS_WRITE MACRO
+ OUT CMOS_CONTROL_PORT,al ; ADDRESS LOCATION AND DISABLE NMI
+ jmp $ + 2 ; I/O DELAY
+ MOV AL,AH ; (AL) = DATA
+ OUT CMOS_DATA_PORT,AL ; PLACE IN REQUESTED CMOS LOCATION
+ jmp $ + 2 ; I/O DELAY
+ENDM
+
+;
+; BCD_TO_BIN
+;
+; Description: Convert BCD value to binary
+;
+; Parameter:
+; Input: (AL) = 2 digit BCD number to convert
+; Output: (AX) = Binary equivalent (all in AL)
+;
+; Return: None.
+;
+
+BCD_TO_BIN macro
+
+ xor ah,ah
+ rol ax,4
+ ror al,4
+ aad
+ENDM
+
+_DATA SEGMENT PARA USE16 PUBLIC 'DATA'
+
+HP_PC db 'HP VECTRA',0
+ATT_PC db 'AT&T',0
+IBMPS2_70P db 'IBM PS2 P70',0
+IBMPS2_L40SX db 'IBM PS2 L40SX',0
+IBM_PS2_E db 'IBM PS2E', 0
+IBM_THINKPAD_750 db 'IBM THINKPAD 750',0
+NEC_PROSPEED db 'NEC PROSPEED',0
+
+ZENITH_386 db 'ZENITH',0
+EVEREX_386_25 db 'EVEREX',0
+NCR_386SX db 'NCR',0
+NEC_PM_SX_PLUS db 'NEC POWERMATE SX PLUS',0
+AST_386_486 db 'AST',0
+TOSHIBA_1200XE db 'TOSHIBA T1200XE',0
+TOSHIBA_1600 db 'TOSHIBA T1600',0
+TOSHIBA_5200 db 'TOSHIBA T5200',0
+ATT_NSX20 db 'AT&T NSX/20',0
+DEC_PC db 'DECPC',0
+DEC_PC_LENGTH equ $ - DEC_PC
+AST_STRING db 'AST RESEARCH'
+AT_COMPATIBLE db 'AT/AT COMPATIBLE',0
+PS2_COMPATIBLE db 'PS2/PS2 COMPATIBLE',0
+PS1_COMPATIBLE db 'PS1/PS1 COMPATIBLE',0
+NEC_VERSA db 'NEC VERSA/COMPATIBLE', 0
+
+;
+;***************************************************************************
+;
+; TEST INSTRUCTION TABLE
+;
+; Table for Machine Detection. This table lists the tests to detect
+; problem (non-standard) machines.
+;
+;***************************************************************************
+;
+
+;
+; The tests need not be performed in the order of there ID's, the only
+; restriction is that the DEFAULT_MACHINE ID be last in this list.
+;
+
+public CompTypeTable
+CompTypeTable dw offset HP_PC
+ dw offset HP_Vectra_Test
+
+ dw offset ATT_PC
+ dw offset ATT_PC_Test
+
+ dw offset IBMPS2_70P
+ dw offset IBMPS2_70P_Test
+
+ dw offset IBMPS2_L40SX
+ dw offset IBMPS2_L40SX_Test
+
+ dw offset NEC_PROSPEED
+ dw offset NEC_Prospeed_Test
+
+ dw offset ZENITH_386
+ dw offset Zenith_386_Test
+
+ dw offset EVEREX_386_25
+ dw offset Everex_386_25_Test
+
+ dw offset NCR_386SX
+ dw offset NCR_386SX_Test
+
+ dw offset NEC_PM_SX_PLUS
+ dw offset NEC_PM_SX_Plus_Test
+
+ dw offset AST_386_486
+ dw offset AST_386_486_Test
+
+ dw offset TOSHIBA_1200XE
+ dw offset Toshiba_1200XE_Test
+
+ dw offset TOSHIBA_1600
+ dw offset Toshiba_1600_Test
+
+ dw offset TOSHIBA_5200
+ dw offset Toshiba_5200_Test
+
+ dw offset ATT_NSX20
+ dw offset ATT_NSX20_Test
+
+;
+; Default Machine must be last since we do not test for it
+;
+ dw 0
+
+
+
+;****************************************************************************
+;
+; Tests for Detecting Non-standard Machines
+;
+; Tests for detecting machines fall into 4 categories:
+;
+; - INT15_C0: Get Model and sub-model bytes by doing an Int15 C0 call
+; - STR_CMP: Look for particular string in a given area of the BIOS
+; - STR_CMP_386: Look for particular string in a given area of the BIOS
+; as well as detemining if machine is 386-based or higher
+; - Specific: A test specific to a given machine which doesn't fall
+; into one of the above three categories.
+;
+;****************************************************************************
+
+;****************************************************************************
+; Test for Hewlett Packard Vectra Computer.
+;****************************************************************************
+
+HP_Vectra_Test db STR_CMP
+ dw 000F8h
+ dw 0F000h ; String is at F000:00F8
+ db 2 ; String is 2 characters long
+ db 'HP'
+
+;****************************************************************************
+; Test for AT&T Personal Computer
+;****************************************************************************
+
+ATT_PC_Test db STR_CMP
+ dw 00050h ; Offset 0050h
+ dw 0FC00h ; String is at FC00:0050h
+ db 3 ; String is 3 characters long
+ db 'OLI'
+
+;****************************************************************************
+; Test for IBM PS/2 Model P70 (portable)
+;****************************************************************************
+
+IBMPS2_70P_Test db INT15_C0
+ db IBM_PS2_70 ; model byte.
+ db IBM_PS2_70_SUBP ; sub-model byte.
+
+;****************************************************************************
+; Test for IBM PS/2 Model P70 (portable)
+;****************************************************************************
+
+IBMPS2_L40SX_Test db INT15_C0
+ db IBM_PS2_L40SX_M ; model byte.
+ db IBM_PS2_L40SX_SM ; sub-model byte.
+
+;****************************************************************************
+
+; Test for NEC Prospeed
+
+;****************************************************************************
+
+NEC_Prospeed_Test db STR_CMP
+ dw 0FFC0h
+ dw 0F000h
+ db 4
+ db 6,6,6,6
+
+;****************************************************************************
+; Test for all Zenith 386 Computers
+;****************************************************************************
+
+Zenith_386_Test db STR_CMP
+ dw 0800Ch ; Offset 800Ch
+ dw 0F000h ; String is at F000:800Ch
+ db 8 ; String is 8 characters long
+ db 'ZDS CORP' ; String to check for
+
+;****************************************************************************
+
+; Test for Everex Step 386/25
+
+;****************************************************************************
+
+Everex_386_25_Test db STR_CMP
+ dw 0FF59h
+ dw 0F000h
+ db 10
+ db '(C)1987AMI'
+
+
+;****************************************************************************
+
+; Test for NCR PC386SX (all versions?)
+
+;****************************************************************************
+
+NCR_386SX_Test db STR_CMP
+ dw 0FFEAh
+ dw 0F000h
+ db 3
+ db 'NCR'
+
+;****************************************************************************
+
+; Test for NEC Powermate SX Plus
+
+;****************************************************************************
+
+NEC_PM_SX_Plus_Test db STR_CMP
+ dw 00000h
+ dw 0FFF4h
+ db 2
+ db 4,2 ; 04 and 02
+
+
+;****************************************************************************
+
+; Test for ALL AST 386 and 486 machines
+
+;****************************************************************************
+
+AST_386_486_Test db AST_TEST ; Specific
+
+
+;****************************************************************************
+
+; Test for Toshiba 1200XE
+
+;****************************************************************************
+
+TOSHIBA_1200XE_Test db STR_CMP
+ dw 00000h
+ dw 0FE00h
+ db 7
+ db 'T1200XE'
+
+
+;****************************************************************************
+
+; Test for Toshiba 1600
+
+;****************************************************************************
+
+TOSHIBA_1600_Test db STR_CMP
+ dw 00000h
+ dw 0FE00h
+ db 5
+ db 'T1600'
+
+
+;****************************************************************************
+
+; Test for Toshiba 5200
+
+;****************************************************************************
+
+TOSHIBA_5200_Test db STR_CMP
+ dw 00000h
+ dw 0FE00h
+ db 5
+ db 'T5200'
+
+
+;******************************************************************************
+
+; Test for AT&T NSX/20 ( Safari ) Notebook Computer
+
+;******************************************************************************
+
+;
+; BUGBUG shielint I don't think this test works.
+;
+
+ATT_NSX20_Test db STR_CMP
+ dw 0FF40h ; Offset 0FF40h
+ dw 0F000h ; String is at F000:FF40h
+ db 7 ; String is 7 characters long
+ db 'AT&TNSX'
+ dw 0FFD5h ; Offset 0FFD5h
+ dw 0F000h ; String is at F000:FF40h
+ db 2 ; String is 2 characters long
+ db 36h
+ db 74h
+; db 0
+
+;****************************************************************************
+;
+; End of machine test tables.
+;
+;****************************************************************************
+
+; ***************************************************************************
+;
+; For Eisa System type detection
+;
+; ***************************************************************************
+;
+
+;
+; szSystemType: SystemType is read from 0c80-0c83h.
+; 0c80-0c81: 0e11: Compressed CPQ (5 bit encoding).
+; 0c82: System Board type.
+; 0c83: System Board revision level.
+;
+
+CPQ_SYSPRO db 'COMPAQ SYSTEMPRO', 0
+ALR_SYSPRO db 'ALR SYSTEMPRO', 0
+CPQ_SMP_SYSPRO db 'COMPAQ SYMMETRIC SYSTEMPRO', 0
+
+
+abSystemTypeTable db 0eh, 11h, 01h
+ dw offset CPQ_SYSPRO ; CPQ01xx 386 ASP
+ db 0eh, 11h, 11h
+ dw offset CPQ_SYSPRO ; CPQ11xx 486 ASP
+ db 05h, 92h, 0a0h
+ dw offset ALR_SYSPRO ; ALRa0xx
+ db 0eh, 11h, 15h
+ dw offset CPQ_SMP_SYSPRO ; CPQ15xx
+SYSTABLE_SIZE equ ($-abSystemTypeTable)/5
+
+SystemType db 0, 0, 0, 0
+
+;
+; Compaq Portable machine IDs
+;
+; For these machines, the BIOS incorrectly specifies its keyboard type to
+; be enhanced keyboard. So, for these machine we must set _NoBiosKbdCheck
+; to TRUE.
+;
+
+CompaqPortableInt15Ids dw 0D0h ; LTE Lite 386/25(Athens)
+ dw 0D8h ; LTE Lite 386/20 (Infinity) 2MB
+ dw 0DCh ; ;LTE Lite 386/25C (Wizard)
+ dw 0E0h ; Contura 3/25 (Rapture)
+ dw 0E1h ; Clipper (Rapture 25 with color panel)
+ dw 0E4h ; Contura 3/20 (Rapture)
+ dw 0E8h ; Reserved for Alladin (H4 Color TFT) 25 MHz
+ dw 0E9h ; Reserved for Houdini
+ dw 0EAh ; Reserved for Alladin (H4 Color TFT) 33Mhz
+ dw 0ECh ; Reserved for Genie (H4 Mono TFT)
+ dw 00F4h ; Reserved for Schooner (Contura 486)
+ dw 0204h ; Caravel (H4 Contura STN Color)
+ dw 0208h ; Catamaran (H4 Contura TFT Color)
+ dw 0FCh ; LTE Lite 386/25E (Mystic)
+COMPAQ_INT15ID_SIZE equ ($ - CompaqPortableInt15Ids) / 2
+
+CompaqPortableCmosIds db 052h ; SLT386s/20 (Alfa, Titan/Targa)
+ db 055h ; LTE 386s (Calypso/Spartan)
+ db 061h ; LTE Lite 386/25(Athens)
+ db 062h ; LTE Lite 386/20 (Infinity) 2MB
+ db 065h ; ;LTE Lite 386/25C (Wizard)
+ db 067h ; Contura 3/25 (Rapture)
+ db 069h ; Clipper (Rapture 25 with color panel)
+ db 068h ; Contura 3/20 (Rapture)
+ db 06ah ; Reserved for Alladin (H4 Color TFT) 25 MHz
+ db 06ah ; Reserved for Genie (H4 Mono TFT)
+ db 06bh ; Reserved for Schooner (Contura 486)
+ db 06ch ; Caravel (H4 Contura STN Color)
+ db 06dh ; Catamaran (H4 Contura TFT Color)
+ db 065h ; LTE Lite 386/25E (Mystic)
+COMPAQ_CMOSID_SIZE equ ($ - CompaqPortableCmosIds)
+
+ public _NoBiosKbdCheck, _NoLogitechPs2Check
+_NoBiosKbdCheck db 0 ; Default FALSE
+_NoLogitechPs2Check db 0 ; Default FALSE
+
+NecVersaStrLen dw 9
+NecVersaStr db 'NEC VERSA'
+AttGlobalystStrLen dw 14
+AttGlobalystStr db 'AT&T GLOBALYST'
+
+_DATA ends
+
+
+_TEXT SEGMENT PARA USE16 PUBLIC 'CODE'
+ ASSUME CS: _TEXT, DS:_DATA, SS:NOTHING
+
+;++
+;
+; PUCHAR
+; GetMachineId (
+; VOID
+; )
+;
+; Routine Description:
+;
+; This function determines mouse type in the system.
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; a machine identifier ascii string.
+;
+;--
+
+ public _GetMachineId
+_GetMachineId proc near
+
+ push es
+ push ds
+ push si
+ push di
+ push bx
+
+;
+; Before we start, check for some type of machines which needs special
+; treatment.
+;
+
+ call SpecialCheckings
+ or ax, ax ; Do we need to do rest of the detection?
+ jnz ExitTest ; if (ax) != 0, no.
+
+ ;
+ ; First, load offset of test table.
+ ;
+ mov si,offset CompTypeTable
+
+ID_Loop:
+ mov ax,[si] ; [Ax]-> Current ID we're testing for
+
+ push ax ; save the ID in case of match.
+ inc si
+ inc si ; [SI] = Offset of test table
+ push si ; Save SI for next ID
+
+ cmp ax, 0 ; If this compares, then we have tested
+ jne Cont ; for all problem machines: use default
+ jmp EndDetect
+
+Cont:
+ mov si,[si] ; [SI] = Test instruction table
+ mov ah,[si] ; AH = Test type
+ inc si ; SI points to 1st param of test
+
+Test1: ; Machine ID instruction test
+ cmp ah,INT15_C0
+ jne short Test2
+
+ mov ah,0c0h ; Here we need to test model bytes.
+ int 15h ; Use int 15h to retrieve pointer.
+ inc bx ; increment ponter to model bytes.
+ inc bx
+ mov ah,[si] ; model byte from table.
+ cmp ah,es:[bx] ; Q: Does model byte match ?
+ jz short Cont2 ; N: No, Not this type of machine.
+ jmp short NotThisID
+Cont2:
+ inc si ; Y: Compare sub-model byte.
+ inc bx ; increment table and model byte ponters
+ mov ah,[si]
+ cmp ah,es:[bx] ; Q: Does sub-model byte match ?
+ jnz short NotThisID ; N: No, not this type of machine.
+
+ jmp short EndDetect ; Sucess
+
+Test2: ; Compare strings instruction test
+ cmp ah,STR_CMP
+ jne short Test3
+
+ mov di,[si] ; DI = Offset of string
+ inc si
+ inc si
+ mov dx,[si]
+ mov es,dx ; ES = Segment of string
+ inc si
+ inc si
+ xor ch,ch
+ mov cl,[si] ; CX = # characters to compare
+ inc si ; [SI] = 1st char of string
+
+ cld ; Be sure to auto-increment
+Test20:
+ mov al, [si]
+ cmp al, '?' ; Is it a match-all character?
+ je short Test25
+
+ mov ah, es:[di]
+ cmp ah, al
+ jne short NotThisID
+
+Test25:
+ inc di
+ inc si
+ dec cx
+ cmp cx, 0
+ je short EndDetect
+ jmp short Test20
+
+Test3:
+ cmp ah,AST_TEST
+ jne short InvalidID ; This can't happen
+
+ mov ah,0c0h ; Use int 15h to retrieve pointer
+ int 15h ; to System Environment Table
+
+ ;
+ ; Pointer is in ES:BX
+ ;
+
+ mov ax,bx ; Point to where 'AST RESEARCH'
+ add ax,15h ; would be on an AST machine
+ mov di,ax ; ES:DI = ES:BX+15h
+
+ ;
+ ; DS:SI is string to compare with
+ ;
+
+ mov si,offset AST_STRING
+
+ mov cx,AST_STR_LEN ; CX = # characters to compare
+
+ cld ; Be sure to auto-increment
+ repe cmpsb ; Q: Do strings match
+ jne short NotThisID
+
+ ;
+ ; Machine is AST, is it 386 or higher? It must be.
+ ;
+
+ jmp short EndDetect ; Sucess
+
+InvalidID:
+
+; This can't happen if CompTypeTable is terminated with DEFAULT_MACHINE
+
+;
+; This section goes through the Machine IDs one at a time, if no ID is
+; found, the last ID (DEFAULT_MACHINE) will be chosen as correct without
+; testing.
+;
+NotThisID:
+ pop si ; Restore pointer to ID table
+ pop ax ; remove previous ID from stack
+ inc si ; Increment to next ID
+ inc si
+ jmp ID_Loop ; And test for that ID
+
+
+EndDetect:
+ pop si ; Finished tests for current category so
+ pop ax ; return current category ID in AL
+ cmp ax, 0 ; if we did not find any we are interested in
+ jne ExitTest
+
+;
+; We did not find any thing by using above approach. Here we will do special
+; checking for certain type of machines.
+;
+
+ cmp _HwBusType, 1 ; Is it an EISA machine?
+ jne short @f
+
+ call DetectEisaSystemType ; mainly for system pro or compatible
+ cmp ax, 0 ; do we recognize the machine?
+ jne short ExitTest ; yes, go exit
+
+@@:
+
+;
+; if we still did not find the type of the machine, assume it is AT or PS2
+; compatible.
+;
+
+ cmp _HwBusType, 2 ; is it a MCA system?
+ jne short EndDetect10
+
+ mov ax, offset PS2_COMPATIBLE
+ jmp short ExitTest
+
+EndDetect10:
+
+;
+; Check if this is IBM PS/1 compatible machine
+;
+
+ call DetectPs1
+ or ax, ax
+ jnz short ExitTest
+
+ mov ax, offset AT_COMPATIBLE
+ExitTest:
+ pop bx
+ pop di
+ pop si
+ pop ds
+ pop es
+ ret
+
+_GetMachineId endp
+
+;++
+; USHORT
+; DetectEisaSystemType (
+; VOID
+; );
+;
+; Routine Description:
+;
+; Determines the type of system (specifically for eisa machines), by reading
+; the system board system ID. It compares the 3 of the 4 bytes ID, to
+; a predefined table <abSystemTypeTable> and return the index to the
+; found entry.
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+; none
+;
+; Note this routine destroys es, bx, di, si
+;--
+
+DetectEisaSystemType proc
+
+ push ds
+ pop es ; es = ds
+
+;
+; 4 byte value is read from 0c80-0c83, and saved in <szSystemType>.
+; The value is compared to table in <abSystemTypeTable>, and
+; the _SystemType is updated accordingly.
+;
+
+ mov di, offset SystemType
+ mov dx, 0c80h
+ cld ; increment edi
+ insb ; 0e CPQ
+ inc dx
+ insb ; 11
+ inc dx
+ insb ; _SystemType
+ inc dx
+ insb ; Revision
+
+ mov di, offset abSystemTypeTable; First entry in table
+ mov bx, 0 ; index to first entry
+@@:
+ mov cx, 3 ; number of bytes per entry
+ mov si, offset SystemType ; match string against table entry
+ ; Note ss = ds
+ repe cmpsb ; if (ecx == 0 and ZF set)
+ jz @f ; we have a winner
+ add di, cx ; next entry in tabl
+ inc di ; Skip TYPE string.
+ inc di
+ inc bx ; index to next enrty
+ cmp bx, SYSTABLE_SIZE ; Is this last entry?
+ jb @b ; NO
+ mov ax, 0
+ ret
+
+@@:
+ mov ax, [di] ; _SystemType is last byte.
+ ret
+
+DetectEisaSystemType endp
+
+;++
+; USHORT
+; DetectDECpc (
+; VOID
+; );
+;
+; Routine Description:
+;
+; This routine determines if the machine is a DECpc by BACKWARD scanning
+; through F000:FFFF - F000:0000 ROM BIOS segment and searching for
+; 'DECPC' string. The reason for backward scanning is because most machines
+; have their identifiers at the high part of ROM BIOS segment.
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; (ax) = 0 Not DECpc
+; (ax) = pointer to ASCii string 'DECpc'
+;
+; Note this routine destroys es, bx, di, si
+;--
+
+DetectDECpc proc
+
+ push es
+ push di
+
+ mov ax, 0f000h
+ mov es, ax ; es = ds
+ mov ecx, 10000h - 6
+ mov di, 0ffffh - 4 + 1
+ mov eax, 'cpCE'
+dd00:
+ cmp eax, es:[di]
+ je short dd10
+
+ dec di
+dd05:
+ loop short dd00
+ mov ax, 0
+ jmp short dd99
+
+dd10:
+ dec di
+ cmp byte ptr es:[di], 'D'
+ jne short dd05
+
+dd20:
+ mov ax, offset DEC_PC
+dd99:
+ pop di
+ pop es
+ ret
+
+DetectDECpc endp
+
+;++
+; PCHAR
+; SpecialChecking (
+; VOID
+; );
+;
+; Routine Description:
+;
+; This routine checks if the target machine is one of COMPAQ portables.
+; If yes, the _NoBiosKbdCheck will be set to TRUE. This is because on
+; these machines, their BIOS incorrectly specify that they are enhanced
+; keyboard.
+;
+; This routine checks if the target machine is OLIVETTI M600-40 or -60.
+; If yes, the _NoLogitechPs2Check will be set to TRUE. This is because
+; a bug in the keyboard controller of 'OLD' Olivetti M600 machines.
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; _NoBiosKbdCheck is set or clear.
+; _NoLogitechPs2Check is set or clear.
+; (ax) -> a machine id string
+;
+;--
+
+SpecialCheckings proc near
+
+ push bx
+ push di
+ push si
+
+;
+; First check Compaq Portable machines
+;
+
+ push ds
+ mov ax, 0f000h
+ mov ds, ax
+ mov di, 0FFEAh
+ mov cx, 0
+ mov eax, dword ptr [di] ; Make sure this is compaq machine
+ mov bx, word ptr [di+4]
+ pop ds
+ cmp eax, 'PMOC'
+ jne short Sc20 ; if nz, not compaq, exit this test
+
+ cmp bx, 'QA'
+ jne short Sc20 ; if nz, not compaq, exit this test
+
+;
+; OK, we know it is compaq machine. Now blindly set cpu speed to highest rate
+;
+
+ mov ax, 0F002H
+ int 16H
+
+ mov ax, 0e800h ; Get int15 SysId, [bx]=SysId if supported
+ int 15h
+ jc short Sc10_TestCmos ; function not supported, not compaq
+ ; portable
+ cmp al, 86h
+ je short Sc10_TestCmos ; function not supported, not compaq
+ ; portable
+ mov di, offset CompaqPortableInt15Ids
+ mov cx, COMPAQ_INT15ID_SIZE
+Sc10:
+ cmp bx, [di]
+ je short Sc20
+
+ add di, 2
+ dec cx
+ cmp cx, 0
+ jne short Sc10
+ jmp short Sc20
+
+Sc10_TestCmos:
+ mov al, 24h
+ CMOS_READ ; [al] = CMOS ID
+ mov di, offset CompaqPortableCmosIds
+ mov cx, COMPAQ_CMOSID_SIZE
+Sc15:
+ cmp al, [di]
+ je short Sc20
+
+ add di, 1
+ dec cx
+ cmp cx, 0
+ jne short Sc15
+
+Sc20:
+ mov _NoBiosKbdCheck, cl ; table < 255 entries
+ mov ax, offset AT_COMPATIBLE
+ or cl, cl
+ jnz Sc_Exit
+
+;
+; Test for Olivetti M600 machines
+; Search for 'OLIVETTI' in f000:c040 - f000:c060
+; and sub model byte 7A at f000:fffd
+;
+
+Sc_Test2:
+ push ds
+
+ mov ax, 0f000h
+ mov ds, ax
+ mov bx, 0fffdh
+ cmp byte ptr [bx], 7ah ; is sub model byte == 7a?
+ jne short Sc_Test2_Exit ; No, exit
+
+ mov cx, 20h
+ mov bx, 0c040h - 1
+ mov al, 'O'
+Sc_Test2_00:
+ inc bx
+ cmp [bx], al
+ je short Sc_Test2_10
+
+ loop short Sc_Test2_00
+ jmp short Sc_Test2_Exit
+
+Sc_Test2_10:
+ mov edx, 'VILO'
+ cmp edx, [bx]
+ jne short Sc_Test2_00
+
+ mov edx, 'ITTE'
+ cmp edx, [bx+4]
+ jne short Sc_Test2_00
+
+ pop ds
+ mov _NoLogitechPs2Check, dl
+ mov ax, offset AT_COMPATIBLE
+ jmp Sc_Exit
+
+Sc_Test2_Exit:
+ pop ds
+
+Sc_Test3:
+
+;
+; Check if this is PS2 E or IBM ThinkPad 750xx model. Floppy driver needs
+; to know this to special handle its ChangeLine bit.
+;
+
+ push es
+ push ds
+
+ mov ah,0c0h ; Here we need to test model bytes.
+ int 15h ; Use int 15h to retrieve pointer.
+ inc bx ; increment ponter to model bytes.
+ inc bx
+;
+; First check if this is PS2 E
+;
+
+ cmp word ptr es:[bx], IBM_PS2_E_MODEL
+ jne short @f
+
+ pop ds
+ pop es
+ mov eax, offset IBM_PS2_E
+ jmp Sc_Exit
+
+;
+; Is this is ThinkPad 750
+;
+
+@@:
+ cmp byte ptr es:[bx], IBM_THINKPAD_750_MODEL
+ ; Q: Does model byte match ?
+ jz short @f ; Y: Check submodel byte
+ jmp short Sc_Test3_Fail ; N: Not IBM ThinkPad
+
+@@:
+ inc bx ; Move to submodel byte
+ cmp byte ptr es:[bx], IBM_THINKPAD_750_SUBMODEL_L
+ ; Q: Does sub-model byte match ?
+ jae short @f ; Y: Possible
+ jmp short Sc_Test3_Fail ; N: Not IBM THinkPad
+
+@@: cmp byte ptr es:[bx], IBM_THINKPAD_750_SUBMODEL1 ; Is it A9?
+ je short Sc_Test3_10 ; Yes
+
+ cmp byte ptr es:[bx], IBM_THINKPAD_750_SUBMODEL_H
+ jbe short Sc_Test3_10 ; Yes
+
+ jmp short Sc_Test3_Fail ; No
+
+Sc_Test3_10:
+;
+; Make sure F000:E00E contains "IBM" string
+;
+
+ mov ax, 0f000h
+ mov ds, ax
+ mov bx, 0e00eh
+ mov eax, [bx]
+ and eax, 0ffffffh ; Only need 3 bytes
+ cmp eax, 'MBI'
+ jne short Sc_Test3_Fail ; No IBM string, Not thinkpad
+
+ pop ds
+ pop es
+ mov eax, offset IBM_THINKPAD_750
+ jmp Sc_Exit
+
+Sc_Test3_Fail:
+ pop ds
+ pop es
+
+;
+; Test for NEC VERSA and compatible machines
+; Search for 'NEV VERSA' in f000:e000 - f000:e300
+;
+
+Sc_Test4:
+ push 300h
+ push 0e000h
+ push 0f000h
+ push NecVersaStrLen
+ push offset NecVersaStr
+ push ds
+ call SearchString
+ cmp ax, 0
+ je short @f
+
+ mov eax, offset NEC_VERSA
+ add sp, 6 * 2
+ jmp short Sc_Exit
+@@:
+ add sp, 3 * 2
+ push AttGlobalystStrLen
+ push offset AttGlobalystStr
+ push ds
+ call SearchString
+ add sp, 6 * 2
+ cmp ax, 0
+ je short Sc_Test5
+
+ mov eax, offset NEC_VERSA
+ jmp short Sc_Exit
+
+Sc_Test5:
+;
+; Check if this is DECpc
+;
+
+ call DetectDECpc ; Is it a DECpcxxx?
+
+Sc_Exit:
+ pop si
+ pop di
+ pop bx
+ ret
+
+SpecialCheckings endp
+
+;++
+; VOID
+; DetectPs1 (
+; VOID
+; );
+;
+; Routine Description:
+;
+; This routine check if the target machine is PS/1 or PS/1 compatible.
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; (ax) = PS/1 Compatible.
+;
+;--
+
+DetectPs1 proc near
+
+if 0
+;
+; This does NOT work because not ALL the IBM Pc/ValuePoint models support
+; this BIOS call!!
+;
+
+;
+; Call PS/1 specific int 15 to read IBM DOS 4.0 Flags for IBM PS/1
+;
+
+; mov ax, 2300h
+; int 15h
+; jc short Dp99 ; function not supported, not compaq
+; ; portable
+; mov al, 2eh ; The return value should match
+; CMOS_READ ; cmos 2d:2e
+; mov ah, al
+; mov al, 2dh
+; CMOS_READ
+; cmp cx, ax
+; jne short Dp99
+
+endif
+
+;
+; Check if the CMOS 2e and 2f contains memory checksum. On PS/1 machine
+; the check should fail.
+;
+
+ mov cx, 2dh ; from 10h to 2dh
+ mov ax, 0
+ mov dx, 0
+Dp10:
+ mov al, cl
+ CMOS_READ
+ add dx, ax
+ dec cx
+ cmp cx, 0fh
+ jne short Dp10
+
+ mov ax, 2eh
+ CMOS_READ
+ mov ah, al
+ mov al, 2fh
+ CMOS_READ
+ cmp ax, dx
+ je short Dp99 ; NOT PS/1
+
+;
+; Next check if CMOS reg 37 contains 19
+; if yes, we assume it is PS/1.
+;
+
+ mov al, 37h
+ CMOS_READ
+ BCD_TO_BIN
+ cmp ax, 19
+ jne short Dp99
+
+ mov ax, offset PS1_COMPATIBLE
+ ret
+Dp99:
+ mov ax, 0
+ ret
+
+DetectPs1 endp
+
+;++
+; BOOLEAN
+; SearchString (
+; IN StringSeg,
+; IN StringOffset,
+; IN StringLength,
+; IN MemorySeg,
+; IN MemoryOffset,
+; IN MemoryLength
+; );
+;
+; Routine Description:
+;
+; This routine searches a string in the specified memory range
+;
+; Arguments:
+;
+;
+; Return Value:
+;
+; (ax) = TRUE or FALSE
+;
+;--
+
+SearchString proc near
+
+StringSeg equ [bp + 4]
+StringOffset equ [bp + 6]
+StringLength equ [bp + 8]
+
+MemorySeg equ [bp + 10]
+MemoryOffset equ [bp + 12]
+MemoryLength equ [bp + 14]
+
+ push bp
+ mov bp, sp
+ push ds
+ push es
+ push si
+ push di
+
+ mov ax, StringSeg
+ mov ds, ax
+ mov si, StringOffset
+ mov dx, StringLength
+
+ mov ax, MemorySeg
+ mov es, ax
+ mov di, MemoryOffset
+ mov cx, MemoryLength
+Ss_FirstLevel:
+ mov ax, 0
+ cmp cx, dx
+ je short Ss_Exit
+
+ mov al, es:[di]
+ cmp al, 61h
+ jb short @f
+
+ cmp al, 7Ah
+ ja short @f
+
+ sub al, 20h
+@@:
+ cmp al, [si]
+ je short Ss_MatchString
+
+ inc di
+ dec cx
+ cmp cx, 0
+ jne short Ss_FirstLevel
+
+ mov ax, 0
+Ss_Exit:
+ pop di
+ pop si
+ pop es
+ pop ds
+ pop bp
+ ret
+
+Ss_MatchString:
+
+ push dx ; Save string length
+ push si
+ push di
+Ss_00:
+ dec dx
+ cmp dx, 0
+ jne short Ss_10
+
+ mov ax, 1
+ pop di
+ pop si
+ pop dx
+ jmp Ss_Exit
+
+Ss_10:
+ inc si
+@@:
+ inc di
+
+ mov al, es:[di]
+ cmp al, 20h ; Is it a space or ctrl-code
+ ja short @f ; No, continue
+
+ mov al, 20h ; make it a space
+ cmp byte ptr es:[di+1], 20h ; Is next char also a space or ctrl-code
+ ja short @f ; No, continue
+
+ jmp short @b ; yes, skip current space
+
+@@:
+ cmp al, 61h
+ jb short @f
+
+ cmp al, 7Ah
+ ja short @f
+
+ sub al, 20h
+@@:
+ cmp al, [si]
+ je short Ss_00
+
+ pop di
+ pop si
+ pop dx
+ inc di
+ dec cx
+ jmp short Ss_FirstLevel
+
+SearchString endp
+
+_TEXT ends
+
+ END
diff --git a/private/ntos/boot/detect/i386/hwmcaa.asm b/private/ntos/boot/detect/i386/hwmcaa.asm
new file mode 100644
index 000000000..0d2fe2fe9
--- /dev/null
+++ b/private/ntos/boot/detect/i386/hwmcaa.asm
@@ -0,0 +1,265 @@
+ title "MicroChannel Detection Assembley Code"
+;++
+;
+; Copyright (c) 1989 Microsoft Corporation
+;
+; Module Name:
+;
+; hwmcaa.asm
+;
+; Abstract:
+;
+; This module implements the assembley code necessary to detect/collect
+; MicroChannel information.
+;
+; Author:
+;
+; Shie-Lin Tzong (shielint) 13-Feb-1992
+;
+; Environment:
+;
+; Real Mode 16-bit code.
+;
+; Revision History:
+;
+;
+;--
+
+
+.386p
+
+extrn _HwMcaPosData:DWORD
+
+;
+; The following definition must match the one defined in Hwmcac.c
+;
+; Define the size of POS data = ( slot 0 - 8 + VideoSubsystem) * (2 id bytes + 4 POS bytes)
+;
+
+VIDEO_POS_INDEX EQU 9
+POS_ENTRY_SIZE EQU 6
+POS_DATA_SIZE EQU 6 * 10
+
+;
+; POS Register ports and bits
+;
+
+SBSETUP = 94h ; system board enable/setup port
+ADSETUP = 96h ; adapter enable/setup port
+POS0 = 100h ; adapter id byte (LSB) port
+POS1 = 101h ; adapter id byte (MSB) port
+CHANNELSU = 08h ; channel setup bit for ADSETUP bit 3
+
+
+_TEXT SEGMENT PARA USE16 PUBLIC 'CODE'
+ ASSUME CS: _TEXT, DS:NOTHING, SS:NOTHING
+
+;++
+;
+; USHORT
+; Ps2SystemBoardVideoId (
+; VOID
+; )
+;
+; Routine Description:
+;
+; This function read mother board video subsystem ID and returns it
+; to the caller.
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; 16 bit Video subsystem ID.
+;
+;--
+
+ Public Ps2SystemBoardVideoId
+Ps2SystemBoardVideoId proc
+
+ push es
+ push bx
+
+ les bx, _HwMcaPosData
+ add bx, POS_ENTRY_SIZE * VIDEO_POS_INDEX
+ mov ax, es:[bx]
+
+ pop bx
+ pop es
+ ret
+
+Ps2SystemBoardVideoId endp
+
+
+;++
+;
+; BOOLEAN
+; CollectPs2PosData (
+; FPUCHAR Buffer
+; )
+;
+; Routine Description:
+;
+; This function reads adapter Id bytes and POS data from POS
+; registers and returns to the caller.
+;
+; Arguments:
+;
+; Buffer - Supplies a far pointer to a buffer to receive all the POS
+; information. Caller must make sure the buffer is big
+; enough to receive all the data.
+;
+; Return Value:
+;
+; TRUE - If operation is successful. Otherwise a value of FALSE
+; is returned.
+;
+;--
+
+ Public _CollectPs2PosData
+_CollectPs2PosData proc
+
+ push bp
+ mov bp, sp
+ push es
+ push si
+ push di
+
+ mov di, [bp + 4] ; [es:di] -> Buffer
+ mov ax, [bp + 6]
+ mov es, ax
+
+ mov cx, 0 ; Starting from slot 0
+
+ mov dx,SBSETUP ; address system board setup
+ mov al,0ffh ; turn off sys board setup mode.
+ out dx,al
+
+next_slot:
+ mov dx,ADSETUP ; address adapter setup
+ mov al,CHANNELSU ; setup bit
+ add al,cl ; channel selection
+ out dx,al ; setup to selected channel
+
+ mov dx,POS0 ; address id LSB
+ in al,dx ;
+ stosb ; store it in caller's Buffer
+ inc dx ; address id MSB
+ in al,dx ;
+ stosb ; store it in caller's Buffer
+ inc dx ; address option select data byte 1
+ in al,dx ;
+ stosb ; store it in caller's Buffer
+ inc dx ; address option select data byte 2
+ in al,dx ;
+ stosb ; store it in caller's Buffer
+ inc dx ; address option select data byte 3
+ in al,dx ;
+ stosb ; store it in caller's Buffer
+ inc dx ; address option select data byte 4
+ in al,dx ;
+ stosb ; store it in caller's Buffer
+
+ mov dx,ADSETUP ; address adapter setup
+ xor al,al ; channel selection off
+ out dx,al ; clear setup selected channel
+
+ inc cx
+ cmp cx, 9 ; Continue until CX == 9
+ jnz next_slot
+
+;
+; Now copy the Systemboard video subsystem POS data
+;
+
+ mov ax,0C400h
+ int 15h ; DX contains Base POS card register Addr.
+
+ cli ; Disable Interrupts while enabling
+ ; adapter for setup
+
+ mov al,0DFh ; Enable adapter for setup and
+ out 94h,al ; Access Video Subsystem POS data
+
+ in al,dx ; read ID (low byte) from POS reg. Addr.
+ stosb
+
+ inc dx
+ in al,dx ; read ID (high byte) from POS reg. Addr.
+ stosb
+
+ inc dx
+ in al,dx ; read Pos Data 0
+ stosb
+
+ inc dx
+ in al,dx ; read PosData 1
+ stosb
+
+ inc dx
+ in al,dx ; Read Pos data 2
+ stosb
+
+ inc dx
+ in al,dx ; read Pos Data 3
+ stosb
+
+ mov al,0FFh ; restore adapter to enabled state
+ out 94h,al
+
+ mov ax,bx ; Video subsytem ID is in BX, return in AX
+
+ sti ; re-enable interrupts
+
+ pop di
+ pop si
+ pop es
+ pop bp
+ ret
+
+_CollectPs2PosData endp
+
+;++
+;
+; BOOLEAN
+; HwIsMcaSystem (
+; VOID
+; )
+;
+; Routine Description:
+;
+; This function determines if the target machines is MCA based machines.
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; TRUE - if this is MCA machine. Otherwise, a value of FALSE is returned.
+;--
+
+ public _HwIsMcaSystem
+_HwIsMcaSystem proc
+
+ push es
+ push bx
+ mov ax, 0c000h
+ int 15h
+ mov ax, 0 ; assume NOT mca system
+ test byte ptr es:[bx+5], 2 ; check Mca bit in misc.config byte
+ jz bims00
+ mov ax, 1
+bims00:
+ pop bx
+ pop es
+ ret
+
+_HwIsMcaSystem endp
+
+_TEXT ends
+ end
+
+ \ No newline at end of file
diff --git a/private/ntos/boot/detect/i386/hwmcac.c b/private/ntos/boot/detect/i386/hwmcac.c
new file mode 100644
index 000000000..bd66b5af0
--- /dev/null
+++ b/private/ntos/boot/detect/i386/hwmcac.c
@@ -0,0 +1,86 @@
+/*++
+
+Copyright (c) 1990, 1991 Microsoft Corporation
+
+
+Module Name:
+
+ hwheap.c
+
+Abstract:
+
+ This is the Mca hardware detection module. Its main function is
+ to detect various mca related hardware.
+
+Author:
+
+ Shie-Lin Tzong (shielint) 21-Jan-92
+
+
+Environment:
+
+ Real mode.
+
+Revision History:
+
+--*/
+
+#include "hwdetect.h"
+
+//
+// Define the size of POS data = ( slot 0 - 8 + VideoSubsystem) * (2 id bytes + 4 POS bytes)
+//
+
+#define POS_DATA_SIZE (10 * 6)
+
+extern
+VOID
+CollectPs2PosData (
+ FPVOID Buffer
+ );
+
+VOID
+GetMcaPosData(
+ FPVOID Buffer,
+ FPULONG Size
+ )
+
+/*++
+
+Routine Description:
+
+ This routine collects all the mca slot POS and Id information
+ and stores it in the caller supplied Buffer and
+ returns the size of the data.
+
+Arguments:
+
+
+ Buffer - A pointer to a PVOID to recieve the address of configuration
+ data.
+
+ Size - a pointer to a ULONG to receive the size of the configuration
+ data.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ FPUCHAR ConfigurationData;
+ ULONG Length;
+
+ Length = POS_DATA_SIZE + DATA_HEADER_SIZE;
+ ConfigurationData = (FPVOID)HwAllocateHeap(Length, FALSE);
+ CollectPs2PosData(ConfigurationData + DATA_HEADER_SIZE);
+ HwSetUpFreeFormDataHeader((FPHWRESOURCE_DESCRIPTOR_LIST)ConfigurationData,
+ 0,
+ 0,
+ 0,
+ (ULONG)POS_DATA_SIZE
+ );
+ *(FPULONG)Buffer = (ULONG)ConfigurationData;
+ *Size = Length;
+}
diff --git a/private/ntos/boot/detect/i386/hwmisca.asm b/private/ntos/boot/detect/i386/hwmisca.asm
new file mode 100644
index 000000000..2cee823e8
--- /dev/null
+++ b/private/ntos/boot/detect/i386/hwmisca.asm
@@ -0,0 +1,363 @@
+ title "Misc. Support Routines"
+;++
+;
+; Copyright (c) 1989 Microsoft Corporation
+;
+; Module Name:
+;
+; misca.asm
+;
+; Abstract:
+;
+; Procedures to correctly touch I/O registers.
+;
+; Author:
+;
+; Shie-Lin Tzong (shielint) Dec-23-1991
+;
+; Environment:
+;
+; x86 real mode.
+;
+; Revision History:
+;
+;--
+
+.386p
+
+SIZE_OF_INT15_C0_BUFFER equ 10
+
+
+_TEXT SEGMENT PARA USE16 PUBLIC 'CODE'
+ ASSUME CS: _TEXT, DS:NOTHING, SS:NOTHING
+
+;++
+;
+; I/O port space read and write functions.
+;
+;--
+
+
+;++
+;
+; UCHAR
+; READ_PORT_UCHAR(
+; PUCHAR Port
+; )
+;
+; Arguments:
+; (sp+2) = Port
+;
+; Returns:
+; Value in Port.
+;
+;--
+ public _READ_PORT_UCHAR
+_READ_PORT_UCHAR proc
+
+ push bp
+ mov bp, sp
+ mov dx, [bp+4]
+ in al,dx
+ pop bp
+ ret
+
+_READ_PORT_UCHAR endp
+
+
+
+;++
+;
+; USHORT
+; READ_PORT_USHORT(
+; PUSHORT Port
+; )
+;
+; Arguments:
+; (sp+2) = Port
+;
+; Returns:
+; Value in Port.
+;
+;--
+ public _READ_PORT_USHORT
+_READ_PORT_USHORT proc
+
+ push bp
+ mov bp, sp
+ mov dx,[bp+4] ; (dx) = Port
+ in ax,dx
+ pop bp
+ ret
+
+_READ_PORT_USHORT endp
+
+;++
+;
+; VOID
+; WRITE_PORT_UCHAR(
+; PUCHAR Port,
+; UCHAR Value
+; )
+;
+; Arguments:
+; (sp+2) = Port
+; (sp+4) = Value
+;
+;--
+ public _WRITE_PORT_UCHAR
+_WRITE_PORT_UCHAR proc
+
+ push bp
+ mov bp, sp
+ mov dx,[bp+4] ; (dx) = Port
+ mov al,[bp+6] ; (al) = Value
+ out dx,al
+ pop bp
+ ret
+
+_WRITE_PORT_UCHAR endp
+
+;++
+;
+; VOID
+; WRITE_PORT_USHORT(
+; PUSHORT Port,
+; USHORT Value
+; )
+;
+; Arguments:
+; (sp+2) = Port
+; (sp+4) = Value
+;
+;--
+ public _WRITE_PORT_USHORT
+_WRITE_PORT_USHORT proc
+
+ push bp
+ mov bp, sp
+ mov dx,[bp+4] ; (dx) = Port
+ mov ax,[bp+6] ; (ax) = Value
+ out dx,ax
+ pop bp
+ ret
+
+_WRITE_PORT_USHORT endp
+
+;++
+;
+; VOID
+; GetBiosSystemEnvironment(
+; PUCHAR Buffer
+; )
+;
+; Description:
+;
+; This function performs int 15h C0H function to get System
+; Environment supplied by BIOS ROM.
+;
+; Arguments:
+;
+; Buffer - Supplies a pointer to a buffer to receive the BIOS
+; System Environment. Caller must ensure that the buffer
+; is big enough.
+;
+;--
+
+GbseBuffer equ [bp + 4]
+
+ public _GetBiosSystemEnvironment
+_GetBiosSystemEnvironment proc near
+
+ push bp
+ mov bp, sp
+
+ push bx
+ push es
+ push ds
+ push si
+ push di
+
+ mov ah, 0c0h
+ int 15h
+ mov ax, es ; exchange es and ds
+ mov cx, ds
+ mov ds, ax
+ mov es, cx
+ mov si, bx ; [ds:si] -> ROM buffer (source)
+ mov di, GbseBuffer ; [es:di] -> caller's buffer (destination)
+ mov cx, SIZE_OF_INT15_C0_BUFFER
+ rep movsb
+
+ pop di
+ pop si
+ pop ds
+ pop es
+ pop bx
+ mov sp, bp
+ pop bp
+ ret
+
+_GetBiosSystemEnvironment endp
+
+;++
+;
+; BOOLEAN
+; HwRomCompare(
+; ULONG Source,
+; ULONG Destination
+; ULONG Size
+; )
+;
+; Description:
+;
+; This function performs ROM comparison between the Source ROM
+; block and Destination ROM block.
+;
+; Arguments:
+;
+; Source - Supplies the physical address of source ROM block.
+;
+; Destination - Supplies the physical address of destination ROM block.
+;
+; Size - The size of the comparison. Must be <= 64k.
+;
+; Return:
+;
+; 0 - if the contents of Source and destination are the same.
+;
+; != 0 if the contents are different.
+;--
+
+HfSource equ [bp + 4]
+HfDestination equ [bp + 8]
+HfSize equ [bp + 12]
+
+ public _HwRomCompare
+_HwRomCompare proc near
+
+ push bp
+ mov bp, sp
+ push esi
+ push edi
+ push ds
+ push es
+ cld
+
+ mov ecx, HfSize
+ cmp ecx, 10000h
+ ja HfNotTheSame
+
+ mov eax, HfSource
+ add eax, ecx
+ cmp eax, 100000h
+ ja short HfNotTheSame
+
+ mov edx, HfDestination
+ add edx, ecx
+ cmp edx, 100000h
+ ja short HfNotTheSame
+
+ mov eax, HfSource
+ shr eax, 4
+ mov es, ax
+ mov edi, HfSource
+ and edi, 0fh
+
+ mov eax, HfDestination
+ shr eax, 4
+ mov ds, ax
+ mov esi, HfDestination
+ and esi, 0fh
+
+ shr ecx, 2
+ repe cmpsd
+
+ jnz short HfNotTheSame
+ mov ax, 0
+ jmp short HfExit
+
+HfNotTheSame:
+ mov ax, 1
+HfExit:
+ pop es
+ pop ds
+ pop edi
+ pop esi
+ pop bp
+ ret
+
+_HwRomCompare endp
+
+;++
+;
+; VOID
+; HwGetKey(
+; VOID
+; )
+;
+; Description:
+;
+; This function waits for a key to be pressed.
+;
+; Arguments:
+; None.
+;
+;--
+
+ public _HwGetKey
+_HwGetkey proc
+
+ mov ax,0100h
+ int 16h
+
+ mov ax,0
+ jz short Hgk99
+
+;
+; Now we call BIOS again, this time to get the key from the keyboard buffer
+;
+
+ int 16h
+
+Hgk99:
+ ret
+_HwGetKey endp
+
+;++
+;
+; VOID
+; HwPushKey(
+; USHORT Key
+; )
+;
+; Description:
+;
+; This function pushes a character and scan code to keyboard
+; type-ahead buffer.
+;
+; Arguments:
+;
+; Key - Supplies the key to be push back.
+; bit 0 - 7 : Character
+; bit 8 - 15: Scan Code
+;
+;--
+
+ public _HwPushKey
+_HwPushkey proc
+
+ mov cx, [esp + 2] ; character and scan code
+ mov ah, 05h
+ int 16h
+
+;
+; I don't care if the function call is successful.
+;
+
+ ret
+_HwPushKey endp
+_TEXT ends
+ end
+
+ \ No newline at end of file
diff --git a/private/ntos/boot/detect/i386/hwpbiosc.c b/private/ntos/boot/detect/i386/hwpbiosc.c
new file mode 100644
index 000000000..aa069888b
--- /dev/null
+++ b/private/ntos/boot/detect/i386/hwpbiosc.c
@@ -0,0 +1,195 @@
+
+/*++
+
+Copyright (c) 1990, 1991 Microsoft Corporation
+
+Module Name:
+
+ hwpbiosc.c
+
+Abstract:
+
+ This modules contains PnP BIOS C supporting routines
+
+Author:
+
+ Shie-Lin Tzong (shielint) 20-Apr-1995
+
+Environment:
+
+ Real mode.
+
+Revision History:
+
+--*/
+
+#include "hwdetect.h"
+#include <string.h>
+#include "pnpbios.h"
+
+BOOLEAN
+HwGetPnpBiosSystemData(
+ IN FPUCHAR *Configuration,
+ OUT PUSHORT Length
+ )
+/*++
+
+Routine Description:
+
+ This routine checks if PNP BIOS is present in the machine. If yes, it
+ also create a registry descriptor to collect the BIOS data.
+
+Arguments:
+
+ Configuration - Supplies a variable to receive the PNP BIOS data.
+
+ Length - Supplies a variable to receive the size of the data + HEADER
+
+Return Value:
+
+ A value of TRUE is returned if success. Otherwise, a value of
+ FALSE is returned.
+
+--*/
+{
+ ULONG romAddr, romEnd;
+ FPUCHAR current;
+ FPPNP_BIOS_INSTALLATION_CHECK header;
+ UCHAR sum, node = 0;
+ USHORT i, totalSize = 0, nodeSize, numberNodes, retCode;
+ ENTRY_POINT biosEntry;
+ FPPNP_BIOS_DEVICE_NODE deviceNode;
+ USHORT control = GET_CURRENT_CONFIGURATION;
+
+ //
+ // Perform PNP BIOS installation Check
+ //
+
+ MAKE_FP(current, PNP_BIOS_START);
+ romAddr = PNP_BIOS_START;
+ romEnd = PNP_BIOS_END;
+
+ while (romAddr < romEnd) {
+ header = (FPPNP_BIOS_INSTALLATION_CHECK)current;
+ if (header->Signature[0] == '$' && header->Signature[1] == 'P' &&
+ header->Signature[2] == 'n' && header->Signature[3] == 'P' &&
+ header->Length >= sizeof(PNP_BIOS_INSTALLATION_CHECK)) {
+#if DBG
+ BlPrint("GetPnpBiosData: find Pnp installation\n");
+#endif
+ sum = 0;
+ for (i = 0; i < header->Length; i++) {
+ sum += current[i];
+ }
+ if (sum == 0) {
+ break;
+ }
+#if DBG
+ BlPrint("GetPnpBiosData: Checksum fails\n");
+#endif
+ }
+ romAddr += PNP_BIOS_HEADER_INCREMENT;
+ MAKE_FP(current, romAddr);
+ }
+ if (romAddr >= romEnd) {
+ return FALSE;
+ }
+
+#if DBG
+ BlPrint("PnP installation check at %lx\n", romAddr);
+#endif
+ //
+ // Determine how much space we will need and allocate heap space
+ //
+
+ totalSize += sizeof(PNP_BIOS_INSTALLATION_CHECK) + DATA_HEADER_SIZE;
+ biosEntry = *(ENTRY_POINT far *)&header->RealModeEntryOffset;
+
+ retCode = biosEntry(PNP_BIOS_GET_NUMBER_DEVICE_NODES,
+ (FPUSHORT)&numberNodes,
+ (FPUSHORT)&nodeSize,
+ header->RealModeDataBaseAddress
+ );
+ if (retCode != 0) {
+#if DBG
+ BlPrint("GetPnpBiosData: PnP Bios GetNumberNodes func returns failure %x.\n", retCode);
+#endif
+ return FALSE;
+ }
+
+#if DBG
+ BlPrint("GetPnpBiosData: Pnp Bios GetNumberNodes returns %x nodes\n", numberNodes);
+#endif
+ deviceNode = (FPPNP_BIOS_DEVICE_NODE) HwAllocateHeap(nodeSize, FALSE);
+ if (!deviceNode) {
+#if DBG
+ BlPrint("GetPnpBiosData: Out of heap space.\n");
+#endif
+ return FALSE;
+ }
+
+ while (node != 0xFF) {
+ retCode = biosEntry(PNP_BIOS_GET_DEVICE_NODE,
+ (FPUCHAR)&node,
+ deviceNode,
+ control,
+ header->RealModeDataBaseAddress
+ );
+ if (retCode != 0) {
+#if DBG
+ BlPrint("GetPnpBiosData: PnP Bios GetDeviceNode func returns failure = %x.\n", retCode);
+#endif
+ HwFreeHeap((ULONG)nodeSize);
+ return FALSE;
+ }
+#if DBG
+ BlPrint("GetPnpBiosData: PnpBios GetDeviceNode returns nodesize %x for node %x\n", deviceNode->Size, node);
+#endif
+ totalSize += deviceNode->Size;
+ }
+
+#if DBG
+ BlPrint("GetPnpBiosData: PnpBios total size of nodes %lx\n", totalSize);
+#endif
+
+ HwFreeHeap((ULONG)nodeSize); // Free temporary buffer
+
+ current = (FPUCHAR) HwAllocateHeap(totalSize, FALSE);
+ if (!current) {
+#if DBG
+ BlPrint("GetPnpBiosData: Out of heap space.\n");
+#endif
+ return FALSE;
+ }
+
+ //
+ // Collect PnP Bios installation check data and device node data.
+ //
+
+ _fmemcpy (current + DATA_HEADER_SIZE,
+ (FPUCHAR)header,
+ sizeof(PNP_BIOS_INSTALLATION_CHECK)
+ );
+ deviceNode = (FPPNP_BIOS_DEVICE_NODE)(current + DATA_HEADER_SIZE +
+ sizeof(PNP_BIOS_INSTALLATION_CHECK));
+ node = 0;
+ while (node != 0xFF) {
+ retCode = biosEntry(PNP_BIOS_GET_DEVICE_NODE,
+ (FPUCHAR)&node,
+ deviceNode,
+ control,
+ header->RealModeDataBaseAddress
+ );
+ if (retCode != 0) {
+#if DBG
+ BlPrint("GetPnpBiosData: PnP Bios func 1 returns failure = %x.\n", retCode);
+#endif
+ HwFreeHeap((ULONG)totalSize);
+ return FALSE;
+ }
+ deviceNode = (FPPNP_BIOS_DEVICE_NODE)((FPUCHAR)deviceNode + deviceNode->Size);
+ }
+ *Configuration = current;
+ *Length = totalSize;
+ return TRUE;
+}
diff --git a/private/ntos/boot/detect/i386/hwpci.inc b/private/ntos/boot/detect/i386/hwpci.inc
new file mode 100644
index 000000000..568985e34
--- /dev/null
+++ b/private/ntos/boot/detect/i386/hwpci.inc
@@ -0,0 +1,44 @@
+;++
+;
+; Copyright (c) 1989 Microsoft Corporation
+;
+; Module Name:
+;
+; hwpci.inc
+;
+; Abstract:
+;
+; Author:
+;
+; Revision History:
+;
+;--
+
+;
+; PCI_INTERFACE_INT interrupt is the PCI BIOS entry point
+; PCI_BIOS_PRESENT AX function code for PCI BIOS entry point
+;
+
+PCI_INTERFACE_INT EQU 01AH
+PCI_BIOS_PRESENT EQU 0B101h
+
+
+; Down level bios checl
+
+PCI10_BIOS_PRESENT EQU 0B001h
+
+;
+; Structure for PCI System Data - it is passed to the system
+; through the register to inform it what type of PCI support,
+; if any, is present.
+;
+
+
+PCI_SYSTEM_DATA struc
+
+ MajorRevision db 0
+ MinorRevision db 0
+ NoBuses db 0
+ HwMechanism db 0
+
+PCI_SYSTEM_DATA ends
diff --git a/private/ntos/boot/detect/i386/hwpcia.asm b/private/ntos/boot/detect/i386/hwpcia.asm
new file mode 100644
index 000000000..f888d204b
--- /dev/null
+++ b/private/ntos/boot/detect/i386/hwpcia.asm
@@ -0,0 +1,279 @@
+ title "PCI bus Support Assembley Code"
+;++
+;
+; Copyright (c) 1989 Microsoft Corporation
+;
+; Module Name:
+;
+; hwpcia.asm
+;
+; Abstract:
+;
+; Calls the PCI rom function to determine what type of PCI
+; support is prsent, if any.
+;
+; Base code provided by Intel
+;
+; Author:
+;
+;--
+
+
+.386p
+ .xlist
+include hwpci.inc
+ .list
+
+if DBG
+ extrn _BlPrint:PROC
+endif
+
+_DATA SEGMENT PARA USE16 PUBLIC 'DATA'
+
+if DBG
+cr equ 11
+
+PciBIOSSig db 'PCI: Scanning for "PCI "', cr, 0
+PciBIOSSigNotFound db 'PCI: BIOS "PCI " not found', cr, 0
+
+
+PciInt db 'PCI: Calling PCI_BIOS_PRESENT', cr, 0
+PciIntFailed db 'PCI: PCI_BIOS_PRESENT returned carry', cr, 0
+PciIntAhFailed db 'PCI: PCI_BIOS_PRESENT returned bad AH value', cr, 0
+PciIDFailed db 'PCI: PCI_BIOS_PRESENT invalid PCI id', cr, 0
+PciInt10IdFailed db 'PCI: PCI10_BIOS_PRESENT invalid PCI id', cr, 0
+
+PciFound db 'PCI BUS FOUND', cr, 0
+endif
+
+_DATA ends
+
+
+_TEXT SEGMENT PARA USE16 PUBLIC 'CODE'
+ ASSUME CS: _TEXT
+
+;++
+;
+; BOOLEAN
+; HwGetPciSystemData (
+; PPCI_SYSTEM_DATA PciSystemData
+; )
+;
+; Routine Description:
+;
+; This function retrieves the PCI System Data
+;
+; Arguments:
+;
+; PciSystemData - Supplies a pointer to the structure which will
+; receive the PCI System Data.
+;
+; Return Value:
+;
+; True - PCI System Detected and System Data valid
+; False - PCI System Not Detected
+;
+;--
+
+SystemInfoPointer equ [bp + 4]
+BiosDateFound equ [bp + 6]
+
+ public _HwGetPciSystemData
+_HwGetPciSystemData proc
+ push bp ; The following INT 15H destroies
+ mov bp, sp ; ALL the general registers.
+ push si
+ push di
+ push bx
+;
+; Set for no PCI buses present
+;
+
+ mov bx, SystemInfoPointer
+ mov byte ptr [bx].NoBuses, 0
+
+;
+; Is the BIOS date >= 11/01/92? If so, make the int-1a call
+;
+ push ds
+ cmp byte ptr [BiosDateFound], 0
+ jnz gpci00
+
+;
+; A valid BIOS date was not found, check for "PCI " in bios code.
+;
+
+if DBG
+ push offset PciBIOSSig
+ call _BlPrint
+ add sp, 2
+endif
+ mov bx, 0f000h
+ mov ds, bx
+ mov bx, 0fffch
+
+spci05: cmp dword ptr ds:[bx], ' ICP' ; 'PCI ' found at this addr?
+ je short gpci00 ; found
+
+ dec bx ; next location
+ jnz short spci05 ; loop
+ jmp spci_notfound ; wrapped, all done - not found
+
+gpci00:
+ pop ds
+
+if DBG
+ push offset PciInt
+ call _BlPrint
+ add sp, 2
+endif
+;
+; Check for a PCI system. Issue the PCI Present request.
+;
+
+ mov ax, PCI_BIOS_PRESENT ; Real Mode Presence Request
+ int PCI_INTERFACE_INT ; Just Do It!
+
+ jc gpci10 ; Carry Set => No PCI
+
+ cmp ah, 0 ; If PCI Present AH == 0
+ jne gpci12 ; AH != 0 => No PCI
+
+ cmp edx, " ICP" ; "PCI" Backwards (with a trailing space)
+ jne gpci14 ; PCI Signature in EDX => PCI Exists
+
+;
+; Found PCI BIOS Version > 1.0
+;
+; The only thing left to do is squirrel the data away for the caller
+;
+
+ mov dx, bx ; Save revision level
+ mov bx, SystemInfoPointer ; Get caller's Pointer
+
+ mov byte ptr [bx].MajorRevision, dh
+ mov byte ptr [bx].MinorRevision, dl
+ inc cl ; NoBuses = LastBus+1
+
+if 0
+;
+; Some PIC BIOS returns very large number of NoBuses. As a work-
+; around we mask the value to 16, unless the BIOS also return CH as
+; neg cl then we believe it.
+;
+
+ cmp cl, 16
+ jbe short @f
+
+ neg ch
+ inc ch
+ cmp cl, ch
+ je short @f
+
+ mov cl, 16
+@@:
+endif
+
+
+ mov byte ptr [bx].NoBuses, cl
+ mov byte ptr [bx].HwMechanism, al
+ jmp Done ; We're done
+
+if DBG
+gpci10: mov ax, offset PciIntFailed
+ jmp short gpci_oldbios
+
+gpci12: mov ax, offset PciIntAhFailed
+ jmp short gpci_oldbios
+
+gpci14: mov ax, offset PciIDFailed
+gpci_oldbios:
+ push ax
+ call _BlPrint
+ add sp, 2
+
+else
+
+gpci10:
+gpci12:
+gpci14:
+
+endif
+
+
+ ;
+ ; Look for BIOS Version 1.0, This has a different function #
+ ;
+
+ mov ax, PCI10_BIOS_PRESENT ; Real Mode Presence Request
+ int PCI_INTERFACE_INT ; Just Do It!
+
+ ; Version 1.0 has "PCI " in dx and cx, the Version number in ax, and the
+ ; carry flag cleared. These are all the indications available.
+ ;
+
+ cmp dx, "CP" ; "PC" Backwards
+ jne gpci50 ; PCI Signature not in DX & CX => No PCI
+
+ cmp cx, " I" ; "I " Backwards
+ jne gpci50 ; PCI Signature not in EDX => No PCI
+
+;
+; Found PCI BIOS Version 1.0
+;
+; The only thing left to do is squirrel the data away for the caller
+;
+
+ mov bx, SystemInfoPointer ; Get caller's Pointer
+
+ mov byte ptr [bx].MajorRevision, ah
+ mov byte ptr [bx].MinorRevision, al
+
+ ;
+ ; The Version 1.0 BIOS is only on early HW that had couldn't support
+ ; Multi Function devices or multiple bus's. So without reading any
+ ; device data, mark it as such.
+ ;
+
+ mov byte ptr [bx].HwMechanism, 2
+ mov byte ptr [bx].NoBuses, 1
+ jmp Done
+
+
+spci_notfound:
+ pop ds ; restore ds
+if DBG
+ push offset PciBIOSSigNotFound
+ call _BlPrint
+ add sp, 2
+endif
+ jmp gpci_exit
+
+
+if DBG
+gpci50: push offset PciInt10IdFailed
+ jmp Done10
+
+Done: push offset PciFound
+Done10: call _BlPrint
+ add sp, 2
+
+else
+
+; non-debug no prints
+gpci50:
+Done:
+
+endif
+
+gpci_exit:
+ pop bx
+ pop di
+ pop si
+ pop bp
+ ret
+
+_HwGetPciSystemData endp
+
+_TEXT ends
+ end
diff --git a/private/ntos/boot/detect/i386/hwvbios.h b/private/ntos/boot/detect/i386/hwvbios.h
new file mode 100644
index 000000000..4612b3014
--- /dev/null
+++ b/private/ntos/boot/detect/i386/hwvbios.h
@@ -0,0 +1,74 @@
+//
+// Defines for machine models
+//
+
+#define PS2_AT 0xF819 // PS/2 non-micro channel
+#define PS2_L40 0xF823 // PS/2 non-micro channel
+#define PS1_386 0xF830 // 386 non-microchannel // 6.13
+
+#define PS2_PORT 0x0001 // PS/2 specific port
+#define ISA_PORT 0x0002 // AT specific port
+#define HYBRID_PORT 0x0004 // PS/2 non-micro channel specific port
+
+//
+// Bios int 15h C0h buffer definition
+//
+
+struct BIOS_INT15_C0_BUFFER {
+ USHORT Size;
+ USHORT Model;
+ UCHAR BiosRevision;
+ UCHAR ConfigurationFlags;
+ UCHAR Reserved[4];
+} BiosSystemEnvironment;
+
+typedef struct _TEMPORARY_ROM_BLOCK {
+ ROM_BLOCK RomBlock;
+ struct _TEMPORARY_ROM_BLOCK far *Next;
+} TEMPORARY_ROM_BLOCK, far * FPTEMPORARY_ROM_BLOCK;
+
+#define POS_MAX_SLOT 8
+
+#define ROMBIOS_START 0xF0000
+#define ROMBIOS_LEN 0x10000
+
+#define PS2BIOS_START 0xE0000
+#define PS2BIOS_LEN 0x20000
+
+#define EXTROM_START 0xC0000 // where and how far to
+#define EXTROM_LEN 0x40000 // search for external adapter ROMs
+
+#define EBIOSDATA_START 0x9FC00
+#define EBIOSDATA_LEN 0x00400
+
+#define NUMBER_VECTORS 0x80
+#define VGA_PARAMETER_POINTER 0x4A8
+#define ALIGN_DOWN(address,amt) ((ULONG)(address) & ~(( amt ) - 1))
+#define ALIGN_UP(address,amt) (ALIGN_DOWN( (address + (amt) - 1), (amt) ))
+
+//
+// ROM format
+//
+
+#define ROM_HEADER_SIGNATURE 0xAA55
+#define ROM_HEADER_INCREMENT 0x800
+#define BLOCKSIZE 512
+
+typedef struct _ROM_HEADER {
+ USHORT Signature; // should be ROMHDR_SIGNATURE
+ UCHAR NumberBlocks; // # of ROM blocks
+ UCHAR Filler[ROM_HEADER_INCREMENT - 3];
+} ROM_HEADER, far *FPROM_HEADER;
+
+//
+// External References
+//
+
+extern
+BOOLEAN
+HwRomCompare (
+ ULONG Source,
+ ULONG Destination,
+ ULONG Size
+ );
+
diff --git a/private/ntos/boot/detect/i386/hwvbiosc.c b/private/ntos/boot/detect/i386/hwvbiosc.c
new file mode 100644
index 000000000..bf58bc584
--- /dev/null
+++ b/private/ntos/boot/detect/i386/hwvbiosc.c
@@ -0,0 +1,968 @@
+/*++
+
+Copyright (c) 1990, 1991 Microsoft Corporation
+
+
+Module Name:
+
+ hwheap.c
+
+Abstract:
+
+ This module goes through ROM area and tries to pick up all the ROM
+ blocks.
+
+Author:
+
+ Shie-Lin Tzong (shielint) 21-Jan-92
+
+
+Environment:
+
+ Real mode.
+
+Revision History:
+
+--*/
+
+#include "hwdetect.h"
+#include "hwvbios.h"
+
+FPTEMPORARY_ROM_BLOCK BlockHead;
+FPTEMPORARY_ROM_BLOCK BlockPointer;
+
+BOOLEAN
+AddRomBlock (
+ ULONG RomAddress,
+ ULONG RomSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds a ROM/RAM block to our ROM list.
+
+Arguments:
+
+ RomAddress - the starting address of the ROM/RAM block to be added.
+
+ RomSize - the size of the ROM/RAM block (in byte).
+
+Return Value:
+
+ A value of TRUE is returned if success. Otherwise, a value of
+ FALSE is returned.
+
+--*/
+
+{
+ LONG AddSize;
+ ULONG AddAddress;
+ FPTEMPORARY_ROM_BLOCK pCurrentBlock, pNextBlock;
+ ULONG CurrentBlock, NextBlock, AddBlock;
+ ULONG EndAddBlock, EndCurrentBlock, EndNextBlock;
+ BOOLEAN fOverlap=FALSE;
+
+ pCurrentBlock = NULL;
+ pNextBlock = NULL;
+ AddSize = RomSize;
+ AddAddress = RomAddress;
+ AddBlock = RomAddress;
+
+ //
+ // If there are other blocks, make sure there is no overlap with them
+ //
+
+ if (BlockHead) {
+
+ pCurrentBlock = BlockHead;
+ pNextBlock = pCurrentBlock->Next;
+ CurrentBlock = pCurrentBlock->RomBlock.Address;
+ EndCurrentBlock = CurrentBlock + pCurrentBlock->RomBlock.Size;
+ EndAddBlock = RomAddress + RomSize;
+
+ while (pCurrentBlock!=NULL) {
+
+ //
+ // calculate location of next block (if it's there)
+ //
+
+ if(pNextBlock) {
+ NextBlock = pNextBlock->RomBlock.Address;
+ EndNextBlock = NextBlock + pNextBlock->RomBlock.Size;
+ }
+
+ //
+ // if overlapping with current block, then stop and
+ // resolve overlap
+ //
+
+ if((RomAddress < EndCurrentBlock)&& (RomAddress >= CurrentBlock)){
+ fOverlap = TRUE;
+ break;
+ }
+
+ //
+ // if add block is lower than the current one,
+ // or there is not a next block, then no need to search further
+ //
+
+ if((EndAddBlock <= CurrentBlock) || (pNextBlock == NULL)) {
+ break;
+ }
+
+ //
+ // if block is lower than next one, but greater than current
+ // one, we have found the right area
+ //
+
+ if ((EndAddBlock <= NextBlock) && (AddBlock >= EndCurrentBlock)) {
+ break;
+ }
+
+ //
+ // if conflicting with next block, stop searching and
+ // resolve conflict after this loop
+ //
+
+ if((EndAddBlock > NextBlock) && (EndAddBlock <= EndNextBlock)) {
+ fOverlap = TRUE;
+ break;
+ }
+
+ pCurrentBlock = pNextBlock;
+ pNextBlock = pCurrentBlock->Next;
+ CurrentBlock = NextBlock;
+ EndCurrentBlock = EndNextBlock;
+ }
+ }
+
+ //
+ // if we have reached this point, there may be a conflict
+ // with the current block.
+ //
+
+ if(fOverlap) {
+ if(AddBlock < EndCurrentBlock) {
+ AddAddress = EndCurrentBlock;
+ AddSize = EndAddBlock - EndCurrentBlock;
+ if(AddSize <= 0) {
+ return TRUE;
+ }
+ }
+ if((pNextBlock != NULL) && (EndAddBlock > NextBlock)) {
+ AddSize = NextBlock - AddBlock;
+ if(AddSize <= 0) {
+ return TRUE;
+ }
+ }
+ }
+
+ BlockPointer->RomBlock.Address = AddAddress;
+ BlockPointer->RomBlock.Size = AddSize;
+
+ //
+ // Put it on the list.
+ // if it belongs on top, put it there
+ //
+
+ if ((pCurrentBlock == NULL)||
+ ((pCurrentBlock == BlockHead) && (CurrentBlock > AddBlock))) {
+ BlockPointer->Next = pCurrentBlock;
+ BlockHead = BlockPointer;
+ } else {
+
+ //
+ // else add to middle or bottom depending on NextBlock
+ //
+
+ BlockPointer->Next = pNextBlock;
+ pCurrentBlock->Next = BlockPointer;
+ }
+ BlockPointer++; // Note that this works because
+ // we know the offset part of
+ // the addr is always < 64k.
+ return TRUE;
+}
+VOID
+AddPs2CardRomRam (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds ROM/RAM block to our ROM list for missed MCA Adapters.
+
+ Notes: This function was constructed to recognize
+ PS/2 cards that normally are missed. Without
+ this code, VBIOS will not recognize certain adapters
+ since they have no ROM header, or use RAM.
+
+ POS ID Adapter Name ROM RAM
+ ------- ------------ --- ---
+ E000 Token Ring x x
+ E001 Token Ring x x
+ E04F 3119 Scanner x
+ E1FF 3270 Ver B x
+ E7FF 3270 Ver A x
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG i;
+ USHORT CardID;
+ ULONG ROMAddr,RAMAddr;
+ ULONG RAMSize, ROMSize;
+ FPMCA_POS_DATA PosData;
+
+ //
+ // for every adapter slot, we search if the card is IBM Token Ring.
+ // if yes, we will calculate RAM and ROM address from POS information
+ // and add these blocks to our ROM BLOCK list.
+ //
+
+ for (i = 0L; i < POS_MAX_SLOT; i++) {
+
+ ROMAddr = 0L;
+ RAMAddr = 0L;
+ RAMSize = 0L;
+ ROMSize = 0L;
+
+ //
+ // get the POS ID of the card
+ //
+
+ PosData = HwMcaPosData + i;
+ CardID = PosData->AdapterId;
+ switch(CardID) {
+
+ //
+ // 4Mhz Token ring (0xE000) or 16/4Mhz Token ring (0xE001)
+ //
+
+ case 0xE000:
+ case 0xE001:
+
+ //
+ // get ROM and RAM addresses of adapter
+ //
+
+ ROMAddr = ((ULONG)PosData->PosData3 & 0xfe)<<12;
+ RAMAddr = ((ULONG)PosData->PosData1 & 0xfe)<<12;
+ RAMSize = (ULONG) (1<<((PosData->PosData2 & 0x0c)>>2)) * 8192L;
+ ROMSize = 8192L;
+ break;
+
+ //
+ // 3119 Scanner
+ // formula (shl (and (not (shr POS[0] 4)) 0xf) 13) + 0xC0000
+ //
+
+ case 0xE04F:
+
+ RAMAddr = (((~((ULONG)PosData->PosData1 >> 4)) & 0xf) << 13) + 0xC0000L;
+ RAMSize = 0x2000L; // size is fixed
+ break;
+
+ //
+ // 3270 Version A
+ //
+
+ case 0xE7FF:
+
+ RAMAddr = 0xCE000L; // address is fixed
+ RAMSize = 8192L; // size is fixed
+ break;
+
+ //
+ // 3270 Version B
+ //
+
+ case 0xE1FF:
+
+ RAMAddr = ((ULONG)PosData->PosData2) << 12;
+ RAMSize = 8192L; // size is fixed
+ break;
+
+ default:
+ break;
+ }
+
+ //
+ // if adapter has ROM, then add it
+ //
+
+ if (ROMAddr) {
+ AddRomBlock(ROMAddr, ROMSize);
+ }
+
+ //
+ // if adapter has RAM, then add it
+ //
+
+ if (RAMAddr) {
+ AddRomBlock(RAMAddr, RAMSize);
+ }
+ }
+}
+
+BOOLEAN
+ScanRomBlocks(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans the ROM IO area and checks for 55AA at every
+ 512 bytes for valid ROM blocks.
+
+
+ NOTES:
+
+ -------------
+ | |
+ | |
+ ------------------100000
+ ^ | |
+ | | |
+ | -------------f0000 (ROMBIOS_START) ---
+ | | | ^
+ | | | |
+ EXTROM_LEN -------------e0000 (PS2BIOS_START) --- |
+ | | | ^ Search |
+ | | | Search | Range |
+ | -------------d0000 Range | on AT |
+ | | | on PS/2| |
+ V | | V V
+ ------------------c0000 (EXTROM_START) --- ---
+
+ ON AT:
+ Scan through EXTROM_START-effff for ROM Blocks
+ ON PS2
+ Scan through EXTROM_START-dffff for ROM Blocks
+
+Arguments:
+
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG BlockSize;
+ BOOLEAN Success = TRUE;
+ FPUCHAR Current;
+ ULONG RomAddr, RomEnd;
+
+ //
+ // As per the machine type restrict the search range
+ //
+
+ MAKE_FP(Current, EXTROM_START);
+ RomAddr = EXTROM_START;
+
+ if ((HwBusType == MACHINE_TYPE_MCA) ||
+ (BiosSystemEnvironment.Model == PS2_L40) ||
+ (BiosSystemEnvironment.Model == PS1_386) ||
+ (BiosSystemEnvironment.Model == PS2_AT)) {
+
+ RomEnd = PS2BIOS_START;
+ } else {
+ RomEnd = ROMBIOS_START;
+ }
+
+ while (RomAddr < RomEnd) {
+
+ if (((FPROM_HEADER)Current)->Signature == ROM_HEADER_SIGNATURE) {
+
+ BlockSize = (ULONG)((FPROM_HEADER)Current)->NumberBlocks * BLOCKSIZE;
+
+ if ((RomAddr + BlockSize) > RomEnd) {
+ BlockSize = RomEnd - RomAddr;
+ }
+
+ //
+ // V7 VRAM card does not correctly report its BlockSize. Since
+ // this is a very popular video card, we provide a workaround
+ // for it.
+ //
+
+ if ((RomAddr == 0xC0000) && (BlockSize < 0x8000)) {
+ BlockSize = 0x8000;
+ }
+ if (!AddRomBlock(RomAddr, BlockSize)) {
+ Success = FALSE;
+ break;
+ }
+ RomAddr += BlockSize;
+ RomAddr = ALIGN_UP(RomAddr, ROM_HEADER_INCREMENT);
+ MAKE_FP(Current, RomAddr);
+ continue;
+ }
+ RomAddr += ROM_HEADER_INCREMENT;
+ MAKE_FP(Current, RomAddr);
+ }
+
+ //
+ // Last but not least, add the system ROM to the list
+ //
+
+ if (Success) {
+
+ RomAddr = ROMBIOS_START;
+ BlockSize = ROMBIOS_LEN;
+ if ((HwBusType == MACHINE_TYPE_MCA) ||
+ (BiosSystemEnvironment.Model == PS2_L40) ||
+ (BiosSystemEnvironment.Model == PS1_386) ||
+ (BiosSystemEnvironment.Model == PS2_AT)) {
+ RomAddr = PS2BIOS_START;
+ BlockSize = PS2BIOS_LEN;
+ }
+
+ if (!AddRomBlock(RomAddr, BlockSize)) {
+ Success = FALSE;
+ }
+ }
+
+ return Success;
+}
+
+FPTEMPORARY_ROM_BLOCK
+MatchRomBlock (
+ ULONG PhysicalAddr
+ )
+
+/*++
+
+Routine Description:
+
+ This routine finds the ROM block which the 'PhysicalAddr' is in.
+
+Arguments:
+
+ PhysicalAddr - the physical address ...
+
+Return Value:
+
+ A pointer to the detected ROM block.
+
+--*/
+
+{
+ FPTEMPORARY_ROM_BLOCK CurrentBlock;
+ ROM_BLOCK RomBlock;
+
+ CurrentBlock = BlockHead;
+ while (CurrentBlock) {
+ RomBlock = CurrentBlock->RomBlock;
+ if (RomBlock.Address <= PhysicalAddr &&
+ RomBlock.Address + RomBlock.Size > PhysicalAddr) {
+ break;
+ } else {
+ CurrentBlock = CurrentBlock->Next;
+ }
+ }
+ return(CurrentBlock);
+}
+
+BOOLEAN
+IsSameRomBlock (
+ FPTEMPORARY_ROM_BLOCK Source,
+ FPTEMPORARY_ROM_BLOCK Destination
+ )
+
+/*++
+
+Routine Description:
+
+ This routine checks if the passed in ROM blocks contain the same
+ information. This ususally happens when the two ROM blocks are for
+ video ROM and shadowed video ROM.
+
+Arguments:
+
+ Source - the source ROM block.
+
+ Destination - the ROM block to compare with.
+
+Return Value:
+
+ BOOLEAN TRUE if the two ROM blocks are the same else FALSE is returned.
+
+--*/
+
+{
+
+ if (Source == NULL || Destination == NULL) {
+ return(FALSE);
+ }
+
+ //
+ // First make sure their sizes are the same.
+ //
+
+ if (Source->RomBlock.Size == Destination->RomBlock.Size) {
+ if (!HwRomCompare(Source->RomBlock.Address,
+ Destination->RomBlock.Address,
+ Source->RomBlock.Size)){
+ return(TRUE);
+ }
+ }
+ return(FALSE);
+
+}
+
+VOID
+CheckVideoRom (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine checks if the int 10h video handler is in the video
+ ROM block detected by us. If not, the video ROM must have been
+ remapped/shadowed to other area (usually 0xE0000.)
+
+ NOTE: In this function, I commented out the code which removes the
+ Video ROM block if it has been shadowed. I found out
+ machine POST code does not modify ALL the VIDEO ROM related
+ pointers.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG Vector, Handler, VectorAddr = 0x10 * sizeof(ULONG);
+ FPULONG pVectorAddr;
+ FPTEMPORARY_ROM_BLOCK RomBlock, VideoRomBlock;
+ ULONG Size;
+
+ MAKE_FP(pVectorAddr, VectorAddr);
+ Vector = *pVectorAddr;
+ Handler = ((Vector >> 16) << 4) + (Vector & 0xffff);
+ RomBlock = MatchRomBlock(Handler);
+
+ //
+ // Check if the int 10h handler falls in one of our ROM blocks.
+ //
+
+ if (RomBlock) {
+ if (RomBlock->RomBlock.Address >= 0xC0000 &&
+ RomBlock->RomBlock.Address < 0xC8000) {
+
+ //
+ // if int 10h handler is in the standard video ROM area, we simply
+ // return. Either the video ROM is not shadowed or it
+ // is a in-place shadow.
+ //
+
+ return;
+ } else {
+
+ //
+ // The ROM block associated with the int 10h handler is not in
+ // standard video bios ROM area. It must have been mapped to
+ // the current location. We now need to make sure we have the
+ // ROM block which contains the 40:a8 VGA parameter.
+ //
+
+ VectorAddr = VGA_PARAMETER_POINTER;
+ MAKE_FP(pVectorAddr, VectorAddr);
+ Vector = *pVectorAddr;
+ Handler = ((Vector >> 16) << 4) + (Vector & 0xffff);
+ VideoRomBlock = MatchRomBlock(Handler);
+ if (VideoRomBlock == NULL) {
+
+ //
+ // We did not find the Video ROM associated with the
+ // VGA parameters. Try detect it.
+ //
+
+ //
+ // In the following memory comparison, we skip the first 16 bytes.
+ // Because most likely the reason we did not find the standard
+ // Video ROM is because the signature word is missing.
+ //
+
+ Handler = (Handler & 0xF0000) +
+ (RomBlock->RomBlock.Address & 0xFFFF);
+ if (!HwRomCompare(RomBlock->RomBlock.Address + 0x10,
+ Handler + 0x10,
+ RomBlock->RomBlock.Size - 0x10)) {
+ if ((Handler & 0xFFFF == 0) && (RomBlock->RomBlock.Size < 0x8000)){
+ Size = 0x8000;
+ } else {
+ Size = RomBlock->RomBlock.Size;
+ }
+ AddRomBlock(Handler, Size);
+ }
+ }
+ }
+ } else {
+
+ //
+ // There is no ROM block associated with the int 10h handler.
+ // We can find the shadowed video ROM block if:
+ // We detected the original video ROM in 0xC0000 - 0xC8000 range
+ //
+
+ VideoRomBlock = MatchRomBlock((Handler & 0xFFFF) + 0xC0000);
+ if (VideoRomBlock != NULL) {
+
+ //
+ // In the following memory comparison, we skip the first 16 bytes.
+ // Because most likely the reason we did not find the shadow rom
+ // is the signature word is missing.
+ //
+
+ if (!HwRomCompare(VideoRomBlock->RomBlock.Address + 0x10,
+ (Handler & 0xF0000) +
+ (VideoRomBlock->RomBlock.Address & 0xFFFF) + 0x10,
+ VideoRomBlock->RomBlock.Size - 0x10)) {
+
+ AddRomBlock((VideoRomBlock->RomBlock.Address & 0xFFFF) +
+ (Handler & 0xF0000),
+ VideoRomBlock->RomBlock.Size);
+ }
+ }
+ }
+}
+
+VOID
+GetRomBlocks(
+ FPUCHAR ReservedBuffer,
+ PUSHORT Size
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans the ROM IO area and collects all the ROM blocks.
+
+Arguments:
+
+ ReservedBuffer - Supplies a far pointer to the buffer.
+
+ Size - Supplies a near pointer to a variable to receive the size
+ of the ROM block.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ FPTEMPORARY_ROM_BLOCK Source;
+ ULONG StartAddr, EndAddr;
+ FPUSHORT TestAddr;
+ FPROM_BLOCK Destination;
+ USHORT BufferSize;
+ ULONG EBiosAddress = 0, EBiosLength = 0;
+ ULONG far *EBiosInformation = (ULONG far *)
+ ((DOS_BEGIN_SEGMENT << 4) + EBIOS_INFO_OFFSET);
+
+ //
+ // First we reserve the max space needed and build our temporary rom
+ // block list in the heap space below the space reservedand. After
+ // the temporary list is built, we then copy it to the caller supplied
+ // reserved space.
+ //
+
+ BlockPointer = (FPTEMPORARY_ROM_BLOCK)HwAllocateHeap(0, FALSE);
+ BlockHead = NULL;
+ *Size = 0;
+
+ GetBiosSystemEnvironment((PUCHAR)&BiosSystemEnvironment);
+ if (BiosSystemEnvironment.ConfigurationFlags & 0x4) {
+
+ //
+ // If extened BIOS data area is allocated, we will find out its
+ // location and size and save in ROM blocks.
+ //
+
+ _asm {
+ push es
+ mov ah, 0xC1
+ int 15h
+ jc short Exit
+
+ cmp ah, 0x86
+ je short Exit
+
+ mov bx, 0
+ mov dx, 0
+ mov ax, 0
+ mov al, es:[bx]
+ shl ax, 10
+ mov word ptr EBiosLength, ax
+ mov ax, es
+ mov dx, es
+ shl ax, 4
+ shr dx, 12
+ mov word ptr EBiosAddress, ax
+ mov word ptr EBiosAddress + 2, dx
+ Exit:
+ pop es
+ }
+ }
+
+ //
+ // Save the Extended BIOS data area address and size at 700:40
+ //
+
+ if (EBiosLength) {
+ *EBiosInformation++ = EBiosAddress;
+ *EBiosInformation = EBiosLength;
+ } else {
+ *EBiosInformation++ = 0L;
+ *EBiosInformation = 0L;
+ }
+ if (!ScanRomBlocks()) {
+ return;
+ }
+
+ if (HwBusType == MACHINE_TYPE_MCA) {
+ AddPs2CardRomRam();
+ }
+
+ //
+ // On some machines, when they shadow video ROM from 0xC0000 to
+ // 0xE0000, they copy code only (no signature.) So, we need
+ // special code to work around the problem.
+ //
+
+ CheckVideoRom();
+
+ //
+ // Now do our special hack for IBM. On SOME IBM PCs, they use
+ // E0000-FFFFF for system BIOS (even on non PS/2 machines.) Since
+ // system BIOS has no ROM header, it is very hard to know the starting
+ // address of system ROM. So we:
+ //
+ // 1. Make sure there is no ROM block in E0000-EFFFF area.
+ // 2. and E0000-EFFFF contains valid data.
+ //
+ // If both 1 and 2 are true, we assume E0000-EFFFF is part of system
+ // ROM.
+ //
+
+ Source = BlockHead;
+ while (Source) {
+ StartAddr = Source->RomBlock.Address;
+ EndAddr = StartAddr + Source->RomBlock.Size - 1;
+ if ((StartAddr < 0xE0000 && EndAddr < 0xE0000) ||
+ (StartAddr >= 0xF0000)) {
+ Source = Source->Next;
+ } else {
+ break;
+ }
+ }
+ if (Source == NULL) {
+ for (StartAddr = 0xE0000; StartAddr < 0xF0000; StartAddr += 0x800) {
+ MAKE_FP(TestAddr, StartAddr);
+ if (*TestAddr != 0xffff) {
+ AddRomBlock(0xE0000, 0x10000);
+ break;
+ }
+ }
+ }
+
+ //
+ // Now copy the rom block list to our reserved space and release
+ // the extra space we reserved.
+ //
+
+ Source = BlockHead;
+ Destination = (FPROM_BLOCK)ReservedBuffer;
+ BufferSize = 0;
+ while (Source) {
+ *Destination = *((FPROM_BLOCK)&Source->RomBlock);
+ BufferSize += sizeof(ROM_BLOCK);
+ Source = Source->Next;
+ Destination++;
+ }
+ *Size = BufferSize;
+}
+
+VOID
+HwGetBiosDate(
+ ULONG StartingAddress,
+ USHORT Length,
+ PUSHORT Year,
+ PUSHORT Month,
+ PUSHORT Day
+ )
+/*++
+
+Routine Description:
+
+ Scans the specified area for the most recent date of the
+ form xx/xx/xx.
+
+Arguments:
+
+ StartingAddress - First address to scan
+ Length - Length of area to scan
+
+Return Value:
+
+ Year - If non-zero, the year of the date (1991, 1992, ...)
+ Month - If non-zero, then month of the date found
+ Day - If non-zero, the day of the date found
+
+
+--*/
+{
+ FPUCHAR fp, date;
+ USHORT y, m, d;
+ UCHAR c;
+
+ //
+ // Zero return values
+ //
+
+ *Year = 0;
+ *Month = 0;
+ *Day = 0;
+
+ //
+ // Search for date with the format MM/DD/YY or M1M1M2M2//D1D1D2D2//Y1Y1Y2Y2
+ //
+
+ MAKE_FP(fp, StartingAddress); // initialize fp pointer
+ while (Length > 8) {
+
+ c = fp[7];
+ if ((c < '0' || c > '9') && (c != '/' && c != '-')) {
+ // these 8 bytes are not a date, next location
+
+ fp += 8;
+ Length -= 8;
+ continue;
+ }
+
+ date = fp; // check for date at this pointer
+ fp += 1; // skip to next byte
+ Length -= 1;
+
+ //
+ // Check for date of the form MM/DD/YY
+ //
+
+ y = 0;
+ if (date[0] >= '0' && date[0] <= '9' &&
+ date[1] >= '0' && date[1] <= '9' &&
+ (date[2] == '/' || date[2] == '-') &&
+ date[3] >= '0' && date[3] <= '9' &&
+ date[4] >= '0' && date[4] <= '9' &&
+ (date[5] == '/' || date[5] == '-') &&
+ date[6] >= '0' && date[6] <= '9' &&
+ date[7] >= '0' && date[7] <= '9' ) {
+
+
+ //
+ // A valid looking date field at date, crack it
+ //
+
+ y = (date[6] - '0') * 10 + date[7] - '0' + 1900;
+ m = (date[0] - '0') * 10 + date[1] - '0';
+ d = (date[3] - '0') * 10 + date[4] - '0';
+
+ if (y < 1980 || m < 1 || m > 12 || d < 1 || d > 31) {
+ y = 0; // bad field in date, skip it
+ }
+ }
+
+ //
+ // Check for date of the form M1M1M2M2//D1D1D2D2//Y1Y1Y2Y2
+ //
+
+ if (Length >= 15 &&
+ date[ 0] >= '0' && date[ 0] <= '9' && date[ 0] == date[ 1] &&
+ date[ 2] >= '0' && date[ 2] <= '9' && date[ 2] == date[ 3] &&
+ (date[ 4] == '/' || date[ 4] == '-') && date[ 4] == date[ 5] &&
+ date[ 6] >= '0' && date[ 6] <= '9' && date[ 6] == date[ 7] &&
+ date[ 8] >= '0' && date[ 8] <= '9' && date[ 8] == date[ 9] &&
+ (date[10] == '/' || date[10] == '-') && date[10] == date[11] &&
+ date[12] >= '0' && date[12] <= '9' && date[12] == date[13] &&
+ date[14] >= '0' && date[14] <= '9' && date[14] == date[15]) {
+
+ //
+ // A valid looking date field at date, crack it
+ //
+
+ y = (date[12] - '0') * 10 + date[14] - '0' + 1900;
+ m = (date[ 0] - '0') * 10 + date[ 2] - '0';
+ d = (date[ 6] - '0') * 10 + date[ 8] - '0';
+
+ if (y < 1980 || m < 1 || m > 12 || d < 1 || d > 31) {
+ y = 0; // bad field in date, skip it
+ }
+ }
+
+ //
+ // Check for date of the form 19xx
+ //
+
+ if (date[0] == '1' &&
+ date[1] == '9' &&
+ date[2] >= '8' && date[2] <= '9' &&
+ date[3] >= '0' && date[3] <= '9' &&
+ (date[4] < '0' || date [4] > '9')) {
+
+ y = (date[2] - '0') * 10 + date[3] - '0' + 1900;
+ m = 0;
+ d = 0;
+ }
+
+ if (!y) {
+ // not a date - skip it
+ continue;
+ }
+
+ if ((y > *Year) ||
+ (y == *Year && m > *Month) ||
+ (y == *Year && m == *Month && d > *Day) ) {
+
+ //
+ // This date is more recent
+ //
+
+ *Year = y;
+ *Month = m;
+ *Day = d;
+ }
+ }
+}
+
+
+
diff --git a/private/ntos/boot/detect/i386/keybda.asm b/private/ntos/boot/detect/i386/keybda.asm
new file mode 100644
index 000000000..ba1b06a36
--- /dev/null
+++ b/private/ntos/boot/detect/i386/keybda.asm
@@ -0,0 +1,480 @@
+ title "Keyboard Detection"
+;++
+;
+; Copyright (c) 1989 Microsoft Corporation
+;
+; Module Name:
+;
+; cpu.asm
+;
+; Abstract:
+;
+; This module implements the assembley code necessary to determine
+; keyboard.
+;
+; Author:
+;
+; Shie-Lin Tzong (shielint) 16-Dec-1991. Most of the code is extracted
+; from Win31 Setup.
+;
+; Environment:
+;
+; 80x86 Real Mode.
+;
+; Revision History:
+;
+;
+;--
+
+extrn _READ_PORT_UCHAR:proc
+
+;
+; Now define the needed equates.
+;
+
+TRUE equ -1
+FALSE equ 0
+
+;
+; equates for ports -- these are used in the keyboard detection module.
+;
+
+ack_port equ 20h ; 8259 acknowledge port
+eoi equ 20h ; 8259 end of interrupt
+
+kb_data equ 60h
+kb_ctl equ 61h
+kb_command equ 64h ;
+kb_status equ 64h ; status port -- bit 1: ok to write
+
+ENABLE_KEYBOARD_COMMAND EQU 0AEH
+DISABLE_KEYBOARD_COMMAND EQU 0ADH
+
+.386
+
+_TEXT SEGMENT PARA USE16 PUBLIC 'CODE'
+ ASSUME CS: _TEXT, DS:NOTHING, SS:NOTHING
+
+
+;++
+;
+; BOOLEAN
+; IsEnhancedKeyboard (
+; VOID
+; )
+;
+; Routine Description:
+;
+; Function looks at bios data area 40:96 to see if an enhanced keyboard
+; is present.
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; TRUE if Enhanced keyboard is present. Else a value of FALSE is returned.
+;
+;--
+
+ Public _IsEnhancedKeyboard
+_IsEnhancedKeyboard proc near
+
+ push es
+
+ mov ax,40h
+ mov es,ax
+ xor ax,ax
+ mov al,byte ptr es:[96h]
+ and al,00010000b
+
+ pop es
+ ret
+
+_IsEnhancedKeyboard endp
+
+
+;++
+;
+; SHORT
+; GetKeyboardIdBytes (
+; PCHAR IdBuffer,
+; SHORT Length
+; )
+;
+; Routine Description:
+;
+; This routine returns keyboard identification bytes.
+;
+; Note that this function accepts one argument. The arg is a pointer to a
+; character buffer allocated to hold five (five) bytes. Upon return from
+; this function the buffer will contain between 1 and 5 bytes of keyboard
+; ID information. The number of valid ID bytes in the buffer is returned
+; in AX as a C proc return value.
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; Id bytes are stored in IdBuffer and the length of Id bytes is returned.
+;
+;--
+
+KeybID EQU [bp + 4] ; parameters
+ReqByte EQU [bp + 6]
+
+nKeyID EQU [bp - 2] ; Local variables
+AckByte EQU [bp - 3]
+
+ public _GetKeyboardIdBytes
+_GetKeyboardIdBytes proc near
+
+ push bp
+ mov bp, sp
+ sub sp, 4 ; space for local variables
+ push bx
+ push es
+
+;
+; First I initialize needed local vars. Next I find out if machine is AT
+; type or non AT type for the purpose of selecting proper acknowledgement
+; byte so I can talk to the interrupt controler.
+;
+
+ mov bx, KeybID ; Initialize base pointer to buffer.
+ mov word ptr nKeyID, 0 ; Initialize count to zero.
+ mov byte ptr AckByte, 20h ; for all but AT-like. acknowledge for
+ ; interrupt controller. 61h for AT's.
+ mov ax, 0fff0h ; look into 0FFF0:0FE location.
+ mov es, ax ; this is where the model byte is.
+ mov al, byte ptr es:[0feh]
+ cmp al, 0fch ; is it AT-like?
+ jne UnlikeAT
+ mov byte ptr AckByte, 61h
+ call _Empty8042
+if 0
+ ;
+ ; Disable keyboard is a right thing to do. But, it turned out
+ ; this causes some keyboards to fail GetId.
+ ;
+
+ call DisableKeyboard
+endif
+
+UnlikeAT:
+
+;
+; Now, let's see if we can get some ID bytes from the keyboard controler.
+;
+
+ mov ah, ReqByte ; AT: send second command.
+ mov dx, 60h ; write to data port
+ call Write8042 ; Output command byte to keyboard, bytes in AH
+ call ReadKeyboard ; Get byte from keyboard, byte in AL if No CF
+ jc gotNoByte
+ mov [bx], al ; save a byte. remember bx is pointer.
+ inc word ptr nKeyID
+ call ReadKeyboard ; Get byte from keyboard, byte in AL if No CF
+ jc gotNoByte
+ mov [bx]+1, al ; save a byte. remember bx is pointer.
+ inc word ptr nKeyID
+ call ReadKeyboard ; check for extra bytes.
+ jc gotNoByte
+ mov [bx]+2, al ; save a byte. remember bx is pointer.
+ inc word ptr nKeyID
+
+gotNoByte:
+ mov al, AckByte
+ out ack_port, al
+ call EnableKeyboard
+ call _Empty8042
+ mov ax, nKeyID ; Return number of valid ID bytes obtained.
+
+ pop es
+ pop bx
+ mov sp, bp
+ pop bp
+ ret
+_GetKeyboardIdBytes endp
+
+;++
+;
+; UCHAR
+; ReadKeyboard (
+; VOID
+; )
+;
+; Routine Description:
+;
+; This routine reads character from keyboard.
+;
+; It is assumed that a command (05H or 0F2H) has been set to request
+; that the keyboard send an identification byte.
+; It is also assumed that interrupts are disabled.
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; If a character is returned, the carry bit is reset.
+; If no character is returned, the carry bit is set.
+;
+;--
+
+ public ReadKeyboard
+ReadKeyboard proc near
+
+ push cx
+ push bx
+ mov bx, 2 ; set outer timeout for double nested.
+ cli
+
+inner_timeout:
+ xor cx, cx ; set inner timeout for double nested.
+
+kbiwait:
+ in al, kb_status ; wait for port ready
+ test al, 1 ; ready?
+ jnz kbiAvailable
+ loop kbiwait
+
+ dec bx ; decrement outer timeout loop.
+ jnz inner_timeout ; zero out inner loop again.
+ stc
+ jmp short no_byte
+
+kbiAvailable: ; we received a byte.
+ mov cx,100
+
+ ;
+ ; We need to let some time elapse before we try to read the data
+ ; because of a problem running this code in the DOS box under
+ ; OS/2.
+ ;
+
+wait_for_data:
+ loop wait_for_data
+
+ in al, kb_data ; get data byte.
+ clc
+
+no_byte:
+ sti
+ pop bx
+ pop cx
+ ret
+
+ReadKeyboard endp
+
+
+;++
+;
+; UCHAR
+; Write8042 (
+; USHORT Port,
+; UCHAR Command
+; )
+;
+; Routine Description:
+;
+; This routine writes command byte to keyboard.
+;
+; It is assumed that a command (05H or 0F2H) has been set to request
+; that the keyboard send an identification byte.
+; It is also assumed that interrupts are disabled.
+;
+; Arguments:
+;
+; Port (dx) - Port to write data to
+; Command (ah) - to be written to keyboard.
+;
+; Return Value:
+;
+; None.
+;
+;--
+ public Write8042
+Write8042 proc near
+
+ push cx
+ push bx
+ mov bx, 4 ; set outer timeout for double nested.
+ cli
+
+reset_inner:
+ xor cx, cx ; set inner timeout for double dested.
+
+koutwait:
+ in al, kb_status ; get 8042 status
+ test al, 10b ; can we output a byte?
+ jz ok_to_send
+ loop koutwait
+
+ dec bx ; decrement outer timeout loop.
+ jnz reset_inner ; zero out inner loop again.
+ jmp short nosiree ; timeout expired, don't try to send.
+
+ok_to_send:
+ call _Empty8042
+ mov al, ah ; ok, send the byte
+ out dx, al
+
+nosiree:
+ sti
+ pop bx
+ pop cx
+ ret
+
+Write8042 endp
+
+;++
+;
+; UCHAR
+; GetKeyboardFlags (
+; VOID
+; )
+;
+; Routine Description:
+;
+; This routine returns the ROM BIOS flags byte that describes the state
+; of the various keyboard toggles and shift keys.
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; Keyboard ROM BIOS Flags byte.
+;
+;--
+
+ public _GetKeyboardFlags
+_GetKeyboardFlags proc near
+
+ mov ah, 02
+ int 16h
+ ret
+
+_GetKeyboardFlags endp
+
+
+;++
+;
+; VOID
+; EnableKeyboard (
+; VOID
+; )
+;
+; Routine Description:
+;
+; This routine enables 8042 keyboard interface.
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; None.
+;
+;--
+
+ public EnableKeyboard
+EnableKeyboard proc near
+
+ mov ah, ENABLE_KEYBOARD_COMMAND
+ mov dx, kb_command
+ call Write8042
+ ret
+
+EnableKeyboard endp
+
+;++
+;
+; VOID
+; DisableKeyboard (
+; VOID
+; )
+;
+; Routine Description:
+;
+; This routine disables 8042 keyboard interface.
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; None.
+;
+;--
+
+ public DisableKeyboard
+DisableKeyboard proc near
+
+ mov ah, DISABLE_KEYBOARD_COMMAND
+ mov dx, kb_command
+ call Write8042
+ ret
+
+DisableKeyboard endp
+
+;++
+;
+; VOID
+; Empty8042 (
+; VOID
+; )
+;
+; Routine Description:
+;
+; This routine drains the i8042 controller's output buffer. This gets
+; rid of stale data that may have resulted from the user hitting a key
+; or moving the mouse, prior to the execution of keyboard initialization.
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; None.
+;
+;--
+
+ public _Empty8042
+_Empty8042 proc near
+
+ push ax
+ push dx
+ pushf
+ cli
+E8Check:
+ in al, kb_status ; wait for port ready
+ test al, 1 ; ready?
+ jz E8Exit
+
+ mov dx, kb_data
+ push dx
+ call _READ_PORT_UCHAR ; use this call to delay I/O
+ add sp, 2
+ jmp E8Check
+E8Exit:
+ popf
+ pop dx
+ pop ax
+ ret
+
+_Empty8042 endp
+
+_TEXT ends
+
+END
+ \ No newline at end of file
diff --git a/private/ntos/boot/detect/i386/keybdc.c b/private/ntos/boot/detect/i386/keybdc.c
new file mode 100644
index 000000000..c898e593d
--- /dev/null
+++ b/private/ntos/boot/detect/i386/keybdc.c
@@ -0,0 +1,356 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ abiosc.c
+
+Abstract:
+
+ This module implements keybaord detection C routines.
+
+Author:
+
+ Shie-Lin Tzong (shielint) 18-Dec-1991
+
+Environment:
+
+ Real Mode.
+
+
+Revision History:
+
+--*/
+
+#include "hwdetect.h"
+#include "string.h"
+
+extern
+UCHAR
+GetKeyboardFlags (
+ VOID
+ );
+
+extern
+USHORT
+HwGetKey (
+ VOID
+ );
+
+extern BOOLEAN NoBiosKbdCheck;
+
+//
+// SavedKey is used to save the key left in the keyboard type-ahead buffer
+// before we start our keyboard/mouse tests. The key will be push back
+// to the type-ahead buffer once the mouse detection is done.
+//
+
+USHORT SavedKey = 0;
+
+//
+// String table to map keyboard id to an ascii string.
+//
+
+PUCHAR KeyboardIdentifier[] = {
+ "UNKNOWN_KEYBOARD",
+ "OLI_83KEY",
+ "OLI_102KEY",
+ "OLI_86KEY",
+ "OLI_A101_102KEY",
+ "XT_83KEY",
+ "ATT_302",
+ "PCAT_ENHANCED",
+ "PCAT_86KEY",
+ "PCXT_84KEY"
+ };
+
+UCHAR KeyboardType[] = {
+ -1,
+ 1,
+ 2,
+ 3,
+ 4,
+ 1,
+ 1,
+ 4,
+ 3,
+ 1
+ };
+
+UCHAR KeyboardSubtype[] = {
+ -1,
+ 0,
+ 1,
+ 10,
+ 4,
+ 42,
+ 4,
+ 0,
+ 0,
+ 0
+ };
+
+USHORT
+GetKeyboardId(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines the Id of the keyboard. It calls GetKeyboardIdBytes
+ to complete the task.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Keyboard ID.
+
+--*/
+
+{
+ char KeybID_Bytes[5];
+ int Num_ID_Bytes;
+ int keytype = UNKNOWN_KEYBOARD;
+
+ SavedKey = HwGetKey();
+
+ Num_ID_Bytes = GetKeyboardIdBytes(KeybID_Bytes, 0x05);
+ if (Num_ID_Bytes > 0) {
+ switch(KeybID_Bytes[0] & 0x00ff) {
+ case 0x02:
+ keytype = OLI_83KEY;
+ break;
+
+ case 0x01:
+ keytype = OLI_102KEY;
+ break;
+
+ case 0x10:
+ keytype = OLI_86KEY;
+ break;
+
+ case 0x40:
+ keytype = OLI_A101_102KEY;
+ break;
+
+ case 0x42:
+ keytype = XT_83KEY;
+ break;
+
+ case 0x9c:
+ keytype = PCXT_84KEY;
+ break;
+
+ case 0x04:
+ keytype = ATT_302;
+ break;
+
+ case 0xfe:
+ Num_ID_Bytes = GetKeyboardIdBytes(KeybID_Bytes, 0xf2);
+ if (Num_ID_Bytes > 0) {
+ if ((KeybID_Bytes[0] & 0x00ff) == 0xfa) {
+ keytype = PCAT_86KEY;
+ } else if ((KeybID_Bytes[0] & 0x00ff) == 0xfe) {
+ keytype = PCAT_86KEY;
+ } else if (Num_ID_Bytes >= 3 &&
+ ((KeybID_Bytes[1] & 0x00ff) == 0xAB) &&
+ ((KeybID_Bytes[2] & 0x00ff) == 0x41)) {
+ keytype = PCAT_ENHANCED;
+ } else {
+ keytype = UNKNOWN_KEYBOARD;
+ }
+ } else {
+ keytype = UNKNOWN_KEYBOARD;
+ }
+ break;
+
+ default:
+ keytype = UNKNOWN_KEYBOARD;
+ break;
+ }
+ } else {
+ keytype = PCXT_84KEY;
+ }
+
+ if (!NoBiosKbdCheck) {
+
+ //
+ // Sometimes enhanced keyboards get detected as 84/86 key keyboards
+ // So we will look into the ROM DATA area (40:96) and see if the
+ // Enhanced Keyboard bit is set. If it is we will assume that the
+ // detection failed to detect the presence of an enhanced keyb.
+ //
+
+ if ((keytype == PCXT_84KEY) ||
+ (keytype == PCAT_86KEY) ||
+ (keytype == UNKNOWN_KEYBOARD)) {
+
+ if (IsEnhancedKeyboard()) {
+ keytype = PCAT_ENHANCED;
+ }
+ }
+ }
+ return(keytype);
+}
+
+FPFWCONFIGURATION_COMPONENT_DATA
+SetKeyboardConfigurationData (
+ USHORT KeyboardId
+ )
+
+/*++
+
+Routine Description:
+
+ This routine maps Keyboard Id information to an ASCII string and
+ stores the string in configuration data heap.
+
+Arguments:
+
+ KeyboardId - Supplies a USHORT which describes the keyboard id information.
+
+ Buffer - Supplies a pointer to a buffer where to put the ascii.
+
+Returns:
+
+ None.
+
+--*/
+{
+ FPFWCONFIGURATION_COMPONENT_DATA Controller, CurrentEntry;
+ FPFWCONFIGURATION_COMPONENT Component;
+ HWCONTROLLER_DATA ControlData;
+ FPHWRESOURCE_DESCRIPTOR_LIST DescriptorList;
+ CM_KEYBOARD_DEVICE_DATA far *KeyboardData;
+ USHORT z, Length;
+
+ //
+ // Set up Keyboard COntroller component
+ //
+
+ ControlData.NumberPortEntries = 0;
+ ControlData.NumberIrqEntries = 0;
+ ControlData.NumberMemoryEntries = 0;
+ ControlData.NumberDmaEntries = 0;
+ z = 0;
+ Controller = (FPFWCONFIGURATION_COMPONENT_DATA)HwAllocateHeap (
+ sizeof(FWCONFIGURATION_COMPONENT_DATA), TRUE);
+
+ Component = &Controller->ComponentEntry;
+
+ Component->Class = ControllerClass;
+ Component->Type = KeyboardController;
+ Component->Flags.ConsoleIn = 1;
+ Component->Flags.Input = 1;
+ Component->Version = 0;
+ Component->Key = 0;
+ Component->AffinityMask = 0xffffffff;
+
+ //
+ // Set up Port information
+ //
+
+ ControlData.NumberPortEntries = 2;
+ ControlData.DescriptorList[z].Type = RESOURCE_PORT;
+ ControlData.DescriptorList[z].ShareDisposition =
+ CmResourceShareDeviceExclusive;
+ ControlData.DescriptorList[z].Flags = CM_RESOURCE_PORT_IO;
+ ControlData.DescriptorList[z].u.Port.Start.LowPart = 0x60;
+ ControlData.DescriptorList[z].u.Port.Start.HighPart = 0;
+ ControlData.DescriptorList[z].u.Port.Length = 1;
+ z++;
+ ControlData.DescriptorList[z].Type = RESOURCE_PORT;
+ ControlData.DescriptorList[z].ShareDisposition =
+ CmResourceShareDeviceExclusive;
+ ControlData.DescriptorList[z].Flags = CM_RESOURCE_PORT_IO;
+ ControlData.DescriptorList[z].u.Port.Start.LowPart = 0x64;
+ ControlData.DescriptorList[z].u.Port.Start.HighPart = 0;
+ ControlData.DescriptorList[z].u.Port.Length = 1;
+ z++;
+
+ //
+ // Set up Irq information
+ //
+
+ ControlData.NumberIrqEntries = 1;
+ ControlData.DescriptorList[z].Type = RESOURCE_INTERRUPT;
+ ControlData.DescriptorList[z].ShareDisposition =
+ CmResourceShareUndetermined;
+ ControlData.DescriptorList[z].u.Interrupt.Affinity = ALL_PROCESSORS;
+ ControlData.DescriptorList[z].u.Interrupt.Level = 1;
+ ControlData.DescriptorList[z].u.Interrupt.Vector = 1;
+ if (HwBusType == MACHINE_TYPE_MCA) {
+ ControlData.DescriptorList[z].Flags = LEVEL_SENSITIVE;
+ } else {
+
+ //
+ // For EISA the LevelTriggered is temporarily set to FALSE.
+ //
+
+ ControlData.DescriptorList[z].Flags = EDGE_TRIGGERED;
+ }
+
+ Controller->ConfigurationData =
+ HwSetUpResourceDescriptor(Component,
+ NULL,
+ &ControlData,
+ 0,
+ NULL
+ );
+
+ //
+ // Set up Keyboard peripheral component
+ //
+
+ CurrentEntry = (FPFWCONFIGURATION_COMPONENT_DATA)HwAllocateHeap (
+ sizeof(FWCONFIGURATION_COMPONENT_DATA), TRUE);
+
+ Component = &CurrentEntry->ComponentEntry;
+
+ Component->Class = PeripheralClass;
+ Component->Type = KeyboardPeripheral;
+ Component->Flags.ConsoleIn = 1;
+ Component->Flags.Input = 1;
+ Component->Version = 0;
+ Component->Key = 0;
+ Component->AffinityMask = 0xffffffff;
+ Component->ConfigurationDataLength = 0;
+ CurrentEntry->ConfigurationData = (FPVOID)NULL;
+ Length = strlen(KeyboardIdentifier[KeyboardId]) + 1;
+ Component->IdentifierLength = Length;
+ Component->Identifier = HwAllocateHeap(Length, FALSE);
+ _fstrcpy(Component->Identifier, KeyboardIdentifier[KeyboardId]);
+
+ if (KeyboardId != UNKNOWN_KEYBOARD) {
+
+ Length = sizeof(HWRESOURCE_DESCRIPTOR_LIST) +
+ sizeof(CM_KEYBOARD_DEVICE_DATA);
+ DescriptorList = (FPHWRESOURCE_DESCRIPTOR_LIST)HwAllocateHeap(
+ Length,
+ TRUE);
+ CurrentEntry->ConfigurationData = DescriptorList;
+ Component->ConfigurationDataLength = Length;
+ DescriptorList->Count = 1;
+ DescriptorList->PartialDescriptors[0].Type = RESOURCE_DEVICE_DATA;
+ DescriptorList->PartialDescriptors[0].u.DeviceSpecificData.DataSize =
+ sizeof(CM_KEYBOARD_DEVICE_DATA);
+ KeyboardData = (CM_KEYBOARD_DEVICE_DATA far *)(DescriptorList + 1);
+ KeyboardData->KeyboardFlags = GetKeyboardFlags();
+ KeyboardData->Type = KeyboardType[KeyboardId];
+ KeyboardData->Subtype = KeyboardSubtype[KeyboardId];
+ }
+
+ Controller->Child = CurrentEntry;
+ Controller->Sibling = NULL;
+ CurrentEntry->Parent = Controller;
+ CurrentEntry->Sibling = NULL;
+ CurrentEntry->Child = NULL;
+ return(Controller);
+}
+
diff --git a/private/ntos/boot/detect/i386/main.asm b/private/ntos/boot/detect/i386/main.asm
new file mode 100644
index 000000000..1f0a5904b
--- /dev/null
+++ b/private/ntos/boot/detect/i386/main.asm
@@ -0,0 +1,207 @@
+ title "Processor type and stepping detection"
+;++
+;
+; Copyright (c) 1989 Microsoft Corporation
+;
+; Module Name:
+;
+; main.asm
+;
+; Abstract:
+;
+; This file implements the main entry code for x86 hardware detection
+; module. This assembly file is required in order to link C modules
+; into a "/TINY" (single segment) memory module.
+;
+; Author:
+;
+; Shie-Lin Tzong (shielint) 15-Feb-1992.
+; The code is extracted from NTLDR su.asm.
+;
+; Environment:
+;
+; x86 Real Mode.
+;
+; Revision History:
+;
+;
+; Build Notes:
+; ~~~~~~~~~~~~
+; The microsoft C compiler will not produce "tiny" model programs. In the
+; tiny model, the entire program consists of only one segment. The small
+; model produced by our compilers consists of two segments: DGROUP and _TEXT.
+; If you convert a small model program into a tiny model program, DS (which
+; should point to DGROUP (bss,const,data) will always be wrong. For this reason
+; we need an assembly module to do a simple run-time fixup on SS and DS. To
+; guarantee that DS will point to DGROUP no matter where the detection module
+; is loaded, the paragraph (shifted right four bits) offset of DGROUP from
+; _TEXT must be added to the value in CS to compute DS and SS.
+;
+; We get the linker to fixup the offset of the beginning of the dgroup segment
+; relative to the beginning of the code segment and it's this value added
+; to the value in CS that allows us to build a "tiny" model program in C
+; without a lot of munging around in order to get the data reference offsets
+; in the code correct.
+;
+; If the _TEXT:DGROUP fixup appears in other files (which it does), the linker
+; will not compute the correct value unless the accumulated data pointer is
+; zero when it gets there. Therefore, no data should be placed in the data segment
+; until after all instances of _TEXT:DGROUP have been encountered by the linker.
+; The linker processes files from right to left on the command line.
+;
+;--
+
+.386p
+
+include main.inc
+
+_DATA SEGMENT PARA USE16 PUBLIC 'DATA'
+
+;
+; Define double wrod to save caller's (ntldr's) stack pointer
+;
+
+NtldrStack df 0 ; saved area for ss:esp
+
+ dw 2048 dup (0)
+DetectionStack equ $
+
+_DATA ends
+
+_TEXT segment para use16 public 'CODE'
+ ASSUME CS: _TEXT, DS: DGROUP, SS: DGROUP
+
+
+;++
+;
+; VOID
+; DetectionMain (
+; ULONG HeapStart,
+; ULONG HeapSize,
+; ULONG ConfigurationTree,
+; ULONG HeapUsed,
+; ULONG LoadOptions,
+; ULONG LoadOptionsLength
+; )
+;
+; Routine Description:
+;
+; This is the entry point of the detection module.
+; Memory from HeapStart to (HeapStart + HeapSize) is allocated for detection
+; module to store the hardware configuration tree.
+; Note that detection module loaded address will be resued by loader after
+; the control is passed back to ntldr.
+;
+; Arguments:
+;
+; HeapStart - supplies a 32 bit FLAT starting addr of the heap
+;
+; HeapSize - Supplies the size of the useable heap
+;
+; ConfigurationTree - Supplies a 32 bit FLAT address of the variable to
+; receive the configuration tree.
+;
+; HeapUsed - Supplies a 32 bit FLAT address of the variable to receive
+; the size of heap we acually used.
+;
+; LoadOptions - Supplies a 32 bit FLAT address of the load options string.
+;
+; LoadOptionsLength - Supplies the length of the LoadOptions string. Note,
+; this is for sanity check to make sure the LoadOptions string is valid.
+; (in case use usews Nt 1.0 ntldr with the new ntdetect.com.)
+;
+; Return Value:
+;
+; None.
+;
+;--
+;
+
+;
+; Run-time fixups for stack and data segment
+;
+
+ public DetectionMain
+DetectionMain:
+
+;
+; Save all the registers we need to preserved on NTLDR's stack
+;
+
+ push ebp
+ mov ebp, esp
+ and ebp, 0ffffh
+ push ds
+ push es
+ push ebx
+ push esi
+ push edi
+
+;
+; Compute the paragraph needed for DS
+;
+
+ mov cx,offset _TEXT:DGROUP ; first calculate offset to data
+ shr cx,4 ; must be para aligned
+
+ mov ax,cs ; get base of code
+ add ax,cx ; add paragraph offset to data
+
+;
+; Make DS point to the paragraph address of DGROUP
+;
+
+ mov ds,ax ; ds now points to beginning of DGROUP
+ mov es,ax
+
+;
+; Save old stack pointer and set up our own stack.
+;
+
+ mov ecx, esp
+ mov dword ptr NtldrStack, ecx
+ mov cx, ss
+ mov word ptr NtldrStack + 4, cx
+
+ mov ebx, [bp + 8] ; [ebx] = Heap Start
+ mov ecx, [bp + 12] ; [ecx] = Heap Size
+ mov esi, [bp + 16] ; [esi] -> addr of ConfigurationTree
+ mov edi, [bp + 20] ; [edi] -> Addr of HeapUsed variable
+ mov edx, [bp + 24] ; [edx]-> Addr of LoadOptions string
+ mov ebp, [bp + 28] ; [ebp] = length of LoadOptions
+
+ mov ss,ax
+ mov esp,offset DGROUP:DetectionStack ; (ss:esp) = top of internal stack
+
+;
+; Set up parameters and invoke real detection code to collect hardware
+; information.
+;
+
+ push ebp
+ push edx
+ push edi
+ push esi
+ push ecx
+ push ebx
+ call _HardwareDetection
+
+;
+; The hardware detection is done. We need to switch to ntldr's stack,
+; restore registers and return back to ntldr.
+;
+
+ lss esp, NtldrStack
+
+ pop edi ; retore registers
+ pop esi
+ pop ebx
+ pop es
+ pop ds
+ pop ebp
+
+ retf
+
+_TEXT ends
+
+ end DetectionMain
diff --git a/private/ntos/boot/detect/i386/main.inc b/private/ntos/boot/detect/i386/main.inc
new file mode 100644
index 000000000..a8f314f0e
--- /dev/null
+++ b/private/ntos/boot/detect/i386/main.inc
@@ -0,0 +1,53 @@
+;++
+;
+; Copyright (c) 1989 Microsoft Corporation
+;
+; Module Name:
+;
+; main.inc
+;
+; Abstract:
+;
+; This module defines the segment for the detection module.
+;
+; Author:
+;
+; Shie-Lin Tzong (shielint) 16-Feb-1992.
+;
+; Revision History:
+;
+;
+;--
+
+.386
+
+;
+; Segment declarations for "Small Model" 16 bit Su Module.
+;
+
+_TEXT segment para use16 public 'CODE'
+_TEXT ends
+
+_DATA segment para use16 public 'DATA'
+_DATA ends
+
+CONST segment para use16 public 'CONST'
+CONST ends
+
+_BSS segment para use16 public 'BSS'
+_BSS ends
+
+DGROUP group const, _BSS, _DATA
+
+;
+; Define the stack location for detection module.
+;
+
+DETECTION_STACK_SP EQU 0fffch
+
+;
+; External references
+;
+
+extrn _HardwareDetection: near
+
diff --git a/private/ntos/boot/detect/i386/mouse.inc b/private/ntos/boot/detect/i386/mouse.inc
new file mode 100644
index 000000000..18ca26897
--- /dev/null
+++ b/private/ntos/boot/detect/i386/mouse.inc
@@ -0,0 +1,392 @@
+;++
+;
+; Copyright (c) 1989 Microsoft Corporation
+;
+; Module Name:
+;
+; mouse.inc
+;
+; Abstract:
+;
+; This file defines the hardware specific equates to be used in
+; the mouse detection code.
+;
+; Author:
+;
+; Shie-Lin (shielint) 22-Feb-1992
+;
+; Revision History:
+;
+;--
+
+;
+; External references
+;
+
+extrn _InportMouseIrqDetection:proc
+extrn _READ_PORT_UCHAR: proc
+extrn _WRITE_PORT_UCHAR: proc
+
+;
+; Internal Macros
+;
+
+IOdelay macro
+ jmp $+2
+ jmp $+2
+endm
+
+address macro StartAddr, EndAddr
+ add dx,StartAddr-EndAddr
+endm
+
+DelayIn macro
+ push dx
+ call _READ_PORT_UCHAR ; destroy AL
+ add sp, 2
+endm
+
+DelayOut macro
+ push ax
+ push dx
+ call _WRITE_PORT_UCHAR ; destroy AL
+ add sp, 4
+endm
+
+;
+; Mouse information structure
+; N.B. This must match the one defined in hwdetect.h
+;
+
+MouseInformation struc
+ MouseType db 0
+ MouseSubtype db 0
+ MousePort dw 0 ; if serial mouse, 1 for com1, 2 for com2 ...
+ MouseIrq dw 0
+ DeviceIdLength dw 0
+ DeviceId db 10 dup(?); Pnp device id if any
+MouseInformation ends
+
+
+;
+; Mouse ID's returned by GetMouseType().
+;
+
+UNKNOWN_MOUSE equ 0 ; Don't know whether or not a mouse is
+ ; installed...
+NO_MOUSE equ 100H ; No mouse installed.
+MS_MOUSE equ 200H ; MS Regular mouse
+MS_BALLPOINT equ 300H ; MS Ballpoint mouse
+LT_MOUSE equ 400H ; LogTec mouse
+
+PS2_MOUSE equ 1h ; Connect to 8042 mouse port
+SERIAL_MOUSE equ 2h
+INPORT_MOUSE equ 3h
+BUS_MOUSE equ 4h
+PS2_MOUSE_WITH_WHEEL equ 5
+SERIAL_MOUSE_WITH_WHEEL equ 6
+
+TRUE EQU 0ffh
+FALSE EQU 0
+
+LW_ClockTickCount EQU 46Ch
+HW_ClockTickCount EQU 46Eh
+
+;************************************************************************
+; I N P O R T D E F I N I T I O N S *
+;************************************************************************
+
+INP_ADDR EQU 0 ; Inport addr register offset.
+INP_DATA EQU 1 ; Inport data register offset.
+INP_ID EQU 2 ; Inport ID register offset.
+INP_TEST EQU 3 ; Inport test register offset.
+
+INPORT_ID EQU 0DEh ; InPort ID byte.
+
+INP_STATUS_REG EQU 0 ; Status register number.
+INP_DATA1_REG EQU 1 ; Internal data register 1.
+INP_DATA2_REG EQU 2 ; Internal data register 2.
+INP_MODE_REG EQU 7 ; Mode register number.
+
+INP_RESET EQU 10000000b ; Value to reset InPort.
+
+HZ0INTR0 EQU 00000000b ; Value to select 0 Hz, INTR=0
+HZ0INTR1 EQU 00000110b ; Value to select 0 Hz, INTR=1
+HZ30 EQU 00000001b ; Value to select 30 Hz.
+DATA_INT_ENAB EQU 00001000b ; Data int enable bit.
+TIMER_INT_ENAB EQU 00010000b ; Timer int enable bit.
+HOLD_BIT EQU 00100000b ; Hold bit.
+
+BUTTON_1_BIT EQU 00000100b ; Bit indicating button 1.
+BUTTON_3_BIT EQU 00000001b ; Bit indicating button 3.
+MOVEMENT_BIT EQU 01000000b ; Bit indicating movement.
+
+INPORT_FIRST_PORT EQU 23Ch ; Address of primary InPort.
+INPORT_LAST_PORT EQU 230h ; Address of secondary InPort.
+
+MACH20_IRQ EQU 0Ch ; IRQ used for Mach 20 InPort
+ ; under Mach 20 OS/2.
+
+;****************************************************************
+; B U S D E F I N I T I O N S *
+;****************************************************************
+; Since the Adaptor for the bus mouse is based on an 8255A, we have to
+; program the 8255A properly in order to function. We need to select:
+;
+; Mode 0 (for all ports).
+; Port A (input - this allows us to read information from the ALPS
+; chip and from the buttons)
+; Port B (output - this allows us to write a value there and then
+; read it back in. It is not connected to anything)
+; Port C, upper half (output - this allows us to send control
+; information to the ALPS chip)
+; Port C, lower half (input - this allows us to poll the current states
+; of IRQs 2, 3, 4, and 5)
+;
+; The value that does this is
+;
+; 10010001
+; ||||||||----- Port C Lower is input
+; |||||||------ Port B is output
+; ||||||------- Mode 0 for Group B (Port B and lower half of Port C)
+; |||||-------- Port C Upper is output
+; ||||--------- Port A is input
+; |------------ Mode 0 for Group A (Port A and upper half of Port C)
+; ------------- Mode set control word
+;
+
+BUS_MOUSE_BASE EQU 023Ch ; Base I/O addr of bus mouse.
+
+BUS_DATA EQU BUS_MOUSE_BASE ; Port where mouse data is read from.
+BUS_SIG EQU BUS_MOUSE_BASE + 1 ; Port unused for mouse, used for de-
+ ; termining existence of bus adaptor.
+BUS_CONTROL EQU BUS_MOUSE_BASE + 2 ; Port used to control adaptor.
+BUS_INIT EQU BUS_MOUSE_BASE + 3 ; Port used to init bus adaptor.
+
+BUS_INIT_VALUE EQU 10010001b ; Value used to init bus adaptor.
+
+LOW_X EQU 090h ; Cmd to read low 4 bits of delta X
+HI_X EQU 0B0h ; Cmd to read high 2 bits of delta X
+LOW_Y EQU 0D0h ; Cmd to read low 4 bits of delta Y
+HI_Y EQU 0F0h ; Cmd to read high 2 bits of delta Y
+
+;************************************************************************
+; S E R I A L D E F I N I T I O N S *
+;************************************************************************
+
+SERIAL_PACKETSIZE EQU 3 ; Bytes in a packet of data.
+
+SYNC_BIT EQU 40H ; Bit 6 is the sync bit
+
+;
+; These are the offsets within the COM chip of the various registers.
+;
+
+TXB EQU 0 ; Transmit buffer
+RXB EQU 0 ; Receive buffer
+LATLSB EQU 0 ; Divisor latch, LSB
+LATMSB EQU 1 ; Divisor latch, MSB
+IER EQU 1 ; Interrupt enable register
+IIR EQU 2 ; Interrupt identification register
+LCR EQU 3 ; Line control register
+MCR EQU 4 ; Modem control register
+LSR EQU 5 ; Line status register
+MSR EQU 6 ; Modem status register
+
+;
+; These give the number of milliseconds to wait while waiting for the serial
+; mouse to reset itself. We will first use the value given by SHORTDELAY
+; and if that fails, we will then use the value given by LONGDELAY.
+;
+
+SHORTDELAY EQU 6 ; 350 msecs = 350/55.5 = 6 clock ticks.
+LONGDELAY EQU 18 ; 1000 msecs = 1000/55.5 = 18 clock ticks.
+
+;
+; These are the values that are written into the divisor latch for the
+; various baud rates. They are obtained by dividing the clock rate
+; (1.8432 MHz) by 16x the desired baud rate.
+;
+
+DIV_50 EQU 900h
+DIV_75 EQU 600h
+DIV_110 EQU 417h
+DIV_150 EQU 300h
+DIV_300 EQU 180h
+DIV_600 EQU 0C0h
+DIV_1200 EQU 060h
+DIV_1800 EQU 040h
+DIV_2000 EQU 03Ah
+DIV_2400 EQU 030h
+DIV_3600 EQU 020h
+DIV_4800 EQU 018h
+DIV_7200 EQU 010h
+DIV_9600 EQU 00Ch
+
+;
+;** Interrupt enable masks
+;
+
+IE_RX EQU 00000001b ; read data available
+IE_TX EQU 00000010b ; transmit buffer empty
+IE_LX EQU 00000100b ; line status change
+IE_MX EQU 00001000b ; modem status change
+
+;
+;** Line control masks
+;
+
+LC_BMASK EQU 00000011b ; data bits mask
+LC_BITS5 EQU 00000000b ; 5 data bits
+LC_BITS6 EQU 00000001b ; 6 data bits
+LC_BITS7 EQU 00000010b ; 7 data bits
+LC_BITS8 EQU 00000011b ; 8 data bits
+
+LC_SMASK EQU 00000100b ; stop bits mask
+LC_STOP1 EQU 00000000b ; 1 stop bit
+LC_STOP2 EQU 00000100b ; 2 stop bits (1.5 if 5 data bits)
+
+LC_PMASK EQU 00111000b ; parity mask
+LC_PNONE EQU 00000000b ; none parity
+LC_PODD EQU 00001000b ; odd parity
+LC_PEVEN EQU 00011000b ; even parity
+LC_PMARK EQU 00101000b ; mark parity
+LC_PSPACE EQU 00111000b ; space parity
+
+LC_BREAK EQU 01000000b ; transmit break
+LC_DLAB EQU 10000000b ; divisor latch access bit
+LC_MASK EQU 01111111b ; documented line control register bits
+
+;
+;** Modem control register masks
+;
+
+MC_DTR EQU 00000001b ; data terminal ready
+MC_RTS EQU 00000010b ; request to send
+MC_OUT1 EQU 00000100b ; output 1
+MC_OUT2 EQU 00001000b ; output 2
+MC_LOOP EQU 00010000b ; loopback mode
+
+;
+;** Line status register masks
+;
+
+LS_DR EQU 00000001b ; data ready
+LS_OERR EQU 00000010b ; overrun error
+LS_PERR EQU 00000100b ; parity error
+LS_FERR EQU 00001000b ; framing error
+LS_BI EQU 00010000b ; break interrupt
+LS_THRE EQU 00100000b ; TX holding register empty
+LS_TSRE EQU 01000000b ; TX shift register empty
+
+;
+;** Modem status register definitions:
+;
+
+MS_DCTS EQU 00000001b ; delta clear to send
+MS_DDSR EQU 00000010b ; delta data set ready
+MS_TERI EQU 00000100b ; trailing edge of ring indicator
+MS_DDCD EQU 00001000b ; delta receiver line signal detect
+MS_CTS EQU 00010000b ; clear to send
+MS_DSR EQU 00100000b ; data set ready
+MS_RI EQU 01000000b ; ring indicator
+MS_DCD EQU 10000000b ; receiver line signal detect
+
+;************************************************************************
+; 8 2 5 9 A D E F I N I T I O N S *
+;************************************************************************
+
+MASTER_MASK_ADDR EQU 021h ; Master's mask register addr.
+SLAVE_MASK_ADDR EQU 0A1h ; Slave's mask register addr.
+IRQS_PER_8259 EQU 8 ; # IRQs on each 8259A.
+SELECT_IRR EQU 0Ah ; Selects int request register.
+SELECT_ISR EQU 0Bh ; Selects in service register.
+
+;****************************************************************
+; P S / 2 D E F I N I T I O N S *
+;****************************************************************
+
+PS2_IRQ EQU 0Ch ; Always IRQ 12 for PS/2 mouse.
+PS2_IRQ_MASK EQU 00010000b ; Bit mask for IRQ 12.
+PS2_PACKETSIZE EQU 3 ; Bytes in a packet of data.
+
+DX_SIGN EQU 00010000b ; Bit 4 is dx sign bit in status byte
+DY_SIGN EQU 00100000b ; Bit 5 is dy sign bit in status byte
+
+PS2_25PPI EQU 0 ; Value to set resolution to 25 ppi.
+PS2_50PPI EQU 1 ; Value to set resolution to 50 ppi.
+PS2_100PPI EQU 2 ; Value to set resolution to 100 ppi.
+PS2_200PPI EQU 3 ; Value to set resolution to 200 ppi.
+
+
+MOUSE_RESET EQU 0FFh ; Reset mouse command
+MOUSE_RESEND EQU 0FEh ; Resend data to mouse
+MOUSE_DIAG_ERR EQU 0FCh ; Error on mouse diagnostics
+MOUSE_ACK EQU 0FAh ; Acknowledge
+MOUSE_DEFAULT EQU 0F6h
+MOUSE_DISABLE EQU 0F5h ; Disable Mouse command
+MOUSE_ENABLE EQU 0F4h ; Enable Mouse command
+MOUSE_RATE EQU 0F3h ; Set sampling rate
+MOUSE_READ_TYPE EQU 0F2h ; Read device type
+MOUSE_REMOTE EQU 0F0h ; Set remote mode
+MOUSE_ECHO EQU 0EEh ; Set wrap mode
+MOUSE_KILL_ECHO EQU 0ECh ; reset wrap mode
+MOUSE_READDATA EQU 0EBh ; Read mouse data
+MOUSE_STREAM EQU 0EAh ; Set stream mode
+MOUSE_STATUS EQU 0E9h ; Status Request
+MOUSE_RESOLUTION EQU 0E8h ; Set Resolution
+MOUSE_SCALE_2_1 EQU 0E7h ; Set scaling 2 to 1
+MOUSE_SCALE_1_1 EQU 0E6h ; Set scaling 1 to 1
+MOUSE_DIAG_OK EQU 0AAh ; Diagnostics ok
+MOUSE_DIAG_ID EQU 000h ; Diagnostic ID number
+
+;
+; The following codes are specific to the Microsoft PS/2 mouse
+;
+
+MOUSE_MS_VERS EQU 052h ; Read current firmware version number
+MOUSE_MS_INPORT EQU 056h ; Read raw InPort data
+MOUSE_MS_DIAG EQU 059h ; enter MS diagnostices mode
+MOUSE_MS_READRAM EQU 05Bh ; read ram byte
+
+;****************************************************************
+; 8 0 4 2 D E F I N I T I O N S *
+;****************************************************************
+
+;
+; 8042 port definitions.
+;
+
+DATA_8042 EQU 60h ; Port where data is sent to/from 8042.
+CONTROL_8042 EQU 64h ; Port where commands are sent to 8042.
+STATUS_8042 EQU 64h ; Port where status is read from 8042.
+CRT_DATA_SEG EQU 40H ; ROM BIOS CRT Data Segment Address
+
+;
+; Status register bit definitions.
+;
+
+OUTPUT_BUFFER_FULL EQU 01h ; 8042's output buffer is full.
+INPUT_BUFFER_FULL EQU 02h ; 8042's input buffer is full.
+AUX_OUTPUT_BUFFER_FULL EQU 20h ; 8042's aux output buffer is full.
+
+;
+; Command byte bit definitions.
+;
+
+AUX_DISABLED EQU 20h ; Auxiliary interface is disabled.
+AUX_INT_ENABLE EQU 02h ; Auxiliary interrupts are enabled.
+KBD_INT_ENABLE EQU 01H ; Keyboard interrupt enabled.
+;
+; 8042 commands.
+;
+
+CMD8042_READ_CMD EQU 020h ; Read command byte.
+CMD8042_WRITE_CMD EQU 060h ; Write command byte.
+CMD8042_DISABLE_AUX EQU 0A7h ; Disable auxiliary interface.
+CMD8042_ENABLE_AUX EQU 0A8h ; Enable auxiliary interface.
+CMD8042_TEST_AUX EQU 0A9h ; Test auxiliary interface.
+CMD8042_DISABLE_KBD EQU 0ADh ; Disable keyboard.
+CMD8042_ENABLE_KBD EQU 0AEh ; Enable keyboard.
+CMD8042_WRITE_AUX EQU 0D4h ; Send data to auxiliary device.
+
diff --git a/private/ntos/boot/detect/i386/mousea.asm b/private/ntos/boot/detect/i386/mousea.asm
new file mode 100644
index 000000000..b1a33ecb7
--- /dev/null
+++ b/private/ntos/boot/detect/i386/mousea.asm
@@ -0,0 +1,1610 @@
+ title "Mouse detection"
+;++
+;
+; Copyright (c) 1989 Microsoft Corporation
+;
+; Module Name:
+;
+; mouse.asm
+;
+; Abstract:
+;
+; This module implements the assembley code necessary to determine
+; various mouse in the system.
+;
+; Author:
+;
+; Shie-Lin Tzong (shielint) 10-Dec-1991.
+; Most of the code is taken from win31 setup code(with modification.)
+;
+; Environment:
+;
+; x86 Real Mode.
+;
+; Revision History:
+;
+;
+;--
+
+ .xlist
+include mouse.inc
+ .list
+
+.386
+extrn _Empty8042:proc
+extrn Write8042:proc
+extrn ReadKeyboard:proc
+extrn _ComPortAddress:word
+extrn _NoLogitechPs2Check:byte
+extrn _DisableSerialMice:word
+
+_DATA SEGMENT PARA USE16 PUBLIC 'DATA'
+
+LATLSBSave db ?
+LATMSBSave db ?
+LCRSave db ?
+MCRSave db ?
+IERSave db ?
+fSingle8259 db 0
+DWFinalCount dw 2 dup (0)
+DWCurrCount dw 2 dup (0)
+
+NextComPort dw 0 ; Offset into ComPortAddress[]
+MouseInfo MouseInformation <0, 0, 0FFFFh, 0FFFFh, 0>
+
+;
+; MouseDetected is used to indicate if any mouse has been detected.
+;
+
+MouseDetected dw 0 ; initialize to no
+InPortIoBase dw 0 ; The Base addr for inport mouse
+
+_DATA ends
+
+_TEXT SEGMENT PARA USE16 PUBLIC 'CODE'
+ ASSUME CS: _TEXT, DS:_DATA, SS:NOTHING
+
+
+;++
+;
+; USHORT
+; LookForPS2Mouse (
+; VOID
+; )
+;
+; Routine Description:
+;
+; This function determines mouse type in the system.
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; (eax): mouse Id.
+;
+;--
+
+ public _LookForPS2Mouse
+_LookForPS2Mouse proc near
+ push bx
+ push si
+ push di
+
+ mov si, offset MouseInfo
+ lea si, [si].DeviceId
+
+ call _Empty8042
+
+ int 11h
+ test ax, 4 ; is bit 2 set?
+ jz No_PS2_Mouse ; No, no PS/2 mouse.
+
+ xor di, di
+
+;
+; Old Olivetti M400-60 and M400-40 will have trouble reading floppy
+; and hard disk if the following call is made .
+;
+
+ test _NoLogitechPs2Check, 0ffh ; Skip int 15 c205?
+ jz short @f ; if z, no.
+
+ mov ax, 0c201h ; reset PS/2 mouse
+ int 15h
+ jc short No_PS2_Mouse
+ jmp short Is_PS2_Mouse
+
+@@:
+ mov bh, 03 ; Packet size = 3 bytes
+ mov ax, 0c205h ; init point device interface
+ int 15h
+ jc short No_PS2_Mouse
+
+ mov ax, 0c201h ; reset PS/2 mouse
+ int 15h
+ jc short No_PS2_Mouse
+
+ call _Empty8042
+
+;
+; The following sequence of Int 15h calls will determine if a Logitech
+; PS/2 mouse is present. This information was obtained from Logitech.
+;
+
+ mov ax,0C203h ; Set resolution to 1 cnt/mm
+ mov bh,0h
+ int 15h
+ jc Is_PS2_Mouse
+
+ mov ax,0C206h ; Set scaling to 1:1
+ mov bh,1h
+ int 15h
+ jc Is_PS2_Mouse
+
+ mov ax,0C206h ; Set scaling to 1:1
+ mov bh,1h
+ int 15h
+ jc Is_PS2_Mouse
+
+ mov ax,0C206h ; Set scaling to 1:1
+ mov bh,1h
+ int 15h
+ jc Is_PS2_Mouse
+
+ mov ax,0C206h ; Get status
+ mov bh,0h
+ int 15h
+ jc Is_PS2_Mouse
+
+ or cl,cl ; Is resolution 1 cnt/mm?
+ jz Is_PS2_Mouse ; Yes, then not a Logitech.
+
+;
+; If cl is not zero (i.e. 1 cnt/mm) then it is the number of buttons
+; and we've found a Logitech 3-button PS/2 mouse
+;
+
+LT_PS2_Mouse:
+ mov ax,LT_MOUSE + PS2_MOUSE
+ jmp short PS2MouseFound
+
+Is_PS2_Mouse:
+ mov ax,MS_MOUSE + PS2_MOUSE
+ jmp short PS2MouseFound
+
+No_PS2_Mouse:
+ mov bx, 0
+ jmp ExitPs2Mouse
+
+PS2MouseFound:
+
+;
+; Set mouse type and subtype to mouse info structure
+;
+
+ mov bx, offset MouseInfo
+ mov [bx].MouseSubtype, al
+ mov [bx].MouseType, ah
+ mov [bx].MouseIrq, 12
+ mov [bx].MousePort, 0ffffh
+ mov [bx].DeviceIdLength, di
+ mov MouseDetected, bx
+
+ExitPs2Mouse:
+
+;
+; Drain 8042 input buffer and leave leave pointing device disabled.
+; We don't want user moves the mouse and hangs the system.
+;
+
+ call _Empty8042
+ mov ax, bx
+ pop di
+ pop si
+ pop bx
+ ret
+
+_LookForPS2Mouse endp
+
+;++
+;
+; USHORT
+; LookForInportMouse (
+; VOID
+; )
+;
+; Routine Description:
+;
+; This function determines mouse type in the system.
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; (eax): mouse Id.
+;
+;--
+
+ public _LookForInportMouse
+_LookForInportMouse proc near
+
+ push bx
+ mov dx,INPORT_FIRST_PORT + 2 ; Get address of ID register.
+
+inport_try_again:
+ call TestForInport ; Does an InPort exist at this address?
+ jnc inport_found ; No carry ! Inport found !
+
+ sub dx,4 ; Nope, try the next possible port.
+ cmp dx,INPORT_LAST_PORT + 2
+ jae inport_try_again
+
+ mov ax, 0 ; Fail to detect inport mouse
+ jmp short no_inport
+
+inport_found:
+
+;
+; Set mouse type and subtype to mouse info structure
+;
+
+ mov ax,MS_MOUSE + INPORT_MOUSE
+ mov cx, dx
+ sub cx, 2
+ mov bx, offset MouseInfo
+ mov [bx].DeviceIdLength, 0
+ mov [bx].MouseSubtype, al
+ mov [bx].MouseType, ah
+ mov [bx].MousePort, cx
+ mov InportIoBase, cx
+ mov MouseDetected, bx
+ lea ax, [bx].MouseIrq
+ push ax
+ push cx ; Current Port
+ call _InportMouseIrqDetection
+ add sp, 4
+ mov ax, offset MouseInfo
+
+no_inport:
+ pop bx
+ ret
+
+_LookForInportMouse endp
+
+;++
+;
+; USHORT
+; LookForBusMouse (
+; VOID
+; )
+;
+; Routine Description:
+;
+; This procedure will attempt to find a bus mouse adaptor in the system
+; and will return the results of this search.
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; (ax) = Mouse ID.
+;
+;--
+
+ public _LookForBusMouse
+_LookForBusMouse proc near
+
+;
+; If We already found Inport mouse and its IO base is 23ch, it is
+; impossible to have a BUS mouse.
+;
+
+ cmp InportIoBase, BUS_MOUSE_BASE
+ jne short @f
+ mov ax, 0
+ ret
+
+@@:
+ push bx
+
+;
+; We determine if the bus mouse adaptor is present by attempting to
+; program the 8255A, and then seeing if we can write a value out to
+; Port B on the 8255A and get that value back. If we can, we assume
+; that we have a bus mouse adaptor.
+;
+
+ mov dx,BUS_INIT ; Get address of 8255A control port.
+ mov al,BUS_INIT_VALUE ; Get proper value.
+ DelayOut ; Set up 8255A.
+ mov ax,0A5A5h ; Get a signature byte.
+ address BUS_SIG BUS_INIT ; Get address of Port B.
+ DelayOut ; Set Port B with signature.
+ DelayIn ; Read back Port B.
+
+ cmp al,ah ; Does it match signature byte?
+ jne No_Bus_Mouse ; Nope - no bus mouse adaptor
+
+ mov ax,MS_MOUSE + BUS_MOUSE
+ jmp short Bus_Mouse_Found
+
+No_Bus_Mouse:
+ mov ax, 0 ; No Bus Mouse detected
+ jmp short Bus_Exit
+
+Bus_Mouse_Found:
+
+;
+; Set mouse type and subtype to mouse info structure
+;
+
+ mov dx, BUS_MOUSE_BASE
+ mov bx, offset MouseInfo
+ mov [bx].DeviceIdLength, 0
+ mov [bx].MouseSubtype, al
+ mov [bx].MouseType, ah
+ mov [bx].MousePort, dx
+ mov MouseDetected, bx
+ call BusMouseIrqDetection
+ mov [bx].MouseIrq, ax ; if (ax) = 0xffff, no irq detected
+ mov ax, offset MouseInfo ; return MouseInfor
+Bus_Exit:
+ pop bx
+ ret
+
+_LookForBusMouse endp
+
+;++
+;
+; USHORT
+; BusMouseIrqDetection (
+; USHORT Port
+; )
+;
+; Routine Description:
+;
+; This procedure will attempt to find the irq level associated with the
+; Bus mouse in the machine.
+;
+; Arguments:
+;
+; (dx) = Bus mouse base I/O port.
+;
+; Return Value:
+;
+; (ax) = Irq level. if (ax)= 0xffff, detection failed.
+;
+;--
+
+BusMouseIrqDetection proc near
+
+ push bx
+
+ add dx, 2 ; use adaptor control port
+ in al,dx ; Get irq 2-5 states
+ IOdelay
+ mov ah,al ; Save states
+ mov cx,10000 ; Set loop count
+ xor bh,bh ; Clear changes buffer
+
+@@:
+ in al,dx ; Get current states of irq 2-5
+ IOdelay
+ xor ah,al ; Compare with last state
+ or bh,ah ; Mark any changes
+ mov ah,al ; Previous := current state
+ loop @B ; Keep looking
+
+ mov ax, 0ffffh
+ or bh,bh ; Any irq found?
+ jz short BusIntExit ; Branch if no interrupt was found
+
+BusIntFound:
+ mov ax,5 ; Assume irq5
+ test bh,0001b ; Is it off?
+ jnz short BusIntExit ; Yes..have irq5
+ mov ax,2 ; Assume irq2
+ test bh,1000b
+ jnz short BusIntExit
+ inc ax ; Try irq3
+ test bh,0100b
+ jnz short BusIntExit
+ inc ax ; Must be irq4
+
+BusIntExit: ; ax contains the IRQ number
+ pop bx
+ ret
+
+BusMouseIrqDetection endp
+
+;++
+;
+; USHORT
+; LookForSerialMouse (
+; VOID
+; )
+;
+; Routine Description:
+;
+; This procedure will attempt to find a serial mouse adaptor in the system
+; and will return the results of this search.
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; (ax) = Mouse ID.
+;
+;--
+
+ public _LookForSerialMouse
+_LookForSerialMouse proc near
+
+ push di
+ push bx
+
+ mov di, NextComPort ; Get untested comport
+ cmp di, 8 ; Have we over the comport limit?
+ jae short No_Serial_Mouse ; if above or e, yes, exit
+
+serial_try_again:
+ mov cx, di
+ mov al, 1
+ shr cx, 1
+ inc cx
+ shl ax, cl
+ test _DisableSerialMice, ax ; Should we skip this com port?
+ jnz short serial_next_port ; yes, try next one.
+
+ mov dx, _ComPortAddress[di] ; Get base address of COM port to test.
+ or dx,dx ; Does this port exist?
+ jz serial_next_port ; No, try next one.
+
+serial_test_port:
+
+;
+; The comport address is initialized by com detection routine. if the port
+; value is not zero, it means that the port exist.
+;
+
+ call TestForSerial ; Is a serial mouse attached to port?
+ cmp ax,NO_MOUSE
+ jne Serial_Mouse_Found ; Yes! found a serial mouse
+
+serial_next_port: ; No serial mouse on this COM port.
+ add di,2 ; move to the next possible port
+ cmp di,8 ; Are we over com limit?
+ jb serial_try_again ; if b, no, go test it.
+
+ mov NextComport, di
+No_Serial_Mouse:
+ mov ax, 0 ; No serial mouse detected
+ jmp short SerialMouseExit
+
+Serial_Mouse_Found:
+ mov NextComport, di
+ add NextComport, 2 ; Next comport to test
+
+ shr di, 1 ; divide di by 2
+
+;
+; Set mouse type and subtype to mouse info structure
+;
+
+ mov bx, offset MouseInfo
+ mov [bx].DeviceIdLength, 0
+ cmp ax, MS_MOUSE + SERIAL_MOUSE_WITH_WHEEL
+ jnz short @f
+
+ mov [bx].DeviceIdLength, 7
+@@:
+ mov [bx].MouseSubtype, al
+ mov [bx].MouseType, ah
+ mov [bx].MousePort, di
+ mov [bx].MouseIrq, 0ffffh
+ mov MouseDetected, bx
+ mov ax, bx
+
+SerialMouseExit:
+ pop bx
+ pop di
+ ret
+
+_LookForSerialMouse endp
+
+
+;++
+;
+; BOOLEAN
+; TestForInport (
+; USHORT Port
+; )
+;
+; Routine Description:
+;
+; This procedure will attempt to find an InPort mouse at the given base
+; I/O address. Note that if an InPort is found, it will be left
+; in a state where it will not be generating any interrupts.
+;
+; Arguments:
+;
+; Port (DX) - I/O address of Inport identification register.
+;
+; Return Value:
+;
+; NC - An Inport was found
+; CY - No Inport was found
+;
+;--
+
+TestForInport PROC NEAR
+
+ push bx
+ push si
+
+;
+; Since the identification register alternates between returning back
+; the Inport chip signature and the version/revision, if we have an
+; InPort chip, the chip signature will be read in one of the following
+; two reads. If it isn't, we do not have an InPort chip.
+;
+
+ mov bl,INPORT_ID
+ in al,dx ; Read ID register.
+ cmp al,bl ; Is value the InPort chip signature?
+ je possible_inport ; Yes, go make sure we have an InPort.
+ in al,dx ; Read ID register again.
+ cmp al,bl ; Is value the InPort chip signature?
+ jne inport_not_found ; No, return error
+
+;
+; At this point, we managed to read the InPort chip signature, so we have
+; a possible InPort chip. The next read from the ID register will
+; return the version/revision. We then make sure that the ID register
+; alternates between the chip signature and this version/revision. If
+; it does, we have an InPort chip.
+;
+
+possible_inport:
+ in al,dx ; Read version/revision.
+ mov ah,al ; Save it.
+ mov cx,5 ; Test ID register 5 times.
+
+inport_check:
+ in al,dx ; Read ID register.
+ cmp al,bl ; Make sure it is the chip signature.
+ jne inport_not_found ; If not, we don't have an InPort chip.
+ in al,dx ; Read ID register.
+ cmp al,ah ; Make sure version/revision is same.
+ jne inport_not_found ; If not, we don't have an InPort chip.
+ loop inport_check ; Test desired number of times.
+
+ clc
+ pop si
+ pop bx
+ ret
+;
+; At this point, we know we have an InPort chip.
+;
+
+inport_not_found: ; We don't have an InPort chip.
+ stc ; Show failure.
+ pop si
+ pop bx
+ ret ; Return to caller.
+
+TestForInport ENDP
+
+
+;++
+;
+; BOOLEAN
+; TestForSerial (
+; USHORT Port
+; )
+;
+; Routine Description:
+;
+; This procedure will attempt to find a serial mouse adaptor in the system
+; and will return the results of this search.
+;
+; Arguments:
+;
+; (dx) = Port Address.
+;
+; Return Value:
+;
+; (ax) = Mouse ID.
+;
+;--
+
+TestForSerial PROC NEAR
+
+ call SaveCOMSetting
+
+ call SetupCOMForMouse ; Set up COM port to talk to mouse.
+
+ mov cx,SHORTDELAY ; Use a short delay time.
+ call ResetSerialMouse ; Reset mouse to see if it is there.
+ cmp ax,NO_MOUSE
+ jne TFS_Found
+
+;
+; If a mouse has been detected, most likely there won't be second mouse.
+; so we don't test for LONGDELAY to save some time
+;
+
+ cmp MouseDetected, 0
+ jne short @f
+
+ mov cx,LONGDELAY ; Maybe the mouse is just slow.
+ call ResetSerialMouse ; Reset mouse to see if it is there.
+ cmp ax,NO_MOUSE
+ jne TFS_Found
+
+@@:
+ call TestForLogitechSerial ; Maybe it's a Logitech Series C
+
+TFS_Found:
+ push ax ; Save return value
+ call RestoreCOMSetting
+ pop ax
+ ret
+
+TestForSerial ENDP
+
+
+;++
+;
+; VOID
+; SaveCOMSetting (
+; USHORT Port
+; )
+;
+; Routine Description:
+;
+; This procedure will save the current state of the COM port given.
+;
+; Arguments:
+;
+; Port (DX) - Base address of COM port.
+;
+; Return Value:
+;
+; None.
+;
+;--
+
+SaveCOMSetting PROC NEAR
+
+ push dx ; Save base I/O address.
+ address LCR RXB ; Get address of Line Control Register.
+ DelayIn ; Get current contents.
+ mov [LCRSave],al ; Save them.
+ or al,LC_DLAB ; Set up to access divisor latches.
+ DelayOut
+ address LATMSB LCR ; Get address of high word of divisor
+ DelayIn ; latch and save its current contents.
+ mov [LATMSBSave],al
+ address LATLSB LATMSB ; Get address of low word of divisor
+ DelayIn ; latch and save its current contents.
+ mov [LATLSBSave],al
+ address LCR LATLSB ; Get address of Line Control Register
+ mov al,[LCRSave] ; and disable access to divisor.
+ and al,NOT LC_DLAB
+ DelayOut
+ address MCR LCR ; Get address of Modem Control Register
+ DelayIn ; and save its current contents.
+ mov [MCRSave],al
+ address IER MCR ; Get address of Interrupt Enable Reg-
+ DelayIn ; ister and save its current contents.
+ mov [IERSave],al
+ pop dx ; Restore base I/O address.
+ ret
+
+SaveCOMSetting ENDP
+
+
+;++
+;
+; VOID
+; RestoreCOMSetting (
+; USHORT Port
+; )
+;
+; Routine Description:
+;
+; This procedure will restore the current state of the COM port given.
+;
+; Arguments:
+;
+; Port (DX) - Base address of COM port.
+;
+; Return Value:
+;
+; None.
+;
+;--
+
+RestoreCOMSetting PROC NEAR
+
+ push dx ; Save base I/O address.
+ address LCR RXB ; Get address of Line Control Register.
+ mov al,LC_DLAB ; Set up to access divisor latches.
+ DelayOut
+ address LATMSB LCR ; Get address of high word of divisor
+ mov al,[LATMSBSave] ; and restore it.
+ DelayOut
+ address LATLSB LATMSB ; Get address of low word of divisor
+ mov al,[LATLSBSave] ; and restore it.
+ DelayOut
+ address LCR LATLSB ; Get address of Line Control Register
+ mov al,[LCRSave] ; and restore it, disabling access to
+ and al,NOT LC_DLAB ; the divisor latches.
+ DelayOut
+ address MCR LCR ; Get addres of Modem Control Register
+ mov al,[MCRSave] ; and restore it.
+ DelayOut
+ address IER MCR ; Get address of Interrupt Enable Reg-
+ mov al,[IERSave] ; ister and restore it.
+ DelayOut
+ pop dx ; Restore base I/O address.
+ ret
+
+RestoreCOMSetting ENDP
+
+
+;++
+;
+; VOID
+; SetupCOMForMouse (
+; USHORT Port
+; )
+;
+; Routine Description:
+;
+; This procedure will set up the given COM port so that it can talk to
+; a serial mouse.
+;
+; Arguments:
+;
+; Port (DX) - Base address of COM port to set up.
+;
+; Return Value:
+;
+; COM port set up, all interrupts disabled at COM port
+;
+;--
+
+SetupCOMForMouse PROC NEAR
+
+ push dx ; Save base I/O address.
+ mov cx, 60h
+ call SetBaudRate
+
+ address LCR RXB
+ mov al,LC_BITS7 + LC_STOP1 + LC_PNONE
+ DelayOut ; Set 7,n,1; disable access to divisor.
+ address IER LCR ; Get address of Int. Enable Register
+ xor al,al ; Disable all interrupts at the COM
+ DelayOut ; port level.
+ address LSR IER ; Get address of Line Status Reg.
+ DelayIn ; Read it to clear any errors.
+ pop dx ; Restore base I/O address
+ ret
+
+SetupCOMForMouse ENDP
+
+
+;++
+;
+; USHORT
+; ResetSerialMouse (
+; USHORT Port,
+; USHORT Delay
+; )
+;
+; Routine Description:
+;
+; This procedure will reset a serial mouse on the given COM port and will
+; return an indication of whether a mouse responded or not.
+;
+; The function now also checks for the presence of a 'B' as well as an
+; 'M' to determine the presence of a pointing device. Also, if the 'M' is
+; followed by a '3' the serial mouse is a Logitech.
+;
+; Mouse returns M
+; Ballpoint returns B
+;
+; Arguments:
+;
+; Port (DX) - Base I/O address of COM port to use
+; Delay (CX) - Number of msecs to use for delays
+;
+; Return Value:
+;
+; (ax) = Mouse Type.
+;
+;--
+
+ResetSerialMouse PROC NEAR
+
+ push dx ; Save environment.
+ push si
+ push di
+ push es
+
+ address IER RXB ; Get address of Interrupt Enable Reg.
+ DelayIn ; Get current contents of IER and
+ push ax ; save them.
+ push dx ; Save address of IER.
+ xor al,al ; Disable all interrupts at the
+ DelayOut ; COM port level.
+
+ address MCR IER ; Get address of Modem Control Reg.
+ mov al,MC_DTR ; Set DTR active; RTS, OUT1, and OUT2
+ DelayOut ; inactive. This powers down mouse.
+
+ push cx ; Save amount of time to delay.
+ call SetupForWait ; Set up BX:CX and ES:DI properly for
+ assume es:nothing ; upcoming delay loop.
+
+ address RXB MCR ; Get address of Receive Buffer.
+
+;
+; Now, we wait the specified amount of time, throwing away any stray
+; data that we receive. This gives the mouse time to properly reset
+; itself.
+;
+
+rsm_waitloop:
+ in al, dx ; Read and ignore any stray data.
+ call IsWaitOver ; Determine if we've delayed enough.
+ jnc rsm_waitloop ; If not, keep waiting.
+
+;
+; Wait is over.
+;
+
+ address LSR RXB ; Get address of Line Status Reg.
+ DelayIn ; Read it to clear any errors.
+ address MCR LSR ; Get address of Modem COntrol Reg.
+ mov al,MC_DTR+MC_RTS ; Set DTR, RTS, and OUT2 active
+ ; OUT1 inactive.
+ DelayOut ; This powers up the mouse.
+
+ pop cx ; Get amount of time to delay.
+ call SetupForWait ; Set up BX:CX and ES:DI properly for
+ assume es:nothing ; the upcoming delay loop.
+
+;
+; We give the mouse the specified amount of time to respond by sending
+; us an M. If it doesn't, or we get more than 5 characters that aren't
+; an M, we return a failure indication.
+;
+
+ address LSR MCR ; Get address of Line Status Reg.
+ mov si, 5 ; Read up to 5 chars from port.
+ mov bl,'3' ; '3' will follow 'M' on Logitech.
+ mov bh,'B' ; 'B' for BALLPOINT
+ mov ah,'M' ; Get an M. (We avoid doing a cmp al,M
+ ; because the M could be left floating
+ ; due to capacitance.)
+rsm_getchar:
+ DelayIn ; Get current status.
+ test al,LS_DR ; Is there a character in Receive Buff?
+ jnz rsm_gotchar ; Yes! Go and read it.
+ call IsWaitOver ; No, determine if we've timed out.
+ jnc rsm_getchar ; Haven't timed out; keep looking.
+
+ mov bx,NO_MOUSE
+ jmp rsm_leave ; Timed out. Leave with NO_MOUSE.
+
+rsm_gotchar:
+
+ address RXB LSR ; Get address of Receive Buffer.
+ DelayIn ; Get character that was sent to us.
+ cmp al,ah ; Is it an M?
+ jne check_for_b
+
+;
+; We received an 'M', now wait for next character to see if it is a '3'.
+;
+
+ mov cx,1 ; Wait between 55.5 and 111ms for
+ call SetupForWait ; next character.
+ address LSR RXB
+
+rsm_waitfor3:
+ DelayIn ; Get current status.
+ test al,LS_DR ; Is there a character in Receive Buff?
+ jnz rsm_gotchar3 ; Yes! Go and read it.
+ call IsWaitOver ; No, determine if we've timed out.
+ jnc rsm_waitfor3 ; Haven't timed out; keep looking.
+
+;
+; Not a Logitech - must be a standard Microsoft compatible serial mouse.
+;
+
+ jmp rsm_notLT
+
+rsm_gotchar3:
+ address RXB LSR ; Get address of Receive Buffer.
+ DelayIn ; Get character that was sent to us.
+ cmp al,bl ; Is it a 3?
+ jne short rsm_check_for_z
+
+ mov bx,LT_MOUSE + SERIAL_MOUSE ; Yes, we've found a Logitech M+
+ jmp rsm_leave ; series, 3 button mouse
+
+rsm_check_for_z:
+
+;
+; Determine if this is Microsoft mouse with wheel.
+; 'M', 'Z', 0x40, 0x00, 0x00, 0x00, PnP String
+;
+ cmp al, 'Z'
+ jnz rsm_notLT
+
+;
+; Check for 0x40, 0x00, 0x00, 0x00
+;
+
+ mov ebx, 040h
+ mov cx, 4
+ address LSR RXB
+rsm_get_byte:
+ push cx
+ mov cx,1 ; Wait between 55.5 and 111ms for
+ call SetupForWait ; next character.
+@@:
+ DelayIn ; Get current status.
+ test al,LS_DR ; Is there a character in Receive Buff?
+ jnz short @f ; Yes! Go and read it.
+
+ call IsWaitOver ; No, determine if we've timed out.
+ jnc short @b ; Haven't timed out; keep looking.
+ jmp rsm_notMZ
+
+@@:
+ address RXB LSR ; Get address of Receive Buffer.
+ DelayIn ; Get character that was sent to us.
+ cmp al,bl ; Is it a MS wheel?
+ jnz rsm_notMZ
+
+ shr ebx, 8
+ address LSR RXB
+ pop cx
+ sub cx, 1
+ jnz rsm_get_byte
+
+;
+; Next read PnP string for the MS wheel mouse
+; First skip 3 bytes: 08 + 2-byte Rev number
+;
+
+ mov cx, 3
+rsm_get_byte1:
+ push cx
+ mov cx,1 ; Wait between 55.5 and 111ms for
+ call SetupForWait ; next character.
+@@:
+ DelayIn ; Get current status.
+ test al,LS_DR ; Is there a character in Receive Buff?
+ jnz short @f ; Yes! Go and read it.
+
+ call IsWaitOver ; No, determine if we've timed out.
+ jnc short @b ; Haven't timed out; keep looking.
+ jmp rsm_notMZ
+
+@@:
+ address RXB LSR ; Get address of Receive Buffer.
+ DelayIn ; Get character that was sent to us.
+ address LSR RXB
+ pop cx
+ sub cx, 1
+ jnz rsm_get_byte1
+
+;
+; Next read 7 bytes PnpDevice id
+
+ mov si, offset MouseInfo
+ lea si, [si].DeviceId
+
+ mov cx, 7
+rsm_get_byte2:
+ push cx
+ mov cx,1 ; Wait between 55.5 and 111ms for
+ call SetupForWait ; next character.
+@@:
+ DelayIn ; Get current status.
+ test al,LS_DR ; Is there a character in Receive Buff?
+ jnz short @f ; Yes! Go and read it.
+
+ call IsWaitOver ; No, determine if we've timed out.
+ jnc short @b ; Haven't timed out; keep looking.
+ jmp rsm_notMZ
+
+@@:
+ address RXB LSR ; Get address of Receive Buffer.
+ DelayIn ; Get character that was sent to us.
+ mov [si], al
+ inc si
+ address LSR RXB
+ pop cx
+ sub cx, 1
+ jnz rsm_get_byte2
+
+ mov byte ptr [si], 0 ; add device id terminated null
+ mov bx, MS_MOUSE + SERIAL_MOUSE_WITH_WHEEL
+ jmp short rsm_leave ; We still have a standard serial mouse.
+
+rsm_notMZ:
+ pop cx
+rsm_notLT:
+ mov bx,MS_MOUSE + SERIAL_MOUSE ; We didn't get the '3' after the 'M'
+ jmp short rsm_leave ; We still have a standard serial mouse.
+
+check_for_b:
+ cmp al,bh ; Is it a B?
+ jne rsm_next_char
+
+ mov bx,MS_BALLPOINT + SERIAL_MOUSE ; We've found a BallPoint Mouse
+ jmp short rsm_leave
+
+rsm_next_char:
+ address LSR RXB ; Oh well. Get address of LSR again.
+ dec si ; Have we read 5 chars yet?
+ jnz rsm_getchar ; Nope, we'll give him another try.
+
+;
+; We've read many characters - No a single 'M' or 'B' in the lot.
+;
+
+ mov bx,NO_MOUSE
+
+rsm_leave:
+ pop dx ; Get address of IER.
+ pop ax ; Get old value of IER.
+ DelayOut ; Restore IER.
+
+ pop es ; Restore environment.
+ assume es:nothing
+ pop di
+ pop si
+ pop dx
+ mov ax,bx ; Set return value.
+ ret
+
+ResetSerialMouse ENDP
+
+
+;++
+;
+; VOID
+; SetupForWait (
+; USHORT WaitTime
+; )
+;
+; Routine Description:
+;
+; This procedure accepts the number of milliseconds that we will want
+; to delay for and will set things up for the wait.
+;
+; Arguments:
+;
+; (CX) = Number of clock ticks to wait for.
+;
+; Return Value:
+;
+; None.
+;
+;--
+
+SetupForWait PROC NEAR
+
+ push ax ; Do your saving !
+ push es
+
+ xor ax,ax
+ mov es,ax ; Point to 40:6C = 0:46C
+
+ cli
+ mov ax,es:[LW_ClockTickCount+2]
+ mov [DWFinalCount+2],ax ; Save ending time (HiWord)
+ mov ax,es:[LW_ClockTickCount] ; Get tick count in AX.
+ sti
+
+ add ax,cx ; [Current + delay] = delay ends.
+ mov [DWFinalCount],ax ; Save ending time (LoWord)
+ jnc SFW_End
+
+ inc [DWFinalCount+2]
+
+SFW_End:
+ pop es ; Restore now !
+ pop ax
+
+ ret
+
+SetupForWait ENDP
+
+
+;++
+;
+; BOOLEAN
+; IsWaitOver (
+; VOID
+; )
+;
+; Routine Description:
+;
+; This procedure accepts the current time and the ending time and
+; return and indication of whether the current time is past
+; the ending time.
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; carry clear Current time is not past ending time
+; carry set Current time is past ending time
+;
+;--
+
+IsWaitOver PROC NEAR
+
+if 0
+ push ax ; Preserve AX
+ push es ; Preserve ES
+ xor ax,ax
+ mov es,ax ; Point to 40:6C = 0:46C
+
+ cli
+ mov ax,es:[LW_ClockTickCount]
+ mov [DWCurrCount],ax ; Save current time (LoWord)
+ mov ax,es:[LW_ClockTickCount+2] ; Get tick count in AX.
+ sti
+
+ cmp [DWFinalCount+2],ax ; Compare HiWords
+ ja WaitNotOver ; Carry will be clear if wait
+ ; is not over.
+ mov ax,es:[LW_ClockTickCount] ; Compare Lowords
+ cmp [DWFinalCount],ax ; This will set CY accordingly
+
+WaitNotOver:
+ pop es ; Restore ES
+ pop ax ; Restore AX
+ ret
+
+else
+
+ push ax ; Preserve AX
+ push es ; Preserve ES
+ xor ax,ax
+ mov es,ax ; Point to 40:6C = 0:46C
+
+ cli
+ mov ax,es:[LW_ClockTickCount]
+ mov [DWCurrCount],ax ; Save current time (LoWord)
+ mov ax,es:[LW_ClockTickCount+2] ; Get tick count in AX.
+ sti
+
+ cmp [DWFinalCount+2],ax ; Compare HiWords
+ jb WaitExit ; Time is up
+
+ jne WaitRollCheck ; If not equal check for
+
+WaitLowCheck:
+ mov ax,[DWCurrCount] ; Compare Lowords
+ cmp [DWFinalCount],ax ; This will set CY accordingly
+
+WaitExit:
+ pop es ; Restore ES
+ pop ax ; Restore AX
+ ret
+
+
+WaitRollCheck:
+
+; If the current time is less than the wait time we must check for
+; roll over. There are 18.2 * 60 * 60 * 24 or 0x1800b0 clock ticks in
+; a day. At midnight the counter rolls over to zero.
+
+ cmp ax,0
+ jne WaitExit ; If current HiWord is not 0,
+ ; no roll over. Exit with
+ ; carry clear.
+
+ cmp [DWFinalCount+2],18h ; Is Final HiWord 0x18
+ je short @f ; Yes, check LoWord for wrap.
+ clc ; No, no roll over. Exit with
+ ; carry clear.
+ jmp WaitExit
+
+@@:
+ mov ax,[DWFinalCount] ; Get final LoWord
+ sub ax, 0b0h ; Check for wrap
+ jb WaitExit ; No, no roll over. Exit with
+ ; cary set
+
+; At this point we have determined that we have wrapped and that the
+; ending time is into the next day. Update the ending time
+
+ mov [DWFinalCount],ax ; Set final LoWord
+ xor ax,ax
+ mov [DWFinalCount+2],ax ; Zero final HiWord
+ jmp WaitLowCheck ; Check LoWord
+
+endif
+
+IsWaitOver ENDP
+
+
+;++
+;
+; USHORT
+; TestForLogitechSerial (
+; VOID
+; )
+;
+; Routine Description:
+;
+; This procedure will detect the presence of a Logitech Series C
+; serial mouse is present
+;
+; Arguments:
+;
+; (edx) = Port Address
+;
+; Return Value:
+;
+; (ax) = Mouse ID.
+;
+;--
+
+
+TestForLogitechSerial PROC NEAR
+
+ push di
+ push bx
+ sub sp, 10
+ mov bx, sp
+ mov word ptr [bx], 60h ; baud = 1200
+ mov word ptr [bx + 2], 30h ; baud = 2400
+ mov word ptr [bx + 4], 18h ; baud = 4800
+ mov word ptr [bx + 6], 0ch ; baud = 9600
+ mov word ptr [bx + 8], 0
+
+;
+; Power up the C series mouse.
+;
+; Set both DTR and RTS to an active state
+; If DTR and RTS are already on, the power is on for at least 500ms
+; due to the MM serial mouse detection.
+;
+
+ address MCR RXB ; Get address of Modem Control Reg.
+ DelayIn ; Get modem control byte
+
+ and al, MC_DTR + MC_RTS ; Check DTR and RTS
+ cmp al, MC_DTR + MC_RTS
+ je short @f ; the lines are high already
+
+ mov al, MC_DTR + MC_RTS ; Set DTR and RTS to an active state
+ DelayOut ; and ...
+
+ mov cx,9 ; wait for 1/2 second to pwrup mouse
+ call SetupForWait ; Set up BX:CX and ES:DI properly for
+ assume es:nothing ; upcoming delay loop.
+ ; ask for current baud rate
+lt_waitloop1:
+ call IsWaitOver ; Determine if we've delayed enough.
+ jnc short lt_waitloop1
+
+@@:
+;
+; Set the line control register to a format that the mouse can
+; understand (see below: the line is set after the report rate).
+;
+
+ address LCR MCR ; Get address of Line Control Reg.
+ mov al,LC_BITS8 + LC_STOP1 + LC_PODD
+ DelayOut
+
+
+;
+; Cycle through the different baud rates to detect the mouse.
+;
+
+ mov di, 0
+ address RXB LCR
+
+Tfs_Next_Baud:
+ mov cx, [bx + di]
+ cmp cx, 0
+ je Tfs110 ; Reach the end of table
+
+ call SetBaudRate ; Set baud rate
+
+;
+; Put the mouse in prompt mode.
+;
+
+ mov cl, 'D'
+ call CSerWriteChar
+
+
+;
+; Set the MM protocol. This way we get the mouse to talk to us in a
+; specific format. This avoids receiving errors from the line
+; register.
+;
+
+ mov cl, 'S'
+ call CSerWriteChar
+
+ address LCR RXB ; Get address of Line Control Reg.
+ mov al,LC_BITS8 + LC_STOP1 + LC_PODD
+ DelayOut
+
+
+;
+; Try to get the status byte.
+;
+
+ address RXB LCR
+ mov cl, 's'
+ call CSerWriteChar
+
+;
+; Read back the status character.
+;
+
+ mov cx,2 ; Wait at least 55.5 ms for response.
+ call SetupForWait
+ assume es:nothing
+ address LSR RXB
+
+lt_waitloop2: ; (dx) = LSR reg
+ DelayIn
+ test al, LS_DR ; Is receiving buffer full?
+ jnz short @f ; Yes, go read it.
+
+lt_waitloop21: ; (dx) = LSR reg
+ call IsWaitOver
+ jnc short lt_waitloop2
+
+ address RXB LSR
+ jmp short Tfs50
+
+@@:
+ address RXB LSR
+ DelayIn
+ cmp al, 04fh ; al = 4Fh means command understood
+ je short Tfs100
+
+ address LSR RXB
+ jmp short lt_waitloop21
+
+Tfs50:
+ add di, 2
+ jmp Tfs_Next_Baud
+
+Tfs100:
+
+;
+; Found the C series mouse. Put the mouse back in a default mode.
+; The protocol is already set.
+;
+
+;
+; Set to default baud rate 1200
+;
+
+ mov cl, '*'
+ call CSerWriteChar
+ mov cl, 'n'
+ call CSerWriteChar
+
+;
+; Wait for TX buffer empty
+;
+
+ mov cx, 1
+ call SetupForWait
+ address LSR RXB
+@@:
+ DelayIn
+ and al, LS_THRE + LS_TSRE
+ cmp al, LS_THRE + LS_TSRE
+ je short @f ; Wait for TX buffer empty
+ call IsWaitOver
+ jnc short @b
+
+@@:
+ address RXB LSR
+ mov cx, 60h ; Set baud rate to 1200
+ call SetBaudRate
+
+;
+; Set mouse to default report rate
+;
+
+ mov cl, 'N'
+ call CSerWriteChar
+
+ mov ax,LT_MOUSE + SERIAL_MOUSE
+ jmp short lt_leave
+
+Tfs110:
+ mov ax,NO_MOUSE
+
+lt_leave:
+ add sp, 10 ; clear stack
+ pop bx
+ pop di
+ ret
+
+TestForLogitechSerial ENDP
+
+
+;++
+;
+; VOID
+; SetBaudRate (
+; USHORT Port,
+; USHORT BaudRate
+; )
+;
+; Routine Description:
+;
+; This procedure will set up the given COM port so that it can talk to
+; a Logitech C series serial mouse.
+;
+; Arguments:
+;
+; (DX) = COM Base address of COM port to set up.
+; (CX) = Baud Rate
+;
+; Return Value:
+;
+; None.
+;
+;--
+
+SetBaudRate PROC NEAR
+ push dx
+ address LCR RXB ; Get address of Line Control Reg.
+ DelayIn
+ or al,LC_DLAB ; Set up to access divisor latches.
+ DelayOut
+
+ address LATMSB LCR ; Get address of high word of divisor
+ mov al, ch ; latch and set it with value for
+ DelayOut ; specified baud.
+ address LATLSB LATMSB ; Get address of low word of divisor
+ mov al, cl ; latch and set it with value for
+ DelayOut ; specified baud.
+
+ address LCR LATLSB ; Get address of Line Control Reg.
+ DelayIn
+ and al, NOT LC_DLAB ; Disable access divisor latches.
+ DelayOut
+
+ mov cx, 1
+ call SetupForWait
+@@:
+ call IsWaitOver
+ jnc short @b
+
+ pop dx
+ ret
+
+SetBaudRate ENDP
+
+
+;++
+;
+; VOID
+; CSerWriteChar (
+; USHORT Port,
+; UCHAR Command
+; )
+;
+; Routine Description:
+;
+; This procedure will write a char/command to logitech C series mouse.
+;
+; Arguments:
+;
+; (DX) = COM Base address of COM port to set up.
+; (CL) = Command
+;
+; Return Value:
+;
+; None.
+;
+;--
+
+CserWriteChar proc near
+
+ push cx
+ mov cx, 1
+ call SetupForWait
+ address LSR RXB
+@@:
+ DelayIn
+ and al, LS_THRE + LS_TSRE
+ cmp al, LS_THRE + LS_TSRE
+ je short @f ; Wait for TX buffer empty
+
+ call IsWaitOver
+ jnc short @b
+
+@@:
+ address TXB LSR
+ pop ax ; Send command
+ DelayOut
+ ret
+CserWriteChar endp
+
+if 0
+
+
+;++
+;
+; VOID
+; FlushReceiveBuffer (
+; USHORT Port
+; )
+;
+; Routine Description:
+;
+; This procedure will flush receive buffer or until time out.
+;
+; Arguments:
+;
+; (DX) = COM Base address of COM port to set up.
+;
+; Return Value:
+;
+; None.
+;
+;--
+
+FlushReceiveBuffer proc near
+
+ mov cx, 5
+ call SetupForWait
+@@:
+ address LSR RXB
+ DelayIn
+ test al, LS_DR
+ jz short @f
+
+ address RXB LSR
+ DelayIn
+ call IsWaitOver
+ jnc short @b
+
+ ret
+@@:
+ address RXB LSR
+ ret
+FlushReceiveBuffer endp
+
+endif
+_TEXT ends
+
+end
diff --git a/private/ntos/boot/detect/i386/mousec.c b/private/ntos/boot/detect/i386/mousec.c
new file mode 100644
index 000000000..c2f5a76ed
--- /dev/null
+++ b/private/ntos/boot/detect/i386/mousec.c
@@ -0,0 +1,758 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ hwdata.c
+
+Abstract:
+
+ This module contains the C code to set up mouse configuration data.
+
+Author:
+
+ Shie-Lin Tzong (shielint) 18-Jan-1991
+
+Revision History:
+
+--*/
+
+#include "hwdetect.h"
+#include "string.h"
+
+//
+// External References
+//
+
+extern PMOUSE_INFORMATION
+LookForPS2Mouse (
+ VOID
+ );
+
+extern PMOUSE_INFORMATION
+LookForInportMouse (
+ VOID
+ );
+
+extern PMOUSE_INFORMATION
+LookForSerialMouse (
+ VOID
+ );
+
+extern PMOUSE_INFORMATION
+LookForBusMouse (
+ VOID
+ );
+
+extern VOID
+Empty8042 (
+ VOID
+ );
+
+extern USHORT
+HwGetKey (
+ VOID
+ );
+
+extern VOID
+HwPushKey (
+ USHORT Key
+ );
+
+extern USHORT SavedKey;
+
+//
+// Define the master and slave i8259 IRQ bitmask.
+//
+
+#define MASTER_IRQ_MASK_BITS 0xB8
+#define SLAVE_IRQ_MASK_BITS 0x02
+
+//
+// Define the lowest i8259 IRQ that the Inport mouse can reside on. This
+// has the highest NT priority.
+//
+
+#define INPORT_LOWEST_IRQ 0x03
+
+//
+// Define the Inport chip reset value.
+//
+
+#define INPORT_RESET 0x80
+
+//
+// Define the data registers (pointed to by the Inport address register).
+//
+
+#define INPORT_DATA_REGISTER_1 1
+#define INPORT_DATA_REGISTER_2 2
+
+//
+// Define the Inport mouse mode register and mode bits.
+//
+
+#define INPORT_MODE_REGISTER 7
+#define INPORT_MODE_0 0x00 // 0 HZ - INTR = 0
+#define INPORT_MODE_30HZ 0x01
+#define INPORT_MODE_50HZ 0x02
+#define INPORT_MODE_100HZ 0x03
+#define INPORT_MODE_200HZ 0x04
+#define INPORT_MODE_1 0x06 // 0 HZ - INTR = 1
+#define INPORT_DATA_INTERRUPT_ENABLE 0x08
+#define INPORT_TIMER_INTERRUPT_ENABLE 0x10
+#define INPORT_MODE_HOLD 0x20
+#define INPORT_MODE_QUADRATURE 0x00
+
+//
+// Video adaptor type identifiers.
+//
+
+PUCHAR MouseIdentifier[] = {
+ "UNKNOWN",
+ "NO MOUSE",
+ "MICROSOFT",
+ "MICROSOFT BALLPOINT",
+ "LOGITECH"
+ };
+
+PUCHAR MouseSubidentifier[] = {
+ "",
+ " PS2 MOUSE",
+ " SERIAL MOUSE",
+ " INPORT MOUSE",
+ " BUS MOUSE",
+ " PS2 MOUSE WITH WHEEL",
+ " SERIAL MOUSE WITH WHEEL"
+ };
+
+//
+// The following table translates keyboard make code to
+// ascii code. Note, only 0-9 and A-Z are translated.
+// Everything else is translated to '?'
+//
+
+UCHAR MakeToAsciiTable[] = {
+ 0x3f, 0x3f, 0x31, 0x32, 0x33, // ?, ?, 1, 2, 3,
+ 0x34, 0x35, 0x36, 0x37, 0x38, // 4, 5, 6, 7, 8,
+ 0x39, 0x30, 0x3f, 0x3f, 0x3f, // 9, 0, ?, ?, ?,
+ 0x3f, 0x51, 0x57, 0x45, 0x52, // ?, Q, W, E, R,
+ 0x54, 0x59, 0x55, 0x49, 0x4f, // T, Y, U, I, O,
+ 0x50, 0x3f, 0x3f, 0x3f, 0x3f, // P, ?, ?, ?, ?,
+ 0x41, 0x53, 0x44, 0x46, 0x47, // A, S, D, F, G,
+ 0x48, 0x4a, 0x4b, 0x4c, 0x3f, // H, J, K, L, ?,
+ 0x3f, 0x3f, 0x3f, 0x3f, 0x5a, // ?, ?, ?, ?, Z,
+ 0x58, 0x43, 0x56, 0x42, 0x4e, // X, C, V, B, N,
+ 0x4d}; // W
+#define MAX_MAKE_CODE_TRANSLATED 0x32
+
+static ULONG MouseControllerKey = 0;
+
+FPFWCONFIGURATION_COMPONENT_DATA
+SetMouseConfigurationData (
+ PMOUSE_INFORMATION MouseInfo,
+ FPFWCONFIGURATION_COMPONENT_DATA MouseList
+ )
+
+/*++
+
+Routine Description:
+
+ This routine fills in mouse configuration data.
+
+Arguments:
+
+ MouseInfo - Supplies a pointer to the MOUSE_INFOR structure
+
+ MouseList - Supplies a pointer to the existing mouse component list.
+
+Returns:
+
+ Returns a pointer to our mice controller list.
+
+--*/
+{
+ UCHAR i = 0;
+ FPFWCONFIGURATION_COMPONENT_DATA CurrentEntry, Controller, PeripheralEntry;
+ FPFWCONFIGURATION_COMPONENT Component;
+ HWCONTROLLER_DATA ControlData;
+ USHORT z, Length;
+ FPUCHAR fpString;
+
+ if ((MouseInfo->MouseSubtype != SERIAL_MOUSE) &&
+ (MouseInfo->MouseSubtype != SERIAL_MOUSE_WITH_WHEEL)) {
+
+ //
+ // Initialize Controller data
+ //
+
+ ControlData.NumberPortEntries = 0;
+ ControlData.NumberIrqEntries = 0;
+ ControlData.NumberMemoryEntries = 0;
+ ControlData.NumberDmaEntries = 0;
+ z = 0;
+
+ //
+ // If it is not SERIAL_MOUSE, set up controller component
+ //
+
+ Controller = (FPFWCONFIGURATION_COMPONENT_DATA)HwAllocateHeap (
+ sizeof(FWCONFIGURATION_COMPONENT_DATA), TRUE);
+
+ Component = &Controller->ComponentEntry;
+
+ Component->Class = ControllerClass;
+ Component->Type = PointerController;
+ Component->Flags.Input = 1;
+ Component->Version = 0;
+ Component->Key = MouseControllerKey;
+ MouseControllerKey++;
+ Component->AffinityMask = 0xffffffff;
+ Component->IdentifierLength = 0;
+ Component->Identifier = NULL;
+
+ //
+ // If we have mouse irq or port information, allocate configuration
+ // data space for mouse controller component to store these information
+ //
+
+ if (MouseInfo->MouseIrq != 0xffff || MouseInfo->MousePort != 0xffff) {
+
+ //
+ // Set up port and Irq information
+ //
+
+ if (MouseInfo->MousePort != 0xffff) {
+ ControlData.NumberPortEntries = 1;
+ ControlData.DescriptorList[z].Type = RESOURCE_PORT;
+ ControlData.DescriptorList[z].ShareDisposition =
+ CmResourceShareDeviceExclusive;
+ ControlData.DescriptorList[z].Flags = CM_RESOURCE_PORT_IO;
+ ControlData.DescriptorList[z].u.Port.Start.LowPart =
+ (ULONG)MouseInfo->MousePort;
+ ControlData.DescriptorList[z].u.Port.Start.HighPart = 0;
+ ControlData.DescriptorList[z].u.Port.Length = 4;
+ z++;
+ }
+ if (MouseInfo->MouseIrq != 0xffff) {
+ ControlData.NumberIrqEntries = 1;
+ ControlData.DescriptorList[z].Type = RESOURCE_INTERRUPT;
+ ControlData.DescriptorList[z].ShareDisposition =
+ CmResourceShareUndetermined;
+ ControlData.DescriptorList[z].u.Interrupt.Affinity = ALL_PROCESSORS;
+ ControlData.DescriptorList[z].u.Interrupt.Level =
+ (ULONG)MouseInfo->MouseIrq;
+ ControlData.DescriptorList[z].u.Interrupt.Vector =
+ (ULONG)MouseInfo->MouseIrq;
+ if (HwBusType == MACHINE_TYPE_MCA) {
+ ControlData.DescriptorList[z].Flags =
+ LEVEL_SENSITIVE;
+ } else {
+
+ //
+ // For EISA the LevelTriggered is temporarily set to FALSE.
+ //
+
+ ControlData.DescriptorList[z].Flags = EDGE_TRIGGERED;
+ }
+ }
+ Controller->ConfigurationData =
+ HwSetUpResourceDescriptor(Component,
+ NULL,
+ &ControlData,
+ 0,
+ NULL
+ );
+
+ } else {
+
+ //
+ // Otherwise, we don't have configuration data for the controller
+ //
+
+ Controller->ConfigurationData = NULL;
+ Component->ConfigurationDataLength = 0;
+ }
+ }
+
+ //
+ // Set up Mouse peripheral component
+ //
+
+ PeripheralEntry = (FPFWCONFIGURATION_COMPONENT_DATA)HwAllocateHeap (
+ sizeof(FWCONFIGURATION_COMPONENT_DATA), TRUE);
+
+ Component = &PeripheralEntry->ComponentEntry;
+
+ Component->Class = PeripheralClass;
+ Component->Type = PointerPeripheral;
+ Component->Flags.Input = 1;
+ Component->Version = 0;
+ Component->Key = 0;
+ Component->AffinityMask = 0xffffffff;
+ Component->ConfigurationDataLength = 0;
+ PeripheralEntry->ConfigurationData = (FPVOID)NULL;
+
+ //
+ // If Mouse PnP device id is found, translate it to ascii code.
+ // (The mouse device id is presented to us by keyboard make code.)
+ //
+
+ Length = 0;
+ if (MouseInfo->DeviceIdLength != 0) {
+ USHORT i;
+
+ if (MouseInfo->MouseSubtype == PS_MOUSE_WITH_WHEEL) {
+ for (i = 0; i < MouseInfo->DeviceIdLength; i++) {
+ if (MouseInfo->DeviceId[i] > MAX_MAKE_CODE_TRANSLATED) {
+ MouseInfo->DeviceId[i] = '?';
+ } else {
+ MouseInfo->DeviceId[i] = MakeToAsciiTable[MouseInfo->DeviceId[i]];
+ }
+ }
+ } else if (MouseInfo->MouseSubtype == SERIAL_MOUSE_WITH_WHEEL) {
+ for (i = 0; i < MouseInfo->DeviceIdLength; i++) {
+ MouseInfo->DeviceId[i] += 0x20;
+ }
+ }
+ Length = MouseInfo->DeviceIdLength + 3;
+ }
+ Length += strlen(MouseIdentifier[MouseInfo->MouseType]) +
+ strlen(MouseSubidentifier[MouseInfo->MouseSubtype]) + 1;
+ fpString = (FPUCHAR)HwAllocateHeap(Length, FALSE);
+ if (MouseInfo->DeviceIdLength != 0) {
+ _fstrcpy(fpString, MouseInfo->DeviceId);
+ _fstrcat(fpString, " - ");
+ _fstrcat(fpString, MouseIdentifier[MouseInfo->MouseType]);
+ } else {
+ _fstrcpy(fpString, MouseIdentifier[MouseInfo->MouseType]);
+ }
+ _fstrcat(fpString, MouseSubidentifier[MouseInfo->MouseSubtype]);
+ Component->IdentifierLength = Length;
+ Component->Identifier = fpString;
+
+ if ((MouseInfo->MouseSubtype != SERIAL_MOUSE) &&
+ (MouseInfo->MouseSubtype != SERIAL_MOUSE_WITH_WHEEL)) {
+ Controller->Child = PeripheralEntry;
+ PeripheralEntry->Parent = Controller;
+ if (MouseList) {
+
+ //
+ // Put the current mouse component to the beginning of the list
+ //
+
+ Controller->Sibling = MouseList;
+ }
+ return(Controller);
+ } else {
+ CurrentEntry = AdapterEntry->Child; // AdapterEntry MUST have child
+ while (CurrentEntry) {
+ if (CurrentEntry->ComponentEntry.Type == SerialController) {
+ if (MouseInfo->MousePort == (USHORT)CurrentEntry->ComponentEntry.Key) {
+
+ //
+ // For serial mouse, the MousePort field contains
+ // COM port number.
+ //
+
+ PeripheralEntry->Parent = CurrentEntry;
+ CurrentEntry->Child = PeripheralEntry;
+ break;
+ }
+ }
+ CurrentEntry = CurrentEntry->Sibling;
+ }
+ return(NULL);
+ }
+}
+
+FPFWCONFIGURATION_COMPONENT_DATA
+GetMouseInformation (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the entry for mouse detection routine. It will invoke
+ lower level routines to detect ALL the mice in the system.
+
+Arguments:
+
+ None.
+
+Returns:
+
+ A pointer to a mouse component structure, if mouse/mice is detected.
+ Otherwise a NULL pointer is returned.
+
+--*/
+{
+ PMOUSE_INFORMATION MouseInfo;
+ FPFWCONFIGURATION_COMPONENT_DATA MouseList = NULL;
+
+ //
+ // Check if there is a key in keyboard look ahead buffer. If yes and
+ // we have not saved any, we will read it and remember it.
+ //
+
+ if (SavedKey == 0) {
+ SavedKey = HwGetKey();
+ }
+ if (MouseInfo = LookForPS2Mouse()) {
+ MouseList = SetMouseConfigurationData(MouseInfo, MouseList);
+ }
+ if (MouseInfo = LookForInportMouse()) {
+ MouseList = SetMouseConfigurationData(MouseInfo, MouseList);
+ }
+
+ while (MouseInfo = LookForSerialMouse()) {
+ SetMouseConfigurationData(MouseInfo, MouseList);
+ }
+
+ if (MouseInfo = LookForBusMouse()) {
+ MouseList = SetMouseConfigurationData(MouseInfo, MouseList);
+ }
+
+ //
+ // Finally drain 8042 output buffer again before we leave
+ //
+
+ Empty8042();
+
+ //
+ // If we have a keystroke before the mouse/keyboard detection, we
+ // needs to push the key back to the keyboard look ahead buffer such
+ // that ntldr can read it.
+ //
+
+ if (SavedKey) {
+ HwPushKey(SavedKey);
+ }
+ return(MouseList);
+}
+
+BOOLEAN
+InportMouseIrqDetection(
+ IN USHORT CurrentPort,
+ OUT PUSHORT Vector
+ )
+
+/*++
+
+Routine Description:
+
+ This routine attempts to locate the interrupt vector for which
+ the Inport mouse is configured. The allowable vectors are
+ 3, 4, 5, 7, and 9. If no interrupt vector is found, or more than
+ one is found, the routine returns FALSE. Otherwise, TRUE is returned.
+
+ Note that we diddle the i8259 interrupt controllers here.
+
+Arguments:
+
+ CurrentPort - I/O port to use for the mouse.
+
+ Vector - Pointer to the location to store the mouse interrupt vector.
+
+Return Value:
+
+ Returns TRUE if the Inport interrupt vector was located; otherwise,
+ FALSE is returned.
+
+--*/
+
+{
+ UCHAR OldMasterMask, OldSlaveMask;
+ UCHAR MasterMask, SlaveMask;
+ UCHAR InterruptBits;
+ UCHAR PossibleInterruptBits;
+ int i;
+ int NumberOfIRQs;
+ BOOLEAN VectorFound = FALSE;
+
+ //
+ // Get the i8259 interrupt masks.
+ //
+
+ OldMasterMask = READ_PORT_UCHAR((PUCHAR) PIC1_PORT1);
+ OldSlaveMask = READ_PORT_UCHAR((PUCHAR) PIC2_PORT1);
+
+ //
+ // Raise IRQL to the highest priority IRQL the inport would use.
+ //
+
+ WRITE_PORT_UCHAR(
+ (PUCHAR) PIC1_PORT1,
+ (UCHAR) 0xff ^ ((UCHAR)(1<<INPORT_LOWEST_IRQ) - 1)
+ );
+
+ WRITE_PORT_UCHAR(
+ (PUCHAR) PIC2_PORT1,
+ (UCHAR) 0xff
+ );
+
+ //
+ // Get the master i8259 interrupt mask.
+ //
+
+ MasterMask = READ_PORT_UCHAR((PUCHAR) PIC1_PORT1);
+
+ //
+ // Reset the Inport chip.
+ //
+
+ WRITE_PORT_UCHAR((PUCHAR)CurrentPort, INPORT_RESET);
+
+ //
+ // Select the Inport mode register for use as the current data register.
+ //
+
+ WRITE_PORT_UCHAR((PUCHAR)CurrentPort, INPORT_MODE_REGISTER);
+
+ //
+ // Disable potential Inport mouse interrupts.
+ //
+
+ WRITE_PORT_UCHAR(
+ (PUCHAR) PIC1_PORT1,
+ (UCHAR) (MasterMask | MASTER_IRQ_MASK_BITS)
+ );
+
+ //
+ // Select the i8259 Interrupt Request Register.
+ //
+
+ WRITE_PORT_UCHAR((PUCHAR) PIC1_PORT0, OCW3_READ_IRR);
+
+ //
+ // Attempt to locate the Inport interrupt line on the master i8259.
+ // Why try this 10 times? It's magic...
+ //
+
+ PossibleInterruptBits = MASTER_IRQ_MASK_BITS;
+ for (i = 0; i < 10; i++) {
+
+ //
+ // Generate a 0 on the Inport IRQ on the master i8259.
+ //
+
+ WRITE_PORT_UCHAR(
+ (PUCHAR)(CurrentPort + INPORT_DATA_REGISTER_1),
+ INPORT_TIMER_INTERRUPT_ENABLE + INPORT_MODE_0
+ );
+
+ //
+ // Read the interrupt bits off the master i8259. Only bits
+ // 7, 5, 4, 3, and 2 are of interest. Eliminate non-functional
+ // IRQs. Only continue looking at the master i8259 if there
+ // is at least one functional IRQ.
+ //
+
+ InterruptBits = READ_PORT_UCHAR((PUCHAR) PIC1_PORT0);
+ InterruptBits &= MASTER_IRQ_MASK_BITS;
+ InterruptBits ^= MASTER_IRQ_MASK_BITS;
+ PossibleInterruptBits &= InterruptBits;
+
+ if (!PossibleInterruptBits)
+ break;
+
+ //
+ // Generate a 1 on the Inport IRQ on the master i8259.
+ //
+
+ WRITE_PORT_UCHAR(
+ (PUCHAR)(CurrentPort + INPORT_DATA_REGISTER_1),
+ INPORT_TIMER_INTERRUPT_ENABLE + INPORT_MODE_1
+ );
+
+ //
+ // Read the interrupt bits off the master i8259. Only bits
+ // 7, 5, 4, 3, and 2 are of interest. Eliminate non-functional
+ // IRQs. Only continue looking at the master i8259 if there
+ // is at least one functional IRQ.
+ //
+
+ InterruptBits = READ_PORT_UCHAR((PUCHAR) PIC1_PORT0);
+ InterruptBits &= MASTER_IRQ_MASK_BITS;
+ PossibleInterruptBits &= InterruptBits;
+
+ if (!PossibleInterruptBits)
+ break;
+ }
+
+ if (PossibleInterruptBits) {
+
+ //
+ // We found at least one IRQ on the master i8259 that could belong
+ // to the Inport mouse. Count how many we found. If there is
+ // more than one, we haven't found the vector. Otherwise, we've
+ // successfully located the Inport interrupt vector on the master
+ // i8259 (provided the interrupt vector is 3, 4, 5, or 7).
+ //
+
+ PossibleInterruptBits >>= 3;
+ NumberOfIRQs = 0;
+ for (i = 3; i <= 7; i++) {
+ if (PossibleInterruptBits & 1) {
+ NumberOfIRQs += 1;
+ *Vector = (CCHAR) i;
+ }
+ PossibleInterruptBits >>= 1;
+ }
+ if (NumberOfIRQs == 1) {
+ VectorFound = TRUE;
+ } else {
+ *Vector = 0xffff;
+ }
+ }
+
+ //
+ // If we didn't locate the interrupt vector on the master i8259, attempt
+ // to locate it on the slave i8259.
+ //
+
+ if (!VectorFound) {
+
+ //
+ // Get the slave i8259 interrupt mask.
+ //
+
+ SlaveMask = READ_PORT_UCHAR((PUCHAR) PIC2_PORT1);
+
+ //
+ // Disable potential Inport mouse interrupts.
+ //
+
+ WRITE_PORT_UCHAR(
+ (PUCHAR) PIC2_PORT1,
+ (UCHAR) (SlaveMask | SLAVE_IRQ_MASK_BITS)
+ );
+
+ //
+ // Select the i8259 Interrupt Request Register.
+ //
+
+ WRITE_PORT_UCHAR((PUCHAR) PIC2_PORT0, OCW3_READ_IRR);
+
+ //
+ // Attempt to locate the Inport interrupt line on the slave i8259.
+ // Why try this 10 times? It's magic...
+ //
+
+ PossibleInterruptBits = SLAVE_IRQ_MASK_BITS;
+ for (i = 0; i < 10; i++) {
+
+ //
+ // Generate a 0 on the Inport IRQ on the slave i8259.
+ //
+
+ WRITE_PORT_UCHAR(
+ (PUCHAR)(CurrentPort + INPORT_DATA_REGISTER_1),
+ INPORT_TIMER_INTERRUPT_ENABLE + INPORT_MODE_0
+ );
+
+ //
+ // Read the interrupt bits off the slave i8259. Only bit 2
+ // is of interest. Eliminate non-functional IRQs. Only continue
+ // looking at the slave i8259 if there is at least one
+ // functional IRQ.
+ //
+
+ InterruptBits = READ_PORT_UCHAR((PUCHAR) PIC2_PORT0);
+ InterruptBits &= SLAVE_IRQ_MASK_BITS;
+ InterruptBits ^= SLAVE_IRQ_MASK_BITS;
+ PossibleInterruptBits &= InterruptBits;
+
+ if (!PossibleInterruptBits)
+ break;
+
+ //
+ // Generate a 1 on the Inport IRQ on the slave i8259.
+ //
+
+ WRITE_PORT_UCHAR(
+ (PUCHAR)(CurrentPort + INPORT_DATA_REGISTER_1),
+ INPORT_TIMER_INTERRUPT_ENABLE + INPORT_MODE_1
+ );
+
+ //
+ // Read the interrupt bits off the slave i8259. Only bit 2
+ // is of interest. Eliminate non-functional IRQs. Only continue
+ // looking at the slave i8259 if there is at least one
+ // functional IRQ.
+ //
+
+ InterruptBits = READ_PORT_UCHAR((PUCHAR) PIC2_PORT0);
+ InterruptBits &= SLAVE_IRQ_MASK_BITS;
+ PossibleInterruptBits &= InterruptBits;
+
+ if (!PossibleInterruptBits)
+ break;
+
+ }
+
+ //
+ // We may have found the Inport IRQ. If it's not 2 on slave (really
+ // 9, overall) then we have NOT found the Inport interrupt vector.
+ // Otherwise, we have successfully located the Inport vector on
+ // the slave i8259.
+ //
+
+ if (PossibleInterruptBits == 2) {
+ *Vector = 9;
+ VectorFound = TRUE;
+ } else {
+ *Vector = 0xffff;
+ }
+
+ //
+ // Restore the i8259 slave.
+ //
+
+ WRITE_PORT_UCHAR((PUCHAR) PIC2_PORT0, OCW3_READ_ISR);
+
+ //
+ // Restore the i8259 slave interrupt mask.
+ //
+
+ WRITE_PORT_UCHAR((PUCHAR) PIC2_PORT1, SlaveMask);
+ }
+
+ //
+ // Tri-state the Inport IRQ line.
+ //
+
+ WRITE_PORT_UCHAR((PUCHAR) (CurrentPort + INPORT_DATA_REGISTER_1), 0);
+
+ //
+ // Restore the i8259 master.
+ //
+
+ WRITE_PORT_UCHAR((PUCHAR) PIC1_PORT0, OCW3_READ_ISR);
+
+ //
+ // Restore the i8259 master interrupt mask.
+ //
+
+ WRITE_PORT_UCHAR((PUCHAR) PIC1_PORT1, MasterMask);
+
+ //
+ // Restore the previous IRQL.
+ //
+
+ WRITE_PORT_UCHAR(
+ (PUCHAR) PIC1_PORT1,
+ OldMasterMask
+ );
+
+ WRITE_PORT_UCHAR(
+ (PUCHAR) PIC2_PORT1,
+ OldSlaveMask
+ );
+
+ return(VectorFound);
+}
+
diff --git a/private/ntos/boot/detect/i386/ntmisc.h b/private/ntos/boot/detect/i386/ntmisc.h
new file mode 100644
index 000000000..2ff84bd40
--- /dev/null
+++ b/private/ntos/boot/detect/i386/ntmisc.h
@@ -0,0 +1,61 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ ntmisc.h
+
+Abstract:
+
+ This module contains the misc. definitions in \nt\public\sdk\inc
+ directory. Note, we created this file because ntdetect uses 16 bit
+ compiler and various new C compiler switches/pragamas are not recognized
+ by the 16 bit C compiler.
+
+Author:
+
+ Shie-Lin Tzong (shielint) 11-Nov-1992
+
+
+Revision History:
+
+
+--*/
+//
+// PHYSICAL_ADDRESS
+//
+
+typedef LARGE_INTEGER PHYSICAL_ADDRESS, *PPHYSICAL_ADDRESS;
+
+//
+// Note all the definitions defined below are used to make compiler shut up.
+// Ntdetect.com does not rely on the correctness of the structures.
+//
+
+//
+// Define the I/O bus interface types.
+//
+
+typedef enum _INTERFACE_TYPE {
+ Internal,
+ Isa,
+ Eisa,
+ MicroChannel,
+ TurboChannel,
+ MaximumInterfaceType
+}INTERFACE_TYPE, *PINTERFACE_TYPE;
+
+//
+// Doubly linked list structure. Can be used as either a list head, or
+// as link words.
+//
+
+typedef struct _LIST_ENTRY {
+ struct _LIST_ENTRY far *Flink;
+ struct _LIST_ENTRY far *Blink;
+} LIST_ENTRY, far *PLIST_ENTRY;
+
+#define PTIME_FIELDS PVOID
+#define KPROCESSOR_STATE ULONG
+#define WCHAR USHORT
diff --git a/private/ntos/boot/detect/i386/pnpbios.h b/private/ntos/boot/detect/i386/pnpbios.h
new file mode 100644
index 000000000..bd063676f
--- /dev/null
+++ b/private/ntos/boot/detect/i386/pnpbios.h
@@ -0,0 +1,87 @@
+/*++ BUILD Version: 0001 // Increment this if a change has global effects
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ biosp.h
+
+Abstract:
+
+ PnP BIOS/ISA sepc related definitions
+
+Author:
+
+ Shie-Lin Tzong (shielint) April 12, 1995
+
+Revision History:
+
+--*/
+
+//
+// Pnp BIOS device node structure
+//
+
+typedef struct _PNP_BIOS_DEVICE_NODE {
+ USHORT Size;
+ UCHAR Node;
+ ULONG ProductId;
+ UCHAR DeviceType[3];
+ USHORT DeviceAttributes;
+ // followed by AllocatedResourceBlock, PossibleResourceBlock
+ // and CompatibleDeviceId
+} PNP_BIOS_DEVICE_NODE, far *FPPNP_BIOS_DEVICE_NODE;
+
+//
+// Pnp BIOS Installation check
+//
+
+typedef struct _PNP_BIOS_INSTALLATION_CHECK {
+ UCHAR Signature[4]; // $PnP (ascii)
+ UCHAR Revision;
+ UCHAR Length;
+ USHORT ControlField;
+ UCHAR Checksum;
+ ULONG EventFlagAddress; // Physical address
+ USHORT RealModeEntryOffset;
+ USHORT RealModeEntrySegment;
+ USHORT ProtectedModeEntryOffset;
+ ULONG ProtectedModeCodeBaseAddress;
+ ULONG OemDeviceId;
+ USHORT RealModeDataBaseAddress;
+ ULONG ProtectedModeDataBaseAddress;
+} PNP_BIOS_INSTALLATION_CHECK, far *FPPNP_BIOS_INSTALLATION_CHECK;
+
+//
+// PnP BIOS ROM definitions
+//
+
+#define PNP_BIOS_START 0xF0000
+#define PNP_BIOS_END 0xFFFFF
+#define PNP_BIOS_HEADER_INCREMENT 16
+
+//
+// PnP BIOS API function codes
+//
+
+#define PNP_BIOS_GET_NUMBER_DEVICE_NODES 0
+#define PNP_BIOS_GET_DEVICE_NODE 1
+#define PNP_BIOS_SET_DEVICE_NODE 2
+#define PNP_BIOS_GET_EVENT 3
+#define PNP_BIOS_SEND_MESSAGE 4
+#define PNP_BIOS_GET_DOCK_INFORMATION 5
+// Function 6 is reserved.
+#define PNP_BIOS_SELECT_BOOT_DEVICE 7
+#define PNP_BIOS_GET_BOOT_DEVICE 8
+#define PNP_BIOS_SET_OLD_ISA_RESOURCES 9
+#define PNP_BIOS_GET_OLD_ISA_RESOURCES 0xA
+#define PNP_BIOS_GET_ISA_CONFIGURATION 0x40
+
+typedef USHORT ( far * ENTRY_POINT) (int Function, ...);
+
+//
+// Control Flags for Get_Device_Node
+//
+
+#define GET_CURRENT_CONFIGURATION 1
+#define GET_NEXT_BOOT_CONFIGURATION 2
diff --git a/private/ntos/boot/detect/i386/string.h b/private/ntos/boot/detect/i386/string.h
new file mode 100644
index 000000000..6b0c591d2
--- /dev/null
+++ b/private/ntos/boot/detect/i386/string.h
@@ -0,0 +1,111 @@
+/***
+*string.h - declarations for string manipulation functions
+*
+* Copyright (c) 1985-1991, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* This file contains the function declarations for the string
+* manipulation functions.
+* [ANSI/System V]
+*
+****/
+
+#ifndef _INC_STRING
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#if (_MSC_VER <= 600)
+#define __cdecl _cdecl
+#endif
+
+#ifndef _SIZE_T_DEFINED
+typedef unsigned int size_t;
+#define _SIZE_T_DEFINED
+#endif
+
+
+#ifndef _WCHAR_T_DEFINED
+typedef unsigned short wchar_t;
+#define _WCHAR_T_DEFINED
+#endif
+
+
+/* define NULL pointer value */
+
+#ifndef NULL
+#ifdef __cplusplus
+#define NULL 0
+#else
+#define NULL ((void *)0)
+#endif
+#endif
+
+
+/* function prototypes */
+
+void * _memccpy(void *, const void *, int, unsigned int);
+void * memchr(const void *, int, size_t);
+int memcmp(const void *, const void *, size_t);
+int _memicmp(const void *, const void *, unsigned int);
+void * memcpy(void *, const void *, size_t);
+void * memmove(void *, const void *, size_t);
+void * memset(void *, int, size_t);
+void _far * _far _fmemset(void _far *, int, size_t);
+void _far * _far _fmemcpy(void _far *, const void _far *, size_t);
+char * strcat(char *, const char *);
+char * strchr(const char *, int);
+int strcmp(const char *, const char *);
+int _strcmpi(const char *, const char *);
+int strcoll(const char *, const char *);
+int _stricmp(const char *, const char *);
+char * strcpy(char *, const char *);
+char _far * _far _fstrcpy(char _far *, const char _far *);
+size_t strcspn(const char *, const char *);
+char * _strdup(const char *);
+char * _strerror(const char *);
+char * strerror(int);
+size_t strlen(const char *);
+char * _strlwr(char *);
+char * strncat(char *, const char *, size_t);
+char _far * _far _fstrcat(char _far *, const char _far *);
+int strncmp(const char *, const char *, size_t);
+int _strnicmp(const char *, const char *, size_t);
+char * strncpy(char *, const char *, size_t);
+char * _strnset(char *, int, size_t);
+char * strpbrk(const char *, const char *);
+char * strrchr(const char *, int);
+char * _strrev(char *);
+char * _strset(char *, int);
+size_t strspn(const char *, const char *);
+char * strstr(const char *, const char *);
+char _far * _far _fstrstr(const char _far *, const char _far *);
+char * strtok(char *, const char *);
+char * _strupr(char *);
+size_t strxfrm (char *, const char *, size_t);
+char * itoa(int, char *, int);
+char * ultoa(unsigned long, char *, int);
+
+#if !__STDC__
+/* Non-ANSI names for compatibility */
+#define memccpy _memccpy
+#define memicmp _memicmp
+#define strcmpi _strcmpi
+#define stricmp _stricmp
+#define strdup _strdup
+#define strlwr _strlwr
+#define strnicmp _strnicmp
+#define strnset _strnset
+#define strrev _strrev
+#define strset _strset
+#define strupr _strupr
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#define _INC_STRING
+#endif /* _INC_STRING */
diff --git a/private/ntos/boot/detect/i386/types.h b/private/ntos/boot/detect/i386/types.h
new file mode 100644
index 000000000..78ec5bd68
--- /dev/null
+++ b/private/ntos/boot/detect/i386/types.h
@@ -0,0 +1,128 @@
+/*
+
+File
+
+ types.h
+
+
+Description
+
+ defines and structure definitions for nt386 hardware detection.
+
+
+Author
+
+ Shie-Lin Tzong (shielint) Feb-15-1992
+
+*/
+
+#define IN
+#define OUT
+#define OPTIONAL
+#define NOTHING
+#define CONST const
+
+//
+// Void
+//
+
+typedef void *PVOID; // winnt
+
+//
+// Basics
+//
+
+#define VOID void
+typedef char CHAR;
+typedef short SHORT;
+typedef long LONG;
+
+//
+// ANSI (Multi-byte Character) types
+//
+
+typedef CHAR *PCHAR;
+
+typedef double DOUBLE;
+
+//
+// Pointer to Basics
+//
+
+typedef SHORT *PSHORT; // winnt
+typedef LONG *PLONG; // winnt
+
+//
+// Unsigned Basics
+//
+
+typedef unsigned char UCHAR;
+typedef unsigned short USHORT;
+typedef unsigned long ULONG;
+
+//
+// Pointer to Unsigned Basics
+//
+
+typedef UCHAR *PUCHAR;
+typedef USHORT *PUSHORT;
+typedef ULONG *PULONG;
+
+//
+// Signed characters
+//
+
+typedef signed char SCHAR;
+typedef SCHAR *PSCHAR;
+
+//
+// Cardinal Data Types [0 - 2**N-2)
+//
+
+typedef char CCHAR; // winnt
+typedef short CSHORT;
+typedef ULONG CLONG;
+
+typedef CCHAR *PCCHAR;
+typedef CSHORT *PCSHORT;
+typedef CLONG *PCLONG;
+
+//
+// Far point to Basic
+//
+
+typedef UCHAR far * FPCHAR;
+typedef UCHAR far * FPUCHAR;
+typedef VOID far * FPVOID;
+typedef USHORT far * FPUSHORT;
+typedef ULONG far * FPULONG;
+
+//
+// Boolean
+//
+
+typedef CCHAR BOOLEAN;
+typedef BOOLEAN *PBOOLEAN;
+
+//
+// Large (64-bit) integer types and operations
+//
+
+typedef struct _LARGE_INTEGER {
+ ULONG LowPart;
+ LONG HighPart;
+} LARGE_INTEGER, *PLARGE_INTEGER;
+
+#define FP_SEG(fp) (*((unsigned *)&(fp) + 1))
+#define FP_OFF(fp) (*((unsigned *)&(fp)))
+
+#define FLAG_CF 0x01L
+#define FLAG_ZF 0x40L
+#define FLAG_TF 0x100L
+#define FLAG_IE 0x200L
+#define FLAG_DF 0x400L
+
+#define TRUE 1
+#define FALSE 0
+#define NULL ((void *)0)
+
diff --git a/private/ntos/boot/detect/i386/video.inc b/private/ntos/boot/detect/i386/video.inc
new file mode 100644
index 000000000..de0e541d4
--- /dev/null
+++ b/private/ntos/boot/detect/i386/video.inc
@@ -0,0 +1,370 @@
+;++
+;
+; Copyright (c) 1989 Microsoft Corporation
+;
+; Module Name:
+;
+; video.inc
+;
+; Abstract:
+;
+; This module implements the assembley definitions necessary to determine
+; display adapter type.
+;
+; Author:
+;
+; Shie-Lin Tzong (shielint) 15-July-1991.
+; Most of the stuff is extracted from win31 setup code.
+;
+; Environment:
+;
+; 80x86 Real Mode.
+;
+; Revision History:
+;
+;
+;--
+
+;
+; Display type definitions.
+; BIT 16-31 Defines video adapter type
+; bit 0 0 - color; 1 - mono
+; bit 1-7 Reserved
+; bit 8-15 Adapter specific information.
+;
+
+VD_UNKNOWN EQU 0
+VD_COLOR EQU 0
+VD_MONO EQU 1
+VD_VGA EQU 10000h
+VD_COMPAQ_AVGA EQU 20000H
+VD_COMPAQ_QVIS EQU 30000H
+VD_8514 EQU 40000H
+VD_GENOA_VGA EQU 50000H
+VD_VIDEO7_VGA EQU 60000H
+VD_TRIDENT_VGA EQU 70000H
+VD_PARADISE_VGA EQU 80000H
+VD_ATI_VGA EQU 90000H
+VD_TSENGLAB_VGA EQU 0A0000H
+VD_CIRRUS_VGA EQU 0B0000H
+VD_DELL_DGX EQU 0C0000H
+VD_S3 EQU 0D0000H
+VD_NCR_77C22 EQU 0E0000H
+VD_WD_90C EQU 0F0000H
+VD_XGA EQU 100000H
+
+;
+; Monitor type for 8514
+; NOte, 0 is not used.
+;
+
+VF_MONITOR_VGA EQU 100h ; Stand VGA
+VF_MONITOR_MONO_8503 EQU 200h ; mono 8503
+VF_MONITOR_GAD_8514 EQU 300h ; 8514 type monitor
+
+;
+; Video 7 VGA specific flags
+;
+
+VF_V7_VRAM EQU 100H
+VF_V7_DRAM EQU 200H
+
+;
+; NCR 77C2x specific flags
+;
+
+VF_NCR_77C22E EQU 100H
+
+;
+; WD90Cxx specific flags
+;
+
+VF_WD_00 EQU 100H
+VF_WD_30 EQU 200H
+VF_WD_31 EQU 300H
+
+;
+; Trident VGA specific flags
+;
+
+VF_TVGA_9100 EQU 100h
+
+;
+; Paradise VGA specific flags
+;
+
+VF_PVGA_PROM EQU 100h ; with Paradise ROM
+VF_PVGA_CHIP_1F EQU 200h ; with 1F chip
+
+;
+; ATI VGA specific flags
+;
+
+VF_ATIVGA_WONDDER3 EQU 100h
+
+;
+; Tseng Lab VGA specific flags
+;
+
+VF_TLVGA_ET3000 EQU 0
+VF_TLVGA_ET4000 EQU 100h
+
+;
+; Cirrus Logic VGA specific definitions
+;
+
+VF_CLVGA_REVC EQU 100h ; 610/620 rev C
+;
+; 070193 - adrianc
+; Added the Cirrus chip detection for COMPAQ servers.
+;
+VF_CLVGA_5420r0 EQU 200h ; COMPAQ Cirrus implementations
+VF_CLVGA_5420r1 EQU 300h
+VF_CLVGA_5428 EQU 400h
+VF_CLVGA_542x EQU 500h
+
+;
+; Equates for 8514 register ports.
+;
+
+ERR_TERM equ 92e8h ; 8514 error term register.
+SUBSYS_STAT equ 42e8h ; 8514 Subsystem status register.
+
+;
+; Video display register equates
+; ...Colr are for CGA and EGA color modes
+; ...Mono are for EGA/VGA monochrome modes
+;
+;NAMING CONVENTIONS
+; pXXXXX is a I/O port definition
+; fXXXXX is a bit mask
+; bXXXXX is a bit number
+; mXXXXX is a bit mask (multiple fXXXX)
+; vXXXXX is a value to output/input to/from a port
+; xXXXXX is a specific index
+
+;
+; CRT registers
+;
+
+pCRTCIndxColr EQU 3D4h ; CRTC index register
+pCRTCIndxMono EQU 3B4h
+
+pCRTCDataColr EQU 3D5h ; CRTC data register
+pCRTCDataMono EQU 3B5h
+
+; Status register
+;
+
+pStatColr EQU 3DAh ; Status register
+pStatMono EQU 3BAh
+fStatEna EQU 00000001b ; Video RAM access OK for processor
+fStatLPTr EQU 00000010b ; Light pen triggered
+fStatLPSw EQU 00000100b ; Light pen switch is "on"
+fStatVRTC EQU 00001000b ; Vertical retrace in progress
+mStat_IVal EQU fStatEna+fStatVRTC ; Initial value for pseudo status
+
+;
+; Feature control
+;
+
+pFeatColr EQU pStatColr ; Feature control
+pFeatMono EQU pStatMono
+pFeatVGAIn EQU 3CAh ; VGA feature control read
+fFeatFC0 EQU 00000001b ; FC0
+fFeatFC1 EQU 00000010b ; FC1
+
+;
+; Light pen
+;
+
+pLPen1Colr EQU 3DBh ; Light pen latch clear
+pLPen1Mono EQU 3BBh
+pLPen2Colr EQU 3DCh ; Light pen latch set
+pLPen2Mono EQU 3BCh
+
+;
+; Misc input/output
+;
+
+pMisc EQU 3C2h ; Miscellaneous output
+pMiscIn EQU 3CCh ; VGA read Misc. output
+fMiscPNum EQU 00000001b ; 3Dx port numbers(vs. 3Bx)
+fMiscREna EQU 00000010b ; Ram enable
+fMiscDot EQU 00001100b ; Dot clock select
+fMiscOSrc EQU 00010000b ; Output source
+fMiscPage EQU 00100000b ; Page bit for odd/even mode
+fMiscHPol EQU 01000000b ; Horizontal retrace polarity
+fMiscVPol EQU 10000000b ; Vertical retrace polarity
+mMiscCRTC EQU fMiscREna+fMiscPage ; Mask for CRTC bits
+mMiscMemC EQU 0FFh - mMiscCRTC ; Mask for MemC bits
+
+;
+; Misc. status
+;
+
+pStt0EGA EQU pMisc ; Miscellaneous status
+fStt0Swit EQU 00010000b ; Switch sense(addr'd by dot clk sel)
+fStt0FCI0 EQU 00100000b ; Feature card input 0
+fStt0FCI1 EQU 01000000b ; Feature card input 1
+fStt0VRTC EQU 10000000b ; VRTC
+
+;
+; Attribute control
+;
+
+pAttr EQU 3C0h ; Attribute(palette) address/data
+fVAI_Indx EQU 10000000b ; sign bit of Attribute index is
+bVAI_Indx EQU 7 ; flag indicating port is index
+fVAI_ScOn EQU 00100000b ; Indicates screen is on
+bVAI_ScOn EQU 5
+
+;
+; Sequencer
+;
+
+pSeqIndx EQU 3C4h ; Sequencer address
+pSeqData EQU 3C5h ; Sequencer data
+fSeq0ARst EQU 00000001b ; 0:Async reset
+fSeq0SRst EQU 00000010b ; 0:Sync reset
+fSeq1DPCh EQU 00000001b ; 1:Dots per character
+fSeq1BWid EQU 00000010b ; 1:Band Width
+fSeq1ShLd EQU 00000100b ; 1:Shift load(0=every char, 1=skip)
+fSeq1DClk EQU 00001000b ; 1:Dot clock(=1 if halved)
+mSeq2WMsk EQU 00001111b ; 2:Write mask
+mSeq3ChrB EQU 00000011b ; 3:Char map B select(attr bit 3 = 0)
+mSeq3ChrA EQU 00001100b ; 3:Char map A select(attr bit 3 = 1)
+fSeq4Alph EQU 00000001b ; 4:Alpha mode(char gen enabled)
+fSeq4ExtM EQU 00000010b ; 4:Extended memory installed
+fSeq4SqAd EQU 00000100b ; 4:Seq'l mem addr'ing(vs. odd/even)
+fSeq4Chain4 EQU 00001000b ; 4:Chain 4 (double odd/even) for
+ ; 256 color (mode 13)
+
+fSeqF9extpgsel EQU 00000001b ;V7F9:Extended page select
+fSeqFCext256m EQU 00000010b ;V7FC:Extended 256 color mode
+fSeqFCext256e EQU 00000100b ;V7FC:Extended 256 color enable
+fSeqFCseqChain4 EQU 00100000b ;V7FC:Sequential Chain 4
+
+;
+; Graphic controller
+;
+
+pGrp1Pos EQU 3CCh ; Graphics posn 1(=0)
+pGrp2Pos EQU 3CAh ; Graphics posn 2(=1)
+pGrpIndx EQU 3CEh ; Graphics controller address
+pGrpData EQU 3CFh ; Graphics controller data
+fGrp0StV0 EQU 00000001b ; 0:Value for plane 0 if enabled
+fGrp0StV1 EQU 00000010b ; 0:Value for plane 1 if enabled
+fGrp0StV2 EQU 00000100b ; 0:Value for plane 2 if enabled
+fGrp0StV3 EQU 00001000b ; 0:Value for plane 3 if enabled
+fGrp1Ena0 EQU 00000001b ; 1:Enable for plane 0
+fGrp1Ena1 EQU 00000010b ; 1:Enable for plane 1
+fGrp1Ena2 EQU 00000100b ; 1:Enable for plane 2
+fGrp1Ena3 EQU 00001000b ; 1:Enable for plane 3
+mGrp2Colr EQU 00001111b ; 2:Color compare value
+mGrp3RCnt EQU 00000111b ; 3:Rotate left count for mode 0
+mGrp3Func EQU 00011000b ; 3:Function for modes 0 and 2
+mGrp4RMsk EQU 00000111b ; 4:Read map select
+mGrp5WMod EQU 00000011b ; 5:Write mode
+fGrp5Test EQU 00000100b ; 5:Test condition
+fGrp5RMod EQU 00001000b ; 5:Read mode(0=plane,1=compare)
+fGrp5SqAd EQU 00010000b ; 5:Seq'l mem addr'ing(vs. odd/even)
+fGrp5CGA EQU 00100000b ; 5:CGA 4 color mode addressing
+fGrp6Char EQU 00000001b ; 6:Char or graphics
+fGrp6Chain EQU 00000010b ; 6:Chain odd maps after even
+mGrp6Addr EQU 00001100b ; 6:Processor view of VRAM start addr
+ ; 00=A000 for 128kb
+ ; 01=A000 for 64kb
+ ; 10=B000 for 32kb
+ ; 11=B800 for 32kb
+bGrp6Addr EQU 2 ; First of 2 bits for start addr
+mGrp7Colr EQU 00001111b ; 7:Color don't care for read compare
+ ; 8:Mask: use latch value vs. data
+
+;
+; VGA subsystem enable
+;
+
+pVGAEna EQU 3C3h ; VGA enable register
+fVGAEna EQU 00000001b ; Enable access to VGA
+
+;
+; VGA DAC
+;
+
+pDACWindx EQU 3C8h ; DAC Write index(R/W)
+pDACRindx EQU 3C7h ; DAC Read index(RO)
+pDACState EQU pDACRindx ; DAC state
+pDACData EQU 3C9h ; DAC data(3 successive accesses)
+pDACMask EQU 3CAh ; DAC mask
+
+;
+; VGA read access to write only registers
+;
+
+pMiscRead EQU 3CCh ; Port to read Misc output register
+pFeatRead EQU 3CAh ; Port to read Feature output register
+
+;
+; 8514 DAC
+;
+
+p8514DACWindx EQU 2ECh ; DAC Write index(R/W)
+p8514DACRindx EQU 2EBh ; DAC Read index(RO)
+p8514DACState EQU pDACRindx ; DAC state
+p8514DACData EQU 2EDh ; DAC data(3 successive accesses)
+
+;
+; values returned from reads of port pDACState:
+;
+
+vDAC_Read_Mode EQU 0
+vDAC_Write_Mode EQU 3
+
+
+xC_CTMiscRead EQU 0Fh ; CHIPS Misc output read index
+xC_CTFeatRead EQU 0Eh ; CHIPS Feat output read index
+xC_CT400 EQU 0F9h ; CHIPS 400 line reg index
+xC_CTTempFE EQU 0FEh ; CHIPS CRTC temp reg FEh
+xG_CTCtl EQU 0F7h ; CHIPS control reg index
+
+;
+
+pCMode EQU 3C6h ; Control mode(Compaq specific)
+
+ATiVGA_extended_reg EQU 01ceh
+
+TVGA_3C5_B_WrMode equ 0
+TVGA_3C5_B_RdMode equ 1
+
+;
+; Definition for IBM XGA video adapter Id.
+;
+
+IBM_XGA_ID_LOW EQU 8FD8h
+IBM_XGA_ID_HIGH EQU 8FDBh
+MCA_POS_DATA_SIZE EQU 6
+
+;
+; Misc. V7 VRAM definitions
+;
+
+VRAM2_ROM_ID_1 EQU 108h
+VRAM2_ROM_ID_2 EQU 208h
+VRAM2ERGO_ROM_ID EQU 308h
+V7_ID_OFFSET EQU 86h ; The offset to V7VGA ROM id
+
+;
+; WD extended registers
+;
+
+WD_EXT_IO_PORT EQU 23C0h
+
+;
+; Misc. definitions
+;
+
+FONT_POINTERS EQU 700h ; physical addr to store font pointers
+ ; This is also the DOS loaded area
+VIDEO_SEG EQU 0C000h ; Video memory segment
+ \ No newline at end of file
diff --git a/private/ntos/boot/detect/i386/videoa.asm b/private/ntos/boot/detect/i386/videoa.asm
new file mode 100644
index 000000000..5db4f9931
--- /dev/null
+++ b/private/ntos/boot/detect/i386/videoa.asm
@@ -0,0 +1,2175 @@
+ title "Display Adapter type detection"
+;++
+;
+; Copyright (c) 1989 Microsoft Corporation
+;
+; Module Name:
+;
+; video.asm
+;
+; Abstract:
+;
+; This module implements the assembley code necessary to determine
+; various display chip sets.
+;
+; Author:
+;
+; Shie-Lin Tzong (shielint) 04-Dec-1991.
+; Most of the code is taken from Win31 vdd and setup code(with modification.)
+;
+; Environment:
+;
+; x86 Real Mode.
+;
+; Revision History:
+;
+;
+;--
+
+if 0 ; Remove video detection
+ .xlist
+include video.inc
+ .list
+
+else
+
+FONT_POINTERS EQU 700h ; physical addr to store font pointers
+ ; This is also the DOS loaded area
+
+endif ; Remove Video detection
+
+.386
+
+if 0 ; Remove video detection
+
+IO_Delay macro
+ jmp $+2
+ jmp $+2
+ endm
+
+TRUE EQU 1
+FALSE EQU 0
+
+extrn _HwIsMcaSystem: near;
+extrn Ps2SystemBoardVideoId: near;
+extrn _HwMcaPosData: DWORD;
+
+endif ; Remove video detection
+
+_DATA SEGMENT PARA USE16 PUBLIC 'DATA'
+
+if 0 ; Remove video detection
+
+;
+; PVGA
+;
+
+str_Paradise DB "PARADISE"
+len_str_Paradise EQU $-str_Paradise
+str_WDIGITAL DB "WESTERN DIGITAL"
+len_str_WDIGITAL EQU $-str_WDIGITAL
+
+;
+; followings are for Paradise 1F chip check - C. Chiang
+;
+
+bSave0F db 0 ; Unlock\Lock PR0-PR4
+bSave29 db 0 ; Unlock\Lock PR11-PR17
+bSave34 db 0 ; Unlock\Lock Flat Panel
+bSave35 db 0 ; Unlock\Lock Mapping Ram
+str_PVGA1F db "OPYRIGHT1990WDC"
+len_str_1F equ $-str_PVGA1F
+str_PVGA1FC db "OPYRIGHTWD90C22"
+len_str_1FC equ $-str_PVGA1FC
+str_1F_GEN db "WD90C2"
+len_str_GEN equ $-str_1F_GEN
+String db len_str_1F dup(?)
+
+;
+; ATIVGA
+;
+
+ATI_Sig DB " 761295520" ; ATI signature at in ROM at offset 30
+ATI_Sig_Len EQU $-ATI_Sig
+
+;
+; TTVGA
+;
+
+TVGA_Sig DB "TRIDENT MICROSYSTEMS"
+TVGA_Sig_Len EQU $-TVGA_Sig
+
+;
+; Compaq
+;
+
+CompaqSig db 'OMPAQ'
+
+endif ; Remove video detection
+
+_DATA ends
+
+_TEXT SEGMENT PARA USE16 PUBLIC 'CODE'
+ ASSUME CS: _TEXT, DS:_DATA, SS:NOTHING
+
+if 0 ; Remove video detection
+
+
+;++
+;
+; ULONG
+; GetVideoAdapterType (
+; VOID
+; )
+;
+; Routine Description:
+;
+; This function determines video adapter type in the system. If possible,
+; it also determines the various chip sets used in the VGA card.
+;
+; N.B. Currently, we determine the chip set ONLY if it is VGA and the
+; following chip sets are detectiable by this routine:
+;
+;
+;
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; (eax): Bit 16 - 31 Adapter type i.e. XGA, VGA, 8514
+; Bit 0 - 15 Adapter subtype, V7VGA, CompaqVGA, TsengLab, ...
+; zero means unknown type or subtype. EGA and CGA are NOT
+; supported.
+;
+;--
+
+ public _GetVideoAdapterType
+_GetVideoAdapterType proc near
+
+ push ebx
+
+;
+; First check if it is a XGA card?
+;
+
+ call IsXga ; Is it XGA?
+ or ax, ax
+ jz gvaCompaqQVision ; if z, no, go check for Comapq QVision
+ mov eax, VD_XGA ; else it is XGA
+ jmp VideoDone
+
+;
+; Check if it is Compaq QVision?
+;
+
+gvaCompaqQVision:
+ call IsCompaqVideo ; Is it Compaq video ROM?
+ or ax, ax
+ jz short gvaCheckVGA ; Don't do any compaq video test
+
+ call IsCompaqQVision ; Is it Compaq QVision?
+ or ax, ax
+ jz gvaCompaqAvga ; if z, no, go check for AVGA
+
+ mov eax, VD_COMPAQ_QVIS
+ jmp VideoDone
+
+;
+; Check if it is Compaq AVGA?
+;
+
+gvaCompaqAvga:
+ call IsCompaqAvga ; Is it Compaq AVGA?
+ or ax, ax
+ jz gvaCheckVga ; if z, no, go check for VGA
+
+ mov eax, VD_COMPAQ_AVGA
+ jmp VideoDone
+
+;
+; Then we check the vga/svga which can be detected by int 10 func 1A.
+;
+
+gvaCheckVga:
+ MOV AX, 1A00h ; read display combination code
+ INT 10h
+ CMP AL, 1Ah ; function supported ?
+ JNZ gvaUnknown ; No, then set it to unknown
+
+;
+; BL contains active display code. I have however, seen that on some vga
+; cards this call will return the active display in BH. For this reason I
+; am checking BL for zero, if I find that BL is zero
+; I will place BH into BL and assume that the only display attached to the
+; system is the active display.
+;
+
+ or bl,bl ; Do we have an active display ?
+ jnz Normal_combo_code ; Yes, then continue on normaly.
+ mov bl,bh ; No, then move bh to bl.
+ or bl,bl
+ jz gvaUnknown ; if fail, we don't know the card
+
+Normal_combo_code:
+
+ mov eax, VD_COLOR ; Assume it is VGA color
+ CMP BL, 08h ; VGA color ?
+ je gvaVgaCheck
+
+ mov eax, VD_MONO ; Assume it is VGA mono
+ CMP BL, 07h ; VGA mono?
+ JNE gvaUnknown ; if nz, it's a code which we don't support
+
+gvaVgaCheck:
+ mov ebx, eax ; [ebx] = video type
+ call GetVgaChipSet
+ or eax, ebx ; combine vga type and subtype
+ jmp VideoDone
+
+gvaUnknown:
+ mov eax, VD_UNKNOWN ; set return type to unknown
+VideoDone:
+ mov edx, eax
+ shr edx, 16 ; return (dx:ax)
+ pop ebx
+ ret
+
+_GetVideoAdapterType endp
+
+;++
+;
+; ULONG
+; GetVgaChipSet (
+; VOID
+; )
+;
+; Routine Description:
+;
+; This function tries to determine the chip set used in the VGA card.
+; Currently the followings are detectable:
+;
+; 8514
+; GENOA VGA
+; VIDEO 7 VRAM/DRAM VGA
+; Trident TVGA
+; Paradise VGA
+; ATI VGA
+; Tseng Lab VGA
+; Cirrus Logic VGA
+; dell dgx
+;
+; N.B. This function can ONLY be called when we already know the video
+; type is VGA.
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; (eax) = Video SubType.
+;
+;--
+
+ public GetVgaChipSet
+GetVgaChipSet proc near
+
+ push bp
+ push bx
+ push si
+ push di
+ push es
+
+;
+; First check if it is 8514.
+;
+
+ xor eax, eax ; clear eax
+ call Is8514Adapter ; Is it 8514?
+ or ax, ax
+ jz gvc10 ; if z, no, go check for other chip sets
+ add eax, VD_8514
+ jmp VRI_Exit
+
+gvc10:
+ mov ax, 1130h
+ mov bh, 2
+ int 10h ; es:bp -> ROM font, so use es as ROM segment
+
+;
+; VGA real mode adapter detection
+; Note that individual adapter detection routines must either
+; jump to VRI_Exit with EDX = VT_Flags value or preserve
+; the ES and DX register. ES is the adapter ROM segment (usually C000h)
+; and DX is the status register port address (for resetting the
+; attribute controller index/value toggle).
+
+;
+; Load status port value in DX
+; This is to prevent duplication in OEM specific detection
+;
+
+ mov dx,pMiscIn
+ in al,dx
+ test al,1
+ mov dl,(pStatColr AND 0FFh)
+ jnz SHORT gvc20
+ mov dl,(pStatMono AND 0FFh)
+gvc20:
+
+
+;
+; ======================= VGA REAL mode adapter detection code ===============
+; ============================================================================
+;
+; The code here is usually supplied by video adapter OEMs.
+; Note that individual adapter detection routines must either
+; jump to VRI_Exit with EAX = VIDEO_SUBTYPE_XXXX or preserve
+; the ES and DX register. ES is the adapter ROM segment (usually C000h)
+; and DX is the status register port address (for resetting the
+; attribute controller index/value toggle).
+;
+; Entry:
+; At this point:
+; [es] = Adapter ROM segment
+; [dx] = status register port addr
+;
+; Exit: [eax] = Video subtype
+;
+; ============================================================================
+; ============================================================================
+
+;
+; ****************************
+; * *
+; * Genoa SuperVGA detection *
+; * *
+; ****************************
+;
+
+ mov bx,WORD PTR ES:[0037h]
+
+;
+; If there is no ROM at this address, then we need to validate that BX is
+; something reasonable, because some pmode guys do not emulate segment
+; wrap correctly.
+;
+
+ cmp bx, 0FFFCh
+ ja SHORT Not_GENVGA
+ mov eax,ES:[bx]
+ cmp eax,66991177h
+ je SHORT Is_GENVGA
+ cmp eax,66992277h
+ jnz SHORT Not_GENVGA
+
+;
+; It is a GENOA VGA
+;
+
+Is_GENVGA:
+ mov eax,VD_GENOA_VGA ; GENOA SuperVGA
+ jmp VRI_Exit
+
+Not_GENVGA:
+
+;
+; ************************************
+; * *
+; * NCR 77C22 chip detection *
+; * *
+; ************************************
+;
+; NCR77C22 detection
+;
+
+ push dx
+
+;
+; save the current sequencer index register.
+;
+
+ mov dx, pSeqIndx ; (dx)=pSeqIndx
+ in al, dx
+ push ax ; (TOS)=content of Seq index
+
+;
+; set the sequencer index register to 0x05 which is lock register.
+; save the data that we find there.
+;
+
+ mov al, 05
+ out dx, al
+ inc dx ; (dx)=pSeqData
+ in al, dx
+ push ax ; (TOS)=context of LOCK reg
+
+;
+; Lock our extended registers
+;
+
+ mov al, 0
+ out dx, al ; (dx)=pSeqData
+
+;
+; Check an extended register to see if it responds
+;
+
+ mov al, 25h
+ dec dx ; (dx)=pSeqIndx
+ out dx, al
+ inc dx
+ in al, dx ; (dx)=pSeqData
+ push ax
+
+;
+; (TOS)= test register content
+; (TOS+2) = Lock reg content
+; (TOS+4) = Sequencer index reg content
+;
+
+ mov al, 0AAh ; detected bit pattern
+ out dx, al
+ xor ecx, ecx ; assume not NCR77C2x
+ in al, dx
+ cmp al, 0AAh
+ je short NcrRestore
+
+;
+; The register didn't respond...maybe the lock is working
+; Unlock the registers and see if the extended register responds now..
+;
+
+ mov al, 5
+ dec dx ; (dx)=pSeqIndx
+ out dx, al
+ mov al, 1 ; unlock it
+ inc dx ; (dx)=pSeqData
+ out dx, al
+
+;
+; Try the lock again. This time we unlock it.
+;
+
+ mov al, 25h
+ dec dx ; (dx)=pSeqIndx
+ out dx, al
+ mov al, 0AAh
+ inc dx ; (dx)=pSeqData
+ out dx, al
+
+;
+; Check if the unlock works
+;
+
+ xor ecx, ecx ; assume not NCR
+ IO_Delay
+ in al, dx
+ cmp al, 0AAh
+ jne short NcrRestore
+
+;
+; The register responded now that we unlocked it.
+; Since our lock register worked, assume an NCR 77C22 style system
+;
+
+ mov al, 8 ; index of version id in SEQ
+ dec dx ; (dx)=pSeqIndx
+ out dx, al
+ inc dx ; (dx)=pSeqData
+ in al, dx
+
+ mov ecx, VD_NCR_77C22
+
+;
+; Determine what kind of 77C2x
+;
+
+ and al, 0f0h
+ shr al, 4
+ cmp al, 0
+ je short NcrRestore
+
+ cmp al, 1
+ je short @f
+
+ cmp al, 2
+ jne short NcrRestore
+
+@@: add ecx, VF_NCR_77C22E
+
+NcrRestore:
+
+ mov al, 25h
+ mov dx, pSeqIndx
+ out dx, al
+ inc dx ; (dx)= pSeqData
+ pop ax ; (al) = test reg content
+ out dx, al ; restore test reg
+
+ mov al, 5
+ dec dx ; (dx)=pSeqIndx
+ out dx, al
+ inc dx ; (dx)=pSeqData
+ pop ax ; (al) = Lock reg content
+ out dx, al ; restore lock reg
+
+ dec dx
+ pop ax ; (al)= Index reg content
+ out dx, al
+
+ or ecx, ecx
+ jz short @f
+
+ mov eax, ecx
+ pop dx
+ jmp VRI_Exit
+
+@@:
+ pop dx
+
+;
+; ************************************
+; * *
+; * DELL DGX video chip detection *
+; * *
+; ************************************
+;
+; DELL_DGX detection
+;
+
+ push dx
+
+ mov dx,6c80h
+ in ax,dx
+ cmp ax,0ac10h
+ jne short NotDgx
+
+ add dx,2
+ in ax,dx
+ cmp ax,1140h
+ je short IsDgx
+
+ cmp ax,0160h
+ jne NotDgx
+
+IsDgx:
+ pop dx
+ mov eax,VD_DELL_DGX
+ jmp VRI_Exit
+
+NotDgx:
+ pop dx
+
+;
+; ******************************
+; * *
+; * Video 7 SuperVGA detection *
+; * *
+; ******************************
+;
+
+ push dx
+ xor bx,bx ; clear it out
+ mov ax,6f00h
+ int 10h
+ cmp bx,'V7' ; any of the products?
+ jnz SHORT VRI_NotV7 ; nope...
+
+;
+; check the chip version #
+;
+
+ mov cx,0ffffh
+ mov ax,06f07h ; get the # from the bios
+ int 10h
+ xor dx,dx ; Assume no flags passed in
+ or cx,cx ; zero?
+ jne SHORT VRI_NotV7
+ and bl,0f0h
+ cmp bl,70h ; V7VGA chip?
+ je SHORT @f ; Yes, this is VRAM 1
+
+ push ds ; Get V7VGA id from c000:86
+ mov cx, VIDEO_SEG
+ mov ds, cx
+ mov bx, V7_ID_OFFSET
+ mov cx, [bx]
+ pop ds
+ cmp cx, VRAM2_ROM_ID_1
+ je short @f
+
+ cmp cx, VRAM2_ROM_ID_2
+ je short @f
+
+ cmp cx, VRAM2ERGO_ROM_ID
+ je short @f
+
+ pop dx
+ mov eax, VD_VIDEO7_VGA
+ jmp VRI_Exit
+
+@@:
+ add sp,2 ; Throw away DX on stack
+ mov cl, ah
+ mov eax,VD_VIDEO7_VGA + VF_V7_DRAM ; assume it's video 7 VRAM
+ test cl, 80h ; is it VRAM?
+ je VRI_Exit
+ mov eax,VD_VIDEO7_VGA + VF_V7_VRAM ; eax = Video 7 DRAM
+ jmp VRI_Exit
+
+VRI_NotV7:
+ pop dx
+
+;
+; ******************************
+; * *
+; * Trident TVGA detection *
+; * *
+; ******************************
+;
+
+;
+; Try to find "TRIDENT MICROSYSTEMS" from ROM BIOS.
+; Search C000h. If not found, try E000h, some motherboard makers
+; put our BIOS there.
+; - Trident, Henry Zeng
+;
+
+ lea si, TVGA_Sig
+ xor di, di
+ mov cx, 128
+
+SearchTrident:
+ push si
+ push di
+ push cx
+ mov cx, TVGA_Sig_Len
+ repe cmpsb ; ? Trident
+ pop cx
+ pop di
+ pop si
+ jz short IsTVGA ; Gotcha!
+
+ inc di
+ loop SearchTrident
+ jmp short NotTVGA
+
+ public IsTVGA
+IsTVGA:
+ mov edx, VD_TRIDENT_VGA ; Trident TVGA
+
+ ;
+ ; Check if TVGA9100
+ ;
+
+ push dx ; ? version # (3C5.B) == 93h
+ mov dx, 03C4h
+ mov al, 0Bh
+ out dx, al
+ inc dx
+ in al, dx
+ pop dx
+ cmp al, 93h
+ jnz short Not9100
+ or edx, VF_TVGA_9100 ; Is TVGA9100
+Not9100:
+ mov eax, edx
+ jmp VRI_Exit
+
+NotTVGA: ; The other guy
+
+
+;
+; ******************************
+; * *
+; * Westerm Digital detection *
+; * *
+; ******************************
+;
+
+ push dx
+ push bx
+
+;
+; Write 3ce.0c
+;
+
+ mov al, 0Ch
+ mov dx, pGrpIndx
+ out dx, al
+ inc dx ; (dx)= grpData
+ in al, dx
+ push ax ; (TOS)= SaveGrph0C
+
+ and al, 0bfh
+ out dx, al
+
+;
+; write 3ce.0f
+;
+
+ mov al, 0Fh
+ mov dx, pGrpIndx
+ out dx, al
+ inc dx ; (dx)= grpData
+ in al, dx
+ push ax ; (TOS)= SaveGrph0F
+
+ mov al, 0
+ out dx, al
+
+;
+; write 3ce.09
+;
+
+ mov al, 09h
+ mov dx, pGrpIndx
+ out dx, al
+ inc dx ; (dx)= grpData
+ in al, dx
+ mov ah, al ; (ah)= temp1
+ inc al
+ out dx, al ; write (temp1+1)
+ IO_Delay
+ xor ecx, ecx ; Assume not WD
+ in al, dx ; Read it back
+ mov bl, al ; (bl)= temp2
+ mov al, ah ; restore the old value
+ out dx, al
+
+ inc al
+ cmp al, bl ; Is (temp1+1)== temp2?
+ je WdRestore ; if yes, not Wd
+
+ mov ax, 050Fh
+ mov dx, pGrpIndx
+ out dx, ax
+ mov ax, 09h
+ mov dx, pGrpIndx
+ out dx, ax
+ inc dx ; (dx)= grpData
+ in al, dx
+ mov ah, al ; (ah)=temp1
+ inc al
+ out dx, al ; write (temp1+1)
+ IO_Delay
+ in al, dx ; read it back
+ mov bl, al ; (bl) = temp 2
+ mov al, ah ; restore old value
+ out dx, al
+
+ inc al ; Is (temp1+1) == temp2
+ cmp al, bl
+ jne WdRestore ; if no, not WD
+
+;
+; it *is* a WDVGA!
+;
+
+;
+; Look for extended regsiters that are only in WD90C31 and over
+;
+
+ mov ecx, VD_WD_90C + VF_WD_31 ; Assume we have 90C31
+
+ mov dx, WD_EXT_IO_PORT
+ in al, dx
+ mov bl, al ; save it
+
+ mov al, 2
+ out dx, al
+ IO_Delay
+ in al, dx
+ cmp al, 2
+ je @f
+
+;
+; WD90C30 or older.
+;
+
+ mov ecx, VD_WD_90C + VF_WD_30
+
+@@:
+ mov al, bl ; restore ext io port value
+ out dx, al
+
+;
+; Get chip type to determine if we have a 90c30 or 90c00
+;
+
+ cmp ecx, VD_WD_90C + VF_WD_30 ; Is 90C30?
+ jne WdRestore ; No, do nothing
+
+ mov al, 06
+ mov dx, pGrpIndx
+ out dx, al
+ inc dx ; (dx)= grpData
+ in al, dx
+ push ax ; save reg 06 content
+
+ mov al, 48h
+ out dx, al
+
+ mov al, 08
+ mov dx, pGrpIndx
+ out dx, al
+ inc dx ; (dx)= grpData
+ in al, dx
+ push ax ; Save reg 08 content
+
+ mov al, 5Ah
+ out dx, al
+ IO_Delay
+ in al, dx
+
+ cmp al, 5Ah
+ je short @f
+
+;
+; old chip, can't support 1R1W banking
+;
+
+ mov ecx, VD_WD_90C + VF_WD_00
+@@:
+ mov al, 08
+ mov dx, pGrpIndx
+ out dx, al
+ inc dx ; (dx)= grpData
+ pop ax
+ out dx, al ; Restore REg 08
+
+ mov al, 06
+ mov dx, pGrpIndx
+ out dx, al
+ inc dx ; (dx)= grpData
+ pop ax
+ out dx, al ; Restore reg 06
+
+;
+; Restore registers to what they were.
+;
+
+WdRestore:
+
+ mov al, 0Ch
+ mov dx, pGrpIndx
+ out dx, al
+ inc dx ; (dx)= grpData
+ pop bx ; (bl)= saved Grp0F
+ pop ax ; (al)= saved Crp0C
+ out dx, al
+
+ mov al, 0Fh
+ mov dx, pGrpIndx
+ out dx, al
+ inc dx ; (dx)= grpData
+ mov al, bl ; (al)= saved Grp0C
+ out dx, al
+
+ or ecx, ecx
+ jz short @f
+
+ mov eax, ecx
+ pop bx
+ pop dx
+ jmp VRI_Exit
+
+@@:
+ pop bx
+ pop dx
+
+if 0
+;
+; ******************************
+; * *
+; * Paradise VGA detection *
+; * *
+; ******************************
+;
+; --------------------------------------------------------------------
+;
+; [1]
+; Paradise 1C has 5 DIP switches, not 4 any more. The 5th switch
+; controls if interlace or non-interlace is used. Register 3CE.0F
+; bit 0-2 used for lock/unlock PR0-PR4, bit 3-7 used to return
+; DIP switch information. This affects flag fvid_pvga used for other
+; modules if paradise is selected. - C. Chiang -
+;
+; --------------------------------------------------------------------
+;
+
+ push dx
+ mov dl,(pGrpIndx AND 0FFh)
+ mov al,0Fh
+ out dx,al
+ inc dx
+ in al,dx
+ push ax
+ and al,0F8h
+ mov ah,al
+ xor al,0F8h ; Reverse upper 5 bits
+ or al,5
+ out dx,al
+ IO_Delay
+ in al,dx
+ xor al,ah ; Q: Are lower bits 5 and
+ cmp al,5 ; upper bits unchanged?
+ pop ax
+ out dx,al ; Restore original value
+ jnz NotPVGA ; N: Must not be PVGA
+
+;
+; It's Paradise VGA, check for Paradise VGA ROM
+;
+
+ mov si,OFFSET str_Paradise
+ xor di,di
+ mov cx,128
+ mov edx,VD_PARADISE_VGA ; Assume not Paradise ROM
+PVGA_FindROMLoop:
+ push di
+ push si
+ push cx
+ mov cx,len_str_Paradise
+ repe cmpsb ; Q: Paradise ROM?
+ pop cx
+ pop si
+ pop di
+ jz SHORT IsPVGARom ; Yes
+ inc di
+ loop PVGA_FindROMLoop ; No, look thru 128 bytes
+
+;
+; PARADISE not found, now look for WESTERN DIGITAL
+;
+
+ mov si,OFFSET str_WDIGITAL
+ xor di,di
+ mov cx,128
+PVGA_FindROMLoop1:
+ push di
+ push si
+ push cx
+ mov cx,len_str_WDigital
+ repe cmpsb ; Q: Paradise ROM?
+ pop cx
+ pop si
+ pop di
+ jz SHORT IsPVGARom ; Yes
+ inc di
+ loop PVGA_FindROMLoop1 ; No, look thru 128 bytes
+
+;
+;--------------------------------------------------------------------
+;
+; [3] It is Paradise Chip, but not Paradise BIOS ROM. In this case,
+; set the flag to fVid_PVGA in order for OEMs who use their own
+; BIOS and our Chip to work properly. - Chiang -
+;
+;---------------------------------------------------------------
+;
+
+ mov edx,VD_PARADISE_VGA ; no Paradise ROM
+ jmp SHORT Chk_1F
+
+IsPVGARom:
+ or edx, VF_PVGA_PROM ; with Paradise ROM
+
+;
+;---------------------------------------------------------------------
+;
+; [2] following are for Paradise chip type checking - C. Chiang -
+;
+;---------------------------------------------------------------------
+;
+
+Chk_1F:
+
+ push es
+
+ ;
+ ; SAVE 3CE.0F
+ ;
+
+ mov dx, 3CEh
+ mov al, 0Fh
+ out dx, al
+ inc dx
+ in al,dx ; Read 3CF.F
+ mov bSave0F, al ; Save the lock register state
+
+ ;
+ ; get 3D4 or 3b4
+ ;
+
+ xor ax, ax
+ mov es, ax
+ mov dx, es:463h ; Fetch the register address to use
+ mov ax, ds ; DS = ES
+ mov es, ax
+ mov cx, len_str_1F
+ lea di, String ; Get the String ptr
+ mov bx, 31h
+
+;
+;--- For 1F we need to unlock\lock the regs:
+;--- 3?4.29 - Unlock PR11-PR17
+;
+; mov al, 29h ; Select PR10
+; out dx, al
+; inc dx
+; in al, dx ; Read the contents
+; mov bSave29, al ; and save it
+; mov al, 80h ; Unlock the date code register
+; out dx, al
+; dec dx
+;
+
+;
+;--- 3?4.34 - Lock Flat Panel
+;
+
+ mov al, 34h ; Select PR1B
+ out dx, al
+ inc dx
+ in al, dx ; Read the contents
+ mov bSave34, al ; and save it
+ mov al, 0 ; Lock the flat panel
+ out dx, al
+ dec dx
+
+;
+;--- 3?4.35 - Lock Mapping Ram
+;
+
+ mov al, 35h ; Select PR30
+ out dx, al
+ inc dx
+ in al, dx ; Read the contents
+ mov bSave35, al ; and save it
+ mov al, 0 ; Lock the mapping ram
+ out dx, al
+ dec dx
+
+
+loopit: mov al, bl ; Loop to read the chip ID
+ out dx, al
+ inc dx
+ in al, dx
+ stosb
+ dec dx
+ inc bx
+ loop loopit
+
+;
+;--- For 1F we need to restore the regs
+;
+
+;
+;--- 3?4.35 - Lock Mapping Ram
+;
+
+ mov al, 35h ; Select PR30
+ out dx, al
+ mov al, bSave35 ; and restore it
+ cmp al, 30h ; If wasn't unlocked
+ jne SHORT skip1 ; then leave alone
+ inc dx
+ out dx, al
+ dec dx
+skip1:
+
+;
+;--- 3?4.34 - Lock Flat Panel
+;
+
+ mov al, 34h ; Select PR1B
+ out dx, al
+ mov al, bSave34 ; and restore it
+ cmp al, 0A6h ; If wasn't unlocked
+ jne SHORT skip2 ; then leave alone
+ inc dx
+ out dx, al
+ dec dx
+skip2:
+
+;
+;--- IT TURNS OUT THAT THE BIOS NEVER LOCKS THESE
+;--- 3?4.29 - Unlock\lock PR11-PR17
+; mov al, 29h ; Select PR10
+; out dx, al
+; inc dx
+; mov al, bSave29 ; and restore it
+; out dx, al
+; dec dx
+
+;
+;--- Restore the state of the lock/unlock register: 3CF.F
+;
+
+exit_pgm:
+ mov dx, 3CEh
+ mov al, 0Fh
+ out dx, al
+ inc dx
+ mov al, bSave0F ; Restore lock/unlock status
+ out dx, al
+
+;
+;--- Now, the chip signature is in String
+;
+
+ mov si, OFFSET str_PVGA1F ; check string "OPYRIGHT1990WDC"
+ mov di, OFFSET String
+ mov cx, len_str_1F
+ repe cmpsb ; Q:
+ jz SHORT isPVGA1F
+
+ mov si, OFFSET str_PVGA1FC ; check string "OPYRIGHTWD90C22"
+ mov di, OFFSET String
+ mov cx, len_str_1FC
+ repe cmpsb ; Q:
+ jz SHORT isPVGA1F
+
+ mov si, OFFSET str_1F_GEN ; check string "OPYRIGHTWD90C22"
+ mov di, OFFSET String
+ mov cx, len_str_GEN
+ repe cmpsb ; Q:
+ jnz SHORT Exit_1F_check
+
+isPVGA1F:
+ or edx, VF_PVGA_CHIP_1F ; set flag for Paradise 1F chip
+Exit_1F_check:
+ pop es
+
+;
+;----------------------------------------------
+; end of Paradise 1F chip checking
+;----------------------------------------------
+;
+
+ add sp,2 ; discard saved DX
+ mov eax, edx
+ jmp VRI_Exit
+
+NotPVGA:
+ pop dx
+endif
+;
+; ******************************
+; * *
+; * ATI VGA detection *
+; * *
+; ******************************
+;
+
+ push dx
+ push bp
+ mov ax,1203h
+ mov bx,5506h
+ mov bp,0ffffh
+ int 10h
+ cmp bp,0ffffh
+ pop bp
+ je short Not_ATI_VGA
+
+ mov si,OFFSET ATI_Sig
+ mov di,30h
+ mov cx, ATI_Sig_Len
+ rep cmpsb
+ jnz SHORT Not_ATI_VGA
+
+;
+; Further checks for version of ATI VGA
+;
+
+ add sp, 2
+ mov edx, VD_ATI_VGA
+ cmp es:byte ptr [40h],'3' ;VGAWONDER product code ?
+ jne SHORT Ati_Vga
+; mov edx,VD_ATI_VGA
+; cmp es:byte ptr [43h],'1' ;VGAWONDDER V3 ?
+; jne short Ati_Vga
+ or edx,VF_ATIVGA_WONDDER3
+Ati_Vga:
+ mov eax, edx
+ jmp VRI_Exit
+
+Not_ATI_VGA:
+ pop dx
+
+
+;
+; ************************************
+; * *
+; * Tseng Lab VGA detection *
+; * *
+; ************************************
+;
+; Tseng Labs VGA detection
+; Attribute Controller Reg 16h is known to exist only on Tseng Labs VGA
+;
+
+ push dx
+ mov bl,0 ;ET3000/ET4000 flag (0=ET3000)
+ mov dx, 3BFh
+ xor al, al
+ out dx, al
+ pop dx
+ push dx
+ sub dl, pStatColr-03D8h ; mode control register is 3B8 or 3D8
+ in al, dx
+ test al, 01000000b ;Q: writing 0 to 3BF cleared bit 6 of
+ ; mode control port?
+ jnz SHORT tlvga_2 ; N: not ET4000
+ mov dx, 3BFh
+ mov al, 10b
+ out dx, al
+ pop dx
+ push dx
+ sub dl, pStatColr-03D8h ; mode control register is 3B8 or 3D8
+ IO_Delay
+ in al, dx
+ test al, 01000000b ;Q: writing 10b to 3BF set bit 6 of
+ ; mode control port?
+ jz SHORT tlvga_2 ; N: not ET4000
+ ; Y: possibly an ET4000
+
+ mov bl,1 ;flag ET4000 not ET3000
+
+;
+; attempt to write ET4000 "KEY"
+;
+ mov dx, 3BFh
+ mov al, 3
+ out dx, al
+ pop dx
+ push dx
+ sub dl, pStatColr-03D8h ; mode control register is 3B8 or 3D8
+ in al, dx
+ mov ah, al
+ IO_Delay
+ mov al, 0A0h
+ out dx, al
+tlvga_2:
+ pop dx
+ push dx
+ push ax
+ push bx
+ call Check_Writing_ATC16 ;sets ECX=0 or VT_Flags for ET3000
+ pop bx
+ pop ax
+ sub dl, pStatColr-03D8h ; mode control register is 3B8 or 3D8
+ mov al, ah
+ out dx, al ; restore mode control register
+ mov dx,03BFh
+ mov al,1
+ out dx,al ;restore 3BF to normal value
+ or ecx,ecx
+ jz SHORT Not_TLVGA ; jump if not ET3000/ET4000
+
+ pop dx
+ mov edx,VD_TSENGLAB_VGA + VF_TLVGA_ET3000 ;if ET4000 with 256k
+ or bl,bl ;test if ET4000
+ jz short tlvga_4
+
+ ;
+ ;is an ET4000:
+ ;
+
+ mov edx,VD_TSENGLAB_VGA + VF_TLVGA_ET4000 ;if ET4000 with 256k
+tlvga_4:
+ mov eax,edx
+ jmp VRI_Exit
+
+Not_TLVGA:
+ pop dx
+
+;
+; ************************************
+; * *
+; * Cirrus VGA detection *
+; * *
+; ************************************
+;
+; Cirrus Logic VGA detection
+;
+
+;
+; First save SR6 and SRIndx
+;
+
+ push dx
+ xor cx,cx ; assume not CLVGA
+ mov dl,(pSeqIndx AND 0FFh)
+ in al,dx
+ IO_Delay
+ mov bh,al ; BH = SR index
+ mov al,6
+ out dx,al
+ IO_Delay
+ inc dx
+ in al,dx
+ IO_Delay
+ mov bl,al ; BH=SRindx,BL=SR6 value
+
+;
+;enable extension register in the CLVGA
+;
+
+ mov ecx,VD_CIRRUS_VGA ; ECX = potential VT_Flags
+
+ mov al,0ECh ; extension enable value
+ out dx,al
+ IO_Delay
+
+ in al,dx
+ IO_Delay
+ cmp al,1 ; Q: Could enable Ext?
+ jnz SHORT Check542x
+
+;
+; now check to see if we can disable the extensions
+;
+
+ mov al,0CEh ; extension disable value
+ out dx,al
+ IO_Delay
+
+ in al,dx
+ IO_Delay
+ and al,al ; Q: extensions disabled successfully?
+ jz short @f ; Y: it is 610/620
+ ; Y: its Cirrus logic
+Check542x:
+
+ mov al, 12h ; Unlock ext regs with 12h
+ out dx, al
+ IO_Delay
+
+ in al, dx
+ IO_Delay
+ cmp al, 12h ; Could enable ext?
+ jnz Not_CLVGA ; No, not CL VGA
+
+ mov al, 0
+ out dx, al
+ IO_Delay
+
+ in al, dx
+ IO_Delay
+ cmp al, 0fh
+ jnz Not_CLVGA
+
+@@:
+;
+; we know its a Cirrus chipset, now find out if it is a 610/620 Rev. C.
+; chipset.
+;
+
+ push ecx ; save flag value
+ push dx
+ mov ah,12h
+ mov bl,80h
+ int 10h ; Inquire VGA type
+ cmp al,3 ; returns 3 for 610/620 LCD controller
+ jnz short Is542x ; otherwise check for 542x
+
+;
+; its a 610/620, now find out if its RevC or not.
+;
+
+ cmp bl,80h
+ jz short CheckChip
+ cmp bl,2
+ jnz short Not610
+
+IsRevC:
+ mov eax,VF_CLVGA_REVC
+ jmp short Done610
+
+CheckChip:
+ mov dx,3c4h
+ mov al,8eh
+ out dx,al
+ inc dx
+ in al,dx ; 8Eh is chip revision.
+ cmp al,0ach
+ jz IsRevC
+
+Not610:
+ xor eax,eax
+Done610:
+ pop dx
+ pop ecx
+ or ecx,eax
+ jmp short Restor_CLVGA ; all done, now get outa here
+
+Is542x:
+ cmp ax, 12h ; check 5420r0
+ jne short @f ; Check next chip version
+
+ mov eax, VF_CLVGA_5420r0 ; We found a 5420r0
+ jmp short Done610
+
+@@:
+ cmp ax, 16h ; check 5420r1
+ jne short @f ; Check next chip version
+
+ mov eax, VF_CLVGA_5420r1 ; We found a 5420r1
+ jmp short Done610
+
+@@:
+ cmp ax, 18h ; check 5428
+ jne short @f ; we did not find any of compaq rev.
+
+ mov eax, VF_CLVGA_5428 ; We found a 5428
+ jmp short Done610
+
+@@:
+ cmp ax, 12h
+ jb short Not610
+
+ mov eax, VF_CLVGA_542x ; if (ax) >= 12h, it's 542x
+ jmp short Done610
+
+Not_CLVGA:
+ xor ecx,ecx ; Indicate not CL VGA
+Restor_CLVGA:
+ dec dx
+ mov al,6
+ out dx,al
+ IO_Delay
+ mov al,bl ; old value of SR6
+ or ecx,ecx ; Q: CL VGA?
+ jz SHORT Restor_SR6 ; N: output value read
+
+ mov bl,0ECh
+Restor_Ena:
+ or al,al ; Q: extensions enabled?
+ mov al,bl ; AL = 0ECh (enable)
+ jnz SHORT Restor_SR6 ; Y: output enable value
+
+ ror al,4 ; N: output disable (0CEh)
+Restor_SR6:
+ inc dx
+ out dx,al ; Restore value of SR6
+ IO_Delay
+ mov al,bh
+ dec dx
+ out dx,al ; Restore index
+ IO_Delay
+ or ecx,ecx
+ jz SHORT Is_Not_CLVGA
+
+ add sp,2
+ mov eax,ecx
+ jmp VRI_Exit
+
+Is_Not_CLVGA:
+ pop dx
+
+;
+; ************************************
+; * *
+; * S3 video chip detection *
+; * *
+; ************************************
+;
+; S3 detection
+;
+
+ mov ax, dx
+ push dx ; save dx
+ push bx
+
+ and ax, 0fff0h
+ or ax, 4h ; (ax) = Crt index
+ mov dx, ax
+
+ inc dx
+ in al, dx
+ mov ah, al
+ dec dx
+ in al, dx ; (ah) = original data reg
+ ; (al) = oroginal addr reg
+ push ax ; Save it
+
+ mov al, 38h
+ out dx, al
+ inc dx
+ in al, dx
+ IO_Delay
+ mov ah, al ; (ah) = original data on index 38
+ mov al, 39h
+ dec dx
+ out dx, al
+ IO_Delay
+ inc dx
+ in al, dx ; (al) = original data on index 39
+ push ax ; save them
+ dec dx
+
+ ;
+ ; Before unlocking all the S3 registers, lets try read the id reg
+ ;
+if 0
+ mov ax, 038h ; lock S3 registers
+ out dx, ax
+ IO_Delay
+ dec dx
+
+ mov ax, 039h
+ out dx, ax
+ IO_Delay
+ dec dx
+
+ mov al, 30h ; crt controller index for s3 ID reg
+ out dx, al
+ IO_Delay
+ inc dx
+ in al, dx ; get (potential) Id
+ mov bl, al ; (bl) = ID reg content before unlocked
+ dec dx
+endif
+ ;
+ ; Now Unlock all the S3 registers
+ ;
+
+ mov ax, 4838h
+ out dx, ax
+ IO_Delay
+ dec dx
+
+ mov ax, 0A039h
+ out dx, ax
+ IO_Delay
+ dec dx
+
+ ;
+ ; Read ID after we unlocked S3 registers
+ ;
+
+ mov al, 30h ; crt controller index for s3 ID reg
+ out dx, al
+ IO_Delay
+ inc dx
+ in al, dx ; get (potential) Id
+ dec dx
+if 0
+ cmp bl, al ; compare ids
+ mov ebx, 0 ; Assume it is NOT S3
+ je short ExitS3Detection
+else
+ mov ebx, 0
+endif
+
+;
+; Check if id is 8?. 9? or A? If yes, it is S3.
+;
+
+ and al, 0f0h
+ cmp al, 80h ; Is Id = 8?h?
+ jz short IsS3 ; if e, it's s3
+
+ cmp al, 90h ; Is Id = 9?h?
+ jz short IsS3 ; if e, it's s3
+
+ cmp al, 0A0h ; Is Id = A?h?
+ jnz short ExitS3Detection ; if nz, not s3
+
+IsS3:
+ mov ebx, VD_S3
+ExitS3Detection:
+ pop ax
+ mov cx, ax
+ mov ah, al
+ mov al, 39h
+ out dx, ax ; Restore reg 39 data
+ IO_Delay
+ dec dx
+ mov ax, cx
+ mov al, 38h
+ out dx, ax ; Restore reg 38 data
+ IO_Delay
+ dec dx
+ pop ax ; (ax) = crt data and index
+ out dx, ax
+ IO_Delay
+ mov eax, ebx ; (eax) = VGA id
+ pop bx
+ pop dx
+ cmp eax, VD_S3
+ je VRI_Exit
+
+;
+; ==================== End of VGA H/W detection ===================
+;
+
+;
+; If we come here, the detection fails.
+;
+
+ mov eax, VD_VGA ; Set it to standard VGA
+
+;
+; eax = Video subtype
+;
+
+VRI_Exit:
+
+;
+; before exit do setmode to init video
+;
+
+ push eax
+ mov ah, 0fh
+ int 10h ; (al) = current display mode
+ mov ah, 0
+ int 10h ; set to current mode
+
+ pop eax
+ pop es
+ pop di
+ pop si
+ pop bx
+ pop bp
+ ret
+
+GetVgaChipSet endp
+
+;++
+;
+; ULONG
+; Check_Writing_ACT16 (
+; VOID
+; )
+;
+; Routine Description:
+;
+; This routine is part of Tseng Lab VGA detection code.
+; In this routine, we try to access Attribute Controller reg 16h. It is
+; known to exist only on Tseng Lab's VGA.
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; (ecx) = 0, if NOT Tseng Lab VGA
+;
+;--
+
+Check_Writing_ATC16 proc near
+
+ push dx
+ in al,dx
+ IO_Delay
+ mov dl,(pAttr AND 0FFh)
+ in al,dx
+ mov bh,al ; BH = current Attr index
+ IO_Delay
+ mov al,16h+20h ; Select 16h (leave video on)
+ out dx,al
+ IO_Delay
+ inc dx
+ in al,dx
+ IO_Delay
+ dec dx
+ mov bl,al ; Save current reg 16h in BL
+ xor al,10h ; Complement bit 4
+ out dx,al ; Write it out
+ IO_Delay
+ pop dx
+ push dx
+ in al,dx
+ mov dl,(pAttr AND 0FFh)
+ mov al,16h+20h ; Select 16h (leave video on)
+ out dx,al
+ IO_Delay
+ inc dx
+ in al,dx
+ IO_Delay
+ xor ecx,ecx ; CX = flag (not TLVGA)
+ dec dx
+ xor al,10h
+ cmp al,bl ; Q: Is value same as written?
+ jnz SHORT Restore16 ; N: Is not TLVGA
+ mov ecx,VD_TSENGLAB_VGA ; Y: Is TLVGA
+Restore16:
+ mov al,bl
+ out dx,al
+ IO_Delay
+ pop dx
+ push dx
+ in al,dx
+ IO_Delay
+ mov dl,(pAttr AND 0FFh)
+ mov al,bh
+ out dx,al
+ pop dx
+ ret
+
+Check_Writing_ATC16 endp
+
+if 0 ; *** Removed
+
+
+;++
+;
+; BOOLEAN
+; IsCompaqAgb (
+; VOID
+; )
+;
+; Routine Description:
+;
+; Function determines if the video system is a Compaq Advanced Graphics
+; Board operating if pass through configuration in conjunction with a
+; VGA card.
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; Function will return TRUE or FALSE as to whether or not the Compaq AGB
+; is present and operating in pass-through mode.
+;
+;--
+
+; public IsCompaqAgb
+;IsCompaqAgb proc near
+;
+; mov dx,298h ; Port address for host CPU status reg.
+; in al,dx ; Read register.
+; mov cl,al ; Save value from reg.
+; and al,00000011b ; Strip all but bit 0 and 1.
+; or al,al ; Bits 0 and 1 should be 0.
+; jnz no_CompaqAGB
+; mov dx,299h ; Ok, next look at host CPU status 2 reg.
+; in al,dx
+; and al,00000001b ; Strip all but bit 0.
+; or al,al
+; jnz no_CompaqAGB ; bit zero should be 0.
+; mov dx,298h
+; in al,dx
+; cmp al,cl ; One final check.
+; jne no_CompaqAGB
+; mov ax, TRUE
+; jmp short AGB_done
+;
+;no_CompaqAGB:
+; mov ax, FALSE ; return FALSE
+;AGB_done:
+; ret
+;
+;IsCompaqAgb endp
+;
+endif ; *** Removed
+
+
+;++
+;
+; BOOLEAN
+; Is8514Adapter (
+; VOID
+; )
+;
+; Routine Description:
+;
+; This function detects the presence of an 8514 display card.
+;
+; The way we do this is to first write to the Error Term Register and then
+; make sure we can read back the value we wrote. Next I read in the value of
+; the subsystem status register and check bit 7 to determine if the 8 plane
+; memory configuration is present. Only if both these conditions are
+; satisfied will we acknowledge that 8524 display driver is present.
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; Function will return TRUE or FALSE as to whether or not the 8514
+; display card is present and contains the proper memory configuration.
+;
+;--
+
+ public Is8514Adapter
+Is8514Adapter proc near
+
+ mov dx, ERR_TERM ; load DX with port address (error term port).
+ mov ax, 5555h ; load AX with value to write to port.
+ out dx, ax ; Write the data.
+ IO_Delay
+ IO_Delay
+ in ax, dx ; Now read the data back in.
+ cmp ax, 5555h ; Q: is 8524 present ?
+ jne Not_8514 ; N: indicate 8514 not present.
+ ; Y: 8514 is present, now check monitor.
+
+
+;
+; Now we need to determine what type of monitor is attached to the
+; 8514 card. To do this we check ID bits 6,5,4 of the subsystem
+; status register. Depending on the Monitor attached we return:
+;
+; There are 4 valid monitor types:
+;
+; bits 6-4 Type
+;
+; 001 Ascot (mono)
+; 010 Henley (color)
+; 011 Invalid (color) This is supposedly valid in spite
+; of what the spec says.
+; 101 Surrey (mono)
+; 110 Conestoga/Crown (color)
+;
+
+ mov dx,SUBSYS_STAT ; Now, we have the adapter. Check monitor.
+ in ax,dx ; Get word from SUBSYS_STAT
+ and ax,0070h ; Mask out bits 6-4
+ cmp ax,0020h ; Is it Henley type?
+ je Disp_8514 ; Yes, then it is an 8514 type
+ cmp ax,0060h ; Is it Conestoga/Crowwn type?
+ je Disp_8514 ; Yes, then it is an 8514 type
+ cmp ax,0030h ; Is it Korys' machine
+ je Disp_8514 ; Yes, then it is an 8514 type
+ cmp ax,0010h ; Is it Ascot type?
+ je Disp_8503 ; Yes, then it is a VGA Mono type
+ cmp ax,0050h ; Is it Surrey type?
+ je Disp_8503 ; Yes, then it is a VGA Mono type
+
+ mov ax,VF_MONITOR_VGA ; If none of the above, then it
+ jmp short fn8514Done ; is just a standard VGA
+
+Disp_8503:
+ mov ax,VF_MONITOR_MONO_8503
+ jmp short fn8514Done
+
+Disp_8514:
+ mov ax,VF_MONITOR_GAD_8514
+ jmp short fn8514Done
+
+Not_8514:
+ mov ax,FALSE
+
+fn8514Done:
+ ret
+
+Is8514Adapter endp
+
+
+;++
+;
+; BOOLEAN
+; IsCompaqVideo (
+; VOID
+; )
+;
+; Routine Description:
+;
+; This function searches ROM BIOS C0000 and E0000 for 'COMPAQ' to
+; determine the presence of COMPAQ video ROM.
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; (ax) = TRUE if it is compaq video rom. Otherwise, a value of FALSE is
+; returned.
+;
+;--
+
+ public IsCompaqVideo
+IsCompaqVideo proc near
+
+ push di
+ push es
+
+ mov ax, 0C000h ; Video ROM is C000:0000 to 8000h
+icvBeginSearch:
+ mov es, ax
+ mov di, 0000h
+ mov al, 'C' ; Look for 'C'
+ mov cx, 7FFCh ; search through 32K
+ cld
+
+icvLoopAgain:
+
+ repne scasb ; search for 'C'
+ jne icvNotFound ; if searched entire video ROM, exit
+
+ mov edx, dword ptr es:[di]
+ cmp edx, 'APMO' ; search for 'OMPA'
+ jne short icvLoopAgain ; fail, continue search
+
+ mov dl, byte ptr es:[di+4]
+ cmp dl, 'Q'
+ jne short icvLoopAgain
+
+;
+; If we get to here we have found COMPAQ in the video ROM.
+;
+
+ mov ax, 1
+ jmp short icvExit
+
+icvNotFound:
+ push es
+ pop ax
+ cmp ax, 0E000h
+ je short @f
+
+ mov ax, 0E000h
+ jmp short icvBeginSearch
+
+@@:
+ xor ax, ax ; NO, return FALSE (AX = 0)
+icvExit:
+ pop es ; restore registers
+ pop di
+ ret
+
+IsCompaqVideo endp
+
+
+; BOOLEAN
+; IsCompaqQVision (
+; VOID
+; )
+;
+; Routine Description:
+;
+; Function determinec if the video system is a Compaq QVision board.
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; Function will return TRUE or FALSE as to whether or not the Compaq QVision
+; is present.
+;
+;--
+ public IsCompaqQvision
+IsCompaqQVision proc near
+
+ push si
+ push di
+ push es
+
+ mov ax, 0BF11h ; Get Extended Environment
+ int 10h
+ cmp al, 0BFh ; is the call supported ?
+ jne QVision_not_found ; no, this is not a QVision card
+ mov eax, DWORD PTR ES:[SI] ; get pointer to extended env DWORD
+ and al, 80h ; are QVision modes supported ?
+ jz QVision_not_found ; no, this is not a QVision card
+ mov eax, 01h ; yes
+ jmp short QVision_exit
+
+QVision_not_found:
+ xor ax, ax ; NO, return FALSE (AX = 0)
+QVision_exit:
+ pop es ; restore registers
+ pop di
+ pop si
+ ret
+
+IsCompaqQVision endp
+
+
+;++
+;
+; BOOLEAN
+; IsCompaqAvga (
+; VOID
+; )
+;
+; Routine Description:
+;
+; This function returns whether a COMPAQ AVGA display adapter is found.
+;
+; This is determined by: 1. Looking for COMPAQ Video ROM
+; 2. Doing COMPAQ int 10h call
+;
+; The presence of COMPAQ video ROM can be determined by searching through
+; the Video ROM (C000:0000 to C000:FFFF) for the string 'COMPAQ'.
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; (ax) = TRUE if it is compaq AVGA. Otherwise, a value of FALSE is
+; returned.
+;
+;--
+
+ public IsCompaqAvga
+IsCompaqAvga proc near
+
+ push si ; Save registers
+ push di
+ push es
+
+ mov ax, 0BF03h
+ xor cx, cx
+ int 10h
+ and cl, 050h ; Are bits 4 (BitBlt Engine
+ cmp cl, 050h ; and 6 (256 colors) both set
+ jne avga_not_found
+ mov eax, 01h ; YES, return TRUE (non-zero AX)
+ jmp short avga_exit
+
+avga_not_found:
+ xor ax, ax ; NO, return FALSE (AX = 0)
+avga_exit:
+ pop es ; restore registers
+ pop di
+ pop si
+ ret
+
+IsCompaqAvga endp
+
+
+;++
+;
+; BOOLEAN
+; IsXga (
+; VOID
+; )
+;
+; Routine Description:
+;
+; This function returns whether a XGA display adapter is found.
+;
+; This is determined by: 1. Make sure this is a MicroChannel machine
+; 2. Make sure Mother board VideoSubsystem Id is XGA
+;
+; N.B. Current assumption is that XGA is MicroChannel specific.
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; (ax) = TRUE if it is IBM XGA. Otherwise, a value of FALSE is
+; returned.
+;
+;--
+
+IsXga proc near
+
+ push es
+ push bx
+
+ call _HwIsMcaSystem ; First check if this is MCA machine
+ or ax, ax ; If ax == 0, it is not.
+ jz short Ix99 ; exit
+
+ call Ps2SystemBoardVideoId ; (ax) = PS2 mother board video id
+ cmp ax, IBM_XGA_ID_LOW ; Is it XGA id?
+ jb short Ix50 ; if z, no, try something else.
+
+ cmp ax, IBM_XGA_ID_HIGH
+ jle short Ix99
+
+Ix50: les bx, _HwMcaPosData
+ mov cx, 0
+Ix60:
+ mov ax, es:[bx]
+ cmp ax, IBM_XGA_ID_LOW ; Is it XGA id?
+ jb short Ix70 ; if z, no, try next slot
+
+ cmp ax, IBM_XGA_ID_HIGH
+ jle short Ix99
+Ix70:
+ add bx, MCA_POS_DATA_SIZE
+ inc cx
+ cmp cx, 8 ; end of slot?
+ jnz short Ix60
+
+Ix90:
+ mov ax, 0
+Ix99: pop bx
+ pop es
+ ret
+
+IsXga endp
+
+endif ; Remove Video detection
+
+;++
+;
+; VOID
+; GetVideoFontInformation (
+; VOID
+; )
+;
+; Routine Description:
+;
+; This function does int 10h, function 1130 to get font information and
+; saves the pointers in the physical 700h addr.
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; None.
+;
+;--
+ ASSUME DS:NOTHING
+ public _GetVideoFontInformation
+_GetVideoFontInformation proc near
+
+ push ds
+ push es
+ push bp
+ push bx
+ push si
+
+ mov ax, FONT_POINTERS
+ shr ax, 4
+ mov ds, ax
+ mov si, FONT_POINTERS
+ and si, 0fh
+ mov bh, 2
+@@:
+ mov ax, 1130h ; Get font information
+ int 10h
+
+ mov [si], bp
+ add si, 2
+ mov [si], es
+ add si, 2 ; (si)= 8
+ inc bh
+ cmp bh, 8
+ jb short @b
+
+ pop si
+ pop bx
+ pop bp
+ pop es
+ pop ds
+ ret
+
+_GetVideoFontInformation endp
+_TEXT ENDS
+ END
diff --git a/private/ntos/boot/detect/i386/videoc.c b/private/ntos/boot/detect/i386/videoc.c
new file mode 100644
index 000000000..270344439
--- /dev/null
+++ b/private/ntos/boot/detect/i386/videoc.c
@@ -0,0 +1,300 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ hwdata.c
+
+Abstract:
+
+ This module contains the C code to translate Video type to an
+ ascii string.
+
+Author:
+
+ Shie-Lin Tzong (shielint) 6-Jan-1991
+
+Revision History:
+
+--*/
+
+#include "hwdetect.h"
+#include "string.h"
+
+//
+// Video adaptor type identifiers.
+//
+
+PUCHAR VideoIdentifier[] = {
+ "UNKNOWN",
+ "VGA",
+ "COMPAQ AVGA",
+ "COMPAQ QVIS",
+ "8514",
+ "GENOA VGA",
+ "VIDEO7 VGA",
+ "TRIDENT VGA",
+ "PARADISE VGA", // should be removed
+ "ATI VGA",
+ "TSENGLAB VGA",
+ "CIRRUS VGA",
+ "DELL DGX",
+ "S3 VGA",
+ "NCR 77C22",
+ "WD90C",
+ "XGA"
+ };
+
+//
+// 8514 Monitor type
+//
+
+PUCHAR x8514Specific[] = {
+ " MONITOR UNKNOWN",
+ " VGA MONITOR",
+ " 8503 MONO",
+ " 8514 GAD"
+ };
+
+//
+// NCR 77C22 specific vga
+//
+
+PUCHAR NcrSpecific[] = {
+ "",
+ "E"
+ };
+
+//
+// Western Digital 90Cxx specific vga
+//
+
+PUCHAR WdSpecific[] = {
+ "",
+ "00",
+ "30",
+ "31"
+ };
+
+//
+// Video 7 specific vga
+//
+
+PUCHAR Video7Specific[] = {
+ "",
+ " VRAM",
+ " DRAM"
+ };
+
+//
+// Trident vga specific
+//
+
+PUCHAR TridentSpecific[] = {
+ "",
+ " 9100"
+ };
+
+//
+// Paradize specific vga
+//
+
+PUCHAR ParadiseSpecific[] = {
+ "",
+ " PROM",
+ " CHIP 1F"
+ };
+
+//
+// Ati specific vga
+//
+
+PUCHAR AtiSpecific[] = {
+ "",
+ " WONDDER3"
+ };
+
+//
+// Tsenglab specific vga
+//
+
+PUCHAR TsenglabSpecific[] = {
+ " ET3000",
+ " ET4000"
+ };
+
+//
+// Cirrus Logic specific
+//
+
+PUCHAR CirrusSpecific[] = {
+ "",
+ " 610-620 REVC",
+ " 5420r0",
+ " 5420r1",
+ " 5428",
+ " 542x"
+ };
+
+FPFWCONFIGURATION_COMPONENT_DATA
+SetVideoConfigurationData (
+ IN ULONG VideoType
+ )
+
+/*++
+
+Routine Description:
+
+ This routine maps VideoType information to an ASCII string and
+ stores the string in configuration data heap.
+
+Arguments:
+
+ VideoType - Supplies a ULONG which describes the video type information.
+
+ Display type definitions.
+ bit 0 0 - color; 1 - mono
+ bit 1-7 Reserved
+ bit 8-15 Adapter specific information.
+ BIT 16-31 Defines video adapter type
+
+Returns:
+
+ None.
+
+--*/
+{
+ USHORT MajorType;
+ USHORT SpecificType;
+ USHORT MonitorType;
+ FPFWCONFIGURATION_COMPONENT_DATA Controller, CurrentEntry;
+ FPFWCONFIGURATION_COMPONENT Component;
+ UCHAR TypeString[40];
+ USHORT Length;
+
+ //
+ // Allocate configuration component space and initialize it.
+ //
+
+ Controller = (FPFWCONFIGURATION_COMPONENT_DATA)HwAllocateHeap (
+ sizeof(FWCONFIGURATION_COMPONENT_DATA), TRUE);
+
+ Component = &Controller->ComponentEntry;
+
+ Component->Class = ControllerClass;
+ Component->Type = DisplayController;
+ Component->Flags.ConsoleOut = 1;
+ Component->Flags.Output = 1;
+ Component->Version = 0;
+ Component->Key = 0;
+ Component->AffinityMask = 0xffffffff;
+
+ //
+ // Set up Identifier string
+ //
+
+ MajorType = (USHORT)(VideoType >> 16);
+ SpecificType = (USHORT)((VideoType & 0xffff) >> 8);
+ MonitorType = (USHORT)(VideoType & 1);
+ strcpy(TypeString, VideoIdentifier[MajorType]);
+ switch (MajorType){
+ case 6: // Video 7
+ strcat(TypeString, Video7Specific[SpecificType]);
+ break;
+
+ case 7: // Trident
+ strcat(TypeString, TridentSpecific[SpecificType]);
+ break;
+
+ case 8: // Paradise
+ strcat(TypeString, ParadiseSpecific[SpecificType]);
+ break;
+
+ case 9: // ATI
+ strcat(TypeString, AtiSpecific[SpecificType]);
+ break;
+
+ case 10: // TsengLab
+ strcat(TypeString, TsenglabSpecific[SpecificType]);
+ break;
+
+ case 11: // Cirrus
+ strcat(TypeString, CirrusSpecific[SpecificType]);
+ break;
+
+ case 14: // NCR
+ strcat(TypeString, NcrSpecific[SpecificType]);
+ break;
+
+ case 15: // NCR
+ strcat(TypeString, WdSpecific[SpecificType]);
+ break;
+
+ default:
+ break;
+ }
+
+ //
+ // Set up Identifier string for controller
+ //
+
+ Length = strlen(TypeString) + 1;
+ Component->IdentifierLength = Length;
+ Component->Identifier = (FPUCHAR)HwAllocateHeap(Length, FALSE);
+ _fstrcpy(Component->Identifier, TypeString);
+ Controller->ConfigurationData = NULL;
+ Component->ConfigurationDataLength = 0;
+
+ //
+ // Set Up monitor peripheral
+ //
+
+ CurrentEntry = (FPFWCONFIGURATION_COMPONENT_DATA)HwAllocateHeap (
+ sizeof(FWCONFIGURATION_COMPONENT_DATA), TRUE);
+
+ Component = &CurrentEntry->ComponentEntry;
+
+ Component->Class = PeripheralClass;
+ Component->Type = MonitorPeripheral;
+ Component->Flags.ConsoleOut = 1;
+ Component->Flags.Output = 1;
+ Component->Version = 0;
+ Component->Key = 0;
+ Component->AffinityMask = 0xffffffff;
+ Component->ConfigurationDataLength = 0;
+ CurrentEntry->ConfigurationData = NULL;
+
+ //
+ // If major type is 8514 we need to further supply monitor information
+ //
+
+ if (MajorType == 4) { // 8514
+ strcpy(TypeString, x8514Specific[SpecificType]);
+ } else if (MonitorType == 0) {
+ strcpy(TypeString, "COLOR MONITOR");
+ } else {
+ strcpy(TypeString, "MONO MONITOR");
+ }
+
+ //
+ // Set up Identifier string for monitor peripheral.
+ //
+
+ Length = strlen(TypeString) + 1;
+ Component->IdentifierLength = Length;
+ Component->Identifier = (FPUCHAR)HwAllocateHeap(Length, FALSE);
+ _fstrcpy(Component->Identifier, TypeString);
+
+ //
+ // Make monitor component be the child of video controller component
+ //
+
+ Controller->Child = CurrentEntry;
+ Controller->Sibling = NULL;
+
+ CurrentEntry->Parent = Controller;
+ CurrentEntry->Sibling = NULL;
+ CurrentEntry->Child = NULL;
+ return(Controller);
+}
diff --git a/private/ntos/boot/dirs b/private/ntos/boot/dirs
new file mode 100644
index 000000000..f028b8841
--- /dev/null
+++ b/private/ntos/boot/dirs
@@ -0,0 +1,29 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+
+Author:
+
+ Steve Wood (stevewo) 17-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\dirs.tpl
+
+!ENDIF
+
+DIRS=lib \
+ bldr \
+ setup \
+ detect \
+ veneer
+
+OPTIONAL_DIRS= startup
diff --git a/private/ntos/boot/inc/bldr.h b/private/ntos/boot/inc/bldr.h
new file mode 100644
index 000000000..ce6bc4dc5
--- /dev/null
+++ b/private/ntos/boot/inc/bldr.h
@@ -0,0 +1,747 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ bldr.h
+
+Abstract:
+
+ This module is the header file for the NT boot loader.
+
+Author:
+
+ David N. Cutler (davec) 10-May-1991
+
+Revision History:
+
+--*/
+
+#ifndef _BLDR_
+#define _BLDR_
+
+#include "ntos.h"
+#include "arccodes.h"
+
+
+//
+// Define boot file id.
+//
+
+#define BOOT_FILEID 2 // boot partition file id
+
+//
+// Define image types.
+//
+
+#define MIPS_IMAGE 0x162
+#define I386_IMAGE 0x14C
+#define ALPHA_IMAGE 0x184
+#define PPC_IMAGE 0x1f0
+
+#if defined(_MIPS_)
+
+#define TARGET_IMAGE MIPS_IMAGE
+
+#endif
+
+#if defined(_X86_)
+
+#define TARGET_IMAGE I386_IMAGE
+#define KSEG0_BASE 0x80000000
+
+#endif
+
+#if defined(_ALPHA_)
+
+#define TARGET_IMAGE ALPHA_IMAGE
+
+#endif
+
+#if defined(_PPC_)
+
+#define TARGET_IMAGE PPC_IMAGE
+
+#endif
+
+//
+// Define size of sector.
+//
+
+#define SECTOR_SIZE 512 // size of disk sector
+#define SECTOR_SHIFT 9 // sector shift value
+
+//
+// Define heap allocation block granularity.
+//
+
+#define BL_GRANULARITY 8
+
+//
+// Define number of entries in file table.
+//
+
+#define BL_FILE_TABLE_SIZE 32
+
+//
+// Define size of memory allocation table.
+//
+
+#define BL_MEMORY_TABLE_SIZE 16
+
+//
+// Define number of loader heap and stack pages.
+//
+
+#define BL_HEAP_PAGES 16
+#define BL_STACK_PAGES 8
+
+//
+// Define buffer alignment macro.
+//
+
+#define ALIGN_BUFFER(Buffer) (PVOID) \
+ ((((ULONG)(Buffer) + BlDcacheFillSize - 1)) & (~(BlDcacheFillSize - 1)))
+
+
+typedef
+ARC_STATUS
+(*PRENAME_ROUTINE)(
+ IN ULONG FileId,
+ IN PCHAR NewName
+ );
+
+typedef struct _BOOTFS_INFO {
+ PWSTR DriverName;
+} BOOTFS_INFO, *PBOOTFS_INFO;
+
+
+//
+// Device entry table structure.
+//
+
+typedef struct _BL_DEVICE_ENTRY_TABLE {
+ PARC_CLOSE_ROUTINE Close;
+ PARC_MOUNT_ROUTINE Mount;
+ PARC_OPEN_ROUTINE Open;
+ PARC_READ_ROUTINE Read;
+ PARC_READ_STATUS_ROUTINE GetReadStatus;
+ PARC_SEEK_ROUTINE Seek;
+ PARC_WRITE_ROUTINE Write;
+ PARC_GET_FILE_INFO_ROUTINE GetFileInformation;
+ PARC_SET_FILE_INFO_ROUTINE SetFileInformation;
+ PRENAME_ROUTINE Rename;
+ PARC_GET_DIRECTORY_ENTRY_ROUTINE GetDirectoryEntry;
+ PBOOTFS_INFO BootFsInfo;
+} BL_DEVICE_ENTRY_TABLE, *PBL_DEVICE_ENTRY_TABLE;
+
+
+//
+// Define main entrypoint.
+//
+ARC_STATUS
+BlOsLoader (
+ IN ULONG Argc,
+ IN PCHAR Argv[],
+ IN PCHAR Envp[]
+ );
+
+
+//
+// Define file I/O prototypes.
+//
+
+ARC_STATUS
+BlIoInitialize (
+ VOID
+ );
+
+ARC_STATUS
+BlClose (
+ IN ULONG FileId
+ );
+
+PBOOTFS_INFO
+BlGetFsInfo(
+ IN ULONG DeviceId
+ );
+
+ARC_STATUS
+BlMount (
+ IN PCHAR MountPath,
+ IN MOUNT_OPERATION Operation
+ );
+
+ARC_STATUS
+BlOpen (
+ IN ULONG DeviceId,
+ IN PCHAR OpenPath,
+ IN OPEN_MODE OpenMode,
+ OUT PULONG FileId
+ );
+
+ARC_STATUS
+BlRead (
+ IN ULONG FileId,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ );
+
+ARC_STATUS
+BlRename (
+ IN ULONG FileId,
+ IN PCHAR NewName
+ );
+
+ARC_STATUS
+BlGetReadStatus (
+ IN ULONG FileId
+ );
+
+ARC_STATUS
+BlSeek (
+ IN ULONG FileId,
+ IN PLARGE_INTEGER Offset,
+ IN SEEK_MODE SeekMode
+ );
+
+ARC_STATUS
+BlWrite (
+ IN ULONG FileId,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ );
+
+ARC_STATUS
+BlGetFileInformation (
+ IN ULONG FileId,
+ IN PFILE_INFORMATION FileInformation
+ );
+
+ARC_STATUS
+BlSetFileInformation (
+ IN ULONG FileId,
+ IN ULONG AttributeFlags,
+ IN ULONG AttributeMask
+ );
+
+#ifdef DBLSPACE_LEGAL
+VOID
+BlSetAutoDoubleSpace (
+ IN BOOLEAN Enable
+ );
+#endif
+
+//
+// Define image manipulation routine prototyupes.
+//
+
+ARC_STATUS
+BlLoadImage(
+ IN ULONG DeviceId,
+ IN TYPE_OF_MEMORY MemoryType,
+ IN PCHAR LoadFile,
+ IN USHORT ImageType,
+ OUT PVOID *ImageBase);
+
+ARC_STATUS
+BlLoadDeviceDriver (
+ IN ULONG DeviceId,
+ IN PCHAR LoadDevice,
+ IN PCHAR DirectoryPath,
+ IN PCHAR DriverName,
+ IN ULONG DriverFlags,
+ IN PLDR_DATA_TABLE_ENTRY *DriverDataTableEntry
+ );
+
+ARC_STATUS
+BlLoadNLSData(
+ IN ULONG DeviceId,
+ IN PCHAR DeviceName,
+ IN PCHAR DirectoryPath,
+ IN PUNICODE_STRING AnsiCodepage,
+ IN PUNICODE_STRING OemCodepage,
+ IN PUNICODE_STRING LanguageTable,
+ OUT PCHAR BadFileName
+ );
+
+ARC_STATUS
+BlLoadOemHalFont(
+ IN ULONG DeviceId,
+ IN PCHAR DeviceName,
+ IN PCHAR DirectoryPath,
+ IN PUNICODE_STRING OemHalFont,
+ OUT PCHAR BadFileName
+ );
+
+
+
+PVOID
+BlImageNtHeader (
+ IN PVOID Base
+ );
+
+ARC_STATUS
+BlSetupForNt(
+ IN PLOADER_PARAMETER_BLOCK BlLoaderBlock
+ );
+
+ARC_STATUS
+BlScanImportDescriptorTable (
+ IN ULONG DeviceId,
+ IN PCHAR DeviceName,
+ IN PCHAR DirectoryPath,
+ IN PLDR_DATA_TABLE_ENTRY DataTableEntry
+ );
+
+ARC_STATUS
+BlScanOsloaderBoundImportTable (
+ IN PLDR_DATA_TABLE_ENTRY ScanEntry
+ );
+
+#if defined(_ALPHA_)
+
+ARC_STATUS
+BlGeneratePalName(
+ IN PCHAR PalFIleName
+ );
+
+ARC_STATUS
+BlLoadPal(
+ IN ULONG DeviceId,
+ IN TYPE_OF_MEMORY MemoryType,
+ IN PCHAR LoadPath,
+ IN USHORT ImageType,
+ OUT PVOID *ImageBase,
+ IN PCHAR LoadDevice
+ );
+
+#endif
+
+#if defined(_PPC_)
+
+ARC_STATUS
+BlPpcInitialize (
+ VOID
+ );
+
+#endif // defined(_PPC)
+
+//
+// Define configuration allocation prototypes.
+//
+
+
+ARC_STATUS
+BlConfigurationInitialize (
+ IN PCONFIGURATION_COMPONENT Parent,
+ IN PCONFIGURATION_COMPONENT_DATA ParentEntry
+ );
+
+//
+// define routines for searching the ARC firmware tree
+//
+typedef
+BOOLEAN
+(*PNODE_CALLBACK)(
+ IN PCONFIGURATION_COMPONENT_DATA FoundComponent
+ );
+
+BOOLEAN
+BlSearchConfigTree(
+ IN PCONFIGURATION_COMPONENT_DATA Node,
+ IN CONFIGURATION_CLASS Class,
+ IN CONFIGURATION_TYPE Type,
+ IN ULONG Key,
+ IN PNODE_CALLBACK CallbackRoutine
+ );
+
+VOID
+BlGetPathnameFromComponent(
+ IN PCONFIGURATION_COMPONENT_DATA Component,
+ OUT PCHAR ArcName
+ );
+
+BOOLEAN
+BlGetPathMnemonicKey(
+ IN PCHAR OpenPath,
+ IN PCHAR Mnemonic,
+ IN PULONG Key
+ );
+
+ARC_STATUS
+BlGetArcDiskInformation(
+ VOID
+ );
+
+BOOLEAN
+BlReadSignature(
+ IN PCHAR DiskName,
+ IN BOOLEAN IsCdRom
+ );
+
+//
+// Define memory allocation prototypes.
+//
+
+typedef enum _ALLOCATION_POLICY {
+ BlAllocateLowestFit,
+ BlAllocateBestFit,
+ BlAllocateHighestFit
+} ALLOCATION_POLICY, *PALLOCATION_POLICY;
+
+VOID
+BlSetAllocationPolicy (
+ IN ALLOCATION_POLICY MemoryAllocationPolicy,
+ IN ALLOCATION_POLICY HeapAllocationPolicy
+ );
+
+ARC_STATUS
+BlMemoryInitialize (
+ VOID
+ );
+
+ARC_STATUS
+BlAllocateDataTableEntry (
+ IN PCHAR BaseDllName,
+ IN PCHAR FullDllName,
+ IN PVOID ImageHeader,
+ OUT PLDR_DATA_TABLE_ENTRY *Entry
+ );
+
+#define BlAllocateDescriptor(_MemoryType, _BasePage, _PageCount, _ActualBase) \
+ BlAllocateAlignedDescriptor((_MemoryType), \
+ (_BasePage), \
+ (_PageCount), \
+ 1, \
+ (_ActualBase))
+
+ARC_STATUS
+BlAllocateAlignedDescriptor (
+ IN TYPE_OF_MEMORY MemoryType,
+ IN ULONG BasePage,
+ IN ULONG PageCount,
+ IN ULONG Alignment,
+ OUT PULONG ActualBase
+ );
+
+PVOID
+BlAllocateHeapAligned (
+ IN ULONG Size
+ );
+
+PVOID
+BlAllocateHeap (
+ IN ULONG Size
+ );
+
+VOID
+BlStartConfigPrompt(
+ VOID
+ );
+
+BOOLEAN
+BlEndConfigPrompt(
+ VOID
+ );
+
+BOOLEAN
+BlCheckForLoadedDll (
+ IN PCHAR DllName,
+ OUT PLDR_DATA_TABLE_ENTRY *FoundEntry
+ );
+
+PMEMORY_ALLOCATION_DESCRIPTOR
+BlFindMemoryDescriptor(
+ IN ULONG BasePage
+ );
+
+ARC_STATUS
+BlInitResources(
+ IN PCHAR StartCommand
+ );
+
+PCHAR
+BlFindMessage(
+ IN ULONG Id
+ );
+
+ARC_STATUS
+BlGenerateDescriptor (
+ IN PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor,
+ IN MEMORY_TYPE MemoryType,
+ IN ULONG BasePage,
+ IN ULONG PageCount
+ );
+
+VOID
+BlInsertDescriptor (
+ IN PMEMORY_ALLOCATION_DESCRIPTOR NewDescriptor
+ );
+
+#define BlRemoveDescriptor(_md_) RemoveEntryList(&(_md_)->ListEntry)
+
+ARC_STATUS
+BlGenerateDeviceNames (
+ IN PCHAR ArcDeviceName,
+ OUT PCHAR ArcCanonicalName,
+ OUT OPTIONAL PCHAR NtDevicePrefix
+ );
+
+BOOLEAN
+BlLastKnownGoodPrompt(
+ IN OUT PBOOLEAN UseLastKnownGood
+ );
+
+PCHAR
+BlGetArgumentValue (
+ IN ULONG Argc,
+ IN PCHAR Argv[],
+ IN PCHAR ArgumentName
+ );
+
+//
+// Define message output prototype.
+//
+
+VOID
+BlOutputLoadMessage (
+ IN PCHAR DeviceName,
+ IN PCHAR FileName
+ );
+
+//
+// Define file structure recognition prototypes.
+//
+
+PBL_DEVICE_ENTRY_TABLE
+IsCdfsFileStructure (
+ IN ULONG DeviceId,
+ IN PVOID StructureContext
+ );
+
+#ifdef DBLSPACE_LEGAL
+PBL_DEVICE_ENTRY_TABLE
+IsDblsFileStructure (
+ IN ULONG DeviceId,
+ IN PVOID StructureContext
+ );
+#endif
+
+PBL_DEVICE_ENTRY_TABLE
+IsFatFileStructure (
+ IN ULONG DeviceId,
+ IN PVOID StructureContext
+ );
+
+PBL_DEVICE_ENTRY_TABLE
+IsHpfsFileStructure (
+ IN ULONG DeviceId,
+ IN PVOID StructureContext
+ );
+
+PBL_DEVICE_ENTRY_TABLE
+IsNtfsFileStructure (
+ IN ULONG DeviceId,
+ IN PVOID StructureContext
+ );
+
+#if defined(ELTORITO)
+PBL_DEVICE_ENTRY_TABLE
+IsEtfsFileStructure (
+ IN ULONG DeviceId,
+ IN PVOID StructureContext
+ );
+#endif
+
+//
+// Define registry prototypes
+//
+
+ARC_STATUS
+BlLoadSystemHive(
+ IN ULONG DeviceId,
+ IN PCHAR DeviceName,
+ IN PCHAR DirectoryPath,
+ IN PCHAR HiveName
+ );
+
+ARC_STATUS
+BlLoadAndScanSystemHive(
+ IN ULONG DeviceId,
+ IN PCHAR DeviceName,
+ IN PCHAR DirectoryPath,
+ IN PWSTR BootFileSystem,
+ OUT PCHAR BadFileName
+ );
+
+ARC_STATUS
+BlLoadAndInitSystemHive(
+ IN ULONG DeviceId,
+ IN PCHAR DeviceName,
+ IN PCHAR DirectoryPath,
+ IN PCHAR HiveName,
+ IN BOOLEAN IsAlternate,
+ OUT PBOOLEAN RestartSetup
+ );
+
+ARC_STATUS
+BlLoadBootDrivers(
+ IN ULONG DeviceId,
+ IN PCHAR LoadDevice,
+ IN PCHAR SystemPath,
+ IN PLIST_ENTRY BootDriverListHead,
+ OUT PCHAR BadFileName
+ );
+
+PCHAR
+BlScanRegistry(
+ IN PWSTR BootFileSystemPath,
+ OUT PLIST_ENTRY BootDriverListHead,
+ OUT PUNICODE_STRING AnsiCodepage,
+ OUT PUNICODE_STRING OemCodepage,
+ OUT PUNICODE_STRING LanguageTable,
+ OUT PUNICODE_STRING OemHalFont
+ );
+
+
+//
+// Define external references.
+//
+
+extern ULONG BlConsoleOutDeviceId;
+extern ULONG BlConsoleInDeviceId;
+
+extern ULONG BlDcacheFillSize;
+
+extern ULONG BlHeapFree;
+extern ULONG BlHeapLimit;
+extern PLOADER_PARAMETER_BLOCK BlLoaderBlock;
+
+extern ULONG DbcsLangId;
+extern BOOLEAN BlRebootSystem;
+//
+// Routine to get graphics characters
+//
+typedef enum {
+ GraphicsCharDoubleRightDoubleDown = 0,
+ GraphicsCharDoubleLeftDoubleDown,
+ GraphicsCharDoubleRightDoubleUp,
+ GraphicsCharDoubleLeftDoubleUp,
+ GraphicsCharDoubleVertical,
+ GraphicsCharDoubleHorizontal,
+ GraphicsCharMax
+} GraphicsChar;
+
+UCHAR
+GetGraphicsChar(
+ IN GraphicsChar WhichOne
+ );
+
+//
+// Control sequence introducer.
+// On x86 machines the loaders support dbcs and so using
+// 0x9b for output is no good (that value is a dbcs lead byte
+// in several codepages). Escape-leftbracket is a synonym for CSI
+// in the emulated ARC console on x86 (and on many ARC machines too
+// but since we can't be sure all the machines out there support
+// this we use the old-style csi on non-x86).
+//
+// We ignore this issue for characters read from the ARC console
+// since we don't ask for any text to be typed in, just arrow keys,
+// escape, F#, enter, etc.
+//
+#define ASCI_CSI_IN 0x9b
+#ifdef _X86_
+#define ASCI_CSI_OUT "\033[" // escape-leftbracket
+#else
+#define ASCI_CSI_OUT "\233" // 0x9b
+#endif
+
+//
+// Define OS/2 executable resource information structure.
+//
+
+#define FONT_DIRECTORY 0x8007
+#define FONT_RESOURCE 0x8008
+
+typedef struct _RESOURCE_TYPE_INFORMATION {
+ USHORT Ident;
+ USHORT Number;
+ LONG Proc;
+} RESOURCE_TYPE_INFORMATION, *PRESOURCE_TYPE_INFORMATION;
+
+//
+// Define OS/2 executable resource name information structure.
+//
+
+typedef struct _RESOURCE_NAME_INFORMATION {
+ USHORT Offset;
+ USHORT Length;
+ USHORT Flags;
+ USHORT Ident;
+ USHORT Handle;
+ USHORT Usage;
+} RESOURCE_NAME_INFORMATION, *PRESOURCE_NAME_INFORMATION;
+
+//
+// Define debug logging macros and functions.
+//
+
+#if !DBG
+
+#define BlLogInitialize(_x_)
+#define BlLogTerminate()
+#define BlLog(_x_)
+#define BlLogArcDescriptors(_x_)
+#define BlLogMemoryDescriptors(_x_)
+#define BlLogWaitForKeystroke()
+
+#else
+
+VOID
+BlLogInitialize (
+ IN ULONG LogfileDeviceId
+ );
+
+VOID
+BlLogTerminate (
+ VOID
+ );
+
+#define BlLog(_x_) BlLogPrint _x_
+
+#define LOG_DISPLAY 0x0001
+#define LOG_LOGFILE 0x0002
+#define LOG_WAIT 0x8000
+#define LOG_ALL (LOG_DISPLAY | LOG_LOGFILE)
+#define LOG_ALL_W (LOG_ALL | LOG_WAIT)
+
+VOID
+BlLogPrint (
+ ULONG Targets,
+ PCHAR Format,
+ ...
+ );
+
+VOID
+BlLogArcDescriptors (
+ ULONG Targets
+ );
+
+VOID
+BlLogMemoryDescriptors (
+ ULONG Targets
+ );
+
+VOID
+BlLogWaitForKeystroke (
+ VOID
+ );
+
+#endif // DBG
+
+#endif // _BLDR_
diff --git a/private/ntos/boot/inc/bldrx86.h b/private/ntos/boot/inc/bldrx86.h
new file mode 100644
index 000000000..216b7fb7b
--- /dev/null
+++ b/private/ntos/boot/inc/bldrx86.h
@@ -0,0 +1,234 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ bldrx86.h
+
+Abstract:
+
+ Contains definitions and prototypes specific to the x86 NTLDR.
+
+Author:
+
+ John Vert (jvert) 20-Dec-1993
+
+Revision History:
+
+--*/
+#include "bldr.h"
+
+
+
+ARC_STATUS
+AEInitializeIo(
+ IN ULONG DriveId
+ );
+
+PVOID
+FwAllocateHeap(
+ IN ULONG Size
+ );
+
+VOID
+AbiosInitDataStructures(
+ VOID
+ );
+
+VOID
+MdShutoffFloppy(
+ VOID
+ );
+
+PCHAR
+BlSelectKernel(
+ IN ULONG DriveId,
+ IN PCHAR BootFile,
+ OUT PCHAR *LoadOptions,
+ IN BOOLEAN UseTimeOut
+ );
+
+BOOLEAN
+BlDetectHardware(
+ IN ULONG DriveId,
+ IN PCHAR LoadOptions
+ );
+
+VOID
+BlStartup(
+ IN PCHAR PartitionName
+ );
+
+typedef struct {
+ ULONG ErrorFlag;
+ ULONG Key;
+ ULONG Size;
+ struct {
+ ULONG BaseAddrLow;
+ ULONG BaseAddrHigh;
+ ULONG SizeLow;
+ ULONG SizeHigh;
+ ULONG MemoryType;
+ } Descriptor;
+} E820FRAME, *PE820FRAME;
+
+
+// E X T E R N A L S E R V I C E S T A B L E
+//
+// External Services Table - machine dependent services
+// like reading a sector from the disk and finding out how
+// much memory is installed are provided by a lower level
+// module or a ROM BIOS. The EST provides entry points
+// for the OS loader.
+//
+
+typedef struct _EXTERNAL_SERVICES_TABLE {
+ VOID (__cdecl * RebootProcessor)(VOID);
+ NTSTATUS (__cdecl * DiskIOSystem)(USHORT,USHORT,USHORT,USHORT,USHORT,USHORT,PUCHAR);
+ ULONG (__cdecl * GetKey)(VOID);
+ ULONG (__cdecl * GetCounter)(VOID);
+ VOID (__cdecl * Reboot)(ULONG);
+ ULONG (__cdecl * AbiosServices)(USHORT,PUCHAR,PUCHAR,PUCHAR,PUCHAR,USHORT,USHORT);
+ VOID (__cdecl * DetectHardware)(ULONG, ULONG, PVOID, PULONG, PCHAR, ULONG);
+ VOID (__cdecl * HardwareCursor)(ULONG,ULONG);
+ VOID (__cdecl * GetDateTime)(PULONG,PULONG);
+ VOID (__cdecl * ComPort)(LONG,ULONG,UCHAR);
+ BOOLEAN (__cdecl * IsMcaMachine)(VOID);
+ ULONG (__cdecl * GetStallCount)(VOID);
+ VOID (__cdecl * InitializeDisplayForNt)(VOID);
+ VOID (__cdecl * GetMemoryDescriptor)(P820FRAME);
+#if defined(ELTORITO)
+ NTSTATUS (__cdecl * GetEddsSector)(ULONG,ULONG,ULONG,ULONG,PUCHAR);
+ NTSTATUS (__cdecl * GetElToritoStatus)(PUCHAR,ULONG);
+#endif
+} EXTERNAL_SERVICES_TABLE, *PEXTERNAL_SERVICES_TABLE;
+extern PEXTERNAL_SERVICES_TABLE ExternalServicesTable;
+
+//
+// External Services Macros
+//
+
+#define REBOOT_PROCESSOR (*ExternalServicesTable->RebootProcessor)
+#define GET_SECTOR (*ExternalServicesTable->DiskIOSystem)
+#define RESET_DISK (*ExternalServicesTable->DiskIOSystem)
+#define BIOS_IO (*ExternalServicesTable->DiskIOSystem)
+#define GET_KEY (*ExternalServicesTable->GetKey)
+#define GET_COUNTER (*ExternalServicesTable->GetCounter)
+#define REBOOT (*ExternalServicesTable->Reboot)
+#define ABIOS_SERVICES (*ExternalServicesTable->AbiosServices)
+#define DETECT_HARDWARE (*ExternalServicesTable->DetectHardware)
+#define HW_CURSOR (*ExternalServicesTable->HardwareCursor)
+#define GET_DATETIME (*ExternalServicesTable->GetDateTime)
+#define COMPORT (*ExternalServicesTable->ComPort)
+#define ISMCA (*ExternalServicesTable->IsMcaMachine)
+#define GET_STALL_COUNT (*ExternalServicesTable->GetStallCount)
+#define SETUP_DISPLAY_FOR_NT (*ExternalServicesTable->InitializeDisplayForNt)
+#define GET_MEMORY_DESCRIPTOR (*ExternalServicesTable->GetMemoryDescriptor)
+#if defined(ELTORITO)
+#define GET_EDDS_SECTOR (*ExternalServicesTable->GetEddsSector)
+#define GET_ELTORITO_STATUS (*ExternalServicesTable->GetElToritoStatus)
+#endif
+
+//
+// Define special key input values
+//
+#define DOWN_ARROW 0x5000
+#define UP_ARROW 0x4800
+#define HOME_KEY 0x4700
+#define END_KEY 0x4F00
+#define F1_KEY 0x3B00
+#define F3_KEY 0x3D00
+#define F5_KEY 0x3F00
+#define F6_KEY 0x4000
+
+
+//
+// x86-specific video support
+//
+VOID
+TextGetCursorPosition(
+ OUT PULONG X,
+ OUT PULONG Y
+ );
+
+VOID
+TextSetCursorPosition(
+ IN ULONG X,
+ IN ULONG Y
+ );
+
+VOID
+TextSetCurrentAttribute(
+ IN UCHAR Attribute
+ );
+
+UCHAR
+TextGetCurrentAttribute(
+ VOID
+ );
+
+VOID
+TextClearDisplay(
+ VOID
+ );
+
+VOID
+TextClearToEndOfDisplay(
+ VOID
+ );
+
+VOID
+TextClearFromStartOfLine(
+ VOID
+ );
+
+VOID
+TextClearToEndOfLine(
+ VOID
+ );
+
+VOID
+TextStringOut(
+ IN PUCHAR String
+ );
+
+PUCHAR
+TextCharOut(
+ IN PUCHAR pc
+ );
+
+VOID
+TextFillAttribute(
+ IN UCHAR Attribute,
+ IN ULONG Length
+ );
+
+UCHAR
+TextGetGraphicsCharacter(
+ IN GraphicsChar WhichOne
+ );
+
+VOID
+TextGrInitialize(
+ IN ULONG DiskId
+ );
+
+VOID
+TextGrTerminate(
+ VOID
+ );
+
+//
+// Printf-style routine for x86 use only. This routine can be called
+// only in the x86-specific part of the library, for example in places
+// where arc emulation for video hasn't been initialized yet. All other
+// display should take place with ArcWrite.
+//
+VOID
+BlPrint(
+ PCHAR cp,
+ ...
+ );
+
+#define BlPuts(str) TextStringOut(str)
diff --git a/private/ntos/boot/inc/cdfsboot.h b/private/ntos/boot/inc/cdfsboot.h
new file mode 100644
index 000000000..7f9e35b99
--- /dev/null
+++ b/private/ntos/boot/inc/cdfsboot.h
@@ -0,0 +1,175 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ CdfsBoot.h
+
+Abstract:
+
+ This module defines globally used procedure and data structures used
+ by Cdfs boot.
+
+Author:
+
+ Brian Andrew [BrianAn] 05-Aug-1991
+
+Revision History:
+
+--*/
+
+#ifndef _CDFSBOOT_
+#define _CDFSBOOT_
+
+#define MAX_CDROM_READ (16 * CD_SECTOR_SIZE)
+
+typedef struct _CDFS_STRUCTURE_CONTEXT {
+
+ //
+ // The following field is the sector offset of the start of
+ // directory data.
+ //
+
+ ULONG RootDirSectorOffset;
+
+ //
+ // The following field is the start of the sector containing the
+ // this directory.
+ //
+
+ ULONG RootDirDiskOffset;
+
+ //
+ // The following field is the size of the directory.
+ //
+
+ ULONG RootDirSize;
+
+ //
+ // The following field is the sector offset of the start of
+ // directory data.
+ //
+
+ ULONG DirSectorOffset;
+
+ //
+ // The following field is the start of the sector containing the
+ // this directory.
+ //
+
+ ULONG DirDiskOffset;
+
+ //
+ // The following field is the size of the directory.
+ //
+
+ ULONG DirSize;
+
+ //
+ // The following field indicates the size of the disk Logical Blocks.
+ //
+
+ ULONG LbnBlockSize;
+
+ //
+ // The following field indicates the number of logical blocks on the
+ // disk.
+ //
+
+ ULONG LogicalBlockCount;
+
+ //
+ // The following indicates whether this is an Iso or Hsg disk.
+ //
+
+ BOOLEAN IsIsoVol;
+
+} CDFS_STRUCTURE_CONTEXT, *PCDFS_STRUCTURE_CONTEXT;
+
+//
+// Define Cdfs file context structure.
+//
+
+typedef struct _CDFS_FILE_CONTEXT {
+
+ //
+ // The following is the disk offset of the read position for the
+ // start of the file. This may include the above number of non-file
+ // bytes.
+ //
+
+ ULONG DiskOffset;
+
+ //
+ // The following field contains the size of the file, in bytes.
+ //
+
+ ULONG FileSize;
+
+ //
+ // The following field indicates whether this is a directory.
+ //
+
+ BOOLEAN IsDirectory;
+
+} CDFS_FILE_CONTEXT, *PCDFS_FILE_CONTEXT;
+
+//
+// Define file I/O prototypes.
+//
+
+ARC_STATUS
+CdfsClose (
+ IN ULONG FileId
+ );
+
+ARC_STATUS
+CdfsOpen (
+ IN PCHAR OpenPath,
+ IN OPEN_MODE OpenMode,
+ OUT PULONG FileId
+ );
+
+ARC_STATUS
+CdfsRead (
+ IN ULONG FileId,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ );
+
+ARC_STATUS
+CdfsSeek (
+ IN ULONG FileId,
+ IN PLARGE_INTEGER Offset,
+ IN SEEK_MODE SeekMode
+ );
+
+ARC_STATUS
+CdfsWrite (
+ IN ULONG FileId,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ );
+
+ARC_STATUS
+CdfsGetFileInformation (
+ IN ULONG FileId,
+ OUT PFILE_INFORMATION Buffer
+ );
+
+ARC_STATUS
+CdfsSetFileInformation (
+ IN ULONG FileId,
+ IN ULONG AttributeFlags,
+ IN ULONG AttributeMask
+ );
+
+ARC_STATUS
+CdfsInitialize(
+ VOID
+ );
+
+#endif // _CDFSBOOT_
diff --git a/private/ntos/boot/inc/fatboot.h b/private/ntos/boot/inc/fatboot.h
new file mode 100644
index 000000000..71b63cc66
--- /dev/null
+++ b/private/ntos/boot/inc/fatboot.h
@@ -0,0 +1,293 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ fatboot.h
+
+Abstract:
+
+ This module defines globally used procedure and data structures used
+ by fat boot.
+
+Author:
+
+ Gary Kimura (garyki) 29-Aug-1989
+
+Revision History:
+
+--*/
+
+#ifndef _FATBOOT_
+#define _FATBOOT_
+#include "fat.h"
+#include "cvf.h"
+
+
+//
+// The following structure is used to define the local mcb structure used within
+// the fat boot loader to maintain a small cache of the retrieval information
+// for a single file/directory
+//
+
+#define FAT_MAXIMUM_MCB (41)
+
+typedef struct _FAT_MCB {
+
+ //
+ // The following fields indicate the number of entries in use by
+ // the boot mcb. and the boot mcb itself. The boot mcb is
+ // just a collection of [vbo, lbo] pairs. The last InUse entry
+ // Lbo's value is ignored, because it is only used to give the
+ // length of the previous run.
+ //
+
+ ULONG InUse;
+
+ VBO Vbo[ FAT_MAXIMUM_MCB ];
+ LBO Lbo[ FAT_MAXIMUM_MCB ];
+
+} FAT_MCB, *PFAT_MCB;
+
+//
+// The following structure is used to define the geometry of the fat volume
+// There is one for every mounted volume. It describes the size/configuration
+// of the volume, contains a small cached mcb for the last file being accessed
+// on the volume, and contains a small cache of the fat. Given a FileId we
+// can access the structure context through the structure context field in the
+// global BlFileTable (e.g., BlFileTable[FileId].StructureContext).
+//
+
+//
+// The following constant is used to determine how much of the fat we keep
+// cached in memory at any one time. It must be a multiple of 6 bytes in order to
+// hold complete 12 and 16 bit fat entries in the cache at any one time.
+//
+
+#define FAT_CACHE_SIZE (512*3)
+
+typedef struct _FAT_STRUCTURE_CONTEXT {
+
+ //
+ // The following field contains an unpacked copy of the bios parameter block
+ // for the mounted volume
+ //
+
+ BIOS_PARAMETER_BLOCK Bpb;
+
+ //
+ // The following two fields contain current file id of the file/directory
+ // whose mcb we are keeping around, and the second field is the mcb itself
+ //
+
+ ULONG FileId;
+ FAT_MCB Mcb;
+
+ //
+ // The following fields describe/contain the current cached fat. The vbo
+ // is the smallest vbo of the fat currently in the cache, and cached fat
+ // is a pointer to the cached data. The extra buffer/indirectiion is needed
+ // to keep everything aligned properly. The dirty flag is used to indicate
+ // if the current cached fat has been modified and needs to be flushed to disk.
+ // Vbo is used because this allows us to do a lot of our computations having
+ // already biased lbo offset to the first fat table.
+ //
+
+ BOOLEAN CachedFatDirty;
+ VBO CachedFatVbo;
+ PUCHAR CachedFat;
+ UCHAR CachedFatBuffer[ FAT_CACHE_SIZE + 256 ];
+
+} FAT_STRUCTURE_CONTEXT, *PFAT_STRUCTURE_CONTEXT;
+
+//
+// The following structure is used to define the location and size of each
+// opened file. There is one of these of every opened file. It is part of
+// the union of a BL_FILE_TABLE structuure. Given a FileId we can access the
+// file context via the BlFileTable (e.g., BlFileTable[FileId].u.FatFileContext)
+//
+
+typedef struct _FAT_FILE_CONTEXT {
+
+ //
+ // The following two fields describe where on the disk the dirent for the
+ // file is located and also contains a copy of the dirent
+ //
+
+ LBO DirentLbo;
+ DIRENT Dirent;
+
+} FAT_FILE_CONTEXT, *PFAT_FILE_CONTEXT;
+
+
+//
+// Define file I/O prototypes.
+//
+
+ARC_STATUS
+FatClose (
+ IN ULONG FileId
+ );
+
+ARC_STATUS
+FatOpen (
+ IN PCHAR OpenPath,
+ IN OPEN_MODE OpenMode,
+ OUT PULONG FileId
+ );
+
+ARC_STATUS
+FatRead (
+ IN ULONG FileId,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ );
+
+ARC_STATUS
+FatSeek (
+ IN ULONG FileId,
+ IN PLARGE_INTEGER Offset,
+ IN SEEK_MODE SeekMode
+ );
+
+ARC_STATUS
+FatWrite (
+ IN ULONG FileId,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ );
+
+ARC_STATUS
+FatGetFileInformation (
+ IN ULONG FileId,
+ OUT PFILE_INFORMATION Buffer
+ );
+
+ARC_STATUS
+FatSetFileInformation (
+ IN ULONG FileId,
+ IN ULONG AttributeFlags,
+ IN ULONG AttributeMask
+ );
+
+ARC_STATUS
+FatRename(
+ IN ULONG FileId,
+ IN PCHAR NewFileName
+ );
+
+ARC_STATUS
+FatGetDirectoryEntry (
+ IN ULONG FileId,
+ IN DIRECTORY_ENTRY *DirEntry,
+ IN ULONG NumberDir,
+ OUT PULONG CountDir
+ );
+
+ARC_STATUS
+FatInitialize(
+ VOID
+ );
+
+#ifdef DBLSPACE_LEGAL
+
+//
+// The remainder of this file contains the double space additions
+//
+
+typedef struct _DBLS_STRUCTURE_CONTEXT {
+
+ //
+ // The following field contains the regular fat structure context
+ // It is important that it be the first field in the struture
+ // because double space boot piggybacks on a lot of the existing
+ // fat boot code, and the context structure is expected to be at
+ // the same offset.
+ //
+
+ FAT_STRUCTURE_CONTEXT FatStructureContext;
+
+ //
+ // For a double space partition we keep track of the cvf, and
+ // vfp (Virtual Fat Partition) layout.
+ //
+
+ CVF_HEADER CvfHeader;
+ CVF_LAYOUT CvfLayout;
+
+ struct {
+
+ COMPONENT_LOCATION Fat;
+ COMPONENT_LOCATION RootDirectory;
+ COMPONENT_LOCATION FileArea;
+
+ ULONG BytesPerCluster;
+
+ } VfpLayout;
+
+ //
+ // The following fields are used to point to the decompression
+ // algorithm's work space.
+ //
+
+ PVOID DecompressWorkSpace;
+ PUCHAR CompressedBuffer;
+ PUCHAR UncompressedBuffer;
+
+ //
+ // The following fields are used to keep a cache of fat extensions
+ //
+
+ LBO CachedFatExtensionsLbo;
+ PCVF_FAT_EXTENSIONS CachedFatExtensions;
+
+} DBLS_STRUCTURE_CONTEXT, *PDBLS_STRUCTURE_CONTEXT;
+
+//
+// Define file I/O prototypes.
+//
+
+ARC_STATUS
+DblsClose (
+ IN ULONG FileId
+ );
+
+ARC_STATUS
+DblsOpen (
+ IN PCHAR OpenPath,
+ IN OPEN_MODE OpenMode,
+ OUT PULONG FileId
+ );
+
+ARC_STATUS
+DblsRead (
+ IN ULONG FileId,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ );
+
+ARC_STATUS
+DblsSeek (
+ IN ULONG FileId,
+ IN PLARGE_INTEGER Offset,
+ IN SEEK_MODE SeekMode
+ );
+
+ARC_STATUS
+DblsGetFileInformation (
+ IN ULONG FileId,
+ OUT PFILE_INFORMATION Buffer
+ );
+
+ARC_STATUS
+DblsInitialize(
+ VOID
+ );
+
+#endif // def DBLSPACE_LEGAL
+
+#endif // _FATBOOT_
diff --git a/private/ntos/boot/inc/hpfsboot.h b/private/ntos/boot/inc/hpfsboot.h
new file mode 100644
index 000000000..9fa25704a
--- /dev/null
+++ b/private/ntos/boot/inc/hpfsboot.h
@@ -0,0 +1,895 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ HpfsBoot.h
+
+Abstract:
+
+ This module defines globally used procedure and data structures used
+ by Hpfs boot.
+
+Author:
+
+ Gary Kimura [GaryKi] 19-Jul-1991
+
+Revision History:
+
+--*/
+
+#ifndef _HPFSBOOT_
+#define _HPFSBOOT_
+
+typedef ULONG LBN;
+typedef LBN *PLBN;
+
+typedef ULONG VBN;
+typedef VBN *PVBN;
+
+
+//
+// The following structure is a context block used by the exported
+// procedures in the Hpfs boot package. The context contains our cached
+// part of the boot mcb structure. The max number must not be smaller than
+// the maximum number of leafs possible in a pinball allocation sector plus
+// one.
+//
+
+#define MAXIMUM_NUMBER_OF_BOOT_MCB (41)
+
+typedef struct _HPFS_BOOT_MCB {
+
+ //
+ // The following fields indicate the number of entries in use by
+ // the boot mcb. and the boot mcb itself. The boot mcb is
+ // just a collection of vbn - lbn pairs. The last InUse entry
+ // Lbn's value is ignored, because it is only used to give the
+ // length of the previous run.
+ //
+
+ ULONG InUse;
+
+ VBN Vbn[ MAXIMUM_NUMBER_OF_BOOT_MCB ];
+ LBN Lbn[ MAXIMUM_NUMBER_OF_BOOT_MCB ];
+
+} HPFS_BOOT_MCB, *PHPFS_BOOT_MCB;
+
+typedef struct _HPFS_STRUCTURE_CONTEXT {
+
+ //
+ // The following field contains the fnode lbn of the file
+ //
+
+ LBN Fnode;
+
+ //
+ // The following field contains the cached mcb
+ //
+
+ HPFS_BOOT_MCB BootMcb;
+
+} HPFS_STRUCTURE_CONTEXT, *PHPFS_STRUCTURE_CONTEXT;
+
+//
+// Define Hpfs file context structure.
+//
+
+typedef struct _HPFS_FILE_CONTEXT {
+
+ //
+ // The following field contains the size of the file, in bytes.
+ //
+
+ ULONG FileSize;
+
+} HPFS_FILE_CONTEXT, *PHPFS_FILE_CONTEXT;
+
+//
+// HPFS file system structures
+//
+typedef ULONG SIGNATURE;
+typedef SIGNATURE *PSIGNATURE;
+
+typedef ULONG PINBALL_TIME;
+typedef PINBALL_TIME *PPINBALL_TIME;
+//
+// There are only three sectors on the disk that have fixed locations. They
+// are the boot sector, the super sector, and the spare sector.
+//
+
+#define BOOT_SECTOR_LBN (0)
+#define SUPER_SECTOR_LBN (16)
+#define SPARE_SECTOR_LBN (17)
+
+typedef struct _SUPER_SECTOR {
+
+ //
+ // The Super Sector starts with a double signature.
+ //
+
+ SIGNATURE Signature1; // offset = 0x000 0
+ SIGNATURE Signature2; // offset = 0x004 4
+
+ //
+ // The version and functional version describe the version of
+ // the on-disk file system structures and the oldest version of the
+ // file system that can understand this disk.
+ //
+
+ UCHAR Version; // offset = 0x008 8
+ UCHAR FunctionalVersion; // offset = 0x009 9
+ USHORT Unused1; // offset = 0x00A 10
+
+ //
+ // This field denotes the sector containing the FNODE for the root
+ // directory for the volume.
+ //
+
+ LBN RootDirectoryFnode; // offset = 0x00C 12
+
+ //
+ // The follow two fields indicate the number of total sectors on the
+ // volume (good and bad), and the number of bad sectors on the volume.
+ //
+
+ ULONG NumberOfSectors; // offset = 0x010 16
+ ULONG NumberOfBadSectors; // offset = 0x014 20
+
+ //
+ // This field denotes the sector containing the first level of the
+ // volumes bitmap table.
+ //
+
+ LBN BitMapIndirect; // offset = 0x018 24
+ ULONG Unused2; // offset = 0x01C 28
+
+ //
+ // This field denotes the sector containing the first bad sector disk
+ // buffer for the volume.
+ //
+
+ LBN BadSectorList; // offset = 0x020 32
+ ULONG Unused3; // offset = 0x024 36
+
+ //
+ // The following two dates are the time of the last execution of
+ // chkdsk and disk optimize on the volume.
+ //
+
+ PINBALL_TIME ChkdskDate; // offset = 0x028 40
+ PINBALL_TIME DiskOptimizeDate; // offset = 0x02C 44
+
+ //
+ // The following four fields describe the directory disk buffer pool.
+ // It is a contiguous run on of sectors on the disk set aside for
+ // holding directory disk buffers. PoolSize is the total number of
+ // sectors in the pool. First and Last Sector denote the boundaries
+ // of the pool, and BitMap denotes the start of a small bitmap used to
+ // describe the directory disk buffer pool's current allocation. The
+ // bitmap is 4 contiguous sectors in size, and each bit in the map
+ // corresponds to 1 Directory Disk Buffer (i.e., 4 Sectors worth)
+ //
+
+ ULONG DirDiskBufferPoolSize; // offset = 0x030 48
+ LBN DirDiskBufferPoolFirstSector; // offset = 0x034 52
+ LBN DirDiskBufferPoolLastSector; // offset = 0x038 56
+ LBN DirDiskBufferPoolBitMap; // offset = 0x03C 60
+
+ //
+ // The following field contains the name of the volume
+ //
+
+ UCHAR VolumeName[32]; // offset = 0x040 64
+
+ //
+ // The following field denotes the start of the Small ID (SID) table
+ // which is used to store the Small ID to GUID mappings used on the
+ // volume. The SID table is 8 contiguous sectors in size.
+ //
+
+ LBN SidTable; // offset = 0x060 96
+ UCHAR Unused4[512-100]; // offset = 0x064 100
+
+} SUPER_SECTOR; // sizeof = 0x200 512
+typedef SUPER_SECTOR *PSUPER_SECTOR;
+
+//
+// Super Sector signatures
+//
+
+#define SUPER_SECTOR_SIGNATURE1 (0xf995e849)
+#define SUPER_SECTOR_SIGNATURE2 (0xfa53e9c5)
+
+//
+// Super Sector versions
+//
+
+#define SUPER_SECTOR_VERSION (0x02)
+#define SUPER_SECTOR_FUNC_VERSION (0x02)
+
+typedef struct _SPARE_SECTOR {
+
+ //
+ // The Spare Sector starts with a double signature.
+ //
+
+ SIGNATURE Signature1; // offset = 0x000 0
+ SIGNATURE Signature2; // offset = 0x004 4
+
+ //
+ // The flags field describe how "clean" the volume is.
+ //
+
+ UCHAR Flags; // offset = 0x008 8
+ UCHAR Unused1[3]; // offset = 0x009 9
+
+ //
+ // The following three fields describe the hotfix structure for the
+ // volume. The List field is denotes the disk buffer used to store
+ // the hotfix table. The InUse describes how many hotfixes are
+ // currently being used, and MaxSize is the total number of hotfixes
+ // that can be in use at any one time.
+ //
+
+ LBN HotFixList; // offset = 0x00C 12
+ ULONG HotFixInUse; // offset = 0x010 16
+ ULONG HotFixMaxSize; // offset = 0x014 20
+
+ //
+ // The following two fields describe the "emergency" pool of spare
+ // directory disk buffers. Free describes how many spare directory
+ // disk buffers are currently available for use. MaxSize is the total
+ // number of spare directory disk buffers available. The actual location
+ // of the spare directory disk buffers is denoted in the table at the
+ // end of the spare sector (i.e., field SpareDirDiskBuffer).
+ //
+
+ ULONG SpareDirDiskBufferAvailable; // offset = 0x018 24
+ ULONG SpareDirDiskBufferMaxSize; // offset = 0x01C 28
+
+ //
+ // The following two fields describe the code page information used
+ // on the volume. The InfoSector field is the sector of the beginning
+ // Code Page Information Sector, and the InUse field is the total number
+ // of code pages currently in use on the volume.
+ //
+
+ LBN CodePageInfoSector; // offset = 0x020 32
+ ULONG CodePageInUse; // offset = 0x024 36
+ ULONG Unused2[17]; // offset = 0x028 40
+
+ //
+ // The following field is an array of LBN's for the spare directory
+ // disk buffers that are for "emergency" use.
+ //
+
+ LBN SpareDirDiskBuffer[101]; // offset = 0x06C 108
+
+} SPARE_SECTOR; // sizeof = 0x200 512
+typedef SPARE_SECTOR *PSPARE_SECTOR;
+
+//
+// Spare Sector signatures
+//
+
+#define SPARE_SECTOR_SIGNATURE1 (0xf9911849)
+#define SPARE_SECTOR_SIGNATURE2 (0xfa5229c5)
+
+
+//
+// The on-disk allocation structure is defined using B-Trees. For every
+// B-Tree block there is an Allocation Header, followed by a list of
+// either Allocation Leafs or Allocation Nodes. This structure will either
+// appear in an FNODE or in an AllocationSector.
+//
+// The allocation header (called Allocation Block in earlier implementations)
+// describes a B-tree block.
+//
+
+typedef struct _ALLOCATION_HEADER {
+
+ //
+ // The following flag describes the state of the B-tree block (e.g.,
+ // indicates if the block is a leaf or an internal node.
+ //
+
+ UCHAR Flags; // offset = 0x000 0
+ UCHAR Unused[3]; // offset = 0x001 1
+
+ //
+ // The following two fields denote the number of free records in the
+ // B-Tree block, and the number of records that are currently in use
+ //
+
+ UCHAR FreeCount; // offset = 0x004 4
+ UCHAR OccupiedCount; // offset = 0x005 5
+
+ //
+ // The next field contains the offset (in bytes) from the beginning
+ // of the allocation header to the first free byte in the B-Tree block
+ //
+
+ USHORT FirstFreeByte; // offset = 0x006 6
+
+} ALLOCATION_HEADER; // sizeof = 0x008 8
+typedef ALLOCATION_HEADER *PALLOCATION_HEADER;
+
+//
+// Allocation header flags
+//
+// NODE - if set this indicates that the B-Tree block contains internal
+// nodes and not leaf entries.
+//
+// BINARY_SEARCH - if set this suggest that a binary search should be used
+// to search the B-Tree block.
+//
+// FNODE_PARENT - if set this indicates that the sector which is the
+// parent of the sector with this header (not this sector), is an
+// FNODE.
+//
+
+#define ALLOCATION_BLOCK_NODE (0x80)
+#define ALLOCATION_BLOCK_BINARY (0x40)
+#define ALLOCATION_BLOCK_FNODE_PARENT (0x20)
+
+//
+// Immediately following an allocation header are one or more allocation nodes
+// of allocation leafs.
+//
+
+typedef struct _ALLOCATION_NODE {
+
+ //
+ // All children of this allocation node will have values less than
+ // the following VBN field.
+ //
+
+ VBN Vbn; // offset = 0x000 0
+
+ //
+ // This is the LBN of the allocation sector refered to by this node
+ //
+
+ LBN Lbn; // offset = 0x004 4
+
+} ALLOCATION_NODE; // sizeof = 0x008 8
+typedef ALLOCATION_NODE *PALLOCATION_NODE;
+
+typedef struct _ALLOCATION_LEAF {
+
+ //
+ // The following field has the starting VBN for this run
+ //
+
+ VBN Vbn; // offset = 0x000 0
+
+ //
+ // This is the length of the run in sectors
+ //
+
+ ULONG Length; // offset = 0x004 4
+
+ //
+ // This is the starting LBN of the run
+ //
+
+ LBN Lbn; // offset = 0x008 8
+
+} ALLOCATION_LEAF; // sizeof = 0x00C 12
+typedef ALLOCATION_LEAF *PALLOCATION_LEAF;
+
+//
+// An allocation sector is an on-disk structure that contains allocation
+// information. It contains some bookkeeping information, an allocation
+// header and then an array of either allocation leafs or allocation nodes.
+//
+// AllocationSector
+// +-------------------+
+// | bookkeeping |
+// +- - - - - - - - - -+
+// | Allocation Header |
+// +- - - - - - - - - -+
+// | Allocation Leafs |
+// | or |
+// | Allocation Nodes |
+// +-------------------+
+//
+// where the number of allocation leafs that can be stored in a sector is
+// 40 and the number of nodes is 60.
+//
+
+#define ALLOCATION_NODES_PER_SECTOR (60)
+#define ALLOCATION_LEAFS_PER_SECTOR (40)
+
+typedef struct _ALLOCATION_SECTOR {
+
+ //
+ // The allocation sector starts off with a signature field
+ //
+
+ SIGNATURE Signature; // offset = 0x000 0
+
+ //
+ // This following two fields contains the LBN of this allocation
+ // sector itself, and the LBN of the parent of this sector (the
+ // parent is either an FNODE or another allocation sector)
+ //
+
+ LBN Lbn; // offset = 0x004 4
+ LBN ParentLbn; // offset = 0x008 8
+
+ //
+ // The allocation header for the sector
+ //
+
+ ALLOCATION_HEADER AllocationHeader; // offset = 0x00C 12
+
+ //
+ // The remainder of the sector is either an array of allocation leafs
+ // of allocation nodes
+ //
+
+ union { // offset = 0x014 20
+ ALLOCATION_NODE Node[ ALLOCATION_NODES_PER_SECTOR ];
+ ALLOCATION_LEAF Leaf[ ALLOCATION_LEAFS_PER_SECTOR ];
+ } Allocation;
+
+ UCHAR Unused[12]; // offset = 0x1F4 500
+
+} ALLOCATION_SECTOR; // sizeof = 0x200 512
+typedef ALLOCATION_SECTOR *PALLOCATION_SECTOR;
+
+//
+// The allocation sector signature
+//
+
+#define ALLOCATION_SECTOR_SIGNATURE (0x37e40aae)
+
+//
+// The on-disk FNODE structure is used to describe both files and directories
+// It contains some fixed data information, the EA and ACL lookup information,
+// allocation information and then a free space for storing some EAs and
+// ACLs that fit in the sector
+//
+
+#define ALLOCATION_NODES_PER_FNODE (12)
+#define ALLOCATION_LEAFS_PER_FNODE (8)
+
+typedef struct _FNODE_SECTOR {
+
+ //
+ // The sector starts with a signature field
+ //
+
+ SIGNATURE Signature; // offset = 0x000 0
+
+ //
+ // The following fields was for history tracking, but in NT Pinball
+ // doesn't need this information.
+ //
+
+ ULONG Unused1[2]; // offset = 0x004 4
+
+ //
+ // The following two fields contain the file name length, and the first
+ // 15 bytes of the filename, as stored in the dirent that references
+ // this fnode. For the root directory theses values are all zeros.
+ //
+
+ UCHAR FileNameLength; // offset = 0x00C 12
+ UCHAR FileName[15]; // offset = 0x00D 13
+
+ //
+ // The following field denotes the parent directory's FNODE
+ //
+
+ LBN ParentFnode; // offset = 0x01C 28
+
+ //
+ // The following four fields describe the ACL for the file/directory.
+ //
+ // AclDiskAllocationLength holds the number of bytes in the ACL that
+ // are stored outside of this FNODE. If this value is not zero
+ // then AclFnodeLength must be equal to zero.
+ //
+ // AclLbn points to the first sector of the data run or the allocation
+ // sector containing describing the ACL. AclFlags indicates if
+ // it is a data run or an allocation sector. AclLbn is only used
+ // if AclDiskAllocationLength is not zero.
+ //
+ // AclFnodeLength holds the number of bytes in the ACL that are
+ // stored within this FNODE. If value is not zero then
+ // AclDiskAllocationLength must be equal to zero. The ACL, if stored
+ // in the FNODE, is located at AclEaFnodeBuffer in this FNODE sector.
+ //
+ // AclFlags if the data is outside the FNODE this flag indicates whether
+ // ACL is stored in a single data run (AclFlags == 0) or via an
+ // allocation sector (AclFlags != 0). AclFlags is only used if
+ // AclDiskAllocationLength is not zero.
+ //
+
+ ULONG AclDiskAllocationLength; // offset = 0x020 32
+ LBN AclLbn; // offset = 0x024 36
+ USHORT AclFnodeLength; // offset = 0x028 40
+ UCHAR AclFlags; // offset = 0x02A 42
+
+ //
+ // The following field was used for the number of valid history
+ // bits but we don't need this field of NT Pinball
+ //
+
+ UCHAR Unused2; // offset = 0x02B 43
+
+ //
+ // The following four fields describe the EA for the file/directory.
+ //
+ // EaDiskAllocationLength holds the number of bytes in the EA that
+ // are stored outside of this FNODE. If this value is not zero
+ // then EaFnodeLength must be equal to zero.
+ //
+ // EaLbn points to the first sector of the data run or the allocation
+ // sector containing describing the EA. EaFlags indicates if
+ // it is a data run or an allocation sector. EaLbn is only used
+ // if EaDiskAllocationLength is not zero.
+ //
+ // EaFnodeLength holds the number of bytes in the EA that are
+ // stored within this FNODE. If value is not zero then
+ // EaDiskAllocationLength must be equal to zero. The EA, if stored
+ // in the FNODE, is located immediately after the ACL stored in the
+ // AclEaFnodeBuffer.
+ //
+ // EaFlags if the data is outside the FNODE this flag indicates whether
+ // EA is stored in a single data run (EaFlags == 0) or via an
+ // allocation sector (EaFlags != 0). EaFlags is only used if
+ // EaDiskAllocationLength is not zero.
+ //
+
+ ULONG EaDiskAllocationLength; // offset = 0x02C 44
+ LBN EaLbn; // offset = 0x030 48
+ USHORT EaFnodeLength; // offset = 0x034 52
+ UCHAR EaFlags; // offset = 0x036 54
+
+ //
+ // The following byte contains the FNODE flags
+ //
+
+ UCHAR Flags; // offset = 0x037 55
+
+ //
+ // The following two fields describe the top level allocation for
+ // this file/directory
+ //
+
+ ALLOCATION_HEADER AllocationHeader; // offset = 0x038 56
+
+ union { // offset = 0x040 64
+ ALLOCATION_NODE Node[ ALLOCATION_NODES_PER_FNODE ];
+ ALLOCATION_LEAF Leaf[ ALLOCATION_LEAFS_PER_FNODE ];
+ } Allocation;
+
+ //
+ // The following field contains the valid length of the file. The size
+ // of the file is stored in the dirent. The difference between these two
+ // values is that the file size is the actual size allocated and visible
+ // to the user. The Valid length is the number of bytes that have
+ // had their data zeroed out or modified. (i.e., if a read request
+ // is greater than valid length but less than file size then the file
+ // system must first zero out the data in the file up to and including
+ // data being read.
+ //
+
+ ULONG ValidDataLength; // offset = 0x0A0 160
+
+ //
+ // The following field contains the number of EAs in this file that have
+ // the need ea attribute set.
+ //
+
+ ULONG NeedEaCount; // offset = 0x0A4 164
+ UCHAR Unused3[16]; // offset = 0x0A8 168
+
+ //
+ // The following field contains the offset, in bytes, from the start of
+ // FNODE to the first ACE stored in the FNODE
+ //
+
+ USHORT AclBase; // offset = 0x0B8 184
+ UCHAR Unused4[10]; // offset = 0x0BA 186
+
+ //
+ // The following buffer is used to store acl/ea in the FNODE
+ //
+
+ UCHAR AclEaFnodeBuffer[316]; // offset = 0x0C4 196
+
+} FNODE_SECTOR; // sizeof = 0x200 512
+typedef FNODE_SECTOR *PFNODE_SECTOR;
+
+//
+// The FNODE Sector signature
+//
+
+#define FNODE_SECTOR_SIGNATURE (0xf7e40aae)
+
+//
+// The on-disk directory disk buffer is used to contain directory entries.
+// It contains a fixed header followed by a collection of one or more
+// dirents. Dirents are variable so size we cannot use a simply C struct
+// declartion for the entire disk buffer.
+//
+
+typedef struct _DIRECTORY_DISK_BUFFER {
+
+ //
+ // The disk buffer starts with a signature field
+ //
+
+ SIGNATURE Signature; // offset = 0x000 0
+
+ //
+ // The following field is the offset to the first free byte in this
+ // disk buffer
+ //
+
+ ULONG FirstFree; // offset = 0x004 4
+
+ //
+ // The following field is a change count that is kept around for
+ // bookkeeping purposes. It is incremented whenever we move any
+ // of the entries in this disk buffer. This means for any file if we
+ // remember its offset and its change count we will be able to quickly
+ // locate the dirent again without needing to search from the top
+ // of the directory again. (i.e., only if the remembered change count
+ // and the current change count match). For this to work the file system
+ // in memory will need to keep track of whenever it removes a Directory
+ // Disk Buffer from a directory, and have each saved dirent location
+ // keep this Directory change count, the Directory Disk Buffer Change
+ // Count, LBN and Offset.
+ //
+ // In addition we overload the bit in this value to indicate if this
+ // is the topmost directory disk buffer for the directory (low order bit
+ // = 1) or if it is a lower lever buffer (low order bit = 0).
+ //
+
+ ULONG ChangeCount; // offset = 0x008 8
+
+ //
+ // The following field contains the LBN of either the parent
+ // directory disk buffer containing this disk buffer or the FNODE.
+ // It is the FNODE if this is a topmost disk buffer and a parent
+ // directory disk buffer otherwise.
+ //
+
+ LBN Parent; // offset = 0x00C 12
+
+ //
+ // The following field is the LBN of the sector containing the
+ // start of this disk buffer
+ //
+
+ LBN Sector; // offset = 0x010 16
+
+ //
+ // This following buffer contains the dirents stored in this disk buffer
+ //
+
+ UCHAR Dirents[2028]; // offset = 0x014 20
+
+} DIRECTORY_DISK_BUFFER; // sizeof = 0x800 2048
+typedef DIRECTORY_DISK_BUFFER *PDIRECTORY_DISK_BUFFER;
+
+//
+// Size of Directory Disk Buffer in sectors.
+//
+
+#define DIRECTORY_DISK_BUFFER_SECTORS (4)
+
+//
+// Directory Disk Buffer Signature
+//
+
+#define DIRECTORY_DISK_BUFFER_SIGNATURE (0x77e40aae)
+
+typedef struct _PBDIRENT {
+
+ USHORT DirentSize; // offset = 0x000 0
+ UCHAR Flags; // offset = 0x002 2
+ UCHAR FatFlags; // offset = 0x003 3
+
+ LBN Fnode; // offset = 0x004 4
+
+ PINBALL_TIME LastModificationTime; // offset = 0x008 8
+
+ ULONG FileSize; // offset = 0x00C 12
+
+ PINBALL_TIME LastAccessTime; // offset = 0x010 16
+
+ PINBALL_TIME FnodeCreationTime; // offset = 0x014 20
+
+ ULONG EaLength; // offset = 0x018 24
+
+ UCHAR ResidentAceCount; // offset = 0x01C 28
+ UCHAR CodePageIndex; // offset = 0x01D 29
+ UCHAR FileNameLength; // offset = 0x01E 30
+ UCHAR FileName[1]; // offset = 0x01F 31
+
+} PBDIRENT; // sizeof = 0x020 32
+typedef PBDIRENT *PPBDIRENT;
+
+//
+// Define sizes of .. and End PBDIRENT.
+//
+
+#define SIZEOF_DIR_DOTDOT (sizeof(PBDIRENT) + sizeof(LONG))
+#define SIZEOF_DIR_END (sizeof(PBDIRENT))
+#define SIZEOF_DIR_MAXPBDIRENT (sizeof(PBDIRENT) + 256 + \
+ (3*sizeof(PINBALL_ACE)) + sizeof(LBN))
+
+#define DIRENT_FIRST_ENTRY (0x0001)
+#define DIRENT_ACL (0x0002)
+#define DIRENT_BTREE_POINTER (0x0004)
+#define DIRENT_END (0x0008)
+#define DIRENT_EXPLICIT_ACL (0x0040)
+#define DIRENT_NEED_EA (0x0080)
+#define DIRENT_NEW_NAMING_RULES (0x4000)
+//
+// The following macros are used to help locate dirents within a Directory
+// Disk Buffer. GetFirstDirent returns a pointer to the first dirent entry
+// in the directory disk buffer. GetNextDirent returns a pointer to the
+// next dirent entry in a directory disk buffer, without checking for the
+// end of the Directory Disk Buffer.
+//
+// PDIRENT
+// GetFirstDirent (
+// IN PDIRECTORY_DISK_BUFFER DirectoryDiskBuffer
+// );
+//
+// PDIRENT
+// GetNextDirent (
+// IN PDIRENT Dirent
+// );
+//
+
+#define GetFirstDirent(DIR) ( \
+ (PDIRENT)&(DIR)->Dirents[0] \
+)
+
+//
+// This macro blindly returns a pointer to the next Dirent, without checking
+// for the end of the Directory Disk Buffer, i.e., callers must always check
+// for the End record in the Directory Disk Buffer. If GetNextDirent is
+// called with the End record as input, it will return the next free byte
+// in the buffer.
+//
+
+#define GetNextDirent(ENT) ( \
+ (PDIRENT)((PUCHAR)(ENT)+(ENT)->DirentSize) \
+)
+//
+// The following macros are used to help retrieve the variable fields
+// within a dirent. GetAceInDirent returns a pointer to the ACE within
+// the dirent corresponding to the supplied index, or NULL if there isn't
+// a corresponding ACE. GetBtreePointerInDirent returns the LBN field of
+// the down B-tree pointer stored in the dirent, or it returns a value of
+// zero if there isn't a down pointer. SetBtreePointerInDirent sets the
+// LBN downpointer field.
+//
+// PPINBALL_ACE
+// GetAceInDirent (
+// IN PDIRENT Dirent,
+// IN ULONG Index // (0, 1, or 2)
+// );
+//
+// LBN
+// GetBtreePointerInDirent (
+// IN PDIRENT Dirent
+// );
+//
+// VOID
+// SetBtreePointerInDirent (
+// IN OUT PDIRENT Dirent,
+// IN LBN Blbn
+// );
+//
+//
+//
+// To return a pointer to an ACE in a dirent we need to check to see if the
+// index is within the resident ace count. The first ace is the address of
+// the first longword after the filename, the second ace is the second long
+// word.
+//
+
+#define GetAceInDirent(ENT,I) ( \
+ ((I) >= 0 && (I) < (ENT)->ResidentAceCount ? \
+ (PPINBALL_ACE)( \
+ (LONG)LongAlign((ENT)->FileName[(ENT)->FileNameLength]) + \
+ (I)*sizeof(PINBALL_ACE) \
+ ) \
+ : \
+ NULL \
+ ) \
+)
+
+//
+// To return the Btree pointer we need to first check to see if there
+// is Btree pointer field, otherwise we return NULL. The field, if present,
+// is located 4 bytes back from the end of the dirent.
+//
+
+#define GetBtreePointerInDirent(ENT) ( \
+ (FlagOn((ENT)->Flags,DIRENT_BTREE_POINTER) ? \
+ *(PLBN)(((PUCHAR)(ENT)) + (ENT)->DirentSize - sizeof(LBN)) \
+ : \
+ 0 \
+ ) \
+)
+
+//
+// To set the Btree pointer we assume there is a Btree pointer field.
+// The field is located 4 bytes back from the end of the dirent.
+//
+
+#define SetBtreePointerInDirent(ENT,BLBN) ( \
+ *(PLBN)(((PUCHAR)(ENT)) + (ENT)->DirentSize - sizeof(LBN)) = (BLBN) \
+)
+
+//
+// Define file I/O prototypes.
+//
+
+ARC_STATUS
+HpfsClose (
+ IN ULONG FileId
+ );
+
+ARC_STATUS
+HpfsOpen (
+ IN PCHAR OpenPath,
+ IN OPEN_MODE OpenMode,
+ OUT PULONG FileId
+ );
+
+ARC_STATUS
+HpfsRead (
+ IN ULONG FileId,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ );
+
+ARC_STATUS
+HpfsSeek (
+ IN ULONG FileId,
+ IN PLARGE_INTEGER Offset,
+ IN SEEK_MODE SeekMode
+ );
+
+ARC_STATUS
+HpfsWrite (
+ IN ULONG FileId,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ );
+
+ARC_STATUS
+HpfsGetFileInformation (
+ IN ULONG FileId,
+ OUT PFILE_INFORMATION Buffer
+ );
+
+ARC_STATUS
+HpfsSetFileInformation (
+ IN ULONG FileId,
+ IN ULONG AttributeFlags,
+ IN ULONG AttributeMask
+ );
+
+ARC_STATUS
+HpfsInitialize(
+ VOID
+ );
+
+#endif // _HPFSBOOT_
diff --git a/private/ntos/boot/inc/ntfsboot.h b/private/ntos/boot/inc/ntfsboot.h
new file mode 100644
index 000000000..a79f09548
--- /dev/null
+++ b/private/ntos/boot/inc/ntfsboot.h
@@ -0,0 +1,204 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ NtfsBoot.h
+
+Abstract:
+
+ This module defines globally used procedure and data structures used by Ntfs boot.
+
+Author:
+
+ Gary Kimura [GaryKi] 10-Apr-1992
+
+Revision History:
+
+--*/
+
+#ifndef _NTFSBOOT_
+#define _NTFSBOOT_
+
+
+//
+// Some important manifest constants. These are the maximum byte size we'll ever
+// see for a file record or an index allocation buffer.
+//
+
+#define MAXIMUM_FILE_RECORD_SIZE (4096)
+
+#define MAXIMUM_INDEX_ALLOCATION_SIZE (4096)
+
+#define MAXIMUM_COMPRESSION_UNIT_SIZE (65536)
+
+//
+// The following structure is an mcb structure for storing cached retrieval pointer
+// information.
+//
+
+#define MAXIMUM_NUMBER_OF_MCB_ENTRIES (16)
+
+typedef struct _NTFS_MCB {
+
+ //
+ // The following fields indicate the number of entries in use by the mcb. and
+ // the mcb itself. The mcb is just a collection of vbo - lbo pairs. The last
+ // InUse entry Lbo's value is ignored, because it is only used to give the
+ // length of the previous run.
+ //
+
+ ULONG InUse;
+
+ LONGLONG Vbo[ MAXIMUM_NUMBER_OF_MCB_ENTRIES ];
+ LONGLONG Lbo[ MAXIMUM_NUMBER_OF_MCB_ENTRIES ];
+
+} NTFS_MCB, *PNTFS_MCB;
+
+//
+// Define the Ntfs file context structure and the attribute context structure.
+//
+
+typedef struct _NTFS_FILE_CONTEXT {
+
+ //
+ // The following field indicates the type of attribute opened
+ //
+
+ ULONG TypeCode;
+
+ //
+ // The following field indicates the size of the data portion of the attribute
+ //
+
+ LONGLONG DataSize;
+
+ //
+ // The following two fields identify and locate the attribute on the volume.
+ // The first number is the file record where the attribute header is located and
+ // the second number is the offset in the file record of the attribute header
+ //
+
+ LONGLONG FileRecord;
+ USHORT FileRecordOffset;
+
+ //
+ // The following field indicates if the attribute is resident
+ //
+
+ BOOLEAN IsAttributeResident;
+
+ //
+ // The following fields are only used if the data stream is compressed.
+ // If it is compressed then the CompressionFormat field is not zero, and
+ // contains the value to pass to the decompression engine. CompressionUnit
+ // is the number of bytes in each unit of compression.
+ //
+
+ USHORT CompressionFormat;
+ ULONG CompressionUnit;
+
+} NTFS_FILE_CONTEXT, *PNTFS_FILE_CONTEXT;
+typedef NTFS_FILE_CONTEXT NTFS_ATTRIBUTE_CONTEXT, *PNTFS_ATTRIBUTE_CONTEXT;
+
+//
+// Define the Ntfs volume structure context
+//
+
+typedef struct _NTFS_STRUCTURE_CONTEXT {
+
+ //
+ // This is the device that we talk to
+ //
+
+ ULONG DeviceId;
+
+ //
+ // Some volume specific constants that describe the size of various records
+ //
+
+ ULONG BytesPerCluster;
+ ULONG BytesPerFileRecord;
+
+ //
+ // The following three fields describe the $DATA stream for the the MFT. We
+ // need two Mcbs one holds the base of the mft and the other to hold any excess
+ // retrival information. I.e., we must not loose the base mcb otherwise we
+ // can't find anything.
+ //
+
+ NTFS_ATTRIBUTE_CONTEXT MftAttributeContext;
+ NTFS_MCB MftBaseMcb;
+
+ //
+ // The following three fields hold a cached mcb that we use for non-resident
+ // attributes other than the mft data stream. The first two fields identify the
+ // attribute and the third field contains the cached mcb.
+ //
+
+ LONGLONG CachedMcbFileRecord[16];
+ USHORT CachedMcbFileRecordOffset[16];
+ NTFS_MCB CachedMcb[16];
+
+} NTFS_STRUCTURE_CONTEXT, *PNTFS_STRUCTURE_CONTEXT;
+
+
+//
+// Define file I/O prototypes.
+//
+
+ARC_STATUS
+NtfsClose (
+ IN ULONG FileId
+ );
+
+ARC_STATUS
+NtfsOpen (
+ IN PCHAR OpenPath,
+ IN OPEN_MODE OpenMode,
+ OUT PULONG FileId
+ );
+
+ARC_STATUS
+NtfsRead (
+ IN ULONG FileId,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ );
+
+ARC_STATUS
+NtfsSeek (
+ IN ULONG FileId,
+ IN PLARGE_INTEGER Offset,
+ IN SEEK_MODE SeekMode
+ );
+
+ARC_STATUS
+NtfsWrite (
+ IN ULONG FileId,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ );
+
+ARC_STATUS
+NtfsGetFileInformation (
+ IN ULONG FileId,
+ OUT PFILE_INFORMATION Buffer
+ );
+
+ARC_STATUS
+NtfsSetFileInformation (
+ IN ULONG FileId,
+ IN ULONG AttributeFlags,
+ IN ULONG AttributeMask
+ );
+
+ARC_STATUS
+NtfsInitialize(
+ VOID
+ );
+
+#endif // _NTFSBOOT_
diff --git a/private/ntos/boot/inc/scsiboot.h b/private/ntos/boot/inc/scsiboot.h
new file mode 100644
index 000000000..9fdc9b412
--- /dev/null
+++ b/private/ntos/boot/inc/scsiboot.h
@@ -0,0 +1,500 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ scsiboot.h
+
+Abstract:
+
+ This file defines the necessary structures, defines, and functions for
+ the common SCSI boot port driver.
+
+Author:
+
+ Jeff Havens (jhavens) 28-Feb-1991
+ Mike Glass
+
+Revision History:
+
+--*/
+
+#include "ntddscsi.h"
+
+//
+// SCSI Get Configuration Information
+//
+// LUN Information
+//
+
+typedef struct _LUNINFO {
+ UCHAR PathId;
+ UCHAR TargetId;
+ UCHAR Lun;
+ BOOLEAN DeviceClaimed;
+ PVOID DeviceObject;
+ struct _LUNINFO *NextLunInfo;
+ UCHAR InquiryData[INQUIRYDATABUFFERSIZE];
+} LUNINFO, *PLUNINFO;
+
+typedef struct _SCSI_BUS_SCAN_DATA {
+ USHORT Length;
+ UCHAR InitiatorBusId;
+ UCHAR NumberOfLogicalUnits;
+ PLUNINFO LunInfoList;
+} SCSI_BUS_SCAN_DATA, *PSCSI_BUS_SCAN_DATA;
+
+typedef struct _SCSI_CONFIGURATION_INFO {
+ UCHAR NumberOfBuses;
+ PSCSI_BUS_SCAN_DATA BusScanData[1];
+} SCSI_CONFIGURATION_INFO, *PSCSI_CONFIGURATION_INFO;
+
+#define MAXIMUM_RETRIES 4
+
+//
+// SCSI device timeout values in seconds
+//
+
+#define SCSI_DISK_TIMEOUT 10
+#define SCSI_CDROM_TIMEOUT 10
+#define SCSI_TAPE_TIMEOUT 120
+
+//
+// Adapter object transfer information.
+//
+
+typedef struct _ADAPTER_TRANSFER {
+ PSCSI_REQUEST_BLOCK Srb;
+ PVOID LogicalAddress;
+ ULONG Length;
+}ADAPTER_TRANSFER, *PADAPTER_TRANSFER;
+
+typedef struct _SRB_SCATTER_GATHER {
+ ULONG PhysicalAddress;
+ ULONG Length;
+}SRB_SCATTER_GATHER, *PSRB_SCATTER_GATHER;
+
+//
+// Srb Structure plus extra storage for the port driver.
+//
+
+#define IRP_STACK_SIZE 2
+
+typedef struct _FULL_SCSI_REQUEST_BLOCK {
+ SCSI_REQUEST_BLOCK Srb;
+ PVOID PreviousIrp;
+ IRP Irp;
+ IO_STACK_LOCATION IrpStack[IRP_STACK_SIZE];
+ ULONG SrbExtensionSize;
+ MDL Mdl;
+ ULONG PageFrame[20];
+}FULL_SCSI_REQUEST_BLOCK, *PFULL_SCSI_REQUEST_BLOCK;
+
+//
+// Logical unit extension
+//
+
+typedef struct _LOGICAL_UNIT_EXTENSION {
+ UCHAR PathId;
+ UCHAR TargetId;
+ UCHAR Lun;
+ ULONG Flags;
+ PIRP CurrentRequest;
+ KSPIN_LOCK CurrentRequestSpinLock;
+ PVOID SpecificLuExtension;
+ struct _LOGICAL_UNIT_EXTENSION *NextLogicalUnit;
+ KDEVICE_QUEUE RequestQueue;
+ KSPIN_LOCK RequestQueueSpinLock;
+ LONG RequestTimeoutCounter;
+ ULONG RetryCount;
+ UCHAR NumberOfLogicalUnits;
+ PVOID MapRegisterBase;
+ ULONG NumberOfMapRegisters;
+ SRB_SCATTER_GATHER ScatterGather[17];
+} LOGICAL_UNIT_EXTENSION, *PLOGICAL_UNIT_EXTENSION;
+
+//
+// Device extension
+//
+
+typedef struct _DEVICE_EXTENSION {
+
+ PDEVICE_OBJECT DeviceObject;
+
+ //
+ // Dma Adapter information.
+ //
+
+ PVOID MapRegisterBase;
+ PADAPTER_OBJECT DmaAdapterObject;
+ ADAPTER_TRANSFER FlushAdapterParameters;
+
+ //
+ // Number of SCSI buses
+ //
+
+ UCHAR NumberOfBuses;
+
+ //
+ // Maximum targets per bus
+ //
+
+ UCHAR MaximumTargetIds;
+
+ //
+ // SCSI Capabilities structure
+ //
+
+ IO_SCSI_CAPABILITIES Capabilities;
+
+ //
+ // SCSI port driver flags
+ //
+
+ ULONG Flags;
+
+ //
+ // SCSI port interrupt flags
+ //
+
+ ULONG InterruptFlags;
+
+ //
+ // List head for singlely linked list of complete IRPs.
+ //
+
+ PIRP CompletedRequests;
+
+ //
+ // Adapter object transfer parameters.
+ //
+
+ ADAPTER_TRANSFER MapTransferParameters;
+
+ KSPIN_LOCK SpinLock;
+
+ //
+ // Miniport Initialization Routine
+ //
+
+ PHW_INITIALIZE HwInitialize;
+
+ //
+ // Miniport Start IO Routine
+ //
+
+ PHW_STARTIO HwStartIo;
+
+ //
+ // Miniport Interrupt Service Routine
+ //
+
+ PHW_INTERRUPT HwInterrupt;
+
+ //
+ // Miniport Reset Routine
+ //
+
+ PHW_RESET_BUS HwReset;
+
+ //
+ // Miniport DMA started Routine
+ //
+
+ PHW_DMA_STARTED HwDmaStarted;
+
+ //
+ // Buffers must be mapped into system space.
+ //
+
+ BOOLEAN MapBuffers;
+
+ //
+ // Is this device a bus master and does it require map registers.
+ //
+
+ BOOLEAN MasterWithAdapter;
+ //
+ // Device extension for miniport routines.
+ //
+
+ PVOID HwDeviceExtension;
+
+ //
+ // Miniport request interrupt enabled/disable routine.
+ //
+
+ PHW_INTERRUPT HwRequestInterrupt;
+
+ //
+ // Miniport timer request routine.
+ //
+
+ PHW_INTERRUPT HwTimerRequest;
+
+ //
+ // SCSI configuration information from inquiries.
+ //
+
+ PSCSI_CONFIGURATION_INFO ScsiInfo;
+
+ //
+ // Miniport noncached device extension
+ //
+
+ PVOID NonCachedExtension;
+
+ //
+ // SrbExtension Zone Pool
+ //
+
+ PVOID SrbExtensionZonePool;
+ PCHAR SrbExtensionPointer;
+
+ //
+ // Physical address of zone pool
+ //
+
+ ULONG PhysicalZoneBase;
+
+ //
+ // Size of Srb extension.
+ //
+
+ ULONG SrbExtensionSize;
+
+ //
+ // Spinlock for zoned hash table entries
+ //
+
+ KSPIN_LOCK ZoneSpinLock;
+
+ //
+ // Logical Unit Extension
+ //
+
+ ULONG HwLogicalUnitExtensionSize;
+
+ PLOGICAL_UNIT_EXTENSION LogicalUnitList;
+
+
+ ULONG TimerValue;
+
+ //
+ // Port timing count.
+ //
+
+ LONG PortTimeoutCounter;
+
+} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
+
+#define DEVICE_EXTENSION_SIZE sizeof(DEVICE_EXTENSION)
+
+//
+// Port driver extension flags.
+//
+
+#define PD_CURRENT_IRP_VALID 0X0001
+#define PD_RESET_DETECTED 0X0002
+#define PD_NOTIFICATION_IN_PROGRESS 0X0004
+#define PD_READY_FOR_NEXT_REQUEST 0X0008
+#define PD_FLUSH_ADAPTER_BUFFERS 0X0010
+#define PD_MAP_TRANSFER 0X0020
+#define PD_CALL_DMA_STARTED 0X01000
+#define PD_DISABLE_CALL_REQUEST 0X02000
+#define PD_DISABLE_INTERRUPTS 0X04000
+#define PD_ENABLE_CALL_REQUEST 0X08000
+#define PD_TIMER_CALL_REQUEST 0X10000
+
+//
+// Logical unit extension flags.
+//
+
+#define PD_QUEUE_FROZEN 0X0001
+#define PD_LOGICAL_UNIT_IS_ACTIVE 0X0002
+#define PD_CURRENT_REQUEST_COMPLETE 0X0004
+#define PD_LOGICAL_UNIT_IS_BUSY 0X0008
+
+//
+// The timer interval for the miniport timer routine specified in
+// units of 100 nanoseconds.
+//
+#define PD_TIMER_INTERVAL (250 * 1000 * 10) // 250 ms
+
+#define PD_TIMER_RESET_HOLD_TIME 4
+
+//
+// The define the interloop stall.
+//
+
+#define PD_INTERLOOP_STALL 5
+
+#define MINIMUM_SRB_EXTENSIONS 8
+#define COMPLETION_DELAY 10
+
+//
+// Port driver error logging
+//
+
+#define ERROR_LOG_ENTRY_LENGTH 8
+
+typedef struct _ERROR_LOG_ENTRY {
+ UCHAR PathId;
+ UCHAR TargetId;
+ UCHAR Lun;
+ ULONG ErrorCode;
+ ULONG UniqueId;
+} ERROR_LOG_ENTRY, *PERROR_LOG_ENTRY;
+
+
+//
+// Define global data structures
+//
+
+extern ULONG ScsiPortCount;
+extern FULL_SCSI_REQUEST_BLOCK PrimarySrb;
+extern FULL_SCSI_REQUEST_BLOCK AbortSrb;
+
+#define MAXIMUM_NUMBER_OF_SCSIPORT_OBJECTS 16
+extern PDEVICE_OBJECT ScsiPortDeviceObject[MAXIMUM_NUMBER_OF_SCSIPORT_OBJECTS];
+
+extern PREAD_CAPACITY_DATA ReadCapacityBuffer;
+extern PUCHAR SenseInfoBuffer;
+
+//
+// Support routine.
+//
+
+PIRP
+InitializeIrp(
+ PFULL_SCSI_REQUEST_BLOCK FullSrb,
+ CCHAR MajorFunction,
+ PVOID DeviceObject,
+ PVOID BufferPointer,
+ ULONG BufferSize
+ );
+
+
+ARC_STATUS
+GetAdapterCapabilities(
+ IN PDEVICE_OBJECT PortDeviceObject,
+ OUT PIO_SCSI_CAPABILITIES *PortCapabilities
+ );
+
+ARC_STATUS
+GetInquiryData(
+ IN PDEVICE_OBJECT PortDeviceObject,
+ IN PSCSI_CONFIGURATION_INFO *ConfigInfo
+ );
+
+ARC_STATUS
+ReadDriveCapacity(
+ IN PPARTITION_CONTEXT PartitionContext
+ );
+
+ARC_STATUS
+ScsiClassIoComplete(
+ IN PPARTITION_CONTEXT PartitionContext,
+ IN PIRP Irp,
+ IN PVOID Context
+ );
+
+ARC_STATUS
+SendSrbSynchronous(
+ PPARTITION_CONTEXT PartitionContext,
+ PSCSI_REQUEST_BLOCK Srb,
+ PVOID BufferAddress,
+ ULONG BufferLength,
+ BOOLEAN WriteToDevice
+ );
+
+BOOLEAN
+InterpretSenseInfo(
+ IN PSCSI_REQUEST_BLOCK Srb,
+ OUT ARC_STATUS *Status,
+ PPARTITION_CONTEXT PartitionContext
+ );
+
+VOID
+RetryRequest(
+ PPARTITION_CONTEXT PartitionContext,
+ PIRP Irp
+ );
+
+PIRP
+BuildRequest(
+ IN PPARTITION_CONTEXT PartitionContext,
+ IN PMDL Mdl,
+ IN ULONG LogicalBlockAddress,
+ IN BOOLEAN Operation
+ );
+
+
+//
+// Define the necessary functions to simulate the I/O environment.
+//
+
+#define ExAllocatePool(Type, Size) FwAllocatePool(Size)
+
+#if defined(_MIPS_) || defined(_ALPHA_) || defined(_PPC_)
+#define DbgPrint FwPrint
+#else
+#define DbgPrint BlPrint
+#define PAUSE while (!GET_KEY());
+
+typedef struct _DRIVER_LOOKUP_ENTRY {
+ PCHAR DevicePath;
+ PBL_DEVICE_ENTRY_TABLE DispatchTable;
+} DRIVER_LOOKUP_ENTRY, *PDRIVER_LOOKUP_ENTRY;
+#undef ASSERT
+#define ASSERT( exp ) { \
+ if (!(#exp)) { \
+ BlPrint("ASSERT File: %s line: %lx\n", __FILE__, __LINE__); \
+ PAUSE; \
+ } \
+}
+
+VOID
+ScsiPortExecute(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+#endif
+#define ExFreePool(Size)
+#ifdef IoCallDriver
+#undef IoCallDriver
+#endif
+#define IoCallDriver(DeviceObject, Irp) ( \
+ DeviceObject->CurrentIrp = Irp, \
+ Irp->Tail.Overlay.CurrentStackLocation--, \
+ ScsiPortExecute(DeviceObject, Irp), \
+ Irp->Tail.Overlay.CurrentStackLocation++ )
+#ifdef IoCompleteRequest
+#undef IoCompleteRequest
+#endif
+#define IoCompleteRequest(Irp, Boost) Irp->PendingReturned = FALSE
+#define IoAllocateErrorLogEntry(DeviceObject, Length) NULL
+#define IoWriteErrorLogEntry(Entry)
+#ifdef KeAcquireSpinLock
+#undef KeAcquireSpinLock
+#endif
+#define KeAcquireSpinLock(Lock, Irql)
+#ifdef KeReleaseSpinLock
+#undef KeReleaseSpinLock
+#endif
+#define KeReleaseSpinLock(Lock, Irql)
+#define KiAcquireSpinLock(Lock)
+#define KiReleaseSpinLock(Lock)
+#define KeSynchronizeExecution(InterruptObject, ExecutionRoutine, Context) \
+ (ExecutionRoutine)(Context)
+
+#ifdef KeRaiseIrql
+#undef KeRaiseIrql
+#endif
+#define KeRaiseIrql(NewLevel, OldLevel)
+#ifdef KeLowerIrql
+#undef KeLowerIrql
+#endif
+#define KeLowerIrql(Level)
diff --git a/private/ntos/boot/lib/alpha/alphamem.c b/private/ntos/boot/lib/alpha/alphamem.c
new file mode 100644
index 000000000..c4fd2ab79
--- /dev/null
+++ b/private/ntos/boot/lib/alpha/alphamem.c
@@ -0,0 +1,189 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ alphamem.c
+
+Abstract:
+
+ This module implements the Alpha AXP specific OS loader memory allocation
+ routines.
+
+Author:
+
+ David N. Cutler (davec) 19-May-1991
+ Rod N. Gamache [DEC] 6-July-1993
+
+ Taken mostly from BLMEMORY.C.
+
+Revision History:
+
+--*/
+
+#include "bldr.h"
+
+//
+// Define memory allocation descriptor listhead and heap storage variables.
+//
+
+extern PLOADER_PARAMETER_BLOCK BlLoaderBlock;
+
+ARC_STATUS
+BlAllocateSpecialMemory (
+ IN TYPE_OF_MEMORY MemoryType,
+ IN ULONG BasePage,
+ IN ULONG PageCount,
+ OUT PULONG ActualBase
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates memory and generates one of more memory
+ descriptors to describe the allocated region. The first attempt
+ is to allocate the specified region of memory that is of type
+ LoaderSpecialMemory. If the memory is not available, then the smallest
+ region of 'special' memory that satisfies the request is allocated.
+
+Arguments:
+
+ MemoryType - Supplies the memory type that is to be assigend to
+ the generated descriptor.
+
+ BasePage - Supplies the base page number of the desired region.
+
+ PageCount - Supplies the number of pages required.
+
+ ActualBase - Supplies a pointer to a variable that receives the
+ page number of the allocated region.
+
+Return Value:
+
+ ESUCCESS is returned if an available block of 'special' memory can be
+ allocated. Otherwise, return a unsuccessful status.
+
+--*/
+
+{
+
+ PMEMORY_ALLOCATION_DESCRIPTOR SpecialDescriptor;
+ PMEMORY_ALLOCATION_DESCRIPTOR NextDescriptor;
+ PLIST_ENTRY NextEntry;
+ LONG Offset;
+ ARC_STATUS Status;
+
+ //
+ // Attempt to find a 'special' memory descriptor that encompasses the
+ // specified region or a 'special' memory descriptor that is large
+ // enough to satisfy the request.
+ //
+
+ SpecialDescriptor = NULL;
+ NextEntry = BlLoaderBlock->MemoryDescriptorListHead.Flink;
+ while (NextEntry != &BlLoaderBlock->MemoryDescriptorListHead) {
+ NextDescriptor = CONTAINING_RECORD(NextEntry,
+ MEMORY_ALLOCATION_DESCRIPTOR,
+ ListEntry);
+
+ if (NextDescriptor->MemoryType == LoaderSpecialMemory) {
+ Offset = BasePage - NextDescriptor->BasePage;
+ if ((Offset >= 0) &&
+ (NextDescriptor->PageCount >= (ULONG)(Offset + PageCount))) {
+ Status = BlGenerateDescriptor(NextDescriptor,
+ MemoryType,
+ BasePage,
+ PageCount);
+
+ *ActualBase = BasePage;
+ return Status;
+
+ } else {
+ if (NextDescriptor->PageCount >= PageCount) {
+ if ((SpecialDescriptor == NULL) ||
+ ((SpecialDescriptor != NULL) &&
+ (NextDescriptor->PageCount < SpecialDescriptor->PageCount))) {
+ SpecialDescriptor = NextDescriptor;
+ }
+ }
+ }
+ }
+
+ NextEntry = NextEntry->Flink;
+ }
+
+ //
+ // If a 'special' region that is large enough to satisfy the request was
+ // found, then allocate the space from that descriptor. Otherwise,
+ // return an unsuccessful status.
+ //
+
+ if (SpecialDescriptor != NULL) {
+ *ActualBase = SpecialDescriptor->BasePage;
+ return BlGenerateDescriptor(SpecialDescriptor,
+ MemoryType,
+ SpecialDescriptor->BasePage,
+ PageCount);
+
+ } else {
+ return ENOMEM;
+ }
+}
+
+ARC_STATUS
+BlAllocateAnyMemory (
+ IN TYPE_OF_MEMORY MemoryType,
+ IN ULONG BasePage,
+ IN ULONG PageCount,
+ OUT PULONG ActualBase
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates memory and generates one of more memory
+ descriptors to describe the allocated region. The first attempt
+ is to allocate the specified region of memory that is of type
+ LoaderSpecialMemory. If the memory is not available, then a region
+ of Free memory is requested. Arguments are the same as
+ BlAllocateSpecialMemory and BlAllocateDescriptor.
+
+Arguments:
+
+ MemoryType - Supplies the memory type that is to be assigend to
+ the generated descriptor.
+
+ BasePage - Supplies the base page number of the desired region.
+
+ PageCount - Supplies the number of pages required.
+
+ ActualBase - Supplies a pointer to a variable that receives the
+ page number of the allocated region.
+
+Return Value:
+
+ ESUCCESS is returned if an available block of 'special' memory can be
+ allocated. Otherwise, return a unsuccessful status.
+
+--*/
+
+{
+ ARC_STATUS Status;
+
+ Status = BlAllocateSpecialMemory(MemoryType,
+ BasePage,
+ PageCount,
+ ActualBase);
+
+ if ( Status == ESUCCESS ) {
+ return Status;
+ } else {
+ return ( BlAllocateDescriptor(MemoryType,
+ BasePage,
+ PageCount,
+ ActualBase) );
+ }
+}
diff --git a/private/ntos/boot/lib/alpha/ntsetup.c b/private/ntos/boot/lib/alpha/ntsetup.c
new file mode 100644
index 000000000..ffbe405bd
--- /dev/null
+++ b/private/ntos/boot/lib/alpha/ntsetup.c
@@ -0,0 +1,855 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+Copyright (c) 1992 Digital Equipment Corporation
+
+Module Name:
+
+ ntsetup.c
+
+Abstract:
+
+ This module is the tail-end of the OS loader program. It performs all
+ ALPHA AXP specific allocations and initialize. The OS loader invokes this
+ this routine immediately before calling the loaded kernel image.
+
+Author:
+
+ John Vert (jvert) 20-Jun-1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ John DeRosa [DEC] 22-Apr-1993
+
+ Added code to remove extra ScsiAdapter node from ARC configuration
+ tree.
+
+ Rod Gamache [DEC] 24-Sep-1992
+
+ Add Alpha AXP hooks.
+--*/
+
+#include "bldr.h"
+#include "arc.h"
+#include "fwcallbk.h"
+#include "stdio.h"
+
+#define chartoi(x) \
+ isalnum(x) ? ( ((x) >= '0') && ((x) <= '9') ? (x) - '0' : \
+ tolower((x)) - 'a' + 10 ) : 0
+
+
+//
+// Define macro to round structure size to next 16-byte boundary
+//
+
+#define ROUND_UP(x) ((sizeof(x) + 15) & (~15))
+
+
+//
+// Configuration Data Header
+// The following structure is copied from fw\mips\oli2msft.h
+// NOTE shielint - Somehow, this structure got incorporated into
+// firmware EISA configuration data. We need to know the size of the
+// header and remove it before writing eisa configuration data to
+// registry.
+//
+
+typedef struct _CONFIGURATION_DATA_HEADER {
+ USHORT Version;
+ USHORT Revision;
+ PCHAR Type;
+ PCHAR Vendor;
+ PCHAR ProductName;
+ PCHAR SerialNumber;
+} CONFIGURATION_DATA_HEADER;
+
+#define CONFIGURATION_DATA_HEADER_SIZE sizeof(CONFIGURATION_DATA_HEADER)
+
+//
+// Internal function references
+//
+
+ARC_STATUS
+ReorganizeEisaConfigurationTree(
+ IN PCONFIGURATION_COMPONENT_DATA RootEntry
+ );
+
+ARC_STATUS
+CreateEisaConfigurationData (
+ IN PCONFIGURATION_COMPONENT_DATA RootEntry,
+ OUT PULONG FloppyControllerNode
+ );
+
+ARC_STATUS
+BlAllocateAnyMemory (
+ IN TYPE_OF_MEMORY MemoryType,
+ IN ULONG BasePage,
+ IN ULONG PageCount,
+ OUT PULONG ActualBase
+ );
+
+
+ARC_STATUS
+BlSetupForNt(
+ IN PLOADER_PARAMETER_BLOCK BlLoaderBlock
+ )
+
+/*++
+
+Routine Description:
+
+ This function initializes the MIPS specific kernel data structures
+ required by the NT system.
+
+Arguments:
+
+ BlLoaderBlock - Supplies the address of the loader parameter block.
+
+Return Value:
+
+ ESUCCESS is returned if the setup is successfully complete. Otherwise,
+ an unsuccessful status is returned.
+
+--*/
+
+{
+
+ PCONFIGURATION_COMPONENT_DATA ConfigEntry;
+ ULONG KernelPage;
+ ULONG LinesPerBlock;
+ ULONG LineSize;
+ ARC_STATUS Status;
+ EXTENDED_SYSTEM_INFORMATION SystemInfo;
+ ULONG FirmwareMajorVersion;
+ ULONG FirmwareMinorVersion;
+ CHAR SystemIdName[32] = "";
+ PCHAR SystemId;
+ PCONFIGURATION_COMPONENT ComponentInfo;
+
+ //
+ // Find the System Class component in the ARC Component Database to get
+ // our System Id.
+ //
+
+ ComponentInfo = ArcGetChild(NULL); // Get ARC component info
+
+ while (ComponentInfo != NULL) {
+
+ if ( ComponentInfo->Class == SystemClass &&
+ ComponentInfo->Identifier != NULL) {
+
+ strncat(SystemIdName, ComponentInfo->Identifier, 31);
+ break;
+
+ } else {
+
+ ComponentInfo = ArcGetPeer(ComponentInfo); // Look through all entries
+
+ }
+ }
+
+ //
+ // The SystemIdName should be of the form: mmm-vrName, where
+ // mmm - is the manufacturer
+ // v - is the system variation
+ // r - is the system revision
+ // Name - is the system name
+ //
+
+ SystemId = strchr(SystemIdName, '-');
+ SystemIdName[0] = '\0';
+
+ if ( SystemId ) {
+ SystemId++; // Skip '-'
+ strncat(SystemIdName, SystemId, 31); // Save System Name
+ }
+
+ // Find System entry and check each of its direct child to
+ // look for EisaAdapter.
+ //
+
+ ConfigEntry = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
+ SystemClass,
+ ArcSystem,
+ NULL);
+ if (ConfigEntry) {
+ ConfigEntry = ConfigEntry->Child;
+ }
+
+ while (ConfigEntry) {
+
+ if ((ConfigEntry->ComponentEntry.Class == AdapterClass) &&
+ (ConfigEntry->ComponentEntry.Type == EisaAdapter)) {
+
+ //
+ // Convert EISA format configuration data to our CM_ format.
+ //
+
+ Status = ReorganizeEisaConfigurationTree(ConfigEntry);
+ if (Status != ESUCCESS) {
+ return(Status);
+ }
+ }
+ ConfigEntry = ConfigEntry->Sibling;
+ }
+
+ //
+ // Find the primary data and instruction cache configuration entries, and
+ // compute the fill size and cache size for each cache. These entries MUST
+ // be present on all ARC compliant systems.
+ //
+
+ ConfigEntry = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
+ CacheClass,
+ PrimaryDcache,
+ NULL);
+
+ if (ConfigEntry != NULL) {
+ LinesPerBlock = ConfigEntry->ComponentEntry.Key >> 24;
+ LineSize = 1 << ((ConfigEntry->ComponentEntry.Key >> 16) & 0xff);
+ BlLoaderBlock->u.Alpha.FirstLevelDcacheFillSize = LinesPerBlock * LineSize;
+ BlLoaderBlock->u.Alpha.FirstLevelDcacheSize =
+ 1 << ((ConfigEntry->ComponentEntry.Key & 0xffff) + PAGE_SHIFT);
+
+ } else {
+ return EINVAL;
+ }
+
+ ConfigEntry = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
+ CacheClass,
+ PrimaryIcache,
+ NULL);
+
+ if (ConfigEntry != NULL) {
+ LinesPerBlock = ConfigEntry->ComponentEntry.Key >> 24;
+ LineSize = 1 << ((ConfigEntry->ComponentEntry.Key >> 16) & 0xff);
+ BlLoaderBlock->u.Alpha.FirstLevelIcacheFillSize = LinesPerBlock * LineSize;
+ BlLoaderBlock->u.Alpha.FirstLevelIcacheSize =
+ 1 << ((ConfigEntry->ComponentEntry.Key & 0xffff) + PAGE_SHIFT);
+
+ } else {
+ return EINVAL;
+ }
+
+ //
+ // Find the secondary data and instruction cache configuration entries,
+ // and if present, compute the fill size and cache size for each cache.
+ // These entries are optional, and may or may not, be present.
+ //
+
+ ConfigEntry = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
+ CacheClass,
+ SecondaryCache,
+ NULL);
+
+ if (ConfigEntry != NULL) {
+ LinesPerBlock = ConfigEntry->ComponentEntry.Key >> 24;
+ LineSize = 1 << ((ConfigEntry->ComponentEntry.Key >> 16) & 0xff);
+ BlLoaderBlock->u.Alpha.SecondLevelDcacheFillSize = LinesPerBlock * LineSize;
+ BlLoaderBlock->u.Alpha.SecondLevelDcacheSize =
+ 1 << ((ConfigEntry->ComponentEntry.Key & 0xffff) + PAGE_SHIFT);
+
+ BlLoaderBlock->u.Alpha.SecondLevelIcacheSize = 0;
+ BlLoaderBlock->u.Alpha.SecondLevelIcacheFillSize = 0;
+
+ } else {
+ ConfigEntry = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
+ CacheClass,
+ SecondaryDcache,
+ NULL);
+
+ if (ConfigEntry != NULL) {
+ LinesPerBlock = ConfigEntry->ComponentEntry.Key >> 24;
+ LineSize = 1 << ((ConfigEntry->ComponentEntry.Key >> 16) & 0xff);
+ BlLoaderBlock->u.Alpha.SecondLevelDcacheFillSize = LinesPerBlock * LineSize;
+ BlLoaderBlock->u.Alpha.SecondLevelDcacheSize =
+ 1 << ((ConfigEntry->ComponentEntry.Key & 0xffff) + PAGE_SHIFT);
+
+ ConfigEntry = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
+ CacheClass,
+ SecondaryIcache,
+ NULL);
+
+ if (ConfigEntry != NULL) {
+ LinesPerBlock = ConfigEntry->ComponentEntry.Key >> 24;
+ LineSize = 1 << ((ConfigEntry->ComponentEntry.Key >> 16) & 0xff);
+ BlLoaderBlock->u.Alpha.SecondLevelIcacheFillSize = LinesPerBlock * LineSize;
+ BlLoaderBlock->u.Alpha.SecondLevelIcacheSize =
+ 1 << ((ConfigEntry->ComponentEntry.Key & 0xffff) + PAGE_SHIFT);
+
+ } else {
+ BlLoaderBlock->u.Alpha.SecondLevelIcacheSize = 0;
+ BlLoaderBlock->u.Alpha.SecondLevelIcacheFillSize = 0;
+ }
+
+ } else {
+ BlLoaderBlock->u.Alpha.SecondLevelDcacheSize = 0;
+ BlLoaderBlock->u.Alpha.SecondLevelDcacheFillSize = 0;
+ BlLoaderBlock->u.Alpha.SecondLevelIcacheSize = 0;
+ BlLoaderBlock->u.Alpha.SecondLevelIcacheFillSize = 0;
+ }
+ }
+
+
+ //
+ // Allocate DPC stack pages for the boot processor.
+ //
+
+ Status = BlAllocateAnyMemory(LoaderStartupDpcStack,
+ 0,
+ KERNEL_STACK_SIZE >> PAGE_SHIFT,
+ &KernelPage);
+
+ if (Status != ESUCCESS) {
+ return(Status);
+ }
+
+ BlLoaderBlock->u.Alpha.DpcStack =
+ (KSEG0_BASE | (KernelPage << PAGE_SHIFT)) + KERNEL_STACK_SIZE;
+
+ //
+ // Allocate kernel stack pages for the boot processor idle thread.
+ //
+
+ Status = BlAllocateAnyMemory(LoaderStartupKernelStack,
+ 0,
+ KERNEL_STACK_SIZE >> PAGE_SHIFT,
+ &KernelPage);
+
+ if (Status != ESUCCESS) {
+ return(Status);
+ }
+
+ BlLoaderBlock->KernelStack =
+ (KSEG0_BASE | (KernelPage << PAGE_SHIFT)) + KERNEL_STACK_SIZE;
+
+ //
+ // Allocate panic stack pages for the boot processor.
+ //
+
+ Status = BlAllocateAnyMemory(LoaderStartupPanicStack,
+ 0,
+ KERNEL_STACK_SIZE >> PAGE_SHIFT,
+ &KernelPage);
+
+ if (Status != ESUCCESS) {
+ return(Status);
+ }
+
+ BlLoaderBlock->u.Alpha.PanicStack =
+ (KSEG0_BASE | (KernelPage << PAGE_SHIFT)) + KERNEL_STACK_SIZE;
+
+ //
+ // Allocate and zero a page for the PCR.
+ //
+
+ Status = BlAllocateAnyMemory(LoaderStartupPcrPage,
+ 0,
+ 1,
+ &BlLoaderBlock->u.Alpha.PcrPage);
+
+ if (Status != ESUCCESS) {
+ return(Status);
+ }
+
+ RtlZeroMemory((PVOID)(KSEG0_BASE | (BlLoaderBlock->u.Alpha.PcrPage << PAGE_SHIFT)),
+ PAGE_SIZE);
+
+ //
+ // Allocate and zero four pages for the PDR.
+ //
+
+ Status = BlAllocateAnyMemory(LoaderStartupPdrPage,
+ 0,
+ 4,
+ &BlLoaderBlock->u.Alpha.PdrPage);
+
+ if (Status != ESUCCESS) {
+ return(Status);
+ }
+
+ RtlZeroMemory((PVOID)(KSEG0_BASE | (BlLoaderBlock->u.Alpha.PdrPage << PAGE_SHIFT)),
+ PAGE_SIZE * 4);
+
+ //
+ // The storage for processor control block, the idle thread object, and
+ // the idle thread process object are allocated from the second half of
+ // the exception page. The addresses of these data structures are computed
+ // and stored in the loader parameter block and the memory is zeroed.
+ //
+
+ //
+ // Allocate a page for PRCB, PROCESS, and THREAD.
+ //
+#define OS_DATA_SIZE ((ROUND_UP(KPRCB)+ROUND_UP(EPROCESS)+ROUND_UP(ETHREAD)+\
+ PAGE_SIZE - 1) >> PAGE_SHIFT)
+
+ Status = BlAllocateAnyMemory(LoaderStartupPdrPage,
+ 0,
+ OS_DATA_SIZE,
+ &KernelPage);
+
+ if (Status != ESUCCESS) {
+ return(Status);
+ }
+
+ BlLoaderBlock->Prcb =
+ (KSEG0_BASE | (KernelPage << PAGE_SHIFT));
+
+ RtlZeroMemory((PVOID)BlLoaderBlock->Prcb, OS_DATA_SIZE << PAGE_SHIFT);
+ BlLoaderBlock->Process = BlLoaderBlock->Prcb + ROUND_UP(KPRCB);
+ BlLoaderBlock->Thread = BlLoaderBlock->Process + ROUND_UP(EPROCESS);
+
+ //
+ // Set up LPB fields from Extended System Information
+ //
+
+ // Defaults
+
+ BlLoaderBlock->u.Alpha.PhysicalAddressBits = 32;
+ BlLoaderBlock->u.Alpha.MaximumAddressSpaceNumber = 0;
+ BlLoaderBlock->u.Alpha.SystemSerialNumber[0] = '\0';
+ BlLoaderBlock->u.Alpha.CycleClockPeriod = 0x8000;
+ BlLoaderBlock->u.Alpha.PageSize = PAGE_SIZE;
+
+ //
+ // Read real system info
+ //
+
+ VenReturnExtendedSystemInformation(&SystemInfo);
+
+ BlLoaderBlock->u.Alpha.PhysicalAddressBits =
+ SystemInfo.NumberOfPhysicalAddressBits;
+
+ BlLoaderBlock->u.Alpha.MaximumAddressSpaceNumber =
+ SystemInfo.MaximumAddressSpaceNumber;
+
+ BlLoaderBlock->u.Alpha.PageSize =
+ SystemInfo.ProcessorPageSize;
+
+ BlLoaderBlock->u.Alpha.CycleClockPeriod =
+ SystemInfo.ProcessorCycleCounterPeriod;
+
+ strncat(BlLoaderBlock->u.Alpha.SystemSerialNumber,
+ SystemInfo.SystemSerialNumber,
+ 15);
+
+ BlLoaderBlock->u.Alpha.ProcessorType = SystemInfo.ProcessorId;
+ BlLoaderBlock->u.Alpha.ProcessorRevision = SystemInfo.ProcessorRevision;
+
+ BlLoaderBlock->u.Alpha.SystemType[0] = '\0';
+ strncat( BlLoaderBlock->u.Alpha.SystemType, &SystemIdName[2], 8 );
+ BlLoaderBlock->u.Alpha.SystemVariant = chartoi(SystemIdName[1]);
+ BlLoaderBlock->u.Alpha.SystemRevision = SystemInfo.SystemRevision;
+
+ BlLoaderBlock->u.Alpha.ProcessorType = SystemInfo.ProcessorId;
+ BlLoaderBlock->u.Alpha.ProcessorRevision = SystemInfo.ProcessorRevision;
+
+ BlLoaderBlock->u.Alpha.RestartBlock = SYSTEM_BLOCK->RestartBlock;
+ BlLoaderBlock->u.Alpha.FirmwareRestartAddress =
+ (LONG)SYSTEM_BLOCK->FirmwareVector[HaltRoutine];
+
+ sscanf(SystemInfo.FirmwareVersion, "%lx %lx", &FirmwareMajorVersion,
+ &FirmwareMinorVersion);
+ FirmwareMinorVersion &= 0xFFFF; // Only low 16 bits of minor version
+ FirmwareMajorVersion = FirmwareMajorVersion << 16; // Shift up major version
+ BlLoaderBlock->u.Alpha.FirmwareRevisionId =
+ FirmwareMajorVersion | FirmwareMinorVersion;
+
+ //
+ // Flush all caches.
+ //
+
+ if (SYSTEM_BLOCK->FirmwareVectorLength > (sizeof(PVOID) * FlushAllCachesRoutine)) {
+ ArcFlushAllCaches();
+ }
+
+#if 0
+ DbgSetup(); // Allow for debug setup
+#endif
+
+ return(ESUCCESS);
+}
+
+
+ARC_STATUS
+ReorganizeEisaConfigurationTree(
+ IN PCONFIGURATION_COMPONENT_DATA RootEntry
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sorts the eisa adapter configuration tree based on
+ the slot the component resided in. It also creates a new configuration
+ data for EisaAdapter component to contain ALL the eisa slot and function
+ information. Finally the Eisa tree will be wiped out.
+
+ A difference between the Alpha AXP and MIPS versions of this function
+ is that one of the Alpha AXP machines (Jensen) needs to retain a Floppy
+ disk controller node under the EISA Adapter, so that the NT floppy
+ driver will start properly. So this function does not delete an
+ independent Floppy Disk Controller subtree under the EISA Adapter.
+ Other Alpha AXP machines may need slightly differ code than this. \TBD\.
+
+Arguments:
+
+ RootEntry - Supplies a pointer to a EisaAdapter component. This is
+ the root of Eisa adapter tree.
+
+
+Returns:
+
+ ESUCCESS is returned if the reorganization is successfully complete.
+ Otherwise, an unsuccessful status is returned.
+
+--*/
+{
+
+ PCONFIGURATION_COMPONENT_DATA CurrentEntry, PreviousEntry;
+ PCONFIGURATION_COMPONENT_DATA EntryFound, EntryFoundPrevious;
+ PCONFIGURATION_COMPONENT_DATA AttachedEntry, DetachedList;
+ ULONG FloppyControllerNode;
+ ARC_STATUS Status;
+
+ //
+ // We sort the direct children of EISA adapter tree based on the slot
+ // they reside in. Only the direct children of EISA root need to be
+ // sorted.
+ // Note the "Key" field of CONFIGURATION_COMPONENT contains
+ // EISA slot number.
+ //
+
+ //
+ // First, detach all the children from EISA root.
+ //
+
+ AttachedEntry = NULL; // Child list of Eisa root
+ DetachedList = RootEntry->Child; // Detached child list
+ PreviousEntry = NULL;
+
+ while (DetachedList) {
+
+ //
+ // Find the component with the smallest slot number from detached
+ // list.
+ //
+
+ EntryFound = DetachedList;
+ EntryFoundPrevious = NULL;
+ CurrentEntry = DetachedList->Sibling;
+ PreviousEntry = DetachedList;
+ while (CurrentEntry) {
+ if (CurrentEntry->ComponentEntry.Key <
+ EntryFound->ComponentEntry.Key) {
+ EntryFound = CurrentEntry;
+ EntryFoundPrevious = PreviousEntry;
+ }
+ PreviousEntry = CurrentEntry;
+ CurrentEntry = CurrentEntry->Sibling;
+ }
+
+ //
+ // Remove the component from the detached child list.
+ // If the component is not the head of the detached list, we remove it
+ // by setting its previous entry's sibling to the component's sibling.
+ // Otherwise, we simply update Detach list head to point to the
+ // component's sibling.
+ //
+
+ if (EntryFoundPrevious) {
+ EntryFoundPrevious->Sibling = EntryFound->Sibling;
+ } else {
+ DetachedList = EntryFound->Sibling;
+ }
+
+ //
+ // Attach the component to the child list of Eisa root.
+ //
+
+ if (AttachedEntry) {
+ AttachedEntry->Sibling = EntryFound;
+ } else {
+ RootEntry->Child = EntryFound;
+ }
+ AttachedEntry = EntryFound;
+ AttachedEntry->Sibling = NULL;
+ }
+
+ //
+ // Finally, we traverse the Eisa tree to collect all the Eisa slot
+ // and function information and put it to the configuration data of
+ // Eisa root entry.
+ //
+
+ Status = CreateEisaConfigurationData(RootEntry, &FloppyControllerNode);
+
+ //
+ // Wipe out all the children of EISA tree except for the Floppy
+ // controller node (if present).
+ //
+ // NOTE shielint - For each child component, we should convert its
+ // configuration data from EISA format to our CM_ format.
+ //
+
+ if( FloppyControllerNode != 0 ){
+
+ RootEntry->Child = (PCONFIGURATION_COMPONENT_DATA)FloppyControllerNode;
+ RootEntry->Child->Sibling = NULL;
+ return(Status);
+
+ } else {
+
+ return ESUCCESS;
+
+ }
+
+}
+
+ARC_STATUS
+CreateEisaConfigurationData (
+ IN PCONFIGURATION_COMPONENT_DATA RootEntry,
+ OUT PULONG FloppyControllerNode
+ )
+
+/*++
+
+Routine Description:
+
+ This routine traverses Eisa configuration tree to collect all the
+ slot and function information and attaches it to the configuration data
+ of Eisa RootEntry.
+
+ Note that this routine assumes that the EISA tree has been sorted based
+ on the slot number.
+
+ A difference between the Alpha AXP and MIPS versions of this function
+ is that one of the Alpha AXP machines (Jensen) needs to retain a Floppy
+ disk controller node under the EISA Adapter, so that the NT floppy
+ driver will start properly. So this function does not incorporate
+ independent Floppy Disk Controller configuration data into the collapsed
+ ESIA Adapter node. Other Alpha AXP machines may need different code than
+ this. \TBD\.
+
+Arguments:
+
+ RootEntry - Supplies a pointer to the Eisa configuration
+ component entry.
+
+ FloppyControllerNode - A pointer to a location that returns with either
+ a NULL or the address of an independent floppy disk
+ controller node underneath the EISA Adapter.
+
+Returns:
+
+ ESUCCESS is returned if the new EisaAdapter configuration data is
+ successfully created. Otherwise, an unsuccessful status is returned.
+
+--*/
+{
+ ULONG DataSize, NextSlot = 0, i;
+ PCM_PARTIAL_RESOURCE_LIST Descriptor;
+ PCONFIGURATION_COMPONENT Component;
+ PCONFIGURATION_COMPONENT_DATA CurrentEntry;
+ PUCHAR DataPointer;
+ CM_EISA_SLOT_INFORMATION EmptySlot =
+ {EISA_EMPTY_SLOT, 0, 0, 0, 0, 0, 0, 0};
+
+ //
+ // The default return value is no floppy controller node found.
+ //
+
+ *FloppyControllerNode = (ULONG)NULL;
+
+ //
+ // Remove the configuration data of Eisa Adapter
+ //
+
+ RootEntry->ConfigurationData = NULL;
+ RootEntry->ComponentEntry.ConfigurationDataLength = 0;
+
+ //
+ // If the EISA stree contains valid slot information, i.e.
+ // root has children attaching to it.
+ //
+
+ if (RootEntry->Child) {
+
+ //
+ // First find out how much memory is needed to store EISA config
+ // data.
+ //
+
+ DataSize = sizeof(CM_PARTIAL_RESOURCE_LIST);
+ CurrentEntry = RootEntry->Child;
+
+ while (CurrentEntry) {
+ Component = &CurrentEntry->ComponentEntry;
+ if (CurrentEntry->ConfigurationData) {
+ if (Component->Key > NextSlot) {
+
+ //
+ // If there is any empty slot between current slot
+ // and previous checked slot, we need to count the
+ // space for the empty slots.
+ //
+
+ DataSize += (Component->Key - NextSlot) *
+ sizeof(CM_EISA_SLOT_INFORMATION);
+ }
+ DataSize += Component->ConfigurationDataLength + 1 -
+ CONFIGURATION_DATA_HEADER_SIZE;
+ NextSlot = Component->Key + 1;
+ }
+ CurrentEntry = CurrentEntry->Sibling;
+ }
+
+ //
+ // Allocate memory from heap to hold the EISA configuration data.
+ //
+
+ DataPointer = BlAllocateHeap(DataSize);
+
+ if (DataPointer == NULL) {
+ return ENOMEM;
+ } else {
+ RootEntry->ConfigurationData = DataPointer;
+ RootEntry->ComponentEntry.ConfigurationDataLength = DataSize;
+ }
+
+ //
+ // Create a CM_PARTIAL_RESOURCE_LIST for the new configuration data.
+ //
+
+ Descriptor = (PCM_PARTIAL_RESOURCE_LIST)DataPointer;
+ Descriptor->Version = 0;
+ Descriptor->Revision = 0;
+ Descriptor->Count = 1;
+ Descriptor->PartialDescriptors[0].Type = CmResourceTypeDeviceSpecific;
+ Descriptor->PartialDescriptors[0].ShareDisposition = 0;
+ Descriptor->PartialDescriptors[0].Flags = 0;
+ Descriptor->PartialDescriptors[0].u.DeviceSpecificData.Reserved1 = 0;
+ Descriptor->PartialDescriptors[0].u.DeviceSpecificData.Reserved2 = 0;
+ Descriptor->PartialDescriptors[0].u.DeviceSpecificData.DataSize =
+ DataSize - sizeof(CM_PARTIAL_RESOURCE_LIST);
+
+ //
+ // Visit each child of the RootEntry and copy its ConfigurationData
+ // to the new configuration data area.
+ // N.B. The configuration data includes a slot information and zero
+ // or more function information. The slot information provided
+ // by ARC eisa data does not have "ReturnedCode" as defined in
+ // our CM_EISA_SLOT_INFORMATION. This code will convert the
+ // standard EISA slot information to our CM format.
+ //
+ // N.B. Configuration data for independent floppy controllers
+ // is not incorporated into the collapsed configuration data.
+ //
+
+ CurrentEntry = RootEntry->Child;
+ DataPointer += sizeof(CM_PARTIAL_RESOURCE_LIST);
+ NextSlot = 0;
+
+ while (CurrentEntry) {
+ Component = &CurrentEntry->ComponentEntry;
+
+ //
+ // If this component is a floppy disk controller, remember where
+ // it is and return the value to the caller. Otherwise, if it
+ // has configuration data, process it.
+ //
+
+ if ((Component->Class == ControllerClass) &&
+ (Component->Type == DiskController) &&
+ (CurrentEntry->Child != NULL) &&
+ (CurrentEntry->Child->ComponentEntry.Class == PeripheralClass) &&
+ (CurrentEntry->Child->ComponentEntry.Type == FloppyDiskPeripheral)) {
+
+ *FloppyControllerNode = (ULONG)CurrentEntry;
+
+ } else if (CurrentEntry->ConfigurationData) {
+
+ //
+ // Check if there is any empty slot. If yes, create empty
+ // slot information. Also make sure the config data area is
+ // big enough.
+ //
+
+ if (Component->Key > NextSlot) {
+ for (i = NextSlot; i < CurrentEntry->ComponentEntry.Key; i++ ) {
+ *(PCM_EISA_SLOT_INFORMATION)DataPointer = EmptySlot;
+ DataPointer += sizeof(CM_EISA_SLOT_INFORMATION);
+ }
+ }
+
+ *DataPointer++ = 0; // See comment above
+ RtlMoveMemory( // Skip config data header
+ DataPointer,
+ (PUCHAR)CurrentEntry->ConfigurationData +
+ CONFIGURATION_DATA_HEADER_SIZE,
+ Component->ConfigurationDataLength -
+ CONFIGURATION_DATA_HEADER_SIZE
+ );
+ DataPointer += Component->ConfigurationDataLength -
+ CONFIGURATION_DATA_HEADER_SIZE;
+ NextSlot = Component->Key + 1;
+ }
+ CurrentEntry = CurrentEntry->Sibling;
+ }
+ }
+ return(ESUCCESS);
+}
+
+
+ARC_STATUS
+DeleteARCVolatileTree (
+ IN PCONFIGURATION_COMPONENT Entry
+ )
+
+/*++
+
+Routine Description:
+
+ This function recursively deletes a subtree from the ARC Component
+ Data Structure. The tree is only deleted in volatile storage, i.e.
+ it is not saved back to the ROM.
+
+Arguments:
+
+ Entry - Supplies a pointer to a component which is the top of the
+ tree to be deleted.
+
+Returns:
+
+ ESUCCESS if the subtree was deleted, otherwise an unsuccessful status
+ is returned.
+
+--*/
+{
+ ARC_STATUS Status;
+ PCONFIGURATION_COMPONENT ChildEntry;
+
+ //
+ // Delete the children of this node.
+ //
+
+ while ((ChildEntry = ArcGetChild(Entry)) != NULL) {
+
+ if ((Status = DeleteARCVolatileTree(ChildEntry)) != ESUCCESS) {
+ return (Status);
+ }
+ }
+
+ //
+ // And now delete this node too.
+ //
+
+ return (ArcDeleteComponent(Entry));
+}
+
diff --git a/private/ntos/boot/lib/alpha/palldr.c b/private/ntos/boot/lib/alpha/palldr.c
new file mode 100644
index 000000000..ad6a644d1
--- /dev/null
+++ b/private/ntos/boot/lib/alpha/palldr.c
@@ -0,0 +1,399 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+Copyright (c) 1992 Digital Equipment Corporation
+
+Module Name:
+
+ palldr.c
+
+Abstract:
+
+ This module implements the code to load the PAL image into memory.
+
+Author:
+
+ Rod N. Gamache [DEC] 12-Sep-1992
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+
+--*/
+
+#include "bldr.h"
+#include "stdio.h"
+#include "string.h"
+#include "ntimage.h"
+
+#define ALIGN_PAL 0x10000 // Align PAL on 64KB boundary
+#define ALIGN_PAL_PAGE (ALIGN_PAL >> PAGE_SHIFT)
+
+extern ULONG BlConsoleOutDeviceId;
+extern ULONG BlConsoleInDeviceId;
+
+
+
+ARC_STATUS
+BlLoadPal(
+ IN ULONG DeviceId,
+ IN TYPE_OF_MEMORY MemoryType,
+ IN PCHAR LoadPath,
+ IN USHORT ImageType,
+ OUT PVOID *ImageBase,
+ IN PCHAR LoadDevice
+ )
+
+/*++
+
+Routine Description:
+
+ This routine attempts to load the PAL file from the specified
+ load path.
+
+Arguments:
+
+ DeviceId - Supplies the file table index of the device to load the
+ specified image file from.
+
+ MemoryType - Supplies the type of memory to to be assigned to the
+ allocated memory descriptor.
+
+ LoadPath - Supplies a pointer to string descriptor for the name of
+ the path to the PAL file to load.
+
+ ImageBase - Supplies a pointer to a variable that receives the
+ address of the PAL image base.
+
+ LoadDevice - Supplies a pointer to a string descriptor for the name
+ of the load device.
+
+Return Value:
+
+ ESUCCESS is returned if the specified image file is loaded
+ successfully. Otherwise, an unsuccessful status is returned
+ that describes the reason for failure.
+
+--*/
+
+{
+ CHAR PalName[256];
+ CHAR PalFileName[32];
+ ARC_STATUS Status;
+ CHAR OutputBuffer[256];
+ ULONG Count;
+
+ PIMAGE_NT_HEADERS NtHeaders;
+ PIMAGE_SECTION_HEADER SectionHeader;
+ PMEMORY_ALLOCATION_DESCRIPTOR PalMemoryDescriptor;
+ PMEMORY_ALLOCATION_DESCRIPTOR NewMemoryDescriptor;
+ ULONG StartVA;
+ PVOID PalImageBase;
+ PVOID NewImageBase;
+ ULONG PalPage;
+ ULONG PageCount;
+ ULONG NewPageCount;
+ ULONG ActualBase;
+ ULONG FreePageCount;
+
+ Status = BlGeneratePalName( PalFileName );
+
+ if ( Status != ESUCCESS ) {
+ return Status;
+ }
+
+ sprintf(PalName, "%s%s", LoadPath, PalFileName);
+
+ BlOutputLoadMessage(LoadDevice, PalName);
+ Status = BlLoadImage(DeviceId,
+ MemoryType,
+ PalName,
+ ImageType,
+ ImageBase);
+
+ if ( Status != ESUCCESS ) {
+ return Status;
+ }
+
+ NtHeaders = RtlImageNtHeader(*ImageBase);
+
+ if (!NtHeaders) {
+ return EBADF;
+ }
+
+ //
+ // Compute the address of the section headers and calculate the
+ // starting virtual address for the image.
+ //
+
+ SectionHeader =
+ (PIMAGE_SECTION_HEADER)((ULONG)NtHeaders + sizeof(ULONG) +
+ sizeof(IMAGE_FILE_HEADER) + NtHeaders->FileHeader.SizeOfOptionalHeader);
+
+ StartVA = SectionHeader->VirtualAddress;
+
+ PalImageBase = (PVOID)((ULONG)*ImageBase & ~KSEG0_BASE);
+ PalPage = (ULONG)PalImageBase >> PAGE_SHIFT;
+
+ //
+ // Check if PAL is aligned correctly. If not, then allocate a new
+ // memory descriptor and copy the PAL image to an aligned buffer.
+ //
+
+ //
+ // Find the memory descriptor for the PAL image that was loaded,
+ // and find the size (in pages) of that loaded image.
+ //
+
+ PalMemoryDescriptor = BlFindMemoryDescriptor(PalPage);
+
+ PageCount = PalMemoryDescriptor->PageCount;
+
+ if ( ((ULONG)PalImageBase & (ALIGN_PAL - 1)) != 0 ) {
+
+ //
+ // Calculate new size + alignment requirement, and allocate a new
+ // memory descriptor. Use any physical address starting from zero.
+ //
+
+ NewPageCount = PageCount + ALIGN_PAL_PAGE - 1;
+
+ //
+ // Allocate a memory descriptor.
+ //
+
+ Status = BlAllocateDescriptor(MemoryType,
+ 0,
+ NewPageCount,
+ &ActualBase);
+
+ if (Status != ESUCCESS) {
+ return Status;
+ }
+
+ NewMemoryDescriptor = BlFindMemoryDescriptor(ActualBase);
+
+ //
+ // Align PAL to 64KB boundary. First, return any free memory at front
+ // of PAL image.
+ //
+ if ( (ActualBase & (ALIGN_PAL_PAGE - 1)) != 0 ) {
+
+ NewMemoryDescriptor = BlFindMemoryDescriptor(ActualBase);
+
+ FreePageCount = ALIGN_PAL_PAGE - (ActualBase & (ALIGN_PAL_PAGE-1));
+
+ BlGenerateDescriptor(NewMemoryDescriptor,
+ MemoryFree,
+ ActualBase,
+ FreePageCount);
+
+ //
+ // Adjust base and pagecount
+ //
+
+ ActualBase = (ActualBase + (ALIGN_PAL - 1 >> PAGE_SHIFT)) &
+ ~(ALIGN_PAL_PAGE - 1);
+
+ NewPageCount -= FreePageCount;
+ }
+
+ //
+ // Compute the new image base.
+ //
+
+ NewImageBase = (PVOID)(KSEG0_BASE | (ActualBase << PAGE_SHIFT));
+
+ //
+ // Copy PAL from the loaded memory block to the new memory block.
+ //
+
+ PalImageBase = (PVOID)(KSEG0_BASE | (ULONG)PalImageBase);
+ RtlMoveMemory(NewImageBase,
+ (PVOID)((PUCHAR)PalImageBase + StartVA),
+ (PageCount << PAGE_SHIFT) - StartVA);
+
+
+ //
+ // Free the original memory descriptor.
+ //
+
+ BlGenerateDescriptor(PalMemoryDescriptor,
+ MemoryFree,
+ PalMemoryDescriptor->BasePage,
+ PalMemoryDescriptor->PageCount);
+
+ *ImageBase = NewImageBase;
+
+ //
+ // Return any blocks free at the end of the new image section.
+ //
+
+ FreePageCount = NewPageCount - PageCount + (StartVA >> PAGE_SHIFT);
+
+ if ( FreePageCount ) {
+
+ BlGenerateDescriptor(NewMemoryDescriptor,
+ MemoryFree,
+ ActualBase + PageCount - (StartVA >> PAGE_SHIFT),
+ FreePageCount);
+
+ }
+
+ } else if ( StartVA != 0 ) {
+
+ //
+ // Move the image down to the start of the memory descriptor
+ //
+
+ PalImageBase = (PVOID)(KSEG0_BASE | (ULONG)PalImageBase);
+
+ RtlMoveMemory(PalImageBase,
+ (PVOID)((PUCHAR)PalImageBase + StartVA),
+ (PageCount << PAGE_SHIFT) - StartVA);
+
+ //
+ // Return any blocks free at the end of the image.
+ //
+
+ FreePageCount = StartVA >> PAGE_SHIFT;
+
+ if ( FreePageCount ) {
+
+ BlGenerateDescriptor(PalMemoryDescriptor,
+ MemoryFree,
+ PalPage + PageCount - (StartVA >> PAGE_SHIFT),
+ FreePageCount);
+ }
+
+ }
+
+ return ESUCCESS;
+
+}
+
+
+ARC_STATUS
+BlGeneratePalName(
+ IN PCHAR PalFileName
+ )
+/*++
+
+Routine Description:
+
+ This routine generates the name of the correct PAL file for the current
+ system.
+
+Arguments:
+
+ PalFileName - Supplies a pointer to string for the name of the PAL file
+ that is generated.
+
+Return Value:
+
+ ESUCCESS is returned if the specified PAL file name is generated.
+ Otherwise, an unsuccessful status is returned that describes the
+ reason for failure.
+
+--*/
+
+{
+ CHAR ProcessorName[32] = "";
+ PCHAR ProcessorId;
+ PCONFIGURATION_COMPONENT ComponentInfo;
+ ARC_STATUS Status;
+ ULONG Max = 7;
+
+ //
+ // Get the Processor Id Name from the ARC component Database.
+ //
+
+ ComponentInfo = ArcGetChild(NULL); // Get ARC component info
+
+ while (ComponentInfo != NULL) {
+
+ if ( ComponentInfo->Class == SystemClass &&
+ ComponentInfo->Identifier != NULL ) {
+
+ ComponentInfo = ArcGetChild(ComponentInfo); // Go Down in tree
+
+ } else if ( ComponentInfo->Class == ProcessorClass &&
+ ComponentInfo->Type == CentralProcessor &&
+ ComponentInfo->Identifier != NULL) {
+
+ strncat(ProcessorName, ComponentInfo->Identifier, 31);
+ break;
+
+ } else {
+
+ ComponentInfo = ArcGetPeer(ComponentInfo); // Look through all entries
+
+ }
+ }
+
+ //
+ // On older firmware:
+ //
+ // The ProcessorName is of the form: mmm-rName, where:
+ // mmm - is the manufacturer of the processor chip
+ // r - is the revision of the processor chip
+ // Name - is the name of the processor chip
+ //
+ // E.G. DEC-321064
+ //
+ // On newer firmware:
+ //
+ // The ProcessorName is of the form: mmm-Name-r, where:
+ // mmm - is the manufacturer of the processor chip
+ // r - is the revision of the processor chip
+ // Name - is the name of the processor chip
+ //
+ // E.G. DEC-21064-3
+ //
+
+ ProcessorId = strchr(ProcessorName, '-');
+
+ //
+ // Load the PAL image into memory. The image will be of the
+ // form <LoadPath>\Axxxxx.PAL. Try loading A<processorname>.PAL.
+ // If that fails, then try AlphaAXP.pal.
+ //
+
+ //
+ // Generate the full path name for the PAL image and load it into
+ // memory.
+ //
+
+ Status = EBADF;
+ if ( ProcessorId ) {
+ CHAR ProcessorIdName[8] = "";
+ PCHAR RevisionId;
+ ULONG Max = 7;
+
+ ProcessorId++; // Skip the hyphen
+
+ //
+ // Check for new ProcessorId format, look for the revision id
+ // after the processor id.
+ //
+ RevisionId = strchr(ProcessorId, '-');
+
+ if ( RevisionId ) {
+ *RevisionId = '\0'; // Terminate the processor id
+ RevisionId++; // Skip the hyphen
+ strncat(ProcessorIdName, RevisionId, 2); // Copy Revision Id
+ Max = Max - strlen( ProcessorIdName );
+ }
+
+ strncat(ProcessorIdName, ProcessorId, Max); // Copy Processor Id
+ sprintf(PalFileName, "A%s.PAL", ProcessorIdName);
+
+ Status = ESUCCESS;
+ }
+
+ return Status;
+}
+
diff --git a/private/ntos/boot/lib/alpha/sources b/private/ntos/boot/lib/alpha/sources
new file mode 100644
index 000000000..b44f99353
--- /dev/null
+++ b/private/ntos/boot/lib/alpha/sources
@@ -0,0 +1,4 @@
+ALPHA_SOURCES=alpha\stubs.c \
+ alpha\ntsetup.c \
+ alpha\palldr.c \
+ alpha\alphamem.c
diff --git a/private/ntos/boot/lib/alpha/stubs.c b/private/ntos/boot/lib/alpha/stubs.c
new file mode 100644
index 000000000..15e9815db
--- /dev/null
+++ b/private/ntos/boot/lib/alpha/stubs.c
@@ -0,0 +1,244 @@
+/*++
+
+Module Name:
+
+ stubs.c
+
+Abstract:
+
+ This module implements stub routines for the boot code.
+
+Author:
+
+ David N. Cutler (davec) 7-Nov-1990
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+ 8-July-1992 John DeRosa [DEC]
+
+ Modified for Alpha/Jensen.
+
+
+--*/
+
+#include "ntos.h"
+#include "arc.h"
+#include "stdio.h"
+
+
+extern ULONG BlConsoleOutDeviceId;
+
+
+VOID
+KeBugCheck (
+ IN ULONG BugCheckCode
+ )
+
+/*++
+
+Routine Description:
+
+ This function crashes the system in a controlled manner.
+
+ Alpha/Jensen firmware will try to run the Monitor instead of the
+ kernel debugger.
+
+Arguments:
+
+ BugCheckCode - Supplies the reason for the bug check.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG Count;
+ UCHAR Buffer[512];
+
+ //
+ // Print out the bug check code and break.
+ //
+
+ sprintf( Buffer, "\n*** BugCheck (%lx) ***\n\n", BugCheckCode );
+ ArcWrite(BlConsoleOutDeviceId,
+ Buffer,
+ strlen(Buffer),
+ &Count);
+
+ while(TRUE) {
+ DbgBreakPoint();
+ };
+
+ return;
+}
+
+
+BOOLEAN
+KeFreezeExecution (
+ IN PKTRAP_FRAME TrapFrame,
+ IN PKEXCEPTION_FRAME ExceptionFrame
+ )
+
+/*++
+
+Routine Description:
+
+ This function freezes the execution of all other processors in the host
+ configuration and then returns to the caller. It is intended for use by
+ the kernel debugger.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Previous IRQL.
+
+--*/
+
+{
+
+ return HIGH_LEVEL;
+}
+
+VOID
+KeThawExecution (
+ IN KIRQL Irql
+ )
+
+/*++
+
+Routine Description:
+
+ This function unfreezes the execution of all other processors in the host
+ configuration and then returns to the caller. It is intended for use by
+ the kernel debugger.
+
+Arguments:
+
+ Irql - Supplies the level that the IRQL is to be lowered to after having
+ unfrozen the execution of all other processors.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ return;
+}
+
+PVOID
+MmDbgReadCheck (
+ IN PVOID VirtualAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the phyiscal address for a virtual address
+ which is valid (mapped) for read access.
+
+Arguments:
+
+ VirtualAddress - Supplies the virtual address to check.
+
+Return Value:
+
+ Returns NULL if the address is not valid or readable, otherwise
+ returns the physical address of the corresponding virtual address.
+
+--*/
+
+{
+
+ return VirtualAddress;
+}
+
+PVOID
+MmDbgTranslatePhysicalAddress (
+ IN PHYSICAL_ADDRESS PhysicalAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the phyiscal address for a physical address
+ which is valid (mapped).
+
+Arguments:
+
+ PhysicalAddress - Supplies the physical address to check.
+
+Return Value:
+
+ Returns NULL if the address is not valid or readable, otherwise
+ returns the physical address of the corresponding virtual address.
+
+--*/
+
+{
+
+ return (PVOID)PhysicalAddress.LowPart;
+}
+
+PVOID
+MmDbgWriteCheck (
+ IN PVOID VirtualAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the phyiscal address for a virtual address
+ which is valid (mapped) for write access.
+
+Arguments:
+
+ VirtualAddress - Supplies the virtual address to check.
+
+Return Value:
+
+ Returns NULL if the address is not valid or readable, otherwise
+ returns the physical address of the corresponding virtual address.
+
+--*/
+
+{
+ return VirtualAddress;
+}
+
+VOID
+RtlAssert(
+ IN PVOID FailedAssertion,
+ IN PVOID FileName,
+ IN ULONG LineNumber,
+ IN PCHAR Message OPTIONAL
+ )
+{
+ ULONG Count;
+ UCHAR Buffer[512];
+
+ sprintf( Buffer, "\n*** Assertion failed\n");
+ ArcWrite(BlConsoleOutDeviceId,
+ Buffer,
+ strlen(Buffer),
+ &Count);
+
+ while (TRUE) {
+ DbgBreakPoint();
+ }
+
+}
diff --git a/private/ntos/boot/lib/arcdisk.c b/private/ntos/boot/lib/arcdisk.c
new file mode 100644
index 000000000..33602577f
--- /dev/null
+++ b/private/ntos/boot/lib/arcdisk.c
@@ -0,0 +1,240 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ arcdisk.c
+
+Abstract:
+
+ Provides the routines for collecting the disk information for all the ARC
+ disks visible in the ARC environment.
+
+Author:
+
+ John Vert (jvert) 3-Nov-1993
+
+Revision History:
+
+--*/
+#include "bootlib.h"
+
+BOOLEAN
+BlpEnumerateDisks(
+ IN PCONFIGURATION_COMPONENT_DATA ConfigData
+ );
+
+
+ARC_STATUS
+BlGetArcDiskInformation(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Enumerates the ARC disks present in the system and collects the identifying disk
+ information from each one.
+
+Arguments:
+
+ LoaderBlock - Supplies a pointer to the LoaderBlock
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PARC_DISK_INFORMATION DiskInfo;
+
+ DiskInfo = BlAllocateHeap(sizeof(ARC_DISK_INFORMATION));
+ if (DiskInfo==NULL) {
+ return(ENOMEM);
+ }
+
+ InitializeListHead(&DiskInfo->DiskSignatures);
+
+ BlLoaderBlock->ArcDiskInformation = DiskInfo;
+
+ BlSearchConfigTree(BlLoaderBlock->ConfigurationRoot,
+ PeripheralClass,
+ DiskPeripheral,
+ (ULONG)-1,
+ BlpEnumerateDisks);
+
+ return(ESUCCESS);
+
+}
+
+
+BOOLEAN
+BlpEnumerateDisks(
+ IN PCONFIGURATION_COMPONENT_DATA ConfigData
+ )
+
+/*++
+
+Routine Description:
+
+ Callback routine for enumerating the disks in the ARC firmware tree. It
+ reads all the necessary information from the disk to uniquely identify
+ it.
+
+Arguments:
+
+ ConfigData - Supplies a pointer to the disk's ARC component data.
+
+Return Value:
+
+ TRUE - continue searching
+
+ FALSE - stop searching tree.
+
+--*/
+
+{
+ CHAR DiskName[100];
+
+ BlGetPathnameFromComponent(ConfigData, DiskName);
+
+ return(BlReadSignature(DiskName,FALSE));
+}
+
+
+BOOLEAN
+BlReadSignature(
+ IN PCHAR DiskName,
+ IN BOOLEAN IsCdRom
+ )
+
+/*++
+
+Routine Description:
+
+ Given an ARC disk name, reads the MBR and adds its signature to the list of
+ disks.
+
+Arguments:
+
+ Diskname - Supplies the name of the disk.
+
+ IsCdRom - Indicates whether the disk is a CD-ROM.
+
+Return Value:
+
+ TRUE - Success
+
+ FALSE - Failure
+
+--*/
+
+{
+ PARC_DISK_SIGNATURE Signature;
+ UCHAR SectorBuffer[2048+256];
+ UCHAR Partition[100];
+ ULONG DiskId;
+ ULONG Status;
+ LARGE_INTEGER SeekValue;
+ PUCHAR Sector;
+ ULONG i;
+ ULONG Sum;
+ ULONG Count;
+ ULONG SectorSize;
+
+ if (IsCdRom) {
+ SectorSize = 2048;
+ } else {
+ SectorSize = 512;
+ }
+
+ Signature = BlAllocateHeap(sizeof(ARC_DISK_SIGNATURE));
+ if (Signature==NULL) {
+ return(FALSE);
+ }
+
+ Signature->ArcName = BlAllocateHeap(strlen(DiskName)+2);
+ if (Signature->ArcName==NULL) {
+ return(FALSE);
+ }
+#if defined(_i386_)
+ //
+ // NTDETECT creates an "eisa(0)..." arcname for detected
+ // BIOS disks on an EISA machine. Change this to "multi(0)..."
+ // in order to be consistent with the rest of the system
+ // (particularly the arcname in boot.ini)
+ //
+ if (_strnicmp(DiskName,"eisa",4)==0) {
+ strcpy(Signature->ArcName,"multi");
+ strcpy(Partition,"multi");
+ strcat(Signature->ArcName,DiskName+4);
+ strcat(Partition,DiskName+4);
+ } else {
+ strcpy(Signature->ArcName, DiskName);
+ strcpy(Partition, DiskName);
+ }
+#else
+ strcpy(Signature->ArcName, DiskName);
+ strcpy(Partition, DiskName);
+#endif
+
+ strcat(Partition, "partition(0)");
+
+ Status = ArcOpen(Partition, ArcOpenReadOnly, &DiskId);
+ if (Status != ESUCCESS) {
+ return(TRUE);
+ }
+
+ //
+ // Read in the first sector
+ //
+ Sector = ALIGN_BUFFER(SectorBuffer);
+ if (IsCdRom) {
+ //
+ // For a CD-ROM, the interesting data starts at 0x8000.
+ //
+ SeekValue.QuadPart = 0x8000;
+ } else {
+ SeekValue.QuadPart = 0;
+ }
+ Status = ArcSeek(DiskId, &SeekValue, SeekAbsolute);
+ if (Status == ESUCCESS) {
+ Status = ArcRead(DiskId,
+ Sector,
+ SectorSize,
+ &Count);
+ }
+ ArcClose(DiskId);
+ if (Status != ESUCCESS) {
+ return(TRUE);
+ }
+
+ //
+ // Check to see whether this disk has a valid partition table signature or not.
+ //
+ if (((PUSHORT)Sector)[BOOT_SIGNATURE_OFFSET] != BOOT_RECORD_SIGNATURE) {
+ Signature->ValidPartitionTable = FALSE;
+ } else {
+ Signature->ValidPartitionTable = TRUE;
+ }
+
+ Signature->Signature = ((PULONG)Sector)[PARTITION_TABLE_OFFSET/2-1];
+
+ //
+ // compute the checksum
+ //
+ Sum = 0;
+ for (i=0; i<(SectorSize/4); i++) {
+ Sum += ((PULONG)Sector)[i];
+ }
+ Signature->CheckSum = ~Sum + 1;
+
+ InsertHeadList(&BlLoaderBlock->ArcDiskInformation->DiskSignatures,
+ &Signature->ListEntry);
+
+ return(TRUE);
+
+}
diff --git a/private/ntos/boot/lib/blbind.c b/private/ntos/boot/lib/blbind.c
new file mode 100644
index 000000000..79cfb2bee
--- /dev/null
+++ b/private/ntos/boot/lib/blbind.c
@@ -0,0 +1,836 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ blbind.c
+
+Abstract:
+
+ This module contains the code that implements the funtions required
+ to relocate an image and bind DLL entry points.
+
+Author:
+
+ David N. Cutler (davec) 21-May-1991
+
+Revision History:
+
+--*/
+
+#include "bldr.h"
+#include "ctype.h"
+#include "string.h"
+
+//
+// Special linker-defined symbols. osloader_EXPORTS is the RVA of the
+// export table in the osloader.exe image.
+// header is the base address of the osloader image.
+//
+// This allows the OsLoader to export entry points for SCSI miniport drivers.
+//
+#if i386
+extern ULONG OsLoaderBase,OsLoaderExports;
+#endif
+
+extern ULONG BlConsoleOutDeviceId;
+
+
+//
+// Define local procedure prototypes.
+//
+
+ARC_STATUS
+BlpBindImportName (
+ IN PVOID DllBase,
+ IN PVOID ImageBase,
+ IN PIMAGE_THUNK_DATA ThunkEntry,
+ IN PIMAGE_EXPORT_DIRECTORY ExportDirectory,
+ IN ULONG ExportSize,
+ IN BOOLEAN SnapForwarder
+ );
+
+BOOLEAN
+BlpCompareDllName (
+ IN PCHAR Name,
+ IN PUNICODE_STRING UnicodeString
+ );
+
+ARC_STATUS
+BlpScanImportAddressTable(
+ IN PVOID DllBase,
+ IN PVOID ImageBase,
+ IN PIMAGE_THUNK_DATA ThunkTable
+ );
+
+
+ARC_STATUS
+BlAllocateDataTableEntry (
+ IN PCHAR BaseDllName,
+ IN PCHAR FullDllName,
+ IN PVOID Base,
+ OUT PLDR_DATA_TABLE_ENTRY *AllocatedEntry
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates a data table entry for the specified image
+ and inserts the entry in the loaded module list.
+
+Arguments:
+
+ BaseDllName - Supplies a pointer to a zero terminated base DLL name.
+
+ FullDllName - Supplies a pointer to a zero terminated full DLL name.
+
+ Base - Supplies a pointer to the base of the DLL image.
+
+ AllocatedEntry - Supplies a pointer to a variable that receives a
+ pointer to the allocated data table entry.
+
+Return Value:
+
+ ESUCCESS is returned if a data table entry is allocated. Otherwise,
+ return a unsuccessful status.
+
+--*/
+
+{
+
+ PWSTR Buffer;
+ PLDR_DATA_TABLE_ENTRY DataTableEntry;
+ PIMAGE_NT_HEADERS NtHeaders;
+ USHORT Length;
+
+ //
+ // Allocate a data table entry.
+ //
+
+ DataTableEntry =
+ (PLDR_DATA_TABLE_ENTRY)BlAllocateHeap(sizeof(LDR_DATA_TABLE_ENTRY));
+
+ if (DataTableEntry == NULL) {
+ return ENOMEM;
+ }
+
+ //
+ // Initialize the address of the DLL image file header and the entry
+ // point address.
+ //
+
+ NtHeaders = RtlImageNtHeader(Base);
+ DataTableEntry->DllBase = Base;
+ DataTableEntry->SizeOfImage = NtHeaders->OptionalHeader.SizeOfImage;
+ DataTableEntry->EntryPoint = (PVOID)((ULONG)Base +
+ NtHeaders->OptionalHeader.AddressOfEntryPoint);
+ DataTableEntry->SectionPointer = 0;
+ DataTableEntry->CheckSum = NtHeaders->OptionalHeader.CheckSum;
+
+ //
+ // Compute the length of the base DLL name, allocate a buffer to hold
+ // the name, copy the name into the buffer, and initialize the base
+ // DLL string descriptor.
+ //
+
+ Length = (USHORT)(strlen(BaseDllName) * sizeof(WCHAR));
+ Buffer = (PWSTR)BlAllocateHeap(Length);
+ if (Buffer == NULL) {
+ return ENOMEM;
+ }
+
+ DataTableEntry->BaseDllName.Length = Length;
+ DataTableEntry->BaseDllName.MaximumLength = Length;
+ DataTableEntry->BaseDllName.Buffer = Buffer;
+ while (*BaseDllName != 0) {
+ *Buffer++ = *BaseDllName++;
+ }
+
+ //
+ // Compute the length of the full DLL name, allocate a buffer to hold
+ // the name, copy the name into the buffer, and initialize the full
+ // DLL string descriptor.
+ //
+
+ Length = (USHORT)(strlen(FullDllName) * sizeof(WCHAR));
+ Buffer = (PWSTR)BlAllocateHeap(Length);
+ if (Buffer == NULL) {
+ return ENOMEM;
+ }
+
+ DataTableEntry->FullDllName.Length = Length;
+ DataTableEntry->FullDllName.MaximumLength = Length;
+ DataTableEntry->FullDllName.Buffer = Buffer;
+ while (*FullDllName != 0) {
+ *Buffer++ = *FullDllName++;
+ }
+
+ //
+ // Initialize the flags, load count, and insert the data table entry
+ // in the loaded module list.
+ //
+
+ DataTableEntry->Flags = LDRP_ENTRY_PROCESSED;
+ DataTableEntry->LoadCount = 1;
+ InsertTailList(&BlLoaderBlock->LoadOrderListHead,
+ &DataTableEntry->InLoadOrderLinks);
+
+ *AllocatedEntry = DataTableEntry;
+ return ESUCCESS;
+}
+
+BOOLEAN
+BlCheckForLoadedDll (
+ IN PCHAR DllName,
+ OUT PLDR_DATA_TABLE_ENTRY *FoundEntry
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans the loaded DLL list to determine if the specified
+ DLL has already been loaded. If the DLL has already been loaded, then
+ its reference count is incremented.
+
+Arguments:
+
+ DllName - Supplies a pointer to a null terminated DLL name.
+
+ FoundEntry - Supplies a pointer to a variable that receives a pointer
+ to the matching data table entry.
+
+Return Value:
+
+ If the specified DLL has already been loaded, then TRUE is returned.
+ Otherwise, FALSE is returned.
+
+--*/
+
+{
+
+ PLDR_DATA_TABLE_ENTRY DataTableEntry;
+ PLIST_ENTRY NextEntry;
+
+ //
+ // Scan the loaded data table list to determine if the specified DLL
+ // has already been loaded.
+ //
+
+ NextEntry = BlLoaderBlock->LoadOrderListHead.Flink;
+ while (NextEntry != &BlLoaderBlock->LoadOrderListHead) {
+ DataTableEntry = CONTAINING_RECORD(NextEntry,
+ LDR_DATA_TABLE_ENTRY,
+ InLoadOrderLinks);
+
+ if (BlpCompareDllName(DllName, &DataTableEntry->BaseDllName) != FALSE) {
+ *FoundEntry = DataTableEntry;
+ DataTableEntry->LoadCount += 1;
+ return TRUE;
+ }
+
+ NextEntry = NextEntry->Flink;
+ }
+
+ return FALSE;
+}
+
+ARC_STATUS
+BlScanImportDescriptorTable (
+ IN ULONG DeviceId,
+ IN PCHAR DeviceName,
+ IN PCHAR DirectoryPath,
+ IN PLDR_DATA_TABLE_ENTRY ScanEntry
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans the import descriptor table for the specified image
+ file and loads each DLL that is referenced.
+
+Arguments:
+
+ DeviceId - Suuplies the device id form which any referenced DLLs
+ are to be loaded from.
+
+ DeviceName - Supplies the name of the device from which any
+ referenced DLLs are to be loaded from.
+
+ DirectoryPath - Supplies a pointer to a zero terminated directory
+ path name.
+
+ DataTableEntry - Supplies a pointer to the data table entry for the
+ image whose import table is to be scanned.
+
+Return Value:
+
+ ESUCCESS is returned in the scan is successful. Otherwise, return an
+ unsuccessful status.
+
+--*/
+
+{
+
+ PLDR_DATA_TABLE_ENTRY DataTableEntry;
+ CHAR FullDllName[256];
+ PVOID Base;
+ PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor;
+ ULONG ImportTableSize;
+ ARC_STATUS Status;
+ PSZ ImportName;
+
+ //
+ // Locate the import table in the image specified by the data table entry.
+ //
+
+ ImportDescriptor =
+ (PIMAGE_IMPORT_DESCRIPTOR)RtlImageDirectoryEntryToData(ScanEntry->DllBase,
+ TRUE,
+ IMAGE_DIRECTORY_ENTRY_IMPORT,
+ &ImportTableSize);
+
+ //
+ // If the image has an import directory, then scan the import table and
+ // load the specified DLLs.
+ //
+
+ if (ImportDescriptor != NULL) {
+ while ((ImportDescriptor->Name != 0) &&
+ (ImportDescriptor->FirstThunk != NULL)) {
+
+ //
+ // Change the name from an RVA to a VA.
+ //
+
+ ImportName = (PSZ)((ULONG)ScanEntry->DllBase + ImportDescriptor->Name);
+
+ //
+ // If the DLL references itself, then skip the import entry.
+ //
+
+ if (BlpCompareDllName((PCHAR)ImportName,
+ &ScanEntry->BaseDllName) == FALSE) {
+
+ //
+ // If the DLL is not already loaded, then load the DLL and
+ // scan its import table.
+ //
+
+ if (BlCheckForLoadedDll((PCHAR)ImportName,
+ &DataTableEntry) == FALSE) {
+
+ strcpy(&FullDllName[0], DirectoryPath);
+ strcat(&FullDllName[0], (PCHAR)ImportName);
+ BlOutputLoadMessage(DeviceName, &FullDllName[0]);
+ Status = BlLoadImage(DeviceId,
+ LoaderHalCode,
+ &FullDllName[0],
+ TARGET_IMAGE,
+ &Base);
+
+ if (Status != ESUCCESS) {
+ return Status;
+ }
+
+ Status =
+ BlAllocateDataTableEntry((PCHAR)ImportName,
+ &FullDllName[0],
+ Base,
+ &DataTableEntry);
+
+ if (Status != ESUCCESS) {
+ return Status;
+ }
+
+ Status = BlScanImportDescriptorTable(DeviceId,
+ DeviceName,
+ DirectoryPath,
+ DataTableEntry);
+
+ if (Status != ESUCCESS) {
+ return Status;
+ }
+ }
+
+ //
+ // Scan the import address table and snap links.
+ //
+
+ Status = BlpScanImportAddressTable(DataTableEntry->DllBase,
+ ScanEntry->DllBase,
+ (PIMAGE_THUNK_DATA)((ULONG)ScanEntry->DllBase +
+ (ULONG)ImportDescriptor->FirstThunk));
+
+ if (Status != ESUCCESS) {
+ return Status;
+ }
+ }
+
+ ImportDescriptor += 1;
+ }
+ }
+
+ return ESUCCESS;
+}
+
+ARC_STATUS
+BlpBindImportName (
+ IN PVOID DllBase,
+ IN PVOID ImageBase,
+ IN PIMAGE_THUNK_DATA ThunkEntry,
+ IN PIMAGE_EXPORT_DIRECTORY ExportDirectory,
+ IN ULONG ExportSize,
+ IN BOOLEAN SnapForwarder
+ )
+
+/*++
+
+Routine Description:
+
+ This routine binds an import table reference with an exported entry
+ point and fills in the thunk data.
+
+Arguments:
+
+ DllBase - Supplies the base address of the DLL image that contains
+ the export directory. On x86 systems, a NULL DllBase binds the
+ import table reference to the OsLoader's exported entry points.
+
+ ImageBase - Supplies the base address of the image that contains
+ the import thunk table.
+
+ ThunkEntry - Supplies a pointer to a thunk table entry.
+
+ ExportDirectory - Supplies a pointer to the export directory of the
+ DLL from which references are to be resolved.
+
+ SnapForwarder - determine if the snap is for a forwarder, and therefore
+ Address of Data is already setup.
+
+Return Value:
+
+ ESUCCESS is returned if the specified thunk is bound. Otherwise, an
+ return an unsuccessful status.
+
+--*/
+
+{
+
+ PULONG FunctionTable;
+ LONG High;
+ ULONG HintIndex;
+ LONG Low;
+ LONG Middle;
+ PULONG NameTable;
+ ULONG Ordinal;
+ PUSHORT OrdinalTable;
+ LONG Result;
+
+#if i386
+ if(DllBase == NULL) {
+ DllBase = (PVOID)OsLoaderBase;
+ }
+#endif
+
+ //
+ // If the reference is by ordinal, then compute the ordinal number.
+ // Otherwise, lookup the import name in the export directory.
+ //
+
+ if (IMAGE_SNAP_BY_ORDINAL(ThunkEntry->u1.Ordinal) && !SnapForwarder) {
+
+ //
+ // Compute the ordinal.
+ //
+
+ Ordinal = (ULONG)(IMAGE_ORDINAL(ThunkEntry->u1.Ordinal) - ExportDirectory->Base);
+
+ } else {
+
+ if (!SnapForwarder) {
+ //
+ // Change AddressOfData from an RVA to a VA.
+ //
+
+ ThunkEntry->u1.AddressOfData = (PIMAGE_IMPORT_BY_NAME)((ULONG)ImageBase +
+ (ULONG)ThunkEntry->u1.AddressOfData);
+ }
+
+ //
+ // Lookup the import name in the export table to determine the
+ // ordinal.
+ //
+
+ NameTable = (PULONG)((ULONG)DllBase +
+ (ULONG)ExportDirectory->AddressOfNames);
+
+ OrdinalTable = (PUSHORT)((ULONG)DllBase +
+ (ULONG)ExportDirectory->AddressOfNameOrdinals);
+
+ //
+ // If the hint index is within the limits of the name table and the
+ // import and export names match, then the ordinal number can be
+ // obtained directly from the ordinal table. Otherwise, the name
+ // table must be searched for the specified name.
+ //
+
+ HintIndex = ThunkEntry->u1.AddressOfData->Hint;
+ if ((HintIndex < ExportDirectory->NumberOfNames) &&
+ (strcmp(&ThunkEntry->u1.AddressOfData->Name[0],
+ (PCHAR)((ULONG)DllBase + NameTable[HintIndex])) == 0)) {
+
+ //
+ // Get the ordinal number from the ordinal table.
+ //
+
+ Ordinal = OrdinalTable[HintIndex];
+
+ } else {
+
+ //
+ // Lookup the import name in the name table using a binary search.
+ //
+
+ Low = 0;
+ High = ExportDirectory->NumberOfNames - 1;
+ while (High >= Low) {
+
+ //
+ // Compute the next probe index and compare the import name
+ // with the export name entry.
+ //
+
+ Middle = (Low + High) >> 1;
+ Result = strcmp(&ThunkEntry->u1.AddressOfData->Name[0],
+ (PCHAR)((ULONG)DllBase + NameTable[Middle]));
+
+ if (Result < 0) {
+ High = Middle - 1;
+
+ } else if (Result > 0) {
+ Low = Middle + 1;
+
+ } else {
+ break;
+ }
+ }
+
+ //
+ // If the high index is less than the low index, then a matching
+ // table entry was not found. Otherwise, get the ordinal number
+ // from the ordinal table.
+ //
+
+ if (High < Low) {
+ return EINVAL;
+
+ } else {
+ Ordinal = OrdinalTable[Middle];
+ }
+ }
+ }
+
+ //
+ // If the ordinal number is valid, then bind the import reference and
+ // return success. Otherwise, return an unsuccessful status.
+ //
+
+
+ if (Ordinal >= ExportDirectory->NumberOfFunctions) {
+ return EINVAL;
+ } else {
+ FunctionTable = (PULONG)((ULONG)DllBase + (ULONG)ExportDirectory->AddressOfFunctions);
+ ThunkEntry->u1.Function = (PULONG)((ULONG)DllBase + FunctionTable[Ordinal]);
+
+ //
+ // Check for a forwarder.
+ //
+ if ( ((ULONG)ThunkEntry->u1.Function > (ULONG)ExportDirectory) &&
+ ((ULONG)ThunkEntry->u1.Function < ((ULONG)ExportDirectory + ExportSize)) ) {
+ CHAR ForwardDllName[10];
+ PLDR_DATA_TABLE_ENTRY DataTableEntry;
+ ULONG TargetExportSize;
+ PIMAGE_EXPORT_DIRECTORY TargetExportDirectory;
+
+ RtlCopyMemory(ForwardDllName,
+ (PCHAR)ThunkEntry->u1.Function,
+ sizeof(ForwardDllName));
+ *strchr(ForwardDllName,'.') = '\0';
+ if (!BlCheckForLoadedDll(ForwardDllName,&DataTableEntry)) {
+ //
+ // Should load the referenced DLL here, just return failure for now.
+ //
+
+ return(EINVAL);
+ }
+ TargetExportDirectory = (PIMAGE_EXPORT_DIRECTORY)
+ RtlImageDirectoryEntryToData(DataTableEntry->DllBase,
+ TRUE,
+ IMAGE_DIRECTORY_ENTRY_EXPORT,
+ &TargetExportSize);
+ if (TargetExportDirectory) {
+
+ IMAGE_THUNK_DATA thunkData;
+ PIMAGE_IMPORT_BY_NAME addressOfData;
+ UCHAR Buffer[128];
+ ULONG length;
+ PCHAR ImportName;
+ ARC_STATUS Status;
+
+ ImportName = strchr((PCHAR)ThunkEntry->u1.Function, '.') + 1;
+ addressOfData = (PIMAGE_IMPORT_BY_NAME)Buffer;
+ RtlCopyMemory(&addressOfData->Name[0], ImportName, strlen(ImportName)+1);
+ addressOfData->Hint = 0;
+ thunkData.u1.AddressOfData = addressOfData;
+ Status = BlpBindImportName(DataTableEntry->DllBase,
+ ImageBase,
+ &thunkData,
+ TargetExportDirectory,
+ TargetExportSize,
+ TRUE);
+ ThunkEntry->u1 = thunkData.u1;
+ return(Status);
+ } else {
+ return(EINVAL);
+ }
+ }
+ return ESUCCESS;
+ }
+}
+
+BOOLEAN
+BlpCompareDllName (
+ IN PCHAR DllName,
+ IN PUNICODE_STRING UnicodeString
+ )
+
+/*++
+
+Routine Description:
+
+ This routine compares a zero terminated character string with a unicode
+ string. The UnicodeString's extension is ignored.
+
+Arguments:
+
+ DllName - Supplies a pointer to a null terminated DLL name.
+
+ UnicodeString - Supplies a pointer to a Unicode string descriptor.
+
+Return Value:
+
+ If the specified name matches the Unicode name, then TRUE is returned.
+ Otherwise, FALSE is returned.
+
+--*/
+
+{
+
+ PWSTR Buffer;
+ ULONG Index;
+ ULONG Length;
+
+ //
+ // Compute the length of the DLL Name and compare with the length of
+ // the Unicode name. If the DLL Name is longer, the strings are not
+ // equal.
+ //
+
+ Length = strlen(DllName);
+ if ((Length * sizeof(WCHAR)) > UnicodeString->Length) {
+ return FALSE;
+ }
+
+ //
+ // Compare the two strings case insensitive, ignoring the Unicode
+ // string's extension.
+ //
+
+ Buffer = UnicodeString->Buffer;
+ for (Index = 0; Index < Length; Index += 1) {
+ if (toupper(*DllName) != toupper((CHAR)*Buffer)) {
+ return FALSE;
+ }
+
+ DllName += 1;
+ Buffer += 1;
+ }
+ if ((UnicodeString->Length == Length * sizeof(WCHAR)) ||
+ (*Buffer == L'.')) {
+ //
+ // Strings match exactly or match up until the UnicodeString's extension.
+ //
+ return(TRUE);
+ }
+ return FALSE;
+}
+
+ARC_STATUS
+BlpScanImportAddressTable(
+ IN PVOID DllBase,
+ IN PVOID ImageBase,
+ IN PIMAGE_THUNK_DATA ThunkTable
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans the import address table for the specified image
+ file and snaps each reference.
+
+Arguments:
+
+ DllBase - Supplies the base address of the specified DLL.
+ If NULL, then references in the image's import table are to
+ be resolved against the osloader's export table.
+
+ ImageBase - Supplies the base address of the image.
+
+ ThunkTable - Supplies a pointer to the import thunk table.
+
+Return Value:
+
+ ESUCCESS is returned in the scan is successful. Otherwise, return an
+ unsuccessful status.
+
+--*/
+
+{
+
+ PIMAGE_EXPORT_DIRECTORY ExportDirectory;
+ ULONG ExportTableSize;
+ ARC_STATUS Status;
+
+ //
+ // Locate the export table in the image specified by the DLL base
+ // address.
+ //
+
+#if i386
+ if (DllBase == NULL) {
+ ExportDirectory = (PIMAGE_EXPORT_DIRECTORY)OsLoaderExports;
+ } else {
+ ExportDirectory =
+ (PIMAGE_EXPORT_DIRECTORY)RtlImageDirectoryEntryToData(DllBase,
+ TRUE,
+ IMAGE_DIRECTORY_ENTRY_EXPORT,
+ &ExportTableSize);
+ }
+#else
+ ExportDirectory =
+ (PIMAGE_EXPORT_DIRECTORY)RtlImageDirectoryEntryToData(DllBase,
+ TRUE,
+ IMAGE_DIRECTORY_ENTRY_EXPORT,
+ &ExportTableSize);
+#endif
+ if (ExportDirectory == NULL) {
+ return EBADF;
+ }
+
+ //
+ // Scan the thunk table and bind each import reference.
+ //
+
+ while (ThunkTable->u1.AddressOfData != NULL) {
+ Status = BlpBindImportName(DllBase,
+ ImageBase,
+ ThunkTable++,
+ ExportDirectory,
+ ExportTableSize,
+ FALSE);
+ if (Status != ESUCCESS) {
+ return Status;
+ }
+ }
+
+ return ESUCCESS;
+}
+
+
+ARC_STATUS
+BlScanOsloaderBoundImportTable (
+ IN PLDR_DATA_TABLE_ENTRY ScanEntry
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans the import descriptor table for the specified image
+ file and loads each DLL that is referenced.
+
+Arguments:
+
+ DataTableEntry - Supplies a pointer to the data table entry for the
+ image whose import table is to be scanned.
+
+Return Value:
+
+ ESUCCESS is returned in the scan is successful. Otherwise, return an
+ unsuccessful status.
+
+--*/
+
+{
+
+ PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor;
+ ULONG ImportTableSize;
+ ARC_STATUS Status;
+ PSZ ImportName;
+
+ //
+ // Locate the import table in the image specified by the data table entry.
+ //
+
+ ImportDescriptor =
+ (PIMAGE_IMPORT_DESCRIPTOR)RtlImageDirectoryEntryToData(ScanEntry->DllBase,
+ TRUE,
+ IMAGE_DIRECTORY_ENTRY_IMPORT,
+ &ImportTableSize);
+
+ //
+ // If the image has an import directory, then scan the import table.
+ //
+
+ if (ImportDescriptor != NULL) {
+ while ((ImportDescriptor->Name != 0) &&
+ (ImportDescriptor->FirstThunk != NULL)) {
+
+ //
+ // Change the name from an RVA to a VA.
+ //
+
+ ImportName = (PSZ)((ULONG)ScanEntry->DllBase + ImportDescriptor->Name);
+
+ //
+ // If the DLL references itself, then skip the import entry.
+ //
+
+ if (BlpCompareDllName((PCHAR)ImportName,
+ &ScanEntry->BaseDllName) == FALSE) {
+
+ //
+ // Scan the import address table and snap links.
+ //
+
+ Status = BlpScanImportAddressTable(NULL,
+ ScanEntry->DllBase,
+ (PIMAGE_THUNK_DATA)((ULONG)ScanEntry->DllBase +
+ (ULONG)ImportDescriptor->FirstThunk));
+
+ if (Status != ESUCCESS) {
+ return Status;
+ }
+ }
+
+ ImportDescriptor += 1;
+ }
+ }
+
+ return ESUCCESS;
+}
diff --git a/private/ntos/boot/lib/blconfig.c b/private/ntos/boot/lib/blconfig.c
new file mode 100644
index 000000000..9ca933821
--- /dev/null
+++ b/private/ntos/boot/lib/blconfig.c
@@ -0,0 +1,939 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ blconfig.c
+
+Abstract:
+
+ This module implements the OS loader configuration initialization.
+
+Author:
+
+ David N. Cutler (davec) 9-Sep-1991
+
+Revision History:
+
+--*/
+#include "bootlib.h"
+#include "stdio.h"
+#include "stdlib.h"
+
+
+ULONG
+BlMatchToken (
+ IN PCHAR TokenValue,
+ IN PCHAR TokenArray[]
+ );
+
+PCHAR
+BlGetNextToken (
+ IN PCHAR TokenString,
+ OUT PCHAR OutputToken,
+ OUT PULONG UnitNumber
+ );
+
+//
+// Define types of adapters that can be booted from.
+//
+
+typedef enum _ADAPTER_TYPES {
+ AdapterEisa,
+ AdapterScsi,
+ AdapterMulti,
+ AdapterMaximum
+ } ADAPTER_TYPES;
+
+//
+// Define type of controllers that can be booted from.
+//
+
+typedef enum _CONTROLLER_TYPES {
+ ControllerDisk,
+ ControllerCdrom,
+ ControllerMaximum
+ } CONTROLLER_TYPES;
+
+//
+// Define type of peripheral that can be booted from.
+//
+
+typedef enum _PERIPHERAL_TYPES {
+ PeripheralRigidDisk,
+ PeripheralFloppyDisk,
+#if defined(ELTORITO)
+ PeripheralElTorito,
+#endif
+ PeripheralMaximum
+ } PERIPHERAL_TYPES;
+
+//
+// Define the ARC pathname mnemonics.
+//
+
+PCHAR MnemonicTable[] = {
+ "arc",
+ "cpu",
+ "fpu",
+ "pic",
+ "pdc",
+ "sic",
+ "sdc",
+ "sc",
+ "eisa",
+ "tc",
+ "scsi",
+ "dti",
+ "multi",
+ "disk",
+ "tape",
+ "cdrom",
+ "worm",
+ "serial",
+ "net",
+ "video",
+ "par",
+ "point",
+ "key",
+ "audio",
+ "other",
+ "rdisk",
+ "fdisk",
+ "tape",
+ "modem",
+ "monitor",
+ "print",
+ "pointer",
+ "keyboard",
+ "term",
+ "other"
+ };
+
+PCHAR BlAdapterTypes[AdapterMaximum + 1] = {"eisa","scsi","multi",NULL};
+PCHAR BlControllerTypes[ControllerMaximum + 1] = {"disk","cdrom",NULL};
+#if defined(ELTORITO)
+PCHAR BlPeripheralTypes[PeripheralMaximum + 1] = {"rdisk","fdisk","cdrom",NULL};
+#else
+PCHAR BlPeripheralTypes[PeripheralMaximum + 1] = {"rdisk","fdisk",NULL};
+#endif
+
+
+ARC_STATUS
+BlConfigurationInitialize (
+ IN PCONFIGURATION_COMPONENT Parent,
+ IN PCONFIGURATION_COMPONENT_DATA ParentEntry
+ )
+
+/*++
+
+Routine Description:
+
+ This routine traverses the firmware configuration tree from the specified
+ parent entry and constructs the corresponding NT configuration tree.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ ESUCCESS is returned if the initialization is successful. Otherwise,
+ an unsuccessful status that describes the error is returned.
+
+--*/
+
+{
+
+ PCONFIGURATION_COMPONENT Child;
+ PCONFIGURATION_COMPONENT_DATA ChildEntry;
+ PCHAR ConfigurationData;
+ PCONFIGURATION_COMPONENT_DATA PreviousSibling;
+ PCONFIGURATION_COMPONENT Sibling;
+ PCONFIGURATION_COMPONENT_DATA SiblingEntry;
+ ARC_STATUS Status;
+
+ //
+ // Traverse the child configuration tree and allocate, initialize, and
+ // construct the corresponding NT configuration tree.
+ //
+
+ Child = ArcGetChild(Parent);
+ while (Child != NULL) {
+
+ //
+ // Allocate an entry of the appropriate size to hold the child
+ // configuration information.
+ //
+
+ ChildEntry = (PCONFIGURATION_COMPONENT_DATA)BlAllocateHeap(
+ sizeof(CONFIGURATION_COMPONENT_DATA) +
+ Child->IdentifierLength +
+ Child->ConfigurationDataLength);
+
+ if (ChildEntry == NULL) {
+ return ENOMEM;
+ }
+
+ //
+ // Initialize the tree pointers and copy the component data.
+ //
+
+ if (ParentEntry == NULL) {
+ BlLoaderBlock->ConfigurationRoot = ChildEntry;
+
+ } else {
+ ParentEntry->Child = ChildEntry;
+ }
+
+ ChildEntry->Parent = ParentEntry;
+ ChildEntry->Sibling = NULL;
+ ChildEntry->Child = NULL;
+ RtlMoveMemory((PVOID)&ChildEntry->ComponentEntry,
+ (PVOID)Child,
+ sizeof(CONFIGURATION_COMPONENT));
+
+ ConfigurationData = (PCHAR)(ChildEntry + 1);
+
+ //
+ // If configuration data is specified, then copy the configuration
+ // data.
+ //
+
+ if (Child->ConfigurationDataLength != 0) {
+ ChildEntry->ConfigurationData = (PVOID)ConfigurationData;
+ Status = ArcGetConfigurationData((PVOID)ConfigurationData,
+ Child);
+
+ if (Status != ESUCCESS) {
+ return Status;
+ }
+
+ ConfigurationData += Child->ConfigurationDataLength;
+
+ } else {
+ ChildEntry->ConfigurationData = NULL;
+ }
+
+ //
+ // If identifier data is specified, then copy the identifier data.
+ //
+
+ if (Child->IdentifierLength !=0) {
+ ChildEntry->ComponentEntry.Identifier = ConfigurationData;
+ RtlMoveMemory((PVOID)ConfigurationData,
+ (PVOID)Child->Identifier,
+ Child->IdentifierLength);
+
+ } else {
+ ChildEntry->ComponentEntry.Identifier = NULL;
+ }
+
+ //
+ // Traverse the sibling configuration tree and allocate, initialize,
+ // and construct the corresponding NT configuration tree.
+ //
+
+ PreviousSibling = ChildEntry;
+ Sibling = ArcGetPeer(Child);
+ while (Sibling != NULL) {
+
+ //
+ // Allocate an entry of the appropriate size to hold the sibling
+ // configuration information.
+ //
+
+ SiblingEntry = (PCONFIGURATION_COMPONENT_DATA)BlAllocateHeap(
+ sizeof(CONFIGURATION_COMPONENT_DATA) +
+ Sibling->IdentifierLength +
+ Sibling->ConfigurationDataLength);
+
+ if (SiblingEntry == NULL) {
+ return ENOMEM;
+ }
+
+ //
+ // Initialize the tree pointers and copy the component data.
+ //
+
+ SiblingEntry->Parent = ParentEntry;
+ SiblingEntry->Sibling = NULL;
+ ChildEntry->Child = NULL;
+ RtlMoveMemory((PVOID)&SiblingEntry->ComponentEntry,
+ (PVOID)Sibling,
+ sizeof(CONFIGURATION_COMPONENT));
+
+ ConfigurationData = (PCHAR)(SiblingEntry + 1);
+
+ //
+ // If configuration data is specified, then copy the configuration
+ // data.
+ //
+
+ if (Sibling->ConfigurationDataLength != 0) {
+ SiblingEntry->ConfigurationData = (PVOID)ConfigurationData;
+ Status = ArcGetConfigurationData((PVOID)ConfigurationData,
+ Sibling);
+
+ if (Status != ESUCCESS) {
+ return Status;
+ }
+
+ ConfigurationData += Sibling->ConfigurationDataLength;
+
+ } else {
+ SiblingEntry->ConfigurationData = NULL;
+ }
+
+ //
+ // If identifier data is specified, then copy the identifier data.
+ //
+
+ if (Sibling->IdentifierLength !=0) {
+ SiblingEntry->ComponentEntry.Identifier = ConfigurationData;
+ RtlMoveMemory((PVOID)ConfigurationData,
+ (PVOID)Sibling->Identifier,
+ Sibling->IdentifierLength);
+
+ } else {
+ SiblingEntry->ComponentEntry.Identifier = NULL;
+ }
+
+ //
+ // If the sibling has a child, then generate the tree for the
+ // child.
+ //
+
+ if (ArcGetChild(Sibling) != NULL) {
+ Status = BlConfigurationInitialize(Sibling, SiblingEntry);
+ if (Status != ESUCCESS) {
+ return Status;
+ }
+ }
+
+ //
+ // Set new sibling pointers and get the next sibling tree entry.
+ //
+
+ PreviousSibling->Sibling = SiblingEntry;
+ PreviousSibling = SiblingEntry;
+ Sibling = ArcGetPeer(Sibling);
+ }
+
+ //
+ // Set new parent pointers and get the next child tree entry.
+ //
+
+ Parent = Child;
+ ParentEntry = ChildEntry;
+ Child = ArcGetChild(Child);
+ }
+
+ return ESUCCESS;
+}
+
+
+
+BOOLEAN
+BlSearchConfigTree(
+ IN PCONFIGURATION_COMPONENT_DATA Node,
+ IN CONFIGURATION_CLASS Class,
+ IN CONFIGURATION_TYPE Type,
+ IN ULONG Key,
+ IN PNODE_CALLBACK CallbackRoutine
+ )
+/*++
+
+Routine Description:
+
+ Conduct a depth-first search of the firmware configuration tree starting
+ at a given node, looking for nodes that match a given class and type.
+ When a matching node is found, call a callback routine.
+
+Arguments:
+
+ CurrentNode - node at which to begin the search.
+
+ Class - configuration class to match, or -1 to match any class
+
+ Type - configuration type to match, or -1 to match any class
+
+ Key - key to match, or -1 to match any key
+
+ FoundRoutine - pointer to a routine to be called when a node whose
+ class and type match the class and type passed in is located.
+ The routine takes a pointer to the configuration node and must
+ return a boolean indicating whether to continue with the traversal.
+
+Return Value:
+
+ FALSE if the caller should abandon the search.
+--*/
+{
+ PCONFIGURATION_COMPONENT_DATA Child;
+
+ do {
+ if (Child = Node->Child) {
+ if (!BlSearchConfigTree(Child,
+ Class,
+ Type,
+ Key,
+ CallbackRoutine)) {
+ return(FALSE);
+ }
+ }
+
+ if (((Class == -1) || (Node->ComponentEntry.Class == Class))
+ &&((Type == -1) || (Node->ComponentEntry.Type == Type))
+ &&((Key == (ULONG)-1) || (Node->ComponentEntry.Key == Key))) {
+
+ if (!CallbackRoutine(Node)) {
+ return(FALSE);
+ }
+ }
+
+ Node = Node->Sibling;
+
+ } while ( Node != NULL );
+
+ return(TRUE);
+}
+
+
+VOID
+BlGetPathnameFromComponent(
+ IN PCONFIGURATION_COMPONENT_DATA Component,
+ OUT PCHAR ArcName
+ )
+
+/*++
+
+Routine Description:
+
+ This function builds an ARC pathname for the specified component.
+
+Arguments:
+
+ Component - Supplies a pointer to a configuration component.
+
+ ArcName - Returns the ARC name of the specified component. Caller must
+ provide a large enough buffer.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ if (Component->Parent != NULL) {
+ BlGetPathnameFromComponent(Component->Parent,ArcName);
+ //
+ // append our segment to the arcname
+ //
+ sprintf(ArcName+strlen(ArcName),
+ "%s(%d)",
+ MnemonicTable[Component->ComponentEntry.Type],
+ Component->ComponentEntry.Key);
+ } else {
+ //
+ // We are the parent, initialize the string and return
+ //
+ ArcName[0] = '\0';
+ }
+
+ return;
+}
+
+
+BOOLEAN
+BlGetPathMnemonicKey(
+ IN PCHAR OpenPath,
+ IN PCHAR Mnemonic,
+ IN PULONG Key
+ )
+
+/*++
+
+Routine Description:
+
+ This routine looks for the given Mnemonic in OpenPath.
+ If Mnemonic is a component of the path, then it converts the key
+ value to an integer wich is returned in Key.
+
+Arguments:
+
+ OpenPath - Pointer to a string that contains an ARC pathname.
+
+ Mnemonic - Pointer to a string that contains a ARC Mnemonic
+
+ Key - Pointer to a ULONG where the Key value is stored.
+
+
+Return Value:
+
+ FALSE if mnemonic is found in path and a valid key is converted.
+ TRUE otherwise.
+
+--*/
+
+{
+
+ PCHAR Tmp;
+ CHAR Digits[4];
+ ULONG i;
+ CHAR String[16];
+
+ //
+ // Construct a string of the form ")mnemonic("
+ //
+ String[0]=')';
+ for(i=1;*Mnemonic;i++) {
+ String[i] = * Mnemonic++;
+ }
+ String[i++]='(';
+ String[i]='\0';
+
+ if ((Tmp=strstr(OpenPath,&String[1])) == NULL) {
+ return TRUE;
+ }
+
+ if (Tmp != OpenPath) {
+ if ((Tmp=strstr(OpenPath,String)) == NULL) {
+ return TRUE;
+ }
+ } else {
+ i--;
+ }
+ //
+ // skip the mnemonic and convert the value in between parentheses to integer
+ //
+ Tmp+=i;
+ for (i=0;i<3;i++) {
+ if (*Tmp == ')') {
+ Digits[i] = '\0';
+ break;
+ }
+ Digits[i] = *Tmp++;
+ }
+ Digits[i]='\0';
+ *Key = atoi(Digits);
+ return FALSE;
+}
+
+
+ARC_STATUS
+BlGenerateDeviceNames (
+ IN PCHAR ArcDeviceName,
+ OUT PCHAR ArcCanonicalName,
+ OUT OPTIONAL PCHAR NtDevicePrefix
+ )
+
+/*++
+
+Routine Description:
+
+ This routine generates an NT device name prefix and a canonical ARC
+ device name from an ARC device name.
+
+Arguments:
+
+ ArcDeviceName - Supplies a pointer to a zero terminated ARC device
+ name.
+
+ ArcCanonicalName - Supplies a pointer to a variable that receives the
+ ARC canonical device name.
+
+ NtDevicePrefix - If present, supplies a pointer to a variable that receives the
+ NT device name prefix.
+
+Return Value:
+
+ ESUCCESS is returned if an NT device name prefix and the canonical
+ ARC device name are successfully generated from the ARC device name.
+ Otherwise, an invalid argument status is returned.
+
+--*/
+
+{
+
+ CHAR AdapterPath[64];
+ CHAR AdapterName[32];
+ ULONG AdapterNumber;
+ CHAR ControllerName[32];
+ ULONG ControllerNumber;
+ ULONG MatchIndex;
+ CHAR PartitionName[32];
+ ULONG PartitionNumber;
+ CHAR PeripheralName[32];
+ ULONG PeripheralNumber;
+ CHAR TokenValue[32];
+
+ //
+ // Get the adapter and make sure it is valid.
+ //
+
+ ArcDeviceName = BlGetNextToken(ArcDeviceName,
+ &AdapterName[0],
+ &AdapterNumber);
+
+ if (ArcDeviceName == NULL) {
+ return EINVAL;
+ }
+
+ MatchIndex = BlMatchToken(&AdapterName[0], &BlAdapterTypes[0]);
+ if (MatchIndex == AdapterMaximum) {
+ return EINVAL;
+ }
+
+ sprintf(AdapterPath, "%s(%d)", AdapterName, AdapterNumber);
+
+ //
+ // The next token is either another adapter or a controller. ARC
+ // names can have multiple adapters. (e.g. "multi(0)scsi(0)disk(0)...")
+ // Iterate until we find a token that is not an adapter.
+ //
+
+ do {
+ ArcDeviceName = BlGetNextToken(ArcDeviceName,
+ &ControllerName[0],
+ &ControllerNumber);
+
+ if (ArcDeviceName == NULL) {
+ return EINVAL;
+ }
+
+ MatchIndex = BlMatchToken(&ControllerName[0], &BlAdapterTypes[0]);
+ if (MatchIndex == AdapterMaximum) {
+ //
+ // If it is not an adapter, we must have reached the last
+ // adapter in the name. Fall through to the controller logic.
+ //
+ break;
+ } else {
+ //
+ // We have found another adapter, add it to
+ // the canonical adapter path
+ //
+ sprintf(AdapterPath+strlen(AdapterPath),
+ "%s(%d)",
+ ControllerName,
+ ControllerNumber);
+ }
+
+ } while ( TRUE );
+
+ MatchIndex = BlMatchToken(&ControllerName[0], &BlControllerTypes[0]);
+ switch (MatchIndex) {
+
+ //
+ // Cdrom controller.
+ //
+ // Get the peripheral name and make sure it is valid.
+ //
+
+ case ControllerCdrom:
+ ArcDeviceName = BlGetNextToken(ArcDeviceName,
+ &PeripheralName[0],
+ &PeripheralNumber);
+
+ if (ArcDeviceName == NULL) {
+ return EINVAL;
+ }
+
+ if (_stricmp(&PeripheralName[0], "fdisk") != 0) {
+ return EINVAL;
+ }
+
+ ArcDeviceName = BlGetNextToken(ArcDeviceName,
+ &TokenValue[0],
+ &MatchIndex);
+
+ if (ArcDeviceName != NULL) {
+ return EINVAL;
+ }
+
+ sprintf(ArcCanonicalName,
+ "%s%s(%d)%s(%d)",
+ &AdapterPath[0],
+ &ControllerName[0],
+ ControllerNumber,
+ &PeripheralName[0],
+ PeripheralNumber);
+
+ if (ARGUMENT_PRESENT(NtDevicePrefix)) {
+ strcpy(NtDevicePrefix, "\\Device\\CDRom");
+ }
+ break;
+
+ //
+ // Disk controller.
+ //
+ // Get the peripheral and make sure it is valid.
+ //
+
+ case ControllerDisk:
+ ArcDeviceName = BlGetNextToken(ArcDeviceName,
+ &PeripheralName[0],
+ &PeripheralNumber);
+
+ if (ArcDeviceName == NULL) {
+ return EINVAL;
+ }
+
+ MatchIndex = BlMatchToken(&PeripheralName[0], &BlPeripheralTypes[0]);
+ switch (MatchIndex) {
+
+ //
+ // Rigid Disk.
+ //
+ // If a partition is specified, then parse the partition number.
+ //
+
+ case PeripheralRigidDisk:
+ ArcDeviceName = BlGetNextToken(ArcDeviceName,
+ &PartitionName[0],
+ &PartitionNumber);
+
+ if (ArcDeviceName == NULL) {
+ strcpy(&PartitionName[0], "partition");
+ PartitionNumber = 1;
+
+ } else {
+ if (_stricmp(&PartitionName[0], "partition") != 0) {
+ return EINVAL;
+ }
+
+ ArcDeviceName = BlGetNextToken(ArcDeviceName,
+ &TokenValue[0],
+ &MatchIndex);
+
+ if (ArcDeviceName != NULL) {
+ return EINVAL;
+ }
+ }
+
+ sprintf(ArcCanonicalName,
+ "%s%s(%d)%s(%d)%s(%d)",
+ &AdapterPath[0],
+ &ControllerName[0],
+ ControllerNumber,
+ &PeripheralName[0],
+ PeripheralNumber,
+ &PartitionName[0],
+ PartitionNumber);
+
+ if (ARGUMENT_PRESENT(NtDevicePrefix)) {
+ strcpy(NtDevicePrefix, "\\Device\\Harddisk");
+ }
+ break;
+
+ //
+ // Floppy disk.
+ //
+
+ case PeripheralFloppyDisk:
+ ArcDeviceName = BlGetNextToken(ArcDeviceName,
+ &TokenValue[0],
+ &MatchIndex);
+
+ if (ArcDeviceName != NULL) {
+ return EINVAL;
+ }
+
+ sprintf(ArcCanonicalName,
+ "%s%s(%d)%s(%d)",
+ &AdapterPath[0],
+ &ControllerName[0],
+ ControllerNumber,
+ &PeripheralName[0],
+ PeripheralNumber);
+
+ if (ARGUMENT_PRESENT(NtDevicePrefix)) {
+ strcpy(NtDevicePrefix, "\\Device\\Floppy");
+ }
+ break;
+
+#if defined(ELTORITO)
+ //
+ // El Torito CD-ROM.
+ //
+
+ case PeripheralElTorito:
+ ArcDeviceName = BlGetNextToken(ArcDeviceName,
+ &TokenValue[0],
+ &MatchIndex);
+
+ if (ArcDeviceName != NULL) {
+ return EINVAL;
+ }
+
+ sprintf(ArcCanonicalName,
+ "%s%s(%d)%s(%d)",
+ &AdapterPath[0],
+ &ControllerName[0],
+ ControllerNumber,
+ &PeripheralName[0],
+ PeripheralNumber);
+
+ if (ARGUMENT_PRESENT(NtDevicePrefix)) {
+ strcpy(NtDevicePrefix, "\\Device\\CDRom");
+ }
+ break;
+#endif
+
+ //
+ // Invalid peripheral.
+ //
+
+ default:
+ return EINVAL;
+ }
+
+ break;
+
+ //
+ // Invalid controller.
+ //
+
+ default:
+ return EINVAL;
+ }
+
+ return ESUCCESS;
+}
+
+PCHAR
+BlGetNextToken (
+ IN PCHAR TokenString,
+ OUT PCHAR OutputToken,
+ OUT PULONG UnitNumber
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans the specified token string for the next token and
+ unit number. The token format is:
+
+ name[(unit)]
+
+Arguments:
+
+ TokenString - Supplies a pointer to a zero terminated token string.
+
+ OutputToken - Supplies a pointer to a variable that receives the next
+ token.
+
+ UnitNumber - Supplies a pointer to a variable that receives the unit
+ number.
+
+Return Value:
+
+ If another token exists in the token string, then a pointer to the
+ start of the next token is returned. Otherwise, a value of NULL is
+ returned.
+
+--*/
+
+{
+
+ //
+ // If there are more characters in the token string, then parse the
+ // next token. Otherwise, return a value of NULL.
+ //
+
+ if (*TokenString == '\0') {
+ return NULL;
+
+ } else {
+ while ((*TokenString != '\0') && (*TokenString != '(')) {
+ *OutputToken++ = *TokenString++;
+ }
+
+ *OutputToken = '\0';
+
+ //
+ // If a unit number is specified, then convert it to binary.
+ // Otherwise, default the unit number to zero.
+ //
+
+ *UnitNumber = 0;
+ if (*TokenString == '(') {
+ TokenString += 1;
+ while ((*TokenString != '\0') && (*TokenString != ')')) {
+ *UnitNumber = (*UnitNumber * 10) + (*TokenString++ - '0');
+ }
+
+ if (*TokenString == ')') {
+ TokenString += 1;
+ }
+ }
+ }
+
+ return TokenString;
+}
+
+ULONG
+BlMatchToken (
+ IN PCHAR TokenValue,
+ IN PCHAR TokenArray[]
+ )
+
+/*++
+
+Routine Description:
+
+ This routine attempts to match a token with an array of possible
+ values.
+
+Arguments:
+
+ TokenValue - Supplies a pointer to a zero terminated token value.
+
+ TokenArray - Supplies a pointer to a vector of pointers to null terminated
+ match strings.
+
+Return Value:
+
+ If a token match is located, then the index of the matching value is
+ returned as the function value. Otherwise, an index one greater than
+ the size of the match array is returned.
+
+--*/
+
+{
+
+ ULONG Index;
+ PCHAR MatchString;
+ PCHAR TokenString;
+
+ //
+ // Scan the match array until either a match is found or all of
+ // the match strings have been scanned.
+ //
+
+ Index = 0;
+ while (TokenArray[Index] != NULL) {
+ MatchString = TokenArray[Index];
+ TokenString = TokenValue;
+ while ((*MatchString != '\0') && (*TokenString != '\0')) {
+ if (toupper(*MatchString) != toupper(*TokenString)) {
+ break;
+ }
+
+ MatchString += 1;
+ TokenString += 1;
+ }
+
+ if ((*MatchString == '\0') && (*TokenString == '\0')) {
+ break;
+ }
+
+ Index += 1;
+ }
+
+ return Index;
+}
diff --git a/private/ntos/boot/lib/blio.c b/private/ntos/boot/lib/blio.c
new file mode 100644
index 000000000..ee12ef5de
--- /dev/null
+++ b/private/ntos/boot/lib/blio.c
@@ -0,0 +1,845 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ blio.c
+
+Abstract:
+
+ This module contains the code that implements the switch function for
+ I/O operations between then operating system loader, the target file
+ system, and the target device.
+
+Author:
+
+ David N. Cutler (davec) 10-May-1991
+
+Revision History:
+
+--*/
+
+#include "bootlib.h"
+
+//
+// Define generic filesystem context area.
+//
+// N.B. An FS_STRUCTURE_CONTEXT structure is temporarily used when
+// determining the file system for a volume. Once the file system
+// is recognized, a file system specific structure is allocated from
+// the heap to retain the file system structure information.
+//
+
+typedef union {
+ CDFS_STRUCTURE_CONTEXT CdfsStructure;
+ FAT_STRUCTURE_CONTEXT FatStructure;
+ HPFS_STRUCTURE_CONTEXT HpfsStructure;
+ NTFS_STRUCTURE_CONTEXT NtfsStructure;
+#if defined(ELTORITO)
+ ETFS_STRUCTURE_CONTEXT EtfsStructure;
+#endif
+#ifdef DBLSPACE_LEGAL
+ DBLS_STRUCTURE_CONTEXT DblsStructure;
+#endif
+} FS_STRUCTURE_CONTEXT, *PFS_STRUCTURE_CONTEXT;
+
+#ifdef DBLSPACE_LEGAL
+//
+// Define value controlling whether we transparently
+// find files in \dblspace.000 cvf in fat drives.
+// See BlSetAutoDoubleSpace for a full description.
+//
+BOOLEAN BlAutoDoubleSpace = FALSE;
+#endif
+
+//
+// Define file table.
+//
+
+BL_FILE_TABLE BlFileTable[BL_FILE_TABLE_SIZE];
+
+ARC_STATUS
+BlIoInitialize (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the file table used by the OS loader and
+ initializes the boot loader filesystems.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ ESUCCESS is returned if the initialization is successful. Otherwise,
+ return an unsuccessful status.
+
+--*/
+
+{
+
+ ULONG Index;
+ ARC_STATUS Status;
+
+ //
+ // Initialize the file table.
+ //
+
+ for (Index = 0; Index < BL_FILE_TABLE_SIZE; Index += 1) {
+ BlFileTable[Index].Flags.Open = 0;
+ }
+
+ if((Status = FatInitialize()) != ESUCCESS) {
+ return Status;
+ }
+
+#ifdef DBLSPACE_LEGAL
+ if((Status = DblsInitialize()) != ESUCCESS) {
+ return Status;
+ }
+#endif
+
+ if((Status = HpfsInitialize()) != ESUCCESS) {
+ return Status;
+ }
+
+ if((Status = NtfsInitialize()) != ESUCCESS) {
+ return Status;
+ }
+
+ if((Status = CdfsInitialize()) != ESUCCESS) {
+ return Status;
+ }
+
+ return ESUCCESS;
+}
+
+
+PBOOTFS_INFO
+BlGetFsInfo(
+ IN ULONG DeviceId
+ )
+
+/*++
+
+Routine Description:
+
+ Returns filesystem information for the filesystem on the specified device
+
+Arguments:
+
+ FileId - Supplies the file table index of the device
+
+Return Value:
+
+ PBOOTFS_INFO - Pointer to the BOOTFS_INFO structure for the filesystem
+
+ NULL - unknown filesystem
+
+--*/
+
+{
+ FS_STRUCTURE_CONTEXT FsStructure;
+ PBL_DEVICE_ENTRY_TABLE Table;
+
+ if ((Table = IsFatFileStructure(DeviceId, &FsStructure)) != NULL) {
+ return(Table->BootFsInfo);
+ }
+
+ if ((Table = IsHpfsFileStructure(DeviceId, &FsStructure)) != NULL) {
+ return(Table->BootFsInfo);
+ }
+
+ if ((Table = IsNtfsFileStructure(DeviceId, &FsStructure)) != NULL) {
+ return(Table->BootFsInfo);
+ }
+
+ if ((Table = IsCdfsFileStructure(DeviceId, &FsStructure)) != NULL) {
+ return(Table->BootFsInfo);
+ }
+
+ return(NULL);
+}
+
+ARC_STATUS
+BlClose (
+ IN ULONG FileId
+ )
+
+/*++
+
+Routine Description:
+
+ This function closes a file or a device that is open.
+
+Arguments:
+
+ FileId - Supplies the file table index.
+
+Return Value:
+
+ If the specified file is open, then a close is attempted and
+ the status of the operation is returned. Otherwise, return an
+ unsuccessful status.
+
+--*/
+
+{
+#ifdef DBLSPACE_LEGAL
+ //
+ // If the file is opened and is a double space file then we need to
+ // also close the cvf.
+ //
+
+ if ((BlFileTable[FileId].Flags.Open == 1) &&
+ (BlFileTable[FileId].Flags.DoubleSpace == 1)) {
+
+ BlFileTable[ BlFileTable[FileId].DeviceId ].DeviceEntryTable->Close(BlFileTable[FileId].DeviceId);
+ }
+#endif
+
+ //
+ // If the file is open, then attempt to close it. Otherwise return an
+ // access error.
+ //
+
+ if (BlFileTable[FileId].Flags.Open == 1) {
+
+ return (BlFileTable[FileId].DeviceEntryTable->Close)(FileId);
+
+ } else {
+ return EACCES;
+ }
+}
+
+ARC_STATUS
+BlMount (
+ IN PCHAR MountPath,
+ IN MOUNT_OPERATION Operation
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER(MountPath);
+ UNREFERENCED_PARAMETER(Operation);
+
+ return ESUCCESS;
+}
+
+ARC_STATUS
+BlOpen (
+ IN ULONG DeviceId,
+ IN PCHAR OpenPath,
+ IN OPEN_MODE OpenMode,
+ OUT PULONG FileId
+ )
+
+/*++
+
+Routine Description:
+
+ This function opens a file on the specified device. The type of file
+ system is automatically recognized.
+
+Arguments:
+
+ DeviceId - Supplies the file table index of the device.
+
+ OpenPath - Supplies a pointer to the name of the file to be opened.
+#ifdef DBLSPACE_LEGAL
+ If auto DoubleSpace is enabled, this routine will attempt to
+ locate this file on \dblspace.000 if the host partition is FAT
+ and that CVF exists. If the file cannot be located in the CVF,
+ then it is looked for in the partition outside the cvf as in a
+ standard non-DoubleSpace open. The caller must not specify
+ the \dblspace.000 prefix in the OpenPath if auto DoubleSpace
+ is enabled. See BlSetAutoDoubleSpace().
+#endif
+
+ OpenMode - Supplies the mode of the open.
+
+ FileId - Supplies a pointer to a variable that receives the file
+ table index of the open file.
+
+Return Value:
+
+ If a free file table entry is available and the file structure on
+ the specified device is recognized, then an open is attempted and
+ the status of the operation is returned. Otherwise, return an
+ unsuccessful status.
+
+--*/
+
+{
+
+ ULONG Index;
+ FS_STRUCTURE_CONTEXT FsStructureTemp;
+ PFS_STRUCTURE_CONTEXT FsStructure;
+ ULONG ContextSize;
+
+#ifdef DBLSPACE_LEGAL
+ //
+ // Special case the double space partition. We do that by looking
+ // for a path name that start with "\dblspace.0"
+ //
+
+ if(BlAutoDoubleSpace || !strncmp(OpenPath, "\\dblspace.0", sizeof("\\dblspace.0")-1)) {
+
+ ARC_STATUS Status;
+ ULONG CvfId;
+ CHAR SavedChar;
+ PCHAR CvfOpenPath;
+
+ //
+ // Search for a free file table index for the cvf
+ //
+
+ for (CvfId = 0; CvfId < BL_FILE_TABLE_SIZE; CvfId += 1) {
+ if (BlFileTable[CvfId].Flags.Open == 0) {
+
+ //
+ // Fat is the only one to recognize a cvf file.
+ //
+ // If automounting DoubleSpace and the host partition
+ // is not FAT, then try a standard non-DoubleSpace open.
+ //
+
+ if ((BlFileTable[CvfId].DeviceEntryTable =
+ IsFatFileStructure(DeviceId, &FsStructureTemp)) == NULL) {
+
+ if(BlAutoDoubleSpace) {
+ goto NonDoubleSpaceOpen;
+ }
+
+ return EACCES;
+ }
+
+ FsStructure = BlAllocateHeap(sizeof(FAT_STRUCTURE_CONTEXT));
+ if (FsStructure == NULL) {
+ return ENOMEM;
+ }
+
+ RtlCopyMemory(FsStructure, &FsStructureTemp, sizeof(FAT_STRUCTURE_CONTEXT));
+
+ BlFileTable[CvfId].StructureContext = FsStructure;
+ BlFileTable[CvfId].DeviceId = DeviceId;
+
+ //
+ // Now we open the cvf file. The name of the cvf file is the
+ // first component of the path name. It must always be
+ // "\dblspace.0xx" long so what we'll do is jam a null into
+ // the open path and use it.
+ //
+ // If automounting dblspace.000, then supply the implied \dblspace.000.
+ //
+
+ if(BlAutoDoubleSpace) {
+ CvfOpenPath = "\\dblspace.000";
+ } else {
+ SavedChar = OpenPath[sizeof("\\dblspace.000")-1];
+ OpenPath[sizeof("\\dblspace.000")-1] = 0;
+ CvfOpenPath = OpenPath;
+ }
+
+ Status = (BlFileTable[CvfId].DeviceEntryTable->Open)(CvfOpenPath,
+ ArcOpenReadOnly,
+ &CvfId);
+
+ if(!BlAutoDoubleSpace) {
+ OpenPath[sizeof("\\dblspace.000")-1] = SavedChar;
+ }
+
+ if (Status != ESUCCESS) {
+
+ //
+ // We were unable to open the DoubleSpace CVF.
+ // If automounting, try a standard non-DoubleSpace open.
+ //
+ if(BlAutoDoubleSpace) {
+ goto NonDoubleSpaceOpen;
+ }
+
+ return Status;
+ }
+
+ break;
+ }
+ }
+
+ //
+ // If we didn't find a free table entry, return error.
+ //
+ if(CvfId == BL_FILE_TABLE_SIZE) {
+ return EACCES;
+ }
+
+ //
+ // Search for a free file table index for the file
+ //
+
+ for (Index = 0; Index < BL_FILE_TABLE_SIZE; Index += 1) {
+ if (BlFileTable[Index].Flags.Open == 0) {
+
+ //
+ // Double space is the only one that can recognize this
+ //
+
+ if ((BlFileTable[Index].DeviceEntryTable =
+ IsDblsFileStructure(CvfId, &FsStructureTemp)) == NULL) {
+
+ BlClose(CvfId);
+
+ //
+ // Dblspace.000 is not a DoubleSpace cvf or is damaged, etc.
+ //
+ if(BlAutoDoubleSpace) {
+ goto NonDoubleSpaceOpen;
+ }
+
+ return EACCES;
+ }
+
+ FsStructure = BlAllocateHeap(sizeof(DBLS_STRUCTURE_CONTEXT));
+ if (FsStructure == NULL) {
+ return ENOMEM;
+ }
+
+ RtlCopyMemory(FsStructure, &FsStructureTemp, sizeof(DBLS_STRUCTURE_CONTEXT));
+
+ BlFileTable[Index].StructureContext = FsStructure;
+ *FileId = Index;
+ BlFileTable[Index].DeviceId = CvfId;
+ BlFileTable[FileId].Flags.DoubleSpace = 1;
+
+ //
+ // If we are automounting, then there is no \dblspace.000
+ // at the beginning of the open path. If not automounting,
+ // the caller must have specified \dblspace.000\xxx explicitly.
+ //
+ CvfOpenPath = BlAutoDoubleSpace
+ ? OpenPath
+ : (OpenPath + sizeof("dblspace.000") - 1);
+
+ Status = (BlFileTable[Index].DeviceEntryTable->Open)(CvfOpenPath,
+ OpenMode,
+ FileId);
+
+ if (Status != ESUCCESS) {
+
+ //
+ // The file could not be located in the cvf.
+ //
+
+ BlClose( CvfId );
+
+ //**** this is just a hack to make everything work. Don't know why but this works...
+ //**** ULONG FileId2;
+ //**** BlOpen(DeviceId, "\\", ArcOpenReadOnly, &FileId2);
+ //**** BlClose(FileId2);
+
+ if(BlAutoDoubleSpace) {
+ goto NonDoubleSpaceOpen;
+ }
+ }
+
+ return Status;
+ }
+ }
+
+ //
+ // We didn't find a free table entry -- close the CVF and return error.
+ //
+ BlClose(CvfId);
+ return EACCES;
+ }
+
+NonDoubleSpaceOpen:
+#endif // def DBLSPACE_LEGAL
+
+ //
+ // Search for a free file table entry.
+ //
+
+ for (Index = 0; Index < BL_FILE_TABLE_SIZE; Index += 1) {
+ if (BlFileTable[Index].Flags.Open == 0) {
+
+ //
+ // Attempt to recognize the file system on the specified
+ // device. If no one recognizes it then return an unsuccessful
+ // status.
+ //
+
+ if ((BlFileTable[Index].DeviceEntryTable =
+ IsFatFileStructure(DeviceId, &FsStructureTemp)) != NULL) {
+ ContextSize = sizeof(FAT_STRUCTURE_CONTEXT);
+
+ } else if ((BlFileTable[Index].DeviceEntryTable =
+ IsHpfsFileStructure(DeviceId, &FsStructureTemp)) != NULL) {
+ ContextSize = sizeof(HPFS_STRUCTURE_CONTEXT);
+
+ } else if ((BlFileTable[Index].DeviceEntryTable =
+ IsNtfsFileStructure(DeviceId, &FsStructureTemp)) != NULL) {
+ ContextSize = sizeof(NTFS_STRUCTURE_CONTEXT);
+
+#if defined(ELTORITO)
+ //
+ // This must go before the check for Cdfs; otherwise Cdfs will be detected.
+ // Since BIOS calls already set up to use EDDS, reads will succeed, and checks
+ // against ISO will succeed. We check El Torito-specific fields here as well as ISO
+ //
+ } else if ((BlFileTable[Index].DeviceEntryTable =
+ IsEtfsFileStructure(DeviceId, &FsStructureTemp)) != NULL) {
+ ContextSize = sizeof(ETFS_STRUCTURE_CONTEXT);
+#endif
+ } else if ((BlFileTable[Index].DeviceEntryTable =
+ IsCdfsFileStructure(DeviceId, &FsStructureTemp)) != NULL) {
+ ContextSize = sizeof(CDFS_STRUCTURE_CONTEXT);
+
+ } else {
+ return EACCES;
+ }
+
+ FsStructure = BlAllocateHeap(ContextSize);
+ if (FsStructure == NULL) {
+ return ENOMEM;
+ }
+
+ RtlCopyMemory(FsStructure, &FsStructureTemp, ContextSize);
+
+ BlFileTable[Index].StructureContext = FsStructure;
+
+ //
+ // Someone has mounted the volume so now attempt to open the file.
+ //
+
+ *FileId = Index;
+ BlFileTable[Index].DeviceId = DeviceId;
+ return (BlFileTable[Index].DeviceEntryTable->Open)(OpenPath,
+ OpenMode,
+ FileId);
+ }
+ }
+
+ //
+ // No free file table entry could be found.
+ //
+
+ return EACCES;
+}
+
+ARC_STATUS
+BlRead (
+ IN ULONG FileId,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ This function reads from a file or a device that is open.
+
+Arguments:
+
+ FileId - Supplies the file table index.
+
+ Buffer - Supplies a pointer to the buffer that receives the data
+ read.
+
+ Length - Supplies the number of bytes that are to be read.
+
+ Count - Supplies a pointer to a variable that receives the number of
+ bytes actually transfered.
+
+Return Value:
+
+ If the specified file is open for read, then a read is attempted
+ and the status of the operation is returned. Otherwise, return an
+ unsuccessful status.
+
+--*/
+
+{
+
+ //
+ // If the file is open for read, then attempt to read from it. Otherwise
+ // return an access error.
+ //
+
+ if ((BlFileTable[FileId].Flags.Open == 1) &&
+ (BlFileTable[FileId].Flags.Read == 1)) {
+ return (BlFileTable[FileId].DeviceEntryTable->Read)(FileId,
+ Buffer,
+ Length,
+ Count);
+
+ } else {
+ return EACCES;
+ }
+}
+
+ARC_STATUS
+BlGetReadStatus (
+ IN ULONG FileId
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+
+ return ESUCCESS;
+}
+
+ARC_STATUS
+BlSeek (
+ IN ULONG FileId,
+ IN PLARGE_INTEGER Offset,
+ IN SEEK_MODE SeekMode
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+ If the specified file is open, then a seek is attempted and
+ the status of the operation is returned. Otherwise, return an
+ unsuccessful status.
+
+--*/
+
+{
+
+ //
+ // If the file is open, then attempt to seek on it. Otherwise return an
+ // access error.
+ //
+
+ if (BlFileTable[FileId].Flags.Open == 1) {
+ return (BlFileTable[FileId].DeviceEntryTable->Seek)(FileId,
+ Offset,
+ SeekMode);
+
+ } else {
+ return EACCES;
+ }
+}
+
+ARC_STATUS
+BlWrite (
+ IN ULONG FileId,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+
+ //
+ // If the file is open for write, then attempt to write to it. Otherwise
+ // return an access error.
+ //
+
+ if ((BlFileTable[FileId].Flags.Open == 1) &&
+ (BlFileTable[FileId].Flags.Write == 1)) {
+ return (BlFileTable[FileId].DeviceEntryTable->Write)(FileId,
+ Buffer,
+ Length,
+ Count);
+
+ } else {
+ return EACCES;
+ }
+}
+
+ARC_STATUS
+BlGetFileInformation (
+ IN ULONG FileId,
+ IN PFILE_INFORMATION FileInformation
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ //
+ // If the file is open, then attempt to get file information. Otherwise
+ // return an access error.
+ //
+
+ if (BlFileTable[FileId].Flags.Open == 1) {
+ return (BlFileTable[FileId].DeviceEntryTable->GetFileInformation)(FileId,
+ FileInformation);
+
+ } else {
+ return EACCES;
+ }
+}
+
+ARC_STATUS
+BlSetFileInformation (
+ IN ULONG FileId,
+ IN ULONG AttributeFlags,
+ IN ULONG AttributeMask
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ //
+ // If the file is open, then attempt to Set file information. Otherwise
+ // return an access error.
+ //
+
+ if (BlFileTable[FileId].Flags.Open == 1) {
+ return (BlFileTable[FileId].DeviceEntryTable->SetFileInformation)(FileId,
+ AttributeFlags,
+ AttributeMask);
+
+ } else {
+ return EACCES;
+ }
+}
+
+
+ARC_STATUS
+BlRename(
+ IN ULONG FileId,
+ IN PCHAR NewName
+ )
+
+/*++
+
+Routine Description:
+
+ Rename an open file or directory.
+
+Arguments:
+
+ FileId - supplies a handle to an open file or directory. The file
+ need not be open for write access.
+
+ NewName - New name to give the file or directory (filename part only).
+
+Return Value:
+
+ Status indicating result of the operation.
+
+--*/
+
+{
+ if(BlFileTable[FileId].Flags.Open == 1) {
+ return(BlFileTable[FileId].DeviceEntryTable->Rename(FileId,
+ NewName
+ )
+ );
+ } else {
+ return(EACCES);
+ }
+}
+
+#ifdef DBLSPACE_LEGAL
+VOID
+BlSetAutoDoubleSpace(
+ IN BOOLEAN Enable
+ )
+
+/*++
+
+Routine Description:
+
+ Enable or disable transparent opens of files contained in a
+ 000 CVF on a partition.
+
+ This "auto DoubleSpace" provides the equivalent of an automount capability.
+ If enabled, BlOpen will attempt to open files on a fat partition in a CVF
+ with sequence 000, without the need for the caller to specify \dblspace.000
+ as part of the file name. If disabled, files on DoubleSpace drives must be
+ explicitly named using \dblspace.0xx as the first component of the path.
+
+
+Arguments:
+
+ Enable - if TRUE (non-0), enable transparent doublespace access.
+ if FALSE (0), disable it.
+
+Return Value:
+
+ Status indicating result of the operation.
+
+--*/
+
+{
+ BlAutoDoubleSpace = Enable;
+}
+#endif
diff --git a/private/ntos/boot/lib/blload.c b/private/ntos/boot/lib/blload.c
new file mode 100644
index 000000000..653ea9765
--- /dev/null
+++ b/private/ntos/boot/lib/blload.c
@@ -0,0 +1,736 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ blload.c
+
+Abstract:
+
+ This module provides common code for loading things like drivers, NLS files, registry.
+ Used by both the osloader and the setupldr.
+
+Author:
+
+ John Vert (jvert) 8-Oct-1993
+
+Environment:
+
+ ARC environment
+
+Revision History:
+
+--*/
+#include "bldr.h"
+#include "stdio.h"
+
+ARC_STATUS
+BlLoadSystemHive(
+ IN ULONG DeviceId,
+ IN PCHAR DeviceName,
+ IN PCHAR DirectoryPath,
+ IN PCHAR HiveName
+ )
+
+/*++
+
+Routine Description:
+
+ Loads the registry SYSTEM hive from <BootDirectory>\config\system.
+
+ Allocates a memory descriptor to hold the hive image, reads the hive
+ image into this descriptor, and updates the registry pointers in the
+ LoaderBlock.
+
+Arguments:
+
+ DeviceId - Supplies the file id of the device the system tree is on.
+
+ DeviceName - Supplies the name of the device the system tree is on.
+
+ DirectoryPath - Supplies a pointer to the zero-terminated directory path
+ of the root of the NT tree.
+
+ HiveName - Supplies the name of the system hive ("SYSTEM" or "SYSTEM.ALT")
+
+Return Value:
+
+ TRUE - system hive successfully loaded.
+
+ FALSE - system hive could not be loaded.
+
+--*/
+
+{
+ CHAR RegistryName[256];
+ ULONG FileId;
+ ARC_STATUS Status;
+ FILE_INFORMATION FileInformation;
+ ULONG FileSize;
+ ULONG ActualBase;
+ PVOID LocalPointer;
+ LARGE_INTEGER SeekValue;
+ ULONG Count;
+ PCHAR FailReason;
+
+ //
+ // Create the full filename for the SYSTEM hive.
+ //
+
+ strcpy(&RegistryName[0], DirectoryPath);
+ strcat(&RegistryName[0], HiveName);
+ BlOutputLoadMessage(DeviceName, &RegistryName[0]);
+ Status = BlOpen(DeviceId, &RegistryName[0], ArcOpenReadOnly, &FileId);
+ if (Status != ESUCCESS) {
+ FailReason = "BlOpen";
+ goto HiveLoadFailed;
+ }
+
+ //
+ // Determine the length of the registry file
+ //
+ Status = BlGetFileInformation(FileId, &FileInformation);
+ if (Status != ESUCCESS) {
+ BlClose(FileId);
+ FailReason = "BlGetFileInformation";
+ goto HiveLoadFailed;
+ }
+
+ FileSize = FileInformation.EndingAddress.LowPart;
+ if (FileSize == 0) {
+ Status = EINVAL;
+ BlClose(FileId);
+ FailReason = "FileSize == 0";
+ goto HiveLoadFailed;
+ }
+
+ //
+ // Round up to a page boundary, allocate a memory
+ // descriptor, fill in the registry fields in the
+ // loader parameter block, and read the registry data
+ // into memory.
+ //
+
+ Status = BlAllocateDescriptor(LoaderRegistryData,
+ 0x0,
+ (FileSize + PAGE_SIZE - 1) >> PAGE_SHIFT,
+ &ActualBase);
+ if (Status != ESUCCESS) {
+ BlClose(FileId);
+ FailReason = "BlAllocateDescriptor";
+ goto HiveLoadFailed;
+ }
+
+ LocalPointer = (PVOID)(KSEG0_BASE | (ActualBase << PAGE_SHIFT));
+ BlLoaderBlock->RegistryLength = FileSize;
+ BlLoaderBlock->RegistryBase = LocalPointer;
+
+ //
+ // Read the SYSTEM hive into the allocated memory.
+ //
+
+ SeekValue.QuadPart = 0;
+ Status = BlSeek(FileId, &SeekValue, SeekAbsolute);
+ if (Status != ESUCCESS) {
+ BlClose(FileId);
+ FailReason = "BlSeek";
+ goto HiveLoadFailed;
+ }
+ Status = BlRead(FileId, LocalPointer, FileSize, &Count);
+ BlClose(FileId);
+ if (Status != ESUCCESS) {
+ FailReason = "BlRead";
+ goto HiveLoadFailed;
+ }
+
+ return(ESUCCESS);
+
+HiveLoadFailed:
+ //
+ // The system hive didn't exist, or was corrupt. Pass a NULL
+ // pointer into the system, so it gets recreated.
+ //
+ return(Status);
+
+}
+
+
+ARC_STATUS
+BlLoadNLSData(
+ IN ULONG DeviceId,
+ IN PCHAR DeviceName,
+ IN PCHAR DirectoryPath,
+ IN PUNICODE_STRING AnsiCodepage,
+ IN PUNICODE_STRING OemCodepage,
+ IN PUNICODE_STRING LanguageTable,
+ OUT PCHAR BadFileName
+ )
+
+/*++
+
+Routine Description:
+
+ This routine loads all the NLS data files into one contiguous block of
+ memory.
+
+Arguments:
+
+ DeviceId - Supplies the file id of the device the system tree is on.
+
+ DeviceName - Supplies the name of the device the system tree is on.
+
+ DirectoryPath - Supplies a pointer to the zero-terminated path
+ of the directory containing the NLS files.
+
+ AnsiCodePage - Supplies the filename of the ANSI codepage data file.
+
+ OemCodePage - Supplies the filename of the OEM codepage data file.
+
+ LanguageTable - Supplies the filename of the Unicode language case table.
+
+ BadFileName - Returns the filename of the NLS file that was missing
+ or invalid. This will not be filled in if ESUCCESS is returned.
+
+Return Value:
+
+ ESUCCESS is returned if the NLS data was successfully loaded.
+ Otherwise, an unsuccessful status is returned.
+
+--*/
+
+{
+ CHAR Filename[100];
+ ULONG AnsiFileId;
+ ULONG OemFileId;
+ ULONG LanguageFileId;
+ ARC_STATUS Status;
+ FILE_INFORMATION FileInformation;
+ ULONG AnsiFileSize;
+ ULONG OemFileSize;
+ ULONG LanguageFileSize;
+ ULONG TotalSize;
+ ULONG ActualBase;
+ PVOID LocalPointer;
+ LARGE_INTEGER SeekValue;
+ ULONG Count;
+ BOOLEAN OemIsSameAsAnsi = FALSE;
+
+ //
+ // Under the Japanese version of NT, ANSI code page and OEM codepage
+ // is same. In this case, we share the same data to save and memory.
+ //
+
+ if ( (AnsiCodepage->Length == OemCodepage->Length) &&
+ (_wcsnicmp(AnsiCodepage->Buffer,
+ OemCodepage->Buffer,
+ AnsiCodepage->Length) == 0)) {
+
+ OemIsSameAsAnsi = TRUE;
+ }
+
+ //
+ // Open the ANSI data file
+ //
+ sprintf(Filename, "%s%wZ", DirectoryPath,AnsiCodepage);
+ BlOutputLoadMessage(DeviceName, Filename);
+ Status = BlOpen(DeviceId, Filename, ArcOpenReadOnly, &AnsiFileId);
+ if (Status != ESUCCESS) {
+ goto NlsLoadFailed;
+ }
+ Status = BlGetFileInformation(AnsiFileId, &FileInformation);
+ BlClose(AnsiFileId);
+ if (Status != ESUCCESS) {
+ goto NlsLoadFailed;
+ }
+ AnsiFileSize = FileInformation.EndingAddress.LowPart;
+
+ //
+ // Open the OEM data file
+ //
+ if (OemIsSameAsAnsi) {
+ OemFileSize = 0;
+ } else {
+ sprintf(Filename, "%s%wZ", DirectoryPath, OemCodepage);
+ BlOutputLoadMessage(DeviceName, Filename);
+ Status = BlOpen(DeviceId, Filename, ArcOpenReadOnly, &OemFileId);
+ if (Status != ESUCCESS) {
+ goto NlsLoadFailed;
+ }
+ Status = BlGetFileInformation(OemFileId, &FileInformation);
+ BlClose(OemFileId);
+ if (Status != ESUCCESS) {
+ goto NlsLoadFailed;
+ }
+ OemFileSize = FileInformation.EndingAddress.LowPart;
+ }
+
+ //
+ // Open the language codepage file
+ //
+ sprintf(Filename, "%s%wZ", DirectoryPath,LanguageTable);
+ BlOutputLoadMessage(DeviceName, Filename);
+ Status = BlOpen(DeviceId, Filename, ArcOpenReadOnly, &LanguageFileId);
+ if (Status != ESUCCESS) {
+ goto NlsLoadFailed;
+ }
+ Status = BlGetFileInformation(LanguageFileId, &FileInformation);
+ BlClose(LanguageFileId);
+ if (Status != ESUCCESS) {
+ goto NlsLoadFailed;
+ }
+ LanguageFileSize = FileInformation.EndingAddress.LowPart;
+
+ //
+ // Calculate the total size of the descriptor needed. We want each
+ // data file to start on a page boundary, so round up each size to
+ // page granularity.
+ //
+ TotalSize = ROUND_TO_PAGES(AnsiFileSize) +
+ ROUND_TO_PAGES(OemFileSize) +
+ ROUND_TO_PAGES(LanguageFileSize);
+
+ Status = BlAllocateDescriptor(LoaderNlsData,
+ 0x0,
+ TotalSize >> PAGE_SHIFT,
+ &ActualBase);
+ if (Status != ESUCCESS) {
+ goto NlsLoadFailed;
+ }
+ LocalPointer = (PVOID)(KSEG0_BASE | (ActualBase << PAGE_SHIFT));
+ BlLoaderBlock->NlsData->AnsiCodePageData = LocalPointer;
+ BlLoaderBlock->NlsData->OemCodePageData = (PVOID)((PUCHAR)LocalPointer +
+ ROUND_TO_PAGES(AnsiFileSize));
+ BlLoaderBlock->NlsData->UnicodeCaseTableData = (PVOID)((PUCHAR)LocalPointer +
+ ROUND_TO_PAGES(AnsiFileSize) +
+ ROUND_TO_PAGES(OemFileSize));
+
+ //
+ // Let OemCodePageData point as same location as AnsiCodePageData.
+ //
+ if( OemIsSameAsAnsi ) {
+ BlLoaderBlock->NlsData->OemCodePageData = BlLoaderBlock->NlsData->AnsiCodePageData;
+ }
+
+ //
+ // Read NLS data into memory
+ //
+ // open and read ANSI file
+ //
+
+ sprintf(Filename, "%s%wZ", DirectoryPath,AnsiCodepage);
+ Status = BlOpen(DeviceId, Filename, ArcOpenReadOnly, &AnsiFileId);
+ if (Status != ESUCCESS) {
+ goto NlsLoadFailed;
+ }
+ SeekValue.QuadPart = 0;
+ Status = BlSeek(AnsiFileId, &SeekValue, SeekAbsolute);
+ if (Status != ESUCCESS) {
+ goto NlsLoadFailed;
+ }
+ Status = BlRead(AnsiFileId,
+ BlLoaderBlock->NlsData->AnsiCodePageData,
+ AnsiFileSize,
+ &Count);
+ if (Status != ESUCCESS) {
+ goto NlsLoadFailed;
+ }
+ BlClose(AnsiFileId);
+
+ //
+ // Open and read OEM file
+ //
+ if (!OemIsSameAsAnsi) {
+ sprintf(Filename, "%s%wZ", DirectoryPath, OemCodepage);
+ Status = BlOpen(DeviceId, Filename, ArcOpenReadOnly, &OemFileId);
+ if (Status != ESUCCESS) {
+ goto NlsLoadFailed;
+ }
+ SeekValue.QuadPart = 0;
+ Status = BlSeek(OemFileId, &SeekValue, SeekAbsolute);
+ if (Status != ESUCCESS) {
+ goto NlsLoadFailed;
+ }
+ Status = BlRead(OemFileId,
+ BlLoaderBlock->NlsData->OemCodePageData,
+ OemFileSize,
+ &Count);
+ if (Status != ESUCCESS) {
+ goto NlsLoadFailed;
+ }
+ BlClose(OemFileId);
+ }
+
+ //
+ // open and read Language file
+ //
+
+ sprintf(Filename, "%s%wZ", DirectoryPath,LanguageTable);
+ Status = BlOpen(DeviceId, Filename, ArcOpenReadOnly, &LanguageFileId);
+ if (Status != ESUCCESS) {
+ goto NlsLoadFailed;
+ }
+ SeekValue.QuadPart = 0;
+ Status = BlSeek(LanguageFileId, &SeekValue, SeekAbsolute);
+ if (Status != ESUCCESS) {
+ goto NlsLoadFailed;
+ }
+ Status = BlRead(LanguageFileId,
+ BlLoaderBlock->NlsData->UnicodeCaseTableData,
+ LanguageFileSize,
+ &Count);
+ if (Status != ESUCCESS) {
+ goto NlsLoadFailed;
+ }
+ BlClose(LanguageFileId);
+
+ return(ESUCCESS);
+
+NlsLoadFailed:
+ strcpy(BadFileName,Filename);
+ return(Status);
+}
+
+ARC_STATUS
+BlLoadOemHalFont(
+ IN ULONG DeviceId,
+ IN PCHAR DeviceName,
+ IN PCHAR DirectoryPath,
+ IN PUNICODE_STRING OemHalFont,
+ OUT PCHAR BadFileName
+ )
+
+/*++
+
+Routine Description:
+
+ This routine loads the OEM font file for use the HAL display string
+ function.
+
+Arguments:
+
+ DeviceId - Supplies the file id of the device the system tree is on.
+
+ DeviceName - Supplies the name of the device the system tree is on.
+
+ DirectoryPath - Supplies a pointer to the directory path of the root
+ of the NT tree.
+
+ Fontfile - Supplies the filename of the OEM font file.
+
+ BadFileName - Returns the filename of the OEM font file that was missing
+ or invalid.
+
+Return Value:
+
+ ESUCCESS is returned if the OEM font was successfully loaded. Otherwise,
+ an unsuccessful status is returned and the bad file name is filled.
+
+--*/
+
+{
+
+ PVOID FileBuffer;
+ ULONG Count;
+ PIMAGE_DOS_HEADER DosHeader;
+ ULONG FileId;
+ FILE_INFORMATION FileInformation;
+ CHAR Filename[100];
+ ULONG FileSize;
+ ARC_STATUS Status;
+ POEM_FONT_FILE_HEADER FontHeader;
+ PIMAGE_OS2_HEADER Os2Header;
+ ULONG ScaleFactor;
+ RESOURCE_TYPE_INFORMATION UNALIGNED *TableAddress;
+ RESOURCE_TYPE_INFORMATION UNALIGNED *TableEnd;
+ RESOURCE_NAME_INFORMATION UNALIGNED *TableName;
+
+ //
+ // Open the OEM font file.
+ //
+
+ BlLoaderBlock->OemFontFile = NULL;
+
+ sprintf(&Filename[0], "%s%wZ", DirectoryPath, OemHalFont);
+ BlOutputLoadMessage(DeviceName, &Filename[0]);
+ Status = BlOpen(DeviceId, &Filename[0], ArcOpenReadOnly, &FileId);
+ if (Status != ESUCCESS) {
+ goto OemLoadExit;
+ }
+
+ //
+ // Get the size of the font file and allocate a buffer from the heap
+ // to hold the font file. Typically this file is about 4kb in length.
+ //
+
+ Status = BlGetFileInformation(FileId, &FileInformation);
+ if (Status != ESUCCESS) {
+ goto OemLoadExit;
+ }
+
+ FileSize = FileInformation.EndingAddress.LowPart;
+ FileBuffer = BlAllocateHeap(FileSize + BlDcacheFillSize - 1);
+ if (FileBuffer == NULL) {
+ Status = ENOMEM;
+ goto OemLoadExit;
+ }
+
+ //
+ // Round the file buffer address up to a cache line boundary and read
+ // the file into memory.
+ //
+
+ FileBuffer = (PVOID)((ULONG)FileBuffer + BlDcacheFillSize - 1);
+ FileBuffer = (PVOID)((ULONG)FileBuffer & ~(BlDcacheFillSize - 1));
+ Status = BlRead(FileId,
+ FileBuffer,
+ FileSize,
+ &Count);
+
+ if (Status != ESUCCESS) {
+ goto OemLoadExit;
+ }
+
+ //
+ // Attempt to recognize the file as either a .fon or .fnt file.
+ //
+ // Check if the file has a DOS header or a font file header. If the
+ // file has a font file header, then it is a .fnt file. Otherwise,
+ // it must be checked for an OS/2 executable with a font resource.
+ //
+
+ Status = EBADF;
+ DosHeader = (PIMAGE_DOS_HEADER)FileBuffer;
+ if (DosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
+
+ //
+ // Check if the file has a font file header.
+ //
+
+ FontHeader = (POEM_FONT_FILE_HEADER)FileBuffer;
+ if ((FontHeader->Version != OEM_FONT_VERSION) ||
+ (FontHeader->Type != OEM_FONT_TYPE) ||
+ (FontHeader->Italic != OEM_FONT_ITALIC) ||
+ (FontHeader->Underline != OEM_FONT_UNDERLINE) ||
+ (FontHeader->StrikeOut != OEM_FONT_STRIKEOUT) ||
+ (FontHeader->CharacterSet != OEM_FONT_CHARACTER_SET) ||
+ (FontHeader->Family != OEM_FONT_FAMILY) ||
+ (FontHeader->PixelWidth > 32)) {
+
+ goto OemLoadExit;
+
+ } else {
+ BlLoaderBlock->OemFontFile = (PVOID)FontHeader;
+ Status = ESUCCESS;
+ goto OemLoadExit;
+ }
+ }
+
+ //
+ // Check if the file has an OS/2 header.
+ //
+
+ if ((FileSize < sizeof(IMAGE_DOS_HEADER)) || (FileSize < (ULONG)DosHeader->e_lfanew)) {
+ goto OemLoadExit;
+ }
+
+ Os2Header = (PIMAGE_OS2_HEADER)((PUCHAR)DosHeader + DosHeader->e_lfanew);
+ if (Os2Header->ne_magic != IMAGE_OS2_SIGNATURE) {
+ goto OemLoadExit;
+ }
+
+ //
+ // Check if the resource table exists.
+ //
+
+ if ((Os2Header->ne_restab - Os2Header->ne_rsrctab) == 0) {
+ goto OemLoadExit;
+ }
+
+ //
+ // Compute address of resource table and search the table for a font
+ // resource.
+ //
+
+ TableAddress =
+ (PRESOURCE_TYPE_INFORMATION)((PUCHAR)Os2Header + Os2Header->ne_rsrctab);
+
+ TableEnd =
+ (PRESOURCE_TYPE_INFORMATION)((PUCHAR)Os2Header + Os2Header->ne_restab);
+
+ ScaleFactor = *((SHORT UNALIGNED *)TableAddress)++;
+ while ((TableAddress < TableEnd) &&
+ (TableAddress->Ident != 0) &&
+ (TableAddress->Ident != FONT_RESOURCE)) {
+
+ TableAddress =
+ (PRESOURCE_TYPE_INFORMATION)((PUCHAR)(TableAddress + 1) +
+ (TableAddress->Number * sizeof(RESOURCE_NAME_INFORMATION)));
+ }
+
+ if ((TableAddress >= TableEnd) || (TableAddress->Ident != FONT_RESOURCE)) {
+ goto OemLoadExit;
+ }
+
+ //
+ // Compute address of resource name information and check if the resource
+ // is within the file.
+ //
+
+ TableName = (PRESOURCE_NAME_INFORMATION)(TableAddress + 1);
+ if (FileSize < ((TableName->Offset << ScaleFactor) + sizeof(OEM_FONT_FILE_HEADER))) {
+ goto OemLoadExit;
+ }
+
+ //
+ // Compute the address of the font file header and check if the header
+ // contains correct information.
+ //
+
+ FontHeader = (POEM_FONT_FILE_HEADER)((PCHAR)FileBuffer +
+ (TableName->Offset << ScaleFactor));
+
+ if ((FontHeader->Version != OEM_FONT_VERSION) ||
+ (FontHeader->Type != OEM_FONT_TYPE) ||
+ (FontHeader->Italic != OEM_FONT_ITALIC) ||
+ (FontHeader->Underline != OEM_FONT_UNDERLINE) ||
+ (FontHeader->StrikeOut != OEM_FONT_STRIKEOUT) ||
+ (FontHeader->CharacterSet != OEM_FONT_CHARACTER_SET) ||
+ (FontHeader->PixelWidth > 32)) {
+ goto OemLoadExit;
+
+ } else {
+ BlLoaderBlock->OemFontFile = (PVOID)FontHeader;
+ Status = ESUCCESS;
+ goto OemLoadExit;
+ }
+
+ //
+ // Exit loading of the OEM font file.
+ //
+
+OemLoadExit:
+ BlClose(FileId);
+ strcpy(BadFileName,&Filename[0]);
+ return(Status);
+}
+
+
+ARC_STATUS
+BlLoadDeviceDriver (
+ IN ULONG DeviceId,
+ IN PCHAR LoadDevice,
+ IN PCHAR DirectoryPath,
+ IN PCHAR DriverName,
+ IN ULONG DriverFlags,
+ OUT PLDR_DATA_TABLE_ENTRY *DriverDataTableEntry
+ )
+
+/*++
+
+Routine Description:
+
+ This routine loads the specified device driver and resolves all DLL
+ references if the driver is not already loaded.
+
+Arguments:
+
+ DeviceId - Supplies the file id of the device on which the specified
+ device driver is loaded from.
+
+ LoadDevice - Supplies a pointer to a zero terminated load device
+ string.
+
+ DirectoryPath - Supplies a pointer to a zero terminated directory
+ path string.
+
+ DriverName - Supplies a pointer to a zero terminated device driver
+ name string.
+
+ DriverFlags - Supplies the driver flags that are to be set in the
+ generated data table entry.
+
+ DriverDataTableEntry - Receives a pointer to the data table entry
+ created for the newly-loaded driver.
+
+Return Value:
+
+ ESUCCESS is returned if the specified driver is successfully loaded
+ or it is already loaded. Otherwise, and unsuccessful status is
+ returned.
+
+--*/
+
+{
+
+ CHAR DllName[256];
+ CHAR FullName[256];
+ PVOID Base;
+ ARC_STATUS Status;
+
+ //
+ // Generate the DLL name for the device driver.
+ //
+
+ strcpy(&DllName[0], DriverName);
+
+ //
+ // If the specified device driver is not already loaded, then load it.
+ //
+
+ if (BlCheckForLoadedDll(&DllName[0], DriverDataTableEntry) == FALSE) {
+
+ //
+ // Generate the full path name of device driver.
+ //
+
+ strcpy(&FullName[0], &DirectoryPath[0]);
+ strcat(&FullName[0], DriverName);
+ BlOutputLoadMessage(LoadDevice, &FullName[0]);
+ Status = BlLoadImage(DeviceId,
+ LoaderBootDriver,
+ &FullName[0],
+ TARGET_IMAGE,
+ &Base);
+
+ if (Status != ESUCCESS) {
+ return Status;
+ }
+
+ //
+ // Generate a data table entry for the driver, then clear the entry
+ // processed flag. The I/O initialization code calls each DLL in the
+ // loaded module list that does not have its entry processed flag set.
+ //
+
+ Status = BlAllocateDataTableEntry(&DllName[0],
+ DriverName,
+ Base,
+ DriverDataTableEntry);
+
+ if (Status != ESUCCESS) {
+ return Status;
+ }
+
+ (*DriverDataTableEntry)->Flags |= DriverFlags;
+
+ //
+ // Scan the import table and load all the referenced DLLs.
+ //
+
+ Status = BlScanImportDescriptorTable(DeviceId,
+ LoadDevice,
+ &DirectoryPath[0],
+ *DriverDataTableEntry);
+
+ if (Status != ESUCCESS) {
+ //
+ // Remove the driver from the load order list.
+ //
+ RemoveEntryList(&(*DriverDataTableEntry)->InLoadOrderLinks);
+ return Status;
+ }
+
+ }
+ return ESUCCESS;
+}
diff --git a/private/ntos/boot/lib/bllog.c b/private/ntos/boot/lib/bllog.c
new file mode 100644
index 000000000..ef6efa55e
--- /dev/null
+++ b/private/ntos/boot/lib/bllog.c
@@ -0,0 +1,287 @@
+/*++
+
+Copyright (c) 1995 Microsoft Corporation
+
+Module Name:
+
+ blprint.c
+
+Abstract:
+
+ This module implements the OS loader debug logging routines.
+
+Author:
+
+ Chuck Lenzmeier (chuckl) 2-Nov-1995
+
+Revision History:
+
+--*/
+
+#include "bldr.h"
+#include <stdio.h>
+
+#if DBG
+
+ULONG BlLogFileId = (ULONG)-1;
+ULONG BlLogActiveTargets = 0;
+
+VOID
+BlLogInitialize (
+ ULONG LogfileDeviceId
+ )
+{
+ ARC_STATUS Status;
+
+ BlLogActiveTargets = 0;
+
+ if (BlLoaderBlock->LoadOptions != NULL) {
+
+ if (strstr(BlLoaderBlock->LoadOptions,"DBGDISPLAY") != NULL) {
+ BlLogActiveTargets |= LOG_DISPLAY;
+ }
+
+ if (strstr(BlLoaderBlock->LoadOptions,"DBGLOG") != NULL) {
+ Status = BlOpen(LogfileDeviceId, "\\LDRDBG.LOG", ArcSupersedeReadWrite, &BlLogFileId);
+ if (Status == 0) {
+ BlLogActiveTargets |= LOG_LOGFILE;
+ }
+ }
+ }
+
+ BlLogArcDescriptors(LOG_ALL);
+ BlLogMemoryDescriptors(LOG_ALL_W);
+
+ return;
+}
+
+VOID
+BlLogTerminate (
+ VOID
+ )
+{
+ BlLogMemoryDescriptors(LOG_ALL);
+ if ((BlLogActiveTargets & LOG_DISPLAY) != 0) {
+ BlLogWaitForKeystroke();
+ }
+ if ((BlLogActiveTargets & LOG_LOGFILE) != 0) {
+ BlClose(BlLogFileId);
+ }
+
+ BlLogActiveTargets = 0;
+
+ return;
+}
+
+VOID
+BlLogPrint (
+ ULONG Targets,
+ PCHAR Format,
+ ...
+ )
+{
+ va_list arglist;
+ int count;
+ UCHAR buffer[79];
+ ULONG activeTargets;
+
+ activeTargets = Targets & BlLogActiveTargets;
+
+ if (activeTargets != 0) {
+
+ va_start(arglist, Format);
+
+ count = _vsnprintf(buffer, sizeof(buffer), Format, arglist);
+ if (count != -1) {
+ RtlFillMemory(&buffer[count], sizeof(buffer)-count-2, ' ');
+ }
+ count = sizeof(buffer);
+ buffer[count-2] = '\r';
+ buffer[count-1] = '\n';
+
+ if ((activeTargets & LOG_LOGFILE) != 0) {
+ BlWrite(BlLogFileId, buffer, count, &count);
+ }
+
+ if ((activeTargets & LOG_DISPLAY) != 0) {
+ ArcWrite(ARC_CONSOLE_OUTPUT, buffer, count, &count);
+ if ((Targets & LOG_WAIT) != 0) {
+ BlLogWaitForKeystroke();
+ }
+ }
+ }
+
+ return;
+}
+
+VOID
+BlLogArcDescriptors (
+ ULONG Targets
+ )
+{
+ PMEMORY_DESCRIPTOR CurrentDescriptor;
+ ULONG activeTargets;
+
+ activeTargets = Targets & BlLogActiveTargets;
+
+ if (activeTargets != 0) {
+
+ BlLog((activeTargets,"***** ARC Memory List *****"));
+
+ CurrentDescriptor = NULL;
+ while ((CurrentDescriptor = ArcGetMemoryDescriptor(CurrentDescriptor)) != NULL) {
+ BlLog((activeTargets,
+ "Descriptor %8x: Type %8x Base %8x Pages %8x",
+ CurrentDescriptor,
+ (USHORT)(CurrentDescriptor->MemoryType),
+ CurrentDescriptor->BasePage,
+ CurrentDescriptor->PageCount));
+ }
+
+ //BlLog((activeTargets,"***************************"));
+
+ if (((activeTargets & LOG_DISPLAY) != 0) && ((Targets & LOG_WAIT) != 0)) {
+ BlLogWaitForKeystroke();
+ }
+ }
+
+ return;
+}
+
+VOID
+BlLogMemoryDescriptors (
+ ULONG Targets
+ )
+{
+ PLIST_ENTRY CurrentLink;
+ PMEMORY_ALLOCATION_DESCRIPTOR CurrentDescriptor;
+ ULONG Index;
+ ULONG ExpectedIndex;
+ ULONG ExpectedBase;
+ ULONG FoundIndex;
+ PMEMORY_ALLOCATION_DESCRIPTOR FoundDescriptor;
+ TYPE_OF_MEMORY LastType;
+ ULONG FreeBlocks = 0;
+ ULONG FreePages = 0;
+ ULONG LargestFree = 0;
+
+ ULONG activeTargets;
+
+ activeTargets = Targets & BlLogActiveTargets;
+
+ if (activeTargets != 0) {
+
+ BlLog((activeTargets,"***** System Memory List *****"));
+
+ ExpectedIndex = 0;
+ ExpectedBase = 0;
+ LastType = (ULONG)-1;
+
+ do {
+ Index = 0;
+ FoundDescriptor = NULL;
+ CurrentLink = BlLoaderBlock->MemoryDescriptorListHead.Flink;
+
+ while (CurrentLink != &BlLoaderBlock->MemoryDescriptorListHead) {
+
+ CurrentDescriptor = (PMEMORY_ALLOCATION_DESCRIPTOR)CurrentLink;
+ if (CurrentDescriptor->BasePage == ExpectedBase) {
+ if ((FoundDescriptor != NULL) && (FoundDescriptor->BasePage == ExpectedBase)) {
+ BlLog((activeTargets,
+ "ACK! Found multiple descriptors with base %x: %x and %x",
+ ExpectedBase,
+ FoundDescriptor,
+ CurrentDescriptor));
+ } else {
+ FoundDescriptor = CurrentDescriptor;
+ FoundIndex = Index;
+ }
+ } else if (CurrentDescriptor->BasePage > ExpectedBase) {
+ if ((FoundDescriptor == NULL) ||
+ (CurrentDescriptor->BasePage < FoundDescriptor->BasePage)) {
+ FoundDescriptor = CurrentDescriptor;
+ FoundIndex = Index;
+ }
+ }
+
+ CurrentLink = CurrentLink->Flink;
+ Index++;
+ }
+
+ if (FoundDescriptor != NULL) {
+
+ if (FoundDescriptor->BasePage != ExpectedBase) {
+ BlLog((activeTargets,
+ " ACK! MISSING MEMORY! ACK! Base %8x Pages %8x",
+ ExpectedBase,
+ FoundDescriptor->BasePage - ExpectedBase));
+ }
+ BlLog((activeTargets,
+ "%c%c%2d Descriptor %8x: Type %8x Base %8x Pages %8x",
+ FoundDescriptor->MemoryType == LastType ? '^' : ' ',
+ FoundIndex == ExpectedIndex ? ' ' : '*',
+ FoundIndex,
+ FoundDescriptor,
+ (USHORT)(FoundDescriptor->MemoryType),
+ FoundDescriptor->BasePage,
+ FoundDescriptor->PageCount));
+
+ if (FoundIndex == ExpectedIndex) {
+ ExpectedIndex++;
+ }
+ ExpectedBase = FoundDescriptor->BasePage + FoundDescriptor->PageCount;
+
+ LastType = FoundDescriptor->MemoryType;
+ if (LastType != MemoryFree) {
+ LastType = (ULONG)-1;
+ } else {
+ FreeBlocks++;
+ FreePages += FoundDescriptor->PageCount;
+ if (FoundDescriptor->PageCount > LargestFree) {
+ LargestFree = FoundDescriptor->PageCount;
+ }
+ }
+ }
+
+ } while ( FoundDescriptor != NULL );
+
+ BlLog((activeTargets,
+ "Total free blocks %2d, free pages %4x, largest free %4x",
+ FreeBlocks,
+ FreePages,
+ LargestFree));
+
+ //BlLog((activeTargets,"******************************"));
+
+ if (((activeTargets & LOG_DISPLAY) != 0) && ((Targets & LOG_WAIT) != 0)) {
+ BlLogWaitForKeystroke();
+ }
+ }
+
+ return;
+}
+
+VOID
+BlLogWaitForKeystroke (
+ VOID
+ )
+{
+ UCHAR Key=0;
+ ULONG Count;
+
+ if ((BlLogActiveTargets & LOG_DISPLAY) != 0) {
+ do {
+ if (ArcGetReadStatus(ARC_CONSOLE_INPUT) == ESUCCESS) {
+ ArcRead(ARC_CONSOLE_INPUT,
+ &Key,
+ sizeof(Key),
+ &Count);
+ break;
+ }
+ } while ( TRUE );
+ }
+
+ return;
+}
+
+#endif // DBG
diff --git a/private/ntos/boot/lib/blmemory.c b/private/ntos/boot/lib/blmemory.c
new file mode 100644
index 000000000..92c7c8d03
--- /dev/null
+++ b/private/ntos/boot/lib/blmemory.c
@@ -0,0 +1,1256 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ blmemory.c
+
+Abstract:
+
+ This module implements the OS loader memory allocation routines.
+
+Author:
+
+ David N. Cutler (davec) 19-May-1991
+
+Revision History:
+
+--*/
+
+#include "bldr.h"
+
+#define MIN(_a,_b) (((_a) <= (_b)) ? (_a) : (_b))
+#define MAX(_a,_b) (((_a) >= (_b)) ? (_a) : (_b))
+
+//
+// PPC needs to allocate initial structures from high memory, in order to
+// leave room in low memory for KSEG0.
+//
+
+#if !defined(_PPC_)
+ALLOCATION_POLICY BlMemoryAllocationPolicy = BlAllocateBestFit;
+ALLOCATION_POLICY BlHeapAllocationPolicy = BlAllocateBestFit;
+#else
+ALLOCATION_POLICY BlMemoryAllocationPolicy = BlAllocateHighestFit;
+ALLOCATION_POLICY BlHeapAllocationPolicy = BlAllocateHighestFit;
+#endif
+
+//
+// Define memory allocation descriptor listhead and heap storage variables.
+//
+
+ULONG BlHeapFree;
+ULONG BlHeapLimit;
+PLOADER_PARAMETER_BLOCK BlLoaderBlock;
+
+#if DBG
+ULONG TotalHeapAbandoned = 0;
+#endif
+
+
+VOID
+BlSetAllocationPolicy (
+ IN ALLOCATION_POLICY MemoryAllocationPolicy,
+ IN ALLOCATION_POLICY HeapAllocationPolicy
+ )
+{
+ BlMemoryAllocationPolicy = MemoryAllocationPolicy;
+ BlHeapAllocationPolicy = HeapAllocationPolicy;
+
+ return;
+}
+
+VOID
+BlInsertDescriptor (
+ IN PMEMORY_ALLOCATION_DESCRIPTOR NewDescriptor
+ )
+
+/*++
+
+Routine Description:
+
+ This routine inserts a memory descriptor in the memory allocation list.
+ It inserts the new descriptor in sorted order, based on the starting
+ page of the block. It also merges adjacent blocks of free memory.
+
+Arguments:
+
+ ListHead - Supplies the address of the memory allocation list head.
+
+ NewDescriptor - Supplies the address of the descriptor that is to be
+ inserted.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PLIST_ENTRY ListHead = &BlLoaderBlock->MemoryDescriptorListHead;
+ PLIST_ENTRY PreviousEntry;
+ PMEMORY_ALLOCATION_DESCRIPTOR PreviousDescriptor;
+ PLIST_ENTRY NextEntry;
+ PMEMORY_ALLOCATION_DESCRIPTOR NextDescriptor;
+
+ //
+ // Find the first descriptor in the list that starts above the new
+ // descriptor. The new descriptor goes in front of this descriptor.
+ //
+
+ PreviousEntry = ListHead;
+ NextEntry = ListHead->Flink;
+ while (NextEntry != ListHead) {
+ NextDescriptor = CONTAINING_RECORD(NextEntry,
+ MEMORY_ALLOCATION_DESCRIPTOR,
+ ListEntry);
+ if (NewDescriptor->BasePage < NextDescriptor->BasePage) {
+ break;
+ }
+ PreviousEntry = NextEntry;
+ PreviousDescriptor = NextDescriptor;
+ NextEntry = NextEntry->Flink;
+ }
+
+ //
+ // If the new descriptor doesn't describe free memory, just insert it
+ // in the list in front of the previous entry. Otherwise, check to see
+ // if free blocks can be merged.
+ //
+
+ if (NewDescriptor->MemoryType != LoaderFree) {
+
+ InsertHeadList(PreviousEntry, &NewDescriptor->ListEntry);
+
+ } else {
+
+ //
+ // If the previous block also describes free memory, and it's
+ // contiguous with the new block, merge them by adding the
+ // page count from the new
+ //
+ // On Alpha, do not merge across the 1GB line, as the initialization
+ // code assumes any memory descriptor that starts in KSEG0 also ends
+ // in KSEG0.
+ //
+
+ if ((PreviousEntry != ListHead) &&
+ (PreviousDescriptor->MemoryType == LoaderFree) &&
+#if defined(_ALPHA_)
+ (NewDescriptor->BasePage != (0x40000000 >> PAGE_SHIFT)) &&
+#endif
+ ((PreviousDescriptor->BasePage + PreviousDescriptor->PageCount) ==
+ NewDescriptor->BasePage)) {
+ PreviousDescriptor->PageCount += NewDescriptor->PageCount;
+ NewDescriptor = PreviousDescriptor;
+ } else {
+ InsertHeadList(PreviousEntry, &NewDescriptor->ListEntry);
+ }
+ if ((NextEntry != ListHead) &&
+ (NextDescriptor->MemoryType == LoaderFree) &&
+ ((NewDescriptor->BasePage + NewDescriptor->PageCount) == NextDescriptor->BasePage)) {
+ NewDescriptor->PageCount += NextDescriptor->PageCount;
+ BlRemoveDescriptor(NextDescriptor);
+ }
+ }
+
+ return;
+}
+
+ARC_STATUS
+BlMemoryInitialize (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates stack space for the OS loader, initializes
+ heap storage, and initializes the memory allocation list.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ ESUCCESS is returned if the initialization is successful. Otherwise,
+ ENOMEM is returned.
+
+--*/
+
+{
+
+ PMEMORY_ALLOCATION_DESCRIPTOR AllocationDescriptor;
+ PMEMORY_DESCRIPTOR HeapDescriptor;
+ PMEMORY_DESCRIPTOR StackDescriptor;
+ PMEMORY_DESCRIPTOR MemoryDescriptor;
+ PMEMORY_DESCRIPTOR ProgramDescriptor;
+ ULONG EndPage;
+ ULONG HeapAndStackPages;
+ ULONG StackPages;
+ ULONG StackBasePage;
+
+ //
+ // Find the memory descriptor that describes the allocation for the OS
+ // loader itself.
+ //
+ // On PPC, there can be multiple descriptors of type MemoryLoadedProgram.
+ // (See lib\ppc\ntsetup.c for more information.) All but one of these
+ // will reside above 8 MB. It is the one below 8 MB that we want.
+ //
+
+ ProgramDescriptor = NULL;
+ while ((ProgramDescriptor = ArcGetMemoryDescriptor(ProgramDescriptor)) != NULL) {
+ if (ProgramDescriptor->MemoryType == MemoryLoadedProgram) {
+#if !defined(_PPC_)
+ break;
+#else
+ if (ProgramDescriptor->BasePage < ((8*1024*1024) >> PAGE_SHIFT)) {
+ break;
+ }
+#endif
+ }
+ }
+
+ //
+ // If a loaded program memory descriptor was found, then it must be
+ // for the OS loader since that is the only program that can be loaded.
+ // If a loaded program memory descriptor was not found, then firmware
+ // is not functioning properly and an unsuccessful status is returned.
+ //
+
+ if (ProgramDescriptor == NULL) {
+ return ENOMEM;
+ }
+
+#if !defined(_PPC_)
+
+ //
+ // Find the free memory descriptor that is just below the loaded
+ // program in memory. There should be several megabytes of free
+ // memory just preceeding the OS loader.
+ //
+
+ StackPages = BL_STACK_PAGES;
+ HeapAndStackPages = BL_HEAP_PAGES + BL_STACK_PAGES;
+ StackDescriptor = NULL;
+
+ HeapDescriptor = NULL;
+ while ((HeapDescriptor = ArcGetMemoryDescriptor(HeapDescriptor)) != NULL) {
+ if (((HeapDescriptor->MemoryType == MemoryFree) ||
+ (HeapDescriptor->MemoryType == MemoryFreeContiguous)) &&
+ ((HeapDescriptor->BasePage + HeapDescriptor->PageCount) ==
+ ProgramDescriptor->BasePage)) {
+ break;
+ }
+ }
+
+ //
+ // If a free memory descriptor was not found that describes the free
+ // memory just below the OS loader, or the memory descriptor is not
+ // large enough for the OS loader stack and heap, then try and find
+ // a suitable one.
+ //
+ if ((HeapDescriptor == NULL) ||
+ (HeapDescriptor->PageCount < (BL_HEAP_PAGES + BL_STACK_PAGES))) {
+
+ HeapDescriptor = NULL;
+ while ((HeapDescriptor = ArcGetMemoryDescriptor(HeapDescriptor)) != NULL) {
+ if (((HeapDescriptor->MemoryType == MemoryFree) ||
+ (HeapDescriptor->MemoryType == MemoryFreeContiguous)) &&
+ (HeapDescriptor->PageCount >= (BL_HEAP_PAGES + BL_STACK_PAGES))) {
+
+ break;
+ }
+ }
+ }
+
+ if (HeapDescriptor != NULL) {
+ StackBasePage = HeapDescriptor->BasePage + HeapDescriptor->PageCount - BL_STACK_PAGES;
+ }
+
+#else // defined(_PPC_)
+
+ //
+ // Some ARC firmwares (IBM and Motorola) put the loader stack
+ // immediately below the program, but do not mark the stack memory
+ // as in use, depending on the loader to mark it. Other firmwares
+ // (Open Firmware) put the loader stack elsewhere and mark it as
+ // FirmwareTemporary. We can't tell which one we're on, so if there
+ // is free memory just below the loader program, we need to assume
+ // that BL_STACK_PAGES of it is the stack. On Open Firmware
+ // machines, this means that we waste some memory, because there is
+ // free memory below the program but it's really free, not stack
+ // memory. Such is life.
+ //
+ // This does not impact our goal of avoiding very low memory for
+ // everything except blocks that really must be in KSEG0, because
+ // all current firmwares put the loader at 0x600000, which should be
+ // well above the KSEG0 line.
+ //
+ // Just to be sure, however, we put the loader heap as high as
+ // possible.
+ //
+ // The first step here is to find free memory just below the loaded
+ // program. If there are at least BL_STACK_PAGES there, we mark
+ // those pages as OsloaderStack and stay away from them. If not, we
+ // assume that the firmware has put the stack elsewhere and marked
+ // it appropriately. In either case, we allocate the loader heap
+ // separately.
+ //
+
+ StackPages = 0;
+ HeapAndStackPages = BL_HEAP_PAGES;
+
+ StackDescriptor = NULL;
+ while ((StackDescriptor = ArcGetMemoryDescriptor(StackDescriptor)) != NULL) {
+ if (((StackDescriptor->MemoryType == MemoryFree) ||
+ (StackDescriptor->MemoryType == MemoryFreeContiguous)) &&
+ ((StackDescriptor->BasePage + StackDescriptor->PageCount) ==
+ ProgramDescriptor->BasePage)) {
+ if (StackDescriptor->PageCount >= BL_STACK_PAGES) {
+ StackPages = BL_STACK_PAGES;
+ StackBasePage = StackDescriptor->BasePage + StackDescriptor->PageCount - StackPages;
+ }
+ break;
+ }
+ }
+
+ //
+ // Now allocate the heap as high as possible.
+ //
+
+ HeapDescriptor = NULL;
+ MemoryDescriptor = NULL;
+ while ((MemoryDescriptor = ArcGetMemoryDescriptor(MemoryDescriptor)) != NULL) {
+ if (((MemoryDescriptor->MemoryType == MemoryFree) ||
+ (MemoryDescriptor->MemoryType == MemoryFreeContiguous)) &&
+ (MemoryDescriptor->PageCount >= BL_HEAP_PAGES)) {
+ if ((HeapDescriptor == NULL) ||
+ ((HeapDescriptor != NULL) &&
+ (MemoryDescriptor->BasePage > HeapDescriptor->BasePage))) {
+ HeapDescriptor = MemoryDescriptor;
+ }
+ }
+ }
+
+#endif // defined(_PPC_)
+
+ //
+ // A suitable descriptor could not be found, return an unsuccessful
+ // status.
+ //
+ if (HeapDescriptor == NULL) {
+ return(ENOMEM);
+ }
+
+ //
+ // Compute the address of the loader heap, initialize the heap
+ // allocation variables, and zero the heap memory.
+ //
+ EndPage = HeapDescriptor->BasePage + HeapDescriptor->PageCount;
+
+ BlHeapFree = KSEG0_BASE | ((EndPage - HeapAndStackPages) << PAGE_SHIFT);
+
+
+ //
+ // always reserve enough space in the heap for one more memory
+ // descriptor, so we can go create more heap if we run out.
+ //
+ BlHeapLimit = (BlHeapFree + (BL_HEAP_PAGES << PAGE_SHIFT)) - sizeof(MEMORY_ALLOCATION_DESCRIPTOR);
+
+ RtlZeroMemory((PVOID)BlHeapFree, BL_HEAP_PAGES << PAGE_SHIFT);
+
+ //
+ // Allocate and initialize the loader parameter block.
+ //
+
+ BlLoaderBlock =
+ (PLOADER_PARAMETER_BLOCK)BlAllocateHeap(sizeof(LOADER_PARAMETER_BLOCK));
+
+ if (BlLoaderBlock == NULL) {
+ return ENOMEM;
+ }
+
+ InitializeListHead(&BlLoaderBlock->LoadOrderListHead);
+ InitializeListHead(&BlLoaderBlock->MemoryDescriptorListHead);
+
+ //
+ // Copy the memory descriptor list from firmware into the local heap and
+ // deallocate the loader heap and stack from the free memory descriptor.
+ //
+
+ MemoryDescriptor = NULL;
+ while ((MemoryDescriptor = ArcGetMemoryDescriptor(MemoryDescriptor)) != NULL) {
+ AllocationDescriptor =
+ (PMEMORY_ALLOCATION_DESCRIPTOR)BlAllocateHeap(
+ sizeof(MEMORY_ALLOCATION_DESCRIPTOR));
+
+ if (AllocationDescriptor == NULL) {
+ return ENOMEM;
+ }
+
+ AllocationDescriptor->MemoryType =
+ (TYPE_OF_MEMORY)MemoryDescriptor->MemoryType;
+
+ if (MemoryDescriptor->MemoryType == MemoryFreeContiguous) {
+ AllocationDescriptor->MemoryType = LoaderFree;
+
+ } else if (MemoryDescriptor->MemoryType == MemorySpecialMemory) {
+ AllocationDescriptor->MemoryType = LoaderSpecialMemory;
+ }
+
+ AllocationDescriptor->BasePage = MemoryDescriptor->BasePage;
+ AllocationDescriptor->PageCount = MemoryDescriptor->PageCount;
+ if (MemoryDescriptor == HeapDescriptor) {
+ AllocationDescriptor->PageCount -= HeapAndStackPages;
+ }
+ if (MemoryDescriptor == StackDescriptor) {
+ AllocationDescriptor->PageCount -= StackPages;
+ }
+
+ BlInsertDescriptor(AllocationDescriptor);
+ }
+
+ //
+ // Allocate a memory descriptor for the loader stack.
+ //
+
+ if (StackPages != 0) {
+
+ AllocationDescriptor =
+ (PMEMORY_ALLOCATION_DESCRIPTOR)BlAllocateHeap(
+ sizeof(MEMORY_ALLOCATION_DESCRIPTOR));
+
+ if (AllocationDescriptor == NULL) {
+ return ENOMEM;
+ }
+
+ AllocationDescriptor->MemoryType = LoaderOsloaderStack;
+ AllocationDescriptor->BasePage = StackBasePage;
+ AllocationDescriptor->PageCount = BL_STACK_PAGES;
+ BlInsertDescriptor(AllocationDescriptor);
+ }
+
+ //
+ // Allocate a memory descriptor for the loader heap.
+ //
+
+ AllocationDescriptor =
+ (PMEMORY_ALLOCATION_DESCRIPTOR)BlAllocateHeap(
+ sizeof(MEMORY_ALLOCATION_DESCRIPTOR));
+
+ if (AllocationDescriptor == NULL) {
+ return ENOMEM;
+ }
+
+ AllocationDescriptor->MemoryType = LoaderOsloaderHeap;
+ AllocationDescriptor->BasePage = EndPage - HeapAndStackPages;
+
+ AllocationDescriptor->PageCount = BL_HEAP_PAGES;
+ BlInsertDescriptor(AllocationDescriptor);
+
+ return ESUCCESS;
+}
+
+ARC_STATUS
+BlAllocateAlignedDescriptor (
+ IN TYPE_OF_MEMORY MemoryType,
+ IN ULONG BasePage,
+ IN ULONG PageCount,
+ IN ULONG Alignment,
+ OUT PULONG ActualBase
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates memory and generates one of more memory
+ descriptors to describe the allocated region. The first attempt
+ is to allocate the specified region of memory (at BasePage).
+ If the memory is not free, then the smallest region of free
+ memory that satisfies the request is allocated. The Alignment
+ parameter can be used to force the block to be allocated at a
+ particular alignment.
+
+Arguments:
+
+ MemoryType - Supplies the memory type that is to be assigend to
+ the generated descriptor.
+
+ BasePage - Supplies the base page number of the desired region.
+ If 0, no particular base page is required.
+
+ PageCount - Supplies the number of pages required.
+
+ Alignment - Supplies the required alignment, in pages. (E.g.,
+ with 4K page size, 16K alignment requires Alignment == 4.)
+ If 0, no particular alignment is required.
+
+ N.B. If BasePage is not 0, and the specified BasePage is
+ available, Alignment is ignored. It is up to the caller
+ to specify a BasePage that meets the caller's alignment
+ requirement.
+
+ ActualBase - Supplies a pointer to a variable that receives the
+ page number of the allocated region.
+
+Return Value:
+
+ ESUCCESS is returned if an available block of free memory can be
+ allocated. Otherwise, return a unsuccessful status.
+
+--*/
+
+{
+
+ PMEMORY_ALLOCATION_DESCRIPTOR FreeDescriptor;
+ PMEMORY_ALLOCATION_DESCRIPTOR NextDescriptor;
+ PLIST_ENTRY NextEntry;
+ LONG Offset;
+ ARC_STATUS Status;
+ ULONG AlignedBasePage;
+
+ //
+ // Simplify the alignment checks by changing 0 to 1.
+ //
+
+ if (Alignment == 0) {
+ Alignment = 1;
+ }
+
+ //
+ // Attempt to find a free memory descriptor that encompasses the
+ // specified region or a free memory descriptor that is large
+ // enough to satisfy the request.
+ //
+
+ FreeDescriptor = NULL;
+ NextEntry = BlLoaderBlock->MemoryDescriptorListHead.Flink;
+ while (NextEntry != &BlLoaderBlock->MemoryDescriptorListHead) {
+ NextDescriptor = CONTAINING_RECORD(NextEntry,
+ MEMORY_ALLOCATION_DESCRIPTOR,
+ ListEntry);
+
+ if (NextDescriptor->MemoryType == LoaderFree) {
+ Offset = BasePage - NextDescriptor->BasePage;
+ if ((Offset >= 0) &&
+ (NextDescriptor->PageCount >= (ULONG)(Offset + PageCount))) {
+ Status = BlGenerateDescriptor(NextDescriptor,
+ MemoryType,
+ BasePage,
+ PageCount);
+
+ *ActualBase = BasePage;
+ return Status;
+
+ } else {
+
+ AlignedBasePage = (NextDescriptor->BasePage + (Alignment - 1)) & ~(Alignment - 1);
+ Offset = AlignedBasePage - NextDescriptor->BasePage;
+ if ((Offset + PageCount) <= NextDescriptor->PageCount) {
+
+ //
+ // This block will work. If the allocation policy is
+ // LowestFit, take this block (the memory list is sorted).
+ // Otherwise, if this block best meets the allocation
+ // policy, remember it and keep looking.
+ //
+
+ if (BlMemoryAllocationPolicy == BlAllocateLowestFit) {
+ FreeDescriptor = NextDescriptor;
+ break;
+ }
+
+ if ((FreeDescriptor == NULL) ||
+ (BlMemoryAllocationPolicy == BlAllocateHighestFit) ||
+ ((FreeDescriptor != NULL) &&
+ (NextDescriptor->PageCount < FreeDescriptor->PageCount))) {
+ FreeDescriptor = NextDescriptor;
+ }
+ }
+ }
+ }
+
+ NextEntry = NextEntry->Flink;
+ }
+
+ //
+ // If a free region that satisfies the request was found, then allocate
+ // the space from that descriptor. Otherwise, return an unsuccessful status.
+ //
+ // If allocating lowest-fit or best-fit, allocate from the start of the block,
+ // rounding up to the required alignment. If allocating highest-fit, allocate
+ // from the end of the block, rounding down to the required alignment.
+ //
+
+ if (FreeDescriptor != NULL) {
+ AlignedBasePage = FreeDescriptor->BasePage + (Alignment - 1);
+ if (BlMemoryAllocationPolicy == BlAllocateHighestFit) {
+ AlignedBasePage = FreeDescriptor->BasePage + FreeDescriptor->PageCount - PageCount;
+ }
+ AlignedBasePage = AlignedBasePage & ~(Alignment - 1);
+ *ActualBase = AlignedBasePage;
+ return BlGenerateDescriptor(FreeDescriptor,
+ MemoryType,
+ AlignedBasePage,
+ PageCount);
+
+ } else {
+ return ENOMEM;
+ }
+}
+
+
+PVOID
+BlAllocateHeapAligned (
+ IN ULONG Size
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates memory from the OS loader heap. The memory
+ will be allocated on a cache line boundary.
+
+Arguments:
+
+ Size - Supplies the size of block required in bytes.
+
+Return Value:
+
+ If a free block of memory of the specified size is available, then
+ the address of the block is returned. Otherwise, NULL is returned.
+
+--*/
+
+{
+ PVOID Buffer;
+
+ Buffer = BlAllocateHeap(Size + BlDcacheFillSize - 1);
+ if (Buffer != NULL) {
+ //
+ // round up to a cache line boundary
+ //
+ Buffer = ALIGN_BUFFER(Buffer);
+ }
+
+ return(Buffer);
+
+}
+
+PVOID
+BlAllocateHeap (
+ IN ULONG Size
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates memory from the OS loader heap.
+
+Arguments:
+
+ Size - Supplies the size of block required in bytes.
+
+Return Value:
+
+ If a free block of memory of the specified size is available, then
+ the address of the block is returned. Otherwise, NULL is returned.
+
+--*/
+
+{
+ PMEMORY_ALLOCATION_DESCRIPTOR AllocationDescriptor;
+ PMEMORY_ALLOCATION_DESCRIPTOR FreeDescriptor;
+ PMEMORY_ALLOCATION_DESCRIPTOR NextDescriptor;
+ PLIST_ENTRY NextEntry;
+ ULONG NewHeapPages;
+ ULONG LastAttempt;
+ ULONG Block;
+
+ //
+ // Round size up to next allocation boundary and attempt to allocate
+ // a block of the requested size.
+ //
+
+ Size = (Size + (BL_GRANULARITY - 1)) & (~(BL_GRANULARITY - 1));
+
+ Block = BlHeapFree;
+ if ((BlHeapFree + Size) <= BlHeapLimit) {
+ BlHeapFree += Size;
+ return (PVOID)Block;
+
+ } else {
+
+#if DBG
+ TotalHeapAbandoned += (BlHeapLimit - BlHeapFree);
+ BlLog((LOG_ALL_W,"ABANDONING %d bytes of heap; total abandoned %d\n",
+ (BlHeapLimit - BlHeapFree), TotalHeapAbandoned));
+#endif
+
+ //
+ // Our heap is full. BlHeapLimit always reserves enough space
+ // for one more MEMORY_ALLOCATION_DESCRIPTOR, so use that to
+ // go try and find more free memory we can use.
+ //
+ AllocationDescriptor = (PMEMORY_ALLOCATION_DESCRIPTOR)BlHeapLimit;
+
+ //
+ // Attempt to find a free memory descriptor big enough to hold this
+ // allocation or BL_HEAP_PAGES, whichever is bigger.
+ //
+ NewHeapPages = ((Size + sizeof(MEMORY_ALLOCATION_DESCRIPTOR) + (PAGE_SIZE-1)) >> PAGE_SHIFT);
+ if (NewHeapPages < BL_HEAP_PAGES) {
+ NewHeapPages = BL_HEAP_PAGES;
+ }
+
+ do {
+
+ FreeDescriptor = NULL;
+ NextEntry = BlLoaderBlock->MemoryDescriptorListHead.Flink;
+ while (NextEntry != &BlLoaderBlock->MemoryDescriptorListHead) {
+ NextDescriptor = CONTAINING_RECORD(NextEntry,
+ MEMORY_ALLOCATION_DESCRIPTOR,
+ ListEntry);
+
+ if ((NextDescriptor->MemoryType == LoaderFree) &&
+ (NextDescriptor->PageCount >= NewHeapPages)) {
+
+ //
+ // This block will work. If the allocation policy is
+ // LowestFit, take this block (the memory list is sorted).
+ // Otherwise, if this block best meets the allocation
+ // policy, remember it and keep looking.
+ //
+
+ if (BlHeapAllocationPolicy == BlAllocateLowestFit) {
+ FreeDescriptor = NextDescriptor;
+ break;
+ }
+
+ if ((FreeDescriptor == NULL) ||
+ (BlHeapAllocationPolicy == BlAllocateHighestFit) ||
+ ((FreeDescriptor != NULL) &&
+ (NextDescriptor->PageCount < FreeDescriptor->PageCount))) {
+ FreeDescriptor = NextDescriptor;
+ }
+ }
+ NextEntry = NextEntry->Flink;
+ }
+
+ //
+ // If we were unable to find a block of the desired size, memory
+ // must be getting tight, so try again, this time looking just
+ // enough to keep us going. (The first time through, we try to
+ // allocate at least BL_HEAP_PAGES.)
+ //
+ if (FreeDescriptor != NULL) {
+ break;
+ }
+ LastAttempt = NewHeapPages;
+ NewHeapPages = ((Size + sizeof(MEMORY_ALLOCATION_DESCRIPTOR) + (PAGE_SIZE-1)) >> PAGE_SHIFT);
+ if (NewHeapPages == LastAttempt) {
+ break;
+ }
+
+ } while (TRUE);
+
+ if (FreeDescriptor == NULL) {
+
+ //
+ // No free memory left.
+ //
+ return(NULL);
+ }
+
+ //
+ // We've found a descriptor that's big enough. Just carve a
+ // piece off the end and use that for our heap. If we're taking
+ // all of the memory from the descriptor, remove it from the
+ // memory list. (This wastes a descriptor, but that's life.)
+ //
+
+ FreeDescriptor->PageCount -= NewHeapPages;
+ if (FreeDescriptor->PageCount == 0) {
+ BlRemoveDescriptor(FreeDescriptor);
+ }
+
+ //
+ // Initialize our new descriptor and add it to the list.
+ //
+ AllocationDescriptor->MemoryType = LoaderOsloaderHeap;
+ AllocationDescriptor->BasePage = FreeDescriptor->BasePage +
+ FreeDescriptor->PageCount;
+ AllocationDescriptor->PageCount = NewHeapPages;
+
+ BlInsertDescriptor(AllocationDescriptor);
+
+ //
+ // initialize new heap values and return pointer to newly
+ // alloc'd memory.
+ //
+ BlHeapFree = KSEG0_BASE | (AllocationDescriptor->BasePage << PAGE_SHIFT);
+
+ BlHeapLimit = (BlHeapFree + (NewHeapPages << PAGE_SHIFT)) - sizeof(MEMORY_ALLOCATION_DESCRIPTOR);
+
+ RtlZeroMemory((PVOID)BlHeapFree, NewHeapPages << PAGE_SHIFT);
+
+ Block = BlHeapFree;
+ if ((BlHeapFree + Size) < BlHeapLimit) {
+ BlHeapFree += Size;
+ return(PVOID)Block;
+ } else {
+ //
+ // we should never get here
+ //
+ return(NULL);
+ }
+ }
+}
+
+VOID
+BlGenerateNewHeap (
+ IN PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor,
+ IN ULONG BasePage,
+ IN ULONG PageCount
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates a new heap block from the specified memory
+ descriptor, avoiding the region specified by BasePage and PageCount.
+ The caller must ensure that this region does not encompass the entire
+ block.
+
+ The allocated heap block may be as small as a single page.
+
+Arguments:
+
+ MemoryDescriptor - Supplies a pointer to a free memory descriptor
+ from which the heap block is to be allocated.
+
+ BasePage - Supplies the base page number of the excluded region.
+
+ PageCount - Supplies the number of pages in the excluded region.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PMEMORY_ALLOCATION_DESCRIPTOR AllocationDescriptor;
+ ULONG NewHeapPages;
+ ULONG AvailableAtFront;
+ ULONG AvailableAtBack;
+
+ //
+ // BlHeapLimit always reserves enough space for one more
+ // MEMORY_ALLOCATION_DESCRIPTOR, so use that to describe the
+ // new heap block.
+ //
+ AllocationDescriptor = (PMEMORY_ALLOCATION_DESCRIPTOR)BlHeapLimit;
+
+ //
+ // Allocate the new heap from either the front or the back of the
+ // specified descriptor, whichever fits best. We'd like to allocate
+ // BL_HEAP_PAGES pages, but we'll settle for less.
+ //
+ AvailableAtFront = BasePage - MemoryDescriptor->BasePage;
+ AvailableAtBack = (MemoryDescriptor->BasePage + MemoryDescriptor->PageCount) -
+ (BasePage + PageCount);
+
+ if ((AvailableAtFront == 0) ||
+ ((AvailableAtBack != 0) && (AvailableAtBack < AvailableAtFront))) {
+ NewHeapPages = MIN(AvailableAtBack, BL_HEAP_PAGES);
+ AllocationDescriptor->BasePage =
+ MemoryDescriptor->BasePage + MemoryDescriptor->PageCount - NewHeapPages;
+ } else {
+ NewHeapPages = MIN(AvailableAtFront, BL_HEAP_PAGES);
+ AllocationDescriptor->BasePage = MemoryDescriptor->BasePage;
+ MemoryDescriptor->BasePage += NewHeapPages;
+ }
+
+ MemoryDescriptor->PageCount -= NewHeapPages;
+
+ //
+ // Initialize our new descriptor and add it to the list.
+ //
+ AllocationDescriptor->MemoryType = LoaderOsloaderHeap;
+ AllocationDescriptor->PageCount = NewHeapPages;
+
+ BlInsertDescriptor(AllocationDescriptor);
+
+ //
+ // Initialize new heap values.
+ //
+ BlHeapFree = KSEG0_BASE | (AllocationDescriptor->BasePage << PAGE_SHIFT);
+
+ BlHeapLimit = (BlHeapFree + (NewHeapPages << PAGE_SHIFT)) - sizeof(MEMORY_ALLOCATION_DESCRIPTOR);
+
+ RtlZeroMemory((PVOID)BlHeapFree, NewHeapPages << PAGE_SHIFT);
+
+ return;
+}
+
+ARC_STATUS
+BlGenerateDescriptor (
+ IN PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor,
+ IN MEMORY_TYPE MemoryType,
+ IN ULONG BasePage,
+ IN ULONG PageCount
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates a new memory descriptor to describe the
+ specified region of memory which is assumed to lie totally within
+ the specified region which is free.
+
+Arguments:
+
+ MemoryDescriptor - Supplies a pointer to a free memory descriptor
+ from which the specified memory is to be allocated.
+
+ MemoryType - Supplies the type that is assigned to the allocated
+ memory.
+
+ BasePage - Supplies the base page number.
+
+ PageCount - Supplies the number of pages.
+
+Return Value:
+
+ ESUCCESS is returned if a descriptor(s) is successfully generated.
+ Otherwise, return an unsuccessful status.
+
+--*/
+
+{
+
+ PMEMORY_ALLOCATION_DESCRIPTOR NewDescriptor1;
+ PMEMORY_ALLOCATION_DESCRIPTOR NewDescriptor2;
+ LONG Offset;
+ TYPE_OF_MEMORY OldType;
+ BOOLEAN SecondDescriptorNeeded;
+
+ //
+ // If the specified region totally consumes the free region, then no
+ // additional descriptors need to be allocated. If the specified region
+ // is at the start or end of the free region, then only one descriptor
+ // needs to be allocated. Otherwise, two additional descriptors need to
+ // be allocated.
+ //
+
+ Offset = BasePage - MemoryDescriptor->BasePage;
+ if ((Offset == 0) && (PageCount == MemoryDescriptor->PageCount)) {
+
+ //
+ // The specified region totally consumes the free region.
+ //
+
+ MemoryDescriptor->MemoryType = MemoryType;
+
+ } else {
+
+ //
+ // Mark the entire given memory descriptor as in use. If we are
+ // out of heap, BlAllocateHeap will search for a new descriptor
+ // to grow the heap and this prevents both routines from trying
+ // to use the same descriptor.
+ //
+ OldType = MemoryDescriptor->MemoryType;
+ MemoryDescriptor->MemoryType = LoaderSpecialMemory;
+
+ //
+ // A memory descriptor must be generated to describe the allocated
+ // memory.
+ //
+
+ SecondDescriptorNeeded =
+ (BOOLEAN)((BasePage != MemoryDescriptor->BasePage) &&
+ ((ULONG)(Offset + PageCount) != MemoryDescriptor->PageCount));
+
+ NewDescriptor1 =
+ (PMEMORY_ALLOCATION_DESCRIPTOR)BlAllocateHeap(
+ sizeof(MEMORY_ALLOCATION_DESCRIPTOR));
+
+ //
+ // If allocation of the first additional memory descriptor failed,
+ // then generate new heap using the block from which we are
+ // allocating. This can only be done if the block is free.
+ //
+ // Note that BlGenerateNewHeap cannot fail, because we know there is
+ // at least one more page in the block than we want to take from it.
+ //
+ // Note also that the allocation following BlGenerateNewHeap is
+ // guaranteed to succeed.
+ //
+
+ if (NewDescriptor1 == NULL) {
+ if (OldType != LoaderFree) {
+ MemoryDescriptor->MemoryType = OldType;
+ return ENOMEM;
+ }
+ BlGenerateNewHeap(MemoryDescriptor, BasePage, PageCount);
+ NewDescriptor1 =
+ (PMEMORY_ALLOCATION_DESCRIPTOR)BlAllocateHeap(
+ sizeof(MEMORY_ALLOCATION_DESCRIPTOR));
+ }
+
+ //
+ // If a second descriptor is needed, allocate it. As above, if the
+ // allocation fails, generate new heap using our block.
+ //
+ // Note that if BlGenerateNewHeap was called above, the first call
+ // to BlAllocateHeap below will not fail. (So we won't call
+ // BlGenerateNewHeap twice.)
+ //
+
+ if (SecondDescriptorNeeded) {
+ NewDescriptor2 =
+ (PMEMORY_ALLOCATION_DESCRIPTOR)BlAllocateHeap(
+ sizeof(MEMORY_ALLOCATION_DESCRIPTOR));
+ if (NewDescriptor2 == NULL) {
+ if (OldType != LoaderFree) {
+ MemoryDescriptor->MemoryType = OldType;
+ return ENOMEM;
+ }
+ NewDescriptor2 =
+ (PMEMORY_ALLOCATION_DESCRIPTOR)BlAllocateHeap(
+ sizeof(MEMORY_ALLOCATION_DESCRIPTOR));
+ }
+ }
+
+ NewDescriptor1->MemoryType = MemoryType;
+ NewDescriptor1->BasePage = BasePage;
+ NewDescriptor1->PageCount = PageCount;
+
+ if (BasePage == MemoryDescriptor->BasePage) {
+
+ //
+ // The specified region lies at the start of the free region.
+ //
+
+ MemoryDescriptor->BasePage += PageCount;
+ MemoryDescriptor->PageCount -= PageCount;
+ MemoryDescriptor->MemoryType = OldType;
+
+ } else if ((ULONG)(Offset + PageCount) == MemoryDescriptor->PageCount) {
+
+ //
+ // The specified region lies at the end of the free region.
+ //
+
+ MemoryDescriptor->PageCount -= PageCount;
+ MemoryDescriptor->MemoryType = OldType;
+
+ } else {
+
+ //
+ // The specified region lies in the middle of the free region.
+ //
+
+ NewDescriptor2->MemoryType = LoaderFree;
+ NewDescriptor2->BasePage = BasePage + PageCount;
+ NewDescriptor2->PageCount =
+ MemoryDescriptor->PageCount - (PageCount + Offset);
+
+ MemoryDescriptor->PageCount = Offset;
+ MemoryDescriptor->MemoryType = OldType;
+
+ BlInsertDescriptor(NewDescriptor2);
+ }
+
+ BlInsertDescriptor(NewDescriptor1);
+ }
+
+ return ESUCCESS;
+}
+
+PMEMORY_ALLOCATION_DESCRIPTOR
+BlFindMemoryDescriptor(
+ IN ULONG BasePage
+ )
+
+/*++
+
+Routine Description:
+
+ Finds the memory allocation descriptor that contains the given page.
+
+Arguments:
+
+ BasePage - Supplies the page whose allocation descriptor is to be found.
+
+Return Value:
+
+ != NULL - Pointer to the requested memory allocation descriptor
+ == NULL - indicates no memory descriptor contains the given page
+
+--*/
+
+{
+ PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor=NULL;
+ PLIST_ENTRY NextEntry;
+
+ NextEntry = BlLoaderBlock->MemoryDescriptorListHead.Flink;
+ while (NextEntry != &BlLoaderBlock->MemoryDescriptorListHead) {
+ MemoryDescriptor = CONTAINING_RECORD(NextEntry,
+ MEMORY_ALLOCATION_DESCRIPTOR,
+ ListEntry);
+ if ((MemoryDescriptor->BasePage <= BasePage) &&
+ (MemoryDescriptor->BasePage + MemoryDescriptor->PageCount > BasePage)) {
+
+ //
+ // Found it.
+ //
+ break;
+ }
+
+ NextEntry = NextEntry->Flink;
+ }
+
+ if (NextEntry == &BlLoaderBlock->MemoryDescriptorListHead) {
+ return(NULL);
+ } else {
+ return(MemoryDescriptor);
+ }
+
+}
+
+#ifdef SETUP
+PMEMORY_ALLOCATION_DESCRIPTOR
+BlFindFreeMemoryBlock(
+ IN ULONG PageCount
+ )
+
+/*++
+
+Routine Description:
+
+ Find a free memory block of at least a given size (using a best-fit
+ algorithm) or find the largest free memory block.
+
+Arguments:
+
+ PageCount - supplies the size in pages of the block. If this is 0,
+ then find the largest free block.
+
+Return Value:
+
+ Pointer to the memory allocation descriptor for the block or NULL if
+ no block could be found matching the search criteria.
+
+--*/
+
+{
+ PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor;
+ PMEMORY_ALLOCATION_DESCRIPTOR FoundMemoryDescriptor=NULL;
+ PLIST_ENTRY NextEntry;
+ ULONG LargestSize = 0;
+ ULONG SmallestLeftOver = (ULONG)(-1);
+
+ NextEntry = BlLoaderBlock->MemoryDescriptorListHead.Flink;
+ while (NextEntry != &BlLoaderBlock->MemoryDescriptorListHead) {
+ MemoryDescriptor = CONTAINING_RECORD(NextEntry,
+ MEMORY_ALLOCATION_DESCRIPTOR,
+ ListEntry);
+
+ if (MemoryDescriptor->MemoryType == LoaderFree) {
+
+ if(PageCount) {
+ //
+ // Looking for a block of a specific size.
+ //
+ if((MemoryDescriptor->PageCount >= PageCount)
+ && (MemoryDescriptor->PageCount - PageCount < SmallestLeftOver))
+ {
+ SmallestLeftOver = MemoryDescriptor->PageCount - PageCount;
+ FoundMemoryDescriptor = MemoryDescriptor;
+ }
+ } else {
+
+ //
+ // Looking for the largest free block.
+ //
+
+ if(MemoryDescriptor->PageCount > LargestSize) {
+ LargestSize = MemoryDescriptor->PageCount;
+ FoundMemoryDescriptor = MemoryDescriptor;
+ }
+ }
+
+ }
+ NextEntry = NextEntry->Flink;
+ }
+
+ return(FoundMemoryDescriptor);
+}
+
+ULONG
+BlDetermineTotalMemory(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Determine the total amount of memory in the machine.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Total amount of memory in the system, in bytes.
+
+--*/
+
+{
+ PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor;
+ PLIST_ENTRY NextEntry;
+ ULONG PageCount;
+
+ NextEntry = BlLoaderBlock->MemoryDescriptorListHead.Flink;
+ PageCount = 0;
+ while(NextEntry != &BlLoaderBlock->MemoryDescriptorListHead) {
+
+ MemoryDescriptor = CONTAINING_RECORD(NextEntry,
+ MEMORY_ALLOCATION_DESCRIPTOR,
+ ListEntry);
+
+ PageCount += MemoryDescriptor->PageCount;
+
+#if i386
+ //
+ // Note: on x86 machines, we never use the 40h pages below the 16
+ // meg line (bios shadow area). But we want to account for them here,
+ // so check for this case.
+ //
+
+ if(MemoryDescriptor->BasePage + MemoryDescriptor->PageCount == 0xfc0) {
+ PageCount += 0x40;
+ }
+#endif
+
+ NextEntry = NextEntry->Flink;
+ }
+
+ return(PageCount << PAGE_SHIFT);
+}
+#endif // def SETUP
diff --git a/private/ntos/boot/lib/blmisc.c b/private/ntos/boot/lib/blmisc.c
new file mode 100644
index 000000000..a3fb773b4
--- /dev/null
+++ b/private/ntos/boot/lib/blmisc.c
@@ -0,0 +1,131 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ blmisc.c
+
+Abstract:
+
+ This module contains miscellaneous routines for use by
+ the boot loader and setupldr.
+
+Author:
+
+ David N. Cutler (davec) 10-May-1991
+
+Revision History:
+
+--*/
+
+#include "bootlib.h"
+
+//
+// Value indicating whether a dbcs locale is active.
+// If this value is non-0 we use alternate display routines, etc,
+// and fetch messages in this language.
+//
+ULONG DbcsLangId;
+
+PCHAR
+BlGetArgumentValue (
+ IN ULONG Argc,
+ IN PCHAR Argv[],
+ IN PCHAR ArgumentName
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans the specified argument list for the named argument
+ and returns the address of the argument value. Argument strings are
+ specified as:
+
+ ArgumentName=ArgumentValue
+
+ Argument names are specified as:
+
+ ArgumentName=
+
+ The argument name match is case insensitive.
+
+Arguments:
+
+ Argc - Supplies the number of argument strings that are to be scanned.
+
+ Argv - Supplies a pointer to a vector of pointers to null terminated
+ argument strings.
+
+ ArgumentName - Supplies a pointer to a null terminated argument name.
+
+Return Value:
+
+ If the specified argument name is located, then a pointer to the argument
+ value is returned as the function value. Otherwise, a value of NULL is
+ returned.
+
+--*/
+
+{
+
+ PCHAR Name;
+ PCHAR String;
+
+ //
+ // Scan the argument strings until either a match is found or all of
+ // the strings have been scanned.
+ //
+
+ while (Argc > 0) {
+ String = Argv[Argc - 1];
+ if (String != NULL) {
+ Name = ArgumentName;
+ while ((*Name != 0) && (*String != 0)) {
+ if (toupper(*Name) != toupper(*String)) {
+ break;
+ }
+
+ Name += 1;
+ String += 1;
+ }
+
+ if ((*Name == 0) && (*String == '=')) {
+ return String + 1;
+ }
+
+ Argc -= 1;
+ }
+ }
+
+ return NULL;
+}
+
+//
+// Line draw chars -- different scheme in Far East vs. SBCS
+//
+UCHAR
+GetGraphicsChar(
+ IN GraphicsChar WhichOne
+ )
+{
+#ifdef _X86_
+ UCHAR TextGetGraphicsCharacter(GraphicsChar);
+
+ return(TextGetGraphicsCharacter(WhichOne));
+#else
+ //
+ // ARC machines don't support dbcs for now
+ //
+ static UCHAR ArcGraphicsChars[GraphicsCharMax] = { (UCHAR)'\311', // right-down
+ (UCHAR)'\273', // left-down
+ (UCHAR)'\310', // right-up
+ (UCHAR)'\274', // left-up
+ (UCHAR)'\272', // vertical
+ (UCHAR)'\315' // horizontal
+ };
+
+ return(((unsigned)WhichOne < (unsigned)GraphicsCharMax) ? ArcGraphicsChars[WhichOne] : ' ');
+#endif
+}
diff --git a/private/ntos/boot/lib/blres.c b/private/ntos/boot/lib/blres.c
new file mode 100644
index 000000000..e237c5a61
--- /dev/null
+++ b/private/ntos/boot/lib/blres.c
@@ -0,0 +1,363 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ blres.c
+
+Abstract:
+
+ Provides rudimentary resource support for the osloader and setupldr
+
+Author:
+
+ John Vert (jvert) 12-Nov-1993
+
+Revision History:
+
+--*/
+#include "bootlib.h"
+
+PUCHAR BlpResourceDirectory = NULL;
+PUCHAR BlpResourceFileOffset = NULL;
+
+//
+// private function prototypes
+//
+PIMAGE_RESOURCE_DIRECTORY
+BlpFindDirectoryEntry(
+ IN PIMAGE_RESOURCE_DIRECTORY Directory,
+ IN ULONG Id,
+ IN PUCHAR SectionStart
+ );
+
+
+ARC_STATUS
+BlInitResources(
+ IN PCHAR StartCommand
+ )
+
+/*++
+
+Routine Description:
+
+ Opens the executable that was run and reads the section headers out of the
+ image to determine where the resource section is located in memory.
+
+Arguments:
+
+ StartCommand - Supplies the command used to start the program (argv[0])
+
+Return Value:
+
+ ESUCCESS if successful
+
+ ARC_STATUS if unsuccessful
+
+--*/
+
+{
+ CHAR DeviceName[80];
+ PCHAR FileName;
+ PCHAR p;
+ ULONG DeviceId;
+ ULONG FileId;
+ ARC_STATUS Status;
+ UCHAR LocalBuffer[(SECTOR_SIZE * 2) + 256];
+ PUCHAR LocalPointer;
+ ULONG Count;
+ PIMAGE_FILE_HEADER FileHeader;
+ PIMAGE_OPTIONAL_HEADER OptionalHeader;
+ PIMAGE_DATA_DIRECTORY ResourceDirectory;
+ PIMAGE_SECTION_HEADER SectionHeader;
+ ULONG NumberOfSections;
+
+ if (BlpResourceDirectory != NULL) {
+ //
+ // Already initialized, just return.
+ //
+ return(ESUCCESS);
+ }
+ //
+ // extract device name from the startup path
+ //
+ p=strrchr(StartCommand,')');
+ if (p==NULL) {
+ return(ENODEV);
+ }
+
+ strncpy(DeviceName, StartCommand, p-StartCommand+1);
+ DeviceName[p-StartCommand+1]='\0';
+
+ FileName = p+1;
+
+ //
+ // Open the device.
+ //
+ Status = ArcOpen(DeviceName, ArcOpenReadOnly, &DeviceId);
+ if (Status != ESUCCESS) {
+ return(Status);
+ }
+
+ //
+ // Open the file.
+ //
+ Status = BlOpen(DeviceId,
+ FileName,
+ ArcOpenReadOnly,
+ &FileId);
+ if (Status != ESUCCESS) {
+ ArcClose(DeviceId);
+ return(Status);
+ }
+
+ //
+ // Read the first two sectors of the image header from the file.
+ //
+ LocalPointer = ALIGN_BUFFER(LocalBuffer);
+ Status = BlRead(FileId, LocalPointer, SECTOR_SIZE*2, &Count);
+ BlClose(FileId);
+ ArcClose(DeviceId);
+
+ if (Status != ESUCCESS) {
+ return(Status);
+ }
+
+ FileHeader = (PIMAGE_FILE_HEADER)LocalPointer;
+ OptionalHeader = (PIMAGE_OPTIONAL_HEADER)(LocalPointer + sizeof(IMAGE_FILE_HEADER));
+
+#if defined(_PPC_)
+
+ //
+ // The PPC ROM format uses an NT optional header, so the data directory
+ // can be used to locate the resource section (if any). The base
+ // address of the resource directory is adjusted by the image base. We
+ // also need to adjust virtual addresses in the resource directory by
+ // this amount which is used as (BlpResourceDirectory -
+ // BlpResourceFileOffset).
+ //
+ ResourceDirectory = (OptionalHeader->DataDirectory +
+ IMAGE_DIRECTORY_ENTRY_RESOURCE);
+
+ if ((FileHeader->Machine == IMAGE_FILE_MACHINE_POWERPC) &&
+ ResourceDirectory->VirtualAddress && ResourceDirectory->Size) {
+ BlpResourceDirectory = OptionalHeader->ImageBase +
+ ResourceDirectory->VirtualAddress;
+
+ BlpResourceFileOffset = ResourceDirectory->VirtualAddress;
+ return(ESUCCESS);
+ }
+
+#else
+
+ NumberOfSections = FileHeader->NumberOfSections;
+ SectionHeader = (PIMAGE_SECTION_HEADER)((PUCHAR)OptionalHeader +
+ FileHeader->SizeOfOptionalHeader);
+
+ //
+ // Find .rsrc section
+ //
+ while (NumberOfSections) {
+ if (_stricmp(SectionHeader->Name, ".rsrc")==0) {
+ BlpResourceDirectory = (PUCHAR)SectionHeader->VirtualAddress;
+ BlpResourceFileOffset = (PUCHAR)SectionHeader->PointerToRawData;
+ if (FileHeader->Machine == IMAGE_FILE_MACHINE_POWERPC) {
+ BlpResourceDirectory += OptionalHeader->ImageBase;
+ }
+
+ return(ESUCCESS);
+ }
+
+ ++SectionHeader;
+ --NumberOfSections;
+ }
+
+#endif //
+
+ return(EBADF);
+}
+
+
+PCHAR
+BlFindMessage(
+ IN ULONG Id
+ )
+
+/*++
+
+Routine Description:
+
+ Looks up a message resource in the given image. Note that this routine
+ ignores the Language ID. It is assumed that the osloader/setupldr only
+ has messages for one language.
+
+Arguments:
+
+ Id - Supplies the message ID to look up.
+
+Return Value:
+
+ PCHAR - pointer to the message string.
+
+ NULL - failure.
+
+--*/
+
+{
+ PIMAGE_RESOURCE_DIRECTORY ResourceDirectory;
+ PIMAGE_RESOURCE_DIRECTORY NextDirectory;
+ PMESSAGE_RESOURCE_DATA MessageData;
+ PMESSAGE_RESOURCE_BLOCK MessageBlock;
+ PMESSAGE_RESOURCE_ENTRY MessageEntry;
+ PIMAGE_RESOURCE_DATA_ENTRY DataEntry;
+ ULONG NumberOfBlocks;
+ ULONG Index;
+
+ if (BlpResourceDirectory==NULL) {
+ return(NULL);
+ }
+
+ ResourceDirectory = (PIMAGE_RESOURCE_DIRECTORY)BlpResourceDirectory;
+
+ //
+ // Search the directory. We are looking for the type RT_MESSAGETABLE (11)
+ //
+ NextDirectory = BlpFindDirectoryEntry(ResourceDirectory,
+ 11,
+ (PUCHAR)ResourceDirectory);
+ if (NextDirectory==NULL) {
+ return(NULL);
+ }
+
+ //
+ // Find the next directory. Should only be one entry here (nameid == 1)
+ //
+ NextDirectory = BlpFindDirectoryEntry(NextDirectory,
+ 1,
+ (PUCHAR)ResourceDirectory);
+ if (NextDirectory==NULL) {
+ return(NULL);
+ }
+
+ // Find the message table.
+ // If a dbcs locale is active, then we look for the appropriate
+ // message table first. Otherwise we just look for the first message table.
+ //
+ if(DbcsLangId) {
+ DataEntry = (PIMAGE_RESOURCE_DATA_ENTRY)BlpFindDirectoryEntry(
+ NextDirectory,
+ DbcsLangId,
+ (PUCHAR)ResourceDirectory
+ );
+ } else {
+ DataEntry = NULL;
+ }
+
+ if(!DataEntry) {
+ DataEntry = (PIMAGE_RESOURCE_DATA_ENTRY)BlpFindDirectoryEntry(
+ NextDirectory,
+ (ULONG)(-1),
+ (PUCHAR)ResourceDirectory
+ );
+ }
+
+ if(!DataEntry) {
+ return(NULL);
+ }
+
+ MessageData = (PMESSAGE_RESOURCE_DATA)(BlpResourceDirectory +
+ DataEntry->OffsetToData -
+ BlpResourceFileOffset);
+
+ NumberOfBlocks = MessageData->NumberOfBlocks;
+ MessageBlock = MessageData->Blocks;
+ while (NumberOfBlocks--) {
+ if ((Id >= MessageBlock->LowId) &&
+ (Id <= MessageBlock->HighId)) {
+
+ //
+ // The requested ID is within this block, scan forward until
+ // we find it.
+ //
+ MessageEntry = (PMESSAGE_RESOURCE_ENTRY)((PCHAR)MessageData + MessageBlock->OffsetToEntries);
+ Index = Id - MessageBlock->LowId;
+ while (Index--) {
+ MessageEntry = (PMESSAGE_RESOURCE_ENTRY)((PUCHAR)MessageEntry + MessageEntry->Length);
+ }
+ return(MessageEntry->Text);
+ }
+
+ //
+ // Check the next block for this ID.
+ //
+
+ MessageBlock++;
+ }
+
+ return(NULL);
+
+}
+
+
+PIMAGE_RESOURCE_DIRECTORY
+BlpFindDirectoryEntry(
+ IN PIMAGE_RESOURCE_DIRECTORY Directory,
+ IN ULONG Id,
+ IN PUCHAR SectionStart
+ )
+
+/*++
+
+Routine Description:
+
+ Searches through a resource directory for the given ID. Ignores entries
+ with actual names, only searches for ID. If the given ID is -1, the
+ first entry is returned.
+
+Arguments:
+
+ Directory - Supplies the resource directory to search.
+
+ Id - Supplies the ID to search for. -1 means return the first ID found.
+
+ SectionStart - Supplies a pointer to the start of the resource section.
+
+Return Value:
+
+ Pointer to the found resource directory.
+
+ NULL for failure.
+
+--*/
+
+{
+ ULONG i;
+ PIMAGE_RESOURCE_DIRECTORY_ENTRY FoundDirectory;
+
+ FoundDirectory = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(Directory+1);
+
+ //
+ // Skip entries with names.
+ //
+ for (i=0;i<Directory->NumberOfNamedEntries;i++) {
+ ++FoundDirectory;
+ }
+
+ //
+ // Search for matching ID.
+ //
+ for (i=0;i<Directory->NumberOfIdEntries;i++) {
+ if ((FoundDirectory->Name == Id) || (Id == (ULONG)-1)) {
+ //
+ // Found a match.
+ //
+ return((PIMAGE_RESOURCE_DIRECTORY)(SectionStart +
+ (FoundDirectory->OffsetToData & ~IMAGE_RESOURCE_DATA_IS_DIRECTORY)));
+
+ }
+ ++FoundDirectory;
+ }
+
+ return(NULL);
+}
diff --git a/private/ntos/boot/lib/bootlib.h b/private/ntos/boot/lib/bootlib.h
new file mode 100644
index 000000000..d21c95b7f
--- /dev/null
+++ b/private/ntos/boot/lib/bootlib.h
@@ -0,0 +1,136 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ bootlib.h
+
+Abstract:
+
+ This module is the header file for the common boot library
+
+Author:
+
+ John Vert (jvert) 5-Oct-1993
+
+Revision History:
+
+--*/
+
+#ifndef _BOOTLIB_
+#define _BOOTLIB_
+
+#include "ntos.h"
+#include "bldr.h"
+#include "fatboot.h"
+#include "cdfsboot.h"
+#include "ntfsboot.h"
+#include "hpfsboot.h"
+#if defined(ELTORITO)
+#include "etfsboot.h"
+#endif
+
+//
+// Define partition context structure.
+//
+
+typedef struct _PARTITION_CONTEXT {
+ LARGE_INTEGER PartitionLength;
+ ULONG StartingSector;
+ ULONG EndingSector;
+ UCHAR DiskId;
+ UCHAR DeviceUnit;
+ UCHAR TargetId;
+ UCHAR PathId;
+ ULONG SectorShift;
+ ULONG Size;
+ struct _DEVICE_OBJECT *PortDeviceObject;
+} PARTITION_CONTEXT, *PPARTITION_CONTEXT;
+
+//
+// Define serial port context structure
+//
+typedef struct _SERIAL_CONTEXT {
+ ULONG PortBase;
+ ULONG PortNumber;
+} SERIAL_CONTEXT, *PSERIAL_CONTEXT;
+
+//
+// Define drive context structure (for x86 BIOS)
+//
+typedef struct _DRIVE_CONTEXT {
+ ULONG Drive;
+ ULONG Cylinders;
+ ULONG Heads;
+ ULONG Sectors;
+} DRIVE_CONTEXT, *PDRIVE_CONTEXT;
+
+//
+// Define Floppy context structure
+//
+typedef struct _FLOPPY_CONTEXT {
+ ULONG DriveType;
+ ULONG SectorsPerTrack;
+ UCHAR DiskId;
+} FLOPPY_CONTEXT, *PFLOPPY_CONTEXT;
+
+//
+// Define keyboard context structure
+//
+typedef struct _KEYBOARD_CONTEXT {
+ BOOLEAN ScanCodes;
+} KEYBOARD_CONTEXT, *PKEYBOARD_CONTEXT;
+
+//
+// Define Console context
+//
+typedef struct _CONSOLE_CONTEXT
+ {
+ ULONG ConsoleNumber;
+ } CONSOLE_CONTEXT, *PCONSOLE_CONTEXT;
+
+
+//
+// Define file table structure.
+//
+
+typedef struct _BL_FILE_FLAGS {
+ ULONG Open : 1;
+ ULONG Read : 1;
+ ULONG Write : 1;
+#ifdef DBLSPACE_LEGAL
+ ULONG DoubleSpace : 1;
+#endif
+} BL_FILE_FLAGS, *PBL_FILE_FLAGS;
+
+#define MAXIMUM_FILE_NAME_LENGTH 32
+
+typedef struct _BL_FILE_TABLE {
+ BL_FILE_FLAGS Flags;
+ ULONG DeviceId;
+ LARGE_INTEGER Position;
+ PVOID StructureContext;
+ PBL_DEVICE_ENTRY_TABLE DeviceEntryTable;
+ UCHAR FileNameLength;
+ CHAR FileName[MAXIMUM_FILE_NAME_LENGTH];
+ union {
+ HPFS_FILE_CONTEXT HpfsFileContext;
+ NTFS_FILE_CONTEXT NtfsFileContext;
+ FAT_FILE_CONTEXT FatFileContext;
+ CDFS_FILE_CONTEXT CdfsFileContext;
+#if defined(ELTORITO)
+ ETFS_FILE_CONTEXT EtfsFileContext;
+#endif
+ PARTITION_CONTEXT PartitionContext;
+ SERIAL_CONTEXT SerialContext;
+ DRIVE_CONTEXT DriveContext;
+ FLOPPY_CONTEXT FloppyContext;
+ KEYBOARD_CONTEXT KeyboardContext;
+ CONSOLE_CONTEXT ConsoleContext;
+ } u;
+} BL_FILE_TABLE, *PBL_FILE_TABLE;
+
+extern BL_FILE_TABLE BlFileTable[BL_FILE_TABLE_SIZE];
+
+#endif _BOOTLIB_
diff --git a/private/ntos/boot/lib/cdfsboot.c b/private/ntos/boot/lib/cdfsboot.c
new file mode 100644
index 000000000..2c05d022b
--- /dev/null
+++ b/private/ntos/boot/lib/cdfsboot.c
@@ -0,0 +1,1695 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ CdfsBoot.c
+
+Abstract:
+
+ This module implements the Cdfs boot file system used by the operating
+ system loader.
+
+Author:
+
+ Brian Andrew [BrianAn] 05-Aug-1991
+
+Revision History:
+
+--*/
+
+#include "bootlib.h"
+#include "cd.h"
+
+BOOTFS_INFO CdfsBootFsInfo = {L"cdfs"};
+
+
+//
+// Local procedure prototypes.
+//
+
+ARC_STATUS
+CdfsReadDisk(
+ IN ULONG DeviceId,
+ IN ULONG Lbo,
+ IN ULONG ByteCount,
+ IN OUT PVOID Buffer
+ );
+
+VOID
+CdfsFirstComponent(
+ IN OUT PSTRING String,
+ OUT PSTRING FirstComponent
+ );
+
+typedef enum _COMPARISON_RESULTS {
+ LessThan = -1,
+ EqualTo = 0,
+ GreaterThan = 1
+} COMPARISON_RESULTS;
+
+COMPARISON_RESULTS
+CdfsCompareNames(
+ IN PSTRING Name1,
+ IN PSTRING Name2
+ );
+
+ARC_STATUS
+CdfsSearchDirectory(
+ IN PSTRING Name,
+ OUT PBOOLEAN IsDirectory
+ );
+
+VOID
+CdfsGetDirectoryInfo(
+ IN PRAW_DIR_REC DirEntry,
+ IN BOOLEAN IsoVol,
+ OUT PULONG SectorOffset,
+ OUT PULONG DiskOffset,
+ OUT PULONG Length
+ );
+
+COMPARISON_RESULTS
+CdfsFileMatch(
+ IN PRAW_DIR_REC DirEntry,
+ IN PSTRING FileName
+ );
+
+
+typedef union _USHORT2 {
+ USHORT Ushort[2];
+ ULONG ForceAlignment;
+} USHORT2, *PUSHORT2;
+
+//
+// This macro copies an unaligned src longword to an aligned dsr longword
+// accessing the source on a word boundary.
+//
+
+#define CopyUshort2(Dst,Src) { \
+ ((PUSHORT2)(Dst))->Ushort[0] = ((UNALIGNED USHORT2 *)(Src))->Ushort[0]; \
+ ((PUSHORT2)(Dst))->Ushort[1] = ((UNALIGNED USHORT2 *)(Src))->Ushort[1]; \
+ }
+
+//
+// The following macro upcases a single ascii character
+//
+
+#define ToUpper(C) ((((C) >= 'a') && ((C) <= 'z')) ? (C) - 'a' + 'A' : (C))
+
+#define SetFlag(Flags,SingleFlag) { (Flags) |= (SingleFlag); }
+
+//
+// The following macro indicate if the flag is on or off
+//
+
+#define FlagOn(Flags,SingleFlag) ((BOOLEAN)( \
+ (((Flags) & (SingleFlag)) != 0 ? TRUE : FALSE) \
+ ) \
+)
+
+
+//
+// Define global data.
+//
+// Context Pointer - This is a pointer to the context for the current file
+// operation that is active.
+//
+
+PCDFS_STRUCTURE_CONTEXT CdfsStructureContext;
+
+//
+// File Descriptor - This is a pointer to the file descriptor for the current
+// file operation that is active.
+//
+
+PBL_FILE_TABLE CdfsFileTableEntry;
+
+//
+// File entry table - This is a structure that provides entry to the Cdfs
+// file system procedures. It is exported when a Cdfs file structure
+// is recognized.
+//
+
+BL_DEVICE_ENTRY_TABLE CdfsDeviceEntryTable;
+
+
+PBL_DEVICE_ENTRY_TABLE
+IsCdfsFileStructure (
+ IN ULONG DeviceId,
+ IN PVOID StructureContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines if the partition on the specified channel
+ contains a Cdfs file system volume.
+
+Arguments:
+
+ DeviceId - Supplies the file table index for the device on which
+ read operations are to be performed.
+
+ StructureContext - Supplies a pointer to a Hpfs file structure context.
+
+Return Value:
+
+ A pointer to the Cdfs entry table is returned if the partition is
+ recognized as containing a Cdfs volume. Otherwise, NULL is returned.
+
+--*/
+
+{
+ UCHAR UnalignedSector[CD_SECTOR_SIZE + 256];
+
+ PRAW_ISO_VD RawVd;
+ PRAW_DIR_REC RootDe;
+
+ UCHAR DescType;
+ UCHAR Version;
+
+ BOOLEAN IsoVol;
+ BOOLEAN HsgVol;
+
+ STRING IsoVolId;
+ STRING HsgVolId;
+
+ STRING DiskId;
+
+ ULONG DiskOffset;
+
+ //
+ // Capture in our global variable the Cdfs Structure context record
+ //
+
+ CdfsStructureContext = (PCDFS_STRUCTURE_CONTEXT)StructureContext;
+ RtlZeroMemory((PVOID)CdfsStructureContext, sizeof(CDFS_STRUCTURE_CONTEXT));
+
+ //
+ // Compute the properly aligned buffer for reading in cdrom
+ // sectors.
+ //
+
+ RawVd = ALIGN_BUFFER( UnalignedSector );
+
+ //
+ // Initialize the string Id's to match.
+ //
+
+ RtlInitString( &IsoVolId, ISO_VOL_ID );
+ RtlInitString( &HsgVolId, HSG_VOL_ID );
+
+ DiskId.Length = 5;
+ DiskId.MaximumLength = 5;
+
+ //
+ // We initially start at the first volume descriptor.
+ //
+
+ DiskOffset = FIRST_VD_SECTOR * CD_SECTOR_SIZE;
+
+ //
+ // We loop, reading in volume descriptors until we find either
+ // a primary, terminator or a sector that cannot contain either.
+ //
+
+ while (TRUE) {
+
+ //
+ // Initialize the Hsg boolean.
+ //
+
+ HsgVol = FALSE;
+
+ //
+ // Read the sector at our current position. Return NULL on an
+ // error
+ //
+
+ if (CdfsReadDisk( DeviceId,
+ DiskOffset,
+ CD_SECTOR_SIZE,
+ RawVd ) != ESUCCESS) {
+
+ return NULL;
+ }
+
+ //
+ // Compare the Id string in the volume descriptor with the Iso
+ // and Hsg values.
+ //
+
+ DiskId.Buffer = RVD_STD_ID( RawVd, TRUE );
+
+ IsoVol = (BOOLEAN)(CdfsCompareNames( &DiskId, &IsoVolId ) == EqualTo);
+
+ if (!IsoVol) {
+
+ //
+ // Repeat the test with the Hsg Id string.
+ //
+
+ DiskId.Buffer = RVD_STD_ID( RawVd, FALSE );
+
+ HsgVol = (BOOLEAN)(CdfsCompareNames( &DiskId, &HsgVolId ) == EqualTo);
+
+ //
+ // If neither, then return NULL.
+ //
+
+ if (!HsgVol) {
+
+ return NULL;
+ }
+ }
+
+ //
+ // Get the volume descriptor type and standard version number.
+ //
+
+ DescType = RVD_DESC_TYPE( RawVd, IsoVol );
+ Version = RVD_VERSION( RawVd, IsoVol );
+
+ //
+ // Return NULL, if the version is incorrect or this is a terminal
+ // volume descriptor.
+ //
+
+ if (Version != VERSION_1
+ || DescType == VD_TERMINATOR) {
+
+ return NULL;
+ }
+
+ //
+ // If this is a primary volume descriptor, then our search is over.
+ //
+
+ if (DescType == VD_PRIMARY) {
+
+ //
+ // Update the fields of the Cdfs context structure that apply
+ // to the volume.
+ //
+
+ CdfsStructureContext->IsIsoVol = IsoVol;
+ CdfsStructureContext->LbnBlockSize = RVD_LB_SIZE( RawVd, IsoVol );
+ CdfsStructureContext->LogicalBlockCount = RVD_VOL_SIZE( RawVd, IsoVol );
+
+ //
+ // Get the information on the root directory and save it in
+ // the context structure.
+ //
+
+ RootDe = (PRAW_DIR_REC) (RVD_ROOT_DE( RawVd, IsoVol ));
+
+ CdfsGetDirectoryInfo( RootDe,
+ IsoVol,
+ &CdfsStructureContext->RootDirSectorOffset,
+ &CdfsStructureContext->RootDirDiskOffset,
+ &CdfsStructureContext->RootDirSize );
+
+ //
+ // Exit the loop.
+ //
+
+ break;
+ }
+
+ //
+ // Otherwise move to the next sector.
+ //
+
+ DiskOffset += CD_SECTOR_SIZE;
+ }
+
+ //
+ // Initialize the file entry table.
+ //
+
+ CdfsDeviceEntryTable.Open = CdfsOpen;
+ CdfsDeviceEntryTable.Close = CdfsClose;
+ CdfsDeviceEntryTable.Read = CdfsRead;
+ CdfsDeviceEntryTable.Seek = CdfsSeek;
+ CdfsDeviceEntryTable.Write = CdfsWrite;
+ CdfsDeviceEntryTable.GetFileInformation = CdfsGetFileInformation;
+ CdfsDeviceEntryTable.SetFileInformation = CdfsSetFileInformation;
+ CdfsDeviceEntryTable.BootFsInfo = &CdfsBootFsInfo;
+
+ //
+ // And return the address of the table to our caller.
+ //
+
+ return &CdfsDeviceEntryTable;
+}
+
+
+ARC_STATUS
+CdfsClose (
+ IN ULONG FileId
+ )
+
+/*++
+
+Routine Description:
+
+ This routine closes the file specified by the file id.
+
+Arguments:
+
+ FileId - Supplies the file table index.
+
+Return Value:
+
+ ESUCCESS if returned as the function value.
+
+--*/
+
+{
+ //
+ // Indicate that the file isn't open any longer
+ //
+
+ BlFileTable[FileId].Flags.Open = 0;
+
+ //
+ // And return to our caller
+ //
+
+ return ESUCCESS;
+}
+
+
+ARC_STATUS
+CdfsOpen (
+ IN PCHAR FileName,
+ IN OPEN_MODE OpenMode,
+ IN PULONG FileId
+ )
+
+/*++
+
+Routine Description:
+
+ This routine searches the root directory for a file matching FileName.
+ If a match is found the dirent for the file is saved and the file is
+ opened.
+
+Arguments:
+
+ FileName - Supplies a pointer to a zero terminated file name.
+
+ OpenMode - Supplies the mode of the open.
+
+ FileId - Supplies a pointer to a variable that specifies the file
+ table entry that is to be filled in if the open is successful.
+
+Return Value:
+
+ ESUCCESS is returned if the open operation is successful. Otherwise,
+ an unsuccessful status is returned that describes the reason for failure.
+
+--*/
+
+{
+ ARC_STATUS Status;
+
+ ULONG DeviceId;
+
+ STRING PathName;
+
+ STRING Name;
+ BOOLEAN IsDirectory;
+ BOOLEAN SearchSucceeded;
+
+ //
+ // Save the address of the file table entry, context area, and the device
+ // id in use.
+ //
+
+ CdfsFileTableEntry = &BlFileTable[*FileId];
+ CdfsStructureContext = (PCDFS_STRUCTURE_CONTEXT)CdfsFileTableEntry->StructureContext;
+
+ DeviceId = CdfsFileTableEntry->DeviceId;
+
+ //
+ // Construct a file name descriptor from the input file name.
+ //
+
+ RtlInitString( &PathName, FileName );
+
+ //
+ // Set the starting directory to be the root directory.
+ //
+
+ CdfsStructureContext->DirSectorOffset = CdfsStructureContext->RootDirSectorOffset;
+ CdfsStructureContext->DirDiskOffset = CdfsStructureContext->RootDirDiskOffset;
+ CdfsStructureContext->DirSize = CdfsStructureContext->RootDirSize;
+
+ //
+ // While the path name has some characters in it we'll go through our
+ // loop which extracts the first part of the path name and searches
+ // the current fnode (which must be a directory) for an the entry.
+ // If what we find is a directory then we have a new directory fnode
+ // and simply continue back to the top of the loop.
+ //
+
+ IsDirectory = TRUE;
+ SearchSucceeded = TRUE;
+
+ while (PathName.Length > 0
+ && IsDirectory) {
+
+ //
+ // Extract the first component.
+ //
+
+ CdfsFirstComponent( &PathName, &Name );
+
+ //
+ // Copy the name into the filename buffer.
+ //
+
+ CdfsFileTableEntry->FileNameLength = (UCHAR) Name.Length;
+ RtlMoveMemory( CdfsFileTableEntry->FileName,
+ Name.Buffer,
+ Name.Length );
+
+ //
+ // Look to see if the file exists.
+ //
+
+ Status = CdfsSearchDirectory( &Name,
+ &IsDirectory );
+
+ if (Status == ENOENT) {
+
+ SearchSucceeded = FALSE;
+ break;
+ }
+
+ if (Status != ESUCCESS) {
+
+ return Status;
+ }
+
+ }
+
+ //
+ // If the path name length is not zero then we were trying to crack a path
+ // with an nonexistent (or non directory) name in it. For example, we tried
+ // to crack a\b\c\d and b is not a directory or does not exist (then the path
+ // name will still contain c\d).
+ //
+
+ if (PathName.Length != 0) {
+
+ return ENOTDIR;
+ }
+
+ //
+ // At this point we've cracked the name up to (an maybe including the last
+ // component). We located the last component if the SearchSucceeded flag is
+ // true, otherwise the last component does not exist. If we located the last
+ // component then this is like an open or a supersede, but not a create.
+ //
+
+ if (SearchSucceeded) {
+
+ //
+ // Check if the last component is a directory
+ //
+
+ if (IsDirectory) {
+
+ //
+ // For an existing directory the only valid open mode is OpenDirectory
+ // all other modes return an error
+ //
+
+ switch (OpenMode) {
+
+ case ArcOpenReadOnly:
+ case ArcOpenWriteOnly:
+ case ArcOpenReadWrite:
+ case ArcCreateWriteOnly:
+ case ArcCreateReadWrite:
+ case ArcSupersedeWriteOnly:
+ case ArcSupersedeReadWrite:
+
+ //
+ // If we reach here then the caller got a directory but didn't
+ // want to open a directory
+ //
+
+ return EISDIR;
+
+ case ArcOpenDirectory:
+
+ //
+ // If we reach here then the caller got a directory and wanted
+ // to open a directory.
+ //
+
+ CdfsFileTableEntry->u.CdfsFileContext.FileSize = CdfsStructureContext->DirSize;
+ CdfsFileTableEntry->u.CdfsFileContext.DiskOffset = CdfsStructureContext->DirDiskOffset;
+ CdfsFileTableEntry->u.CdfsFileContext.IsDirectory = TRUE;
+
+ CdfsFileTableEntry->Flags.Open = 1;
+ CdfsFileTableEntry->Flags.Read = 1;
+ CdfsFileTableEntry->Position.LowPart = 0;
+ CdfsFileTableEntry->Position.HighPart = 0;
+
+ return ESUCCESS;
+
+ case ArcCreateDirectory:
+
+ //
+ // If we reach here then the caller got a directory and wanted
+ // to create a new directory
+ //
+
+ return EACCES;
+ }
+ }
+
+ //
+ // If we get there then we have an existing file that is being opened.
+ // We can open existing files only read only.
+ //
+
+ switch (OpenMode) {
+
+ case ArcOpenReadOnly:
+
+ //
+ // If we reach here then the user got a file and wanted to open the
+ // file read only
+ //
+
+ CdfsFileTableEntry->u.CdfsFileContext.FileSize = CdfsStructureContext->DirSize;
+ CdfsFileTableEntry->u.CdfsFileContext.DiskOffset = CdfsStructureContext->DirDiskOffset;
+ CdfsFileTableEntry->u.CdfsFileContext.IsDirectory = FALSE;
+
+ CdfsFileTableEntry->Flags.Open = 1;
+ CdfsFileTableEntry->Flags.Read = 1;
+ CdfsFileTableEntry->Position.LowPart = 0;
+ CdfsFileTableEntry->Position.HighPart = 0;
+
+ return ESUCCESS;
+
+ case ArcOpenWriteOnly:
+ case ArcOpenReadWrite:
+ case ArcCreateWriteOnly:
+ case ArcCreateReadWrite:
+ case ArcSupersedeWriteOnly:
+ case ArcSupersedeReadWrite:
+
+ //
+ // If we reach here then we are trying to open a read only
+ // device for write.
+ //
+
+ return EROFS;
+
+ case ArcOpenDirectory:
+ case ArcCreateDirectory:
+
+ //
+ // If we reach here then the user got a file and wanted a directory
+ //
+
+ return ENOTDIR;
+ }
+ }
+
+ //
+ // If we get here the last component does not exist so we are trying to create
+ // either a new file or a directory.
+ //
+
+ switch (OpenMode) {
+
+ case ArcOpenReadOnly:
+ case ArcOpenWriteOnly:
+ case ArcOpenReadWrite:
+ case ArcOpenDirectory:
+
+ //
+ // If we reach here then the user did not get a file but wanted a file
+ //
+
+ return ENOENT;
+
+ case ArcCreateWriteOnly:
+ case ArcSupersedeWriteOnly:
+ case ArcCreateReadWrite:
+ case ArcSupersedeReadWrite:
+ case ArcCreateDirectory:
+
+ //
+ // If we get hre the user wants to create something.
+ //
+
+ return EROFS;
+ }
+
+ //
+ // If we reach here then the path name is exhausted and we didn't
+ // reach a file so return an error to our caller
+ //
+
+ return ENOENT;
+}
+
+
+ARC_STATUS
+CdfsRead (
+ IN ULONG FileId,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Transfer
+ )
+
+/*++
+
+Routine Description:
+
+ This routine reads data from the specified file.
+
+Arguments:
+
+ FileId - Supplies the file table index.
+
+ Buffer - Supplies a pointer to the buffer that receives the data
+ read.
+
+ Length - Supplies the number of bytes that are to be read.
+
+ Transfer - Supplies a pointer to a variable that receives the number
+ of bytes actually transfered.
+
+Return Value:
+
+ ESUCCESS is returned if the read operation is successful. Otherwise,
+ an unsuccessful status is returned that describes the reason for failure.
+
+--*/
+
+{
+ ARC_STATUS Status;
+
+ ULONG DeviceId;
+ ULONG DiskOffset;
+
+ //
+ // Save the address of the file table entry, context area, and the device
+ // id in use.
+ //
+
+ CdfsFileTableEntry = &BlFileTable[FileId];
+ CdfsStructureContext = (PCDFS_STRUCTURE_CONTEXT)CdfsFileTableEntry->StructureContext;
+
+ DeviceId = CdfsFileTableEntry->DeviceId;
+
+ //
+ // Clear the transfer count and set the initial disk offset.
+ //
+
+ *Transfer = 0;
+
+ //
+ // Check for end of file.
+ //
+
+ //
+ // If the file position is currently at the end of file, then return
+ // a success status with no bytes read from the file. If the file
+ // plus the length of the transfer is beyond the end of file, then
+ // read only the remaining part of the file. Otherwise, read the
+ // requested number of bytes.
+ //
+
+ if (CdfsFileTableEntry->Position.LowPart ==
+ CdfsFileTableEntry->u.CdfsFileContext.FileSize) {
+ return ESUCCESS;
+
+ } else {
+ if ((CdfsFileTableEntry->Position.LowPart + Length) >=
+ CdfsFileTableEntry->u.CdfsFileContext.FileSize) {
+ Length = CdfsFileTableEntry->u.CdfsFileContext.FileSize -
+ CdfsFileTableEntry->Position.LowPart;
+ }
+ }
+
+ DiskOffset = CdfsFileTableEntry->Position.LowPart
+ + CdfsFileTableEntry->u.CdfsFileContext.DiskOffset;
+
+ //
+ // Read in runs (i.e., sectors) until the byte count goes to zero
+ //
+
+ while (Length > 0) {
+
+ ULONG CurrentRunByteCount;
+
+ //
+ // Compute the current read byte count.
+ //
+
+ if (Length > MAX_CDROM_READ) {
+
+ CurrentRunByteCount = MAX_CDROM_READ;
+
+ } else {
+
+ CurrentRunByteCount = Length;
+ }
+
+ //
+ // Read from the disk.
+ //
+
+ if ((Status = CdfsReadDisk( DeviceId,
+ DiskOffset,
+ CurrentRunByteCount,
+ Buffer)) != ESUCCESS) {
+
+ return Status;
+ }
+
+ //
+ // Update the remaining length.
+ //
+
+ Length -= CurrentRunByteCount;
+
+ //
+ // Update the current position and the number of bytes transfered
+ //
+
+ CdfsFileTableEntry->Position.LowPart += CurrentRunByteCount;
+ DiskOffset += CurrentRunByteCount;
+
+ *Transfer += CurrentRunByteCount;
+
+ //
+ // Update buffer to point to the next byte location to fill in
+ //
+
+ Buffer = (PCHAR)Buffer + CurrentRunByteCount;
+ }
+
+ //
+ // If we get here then remaining sector count is zero so we can
+ // return success to our caller
+ //
+
+ return ESUCCESS;
+}
+
+
+ARC_STATUS
+CdfsSeek (
+ IN ULONG FileId,
+ IN PLARGE_INTEGER Offset,
+ IN SEEK_MODE SeekMode
+ )
+
+/*++
+
+Routine Description:
+
+ This routine seeks to the specified position for the file specified
+ by the file id.
+
+Arguments:
+
+ FileId - Supplies the file table index.
+
+ Offset - Supplies the offset in the file to position to.
+
+ SeekMode - Supplies the mode of the seek operation.
+
+Return Value:
+
+ ESUCCESS if returned as the function value.
+
+--*/
+
+{
+ ULONG NewPosition;
+
+ //
+ // Compute the new position
+ //
+
+ if (SeekMode == SeekAbsolute) {
+
+ NewPosition = Offset->LowPart;
+
+ } else {
+
+ NewPosition = BlFileTable[FileId].Position.LowPart + Offset->LowPart;
+ }
+
+ //
+ // If the new position is greater than the file size then return
+ // an error
+ //
+
+ if (NewPosition > BlFileTable[FileId].u.CdfsFileContext.FileSize) {
+
+ return EINVAL;
+ }
+
+ //
+ // Otherwise set the new position and return to our caller
+ //
+
+ BlFileTable[FileId].Position.LowPart = NewPosition;
+
+ return ESUCCESS;
+}
+
+
+ARC_STATUS
+CdfsWrite (
+ IN ULONG FileId,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Transfer
+ )
+
+/*++
+
+Routine Description:
+
+ This routine writes data to the specified file.
+
+Arguments:
+
+ FileId - Supplies the file table index.
+
+ Buffer - Supplies a pointer to the buffer that contains the data
+ written.
+
+ Length - Supplies the number of bytes that are to be written.
+
+ Transfer - Supplies a pointer to a variable that receives the number
+ of bytes actually transfered.
+
+Return Value:
+
+ ESUCCESS is returned if the write operation is successful. Otherwise,
+ an unsuccessful status is returned that describes the reason for failure.
+
+--*/
+
+{
+ return EROFS;
+
+ UNREFERENCED_PARAMETER( FileId );
+ UNREFERENCED_PARAMETER( Buffer );
+ UNREFERENCED_PARAMETER( Length );
+ UNREFERENCED_PARAMETER( Transfer );
+}
+
+
+ARC_STATUS
+CdfsGetFileInformation (
+ IN ULONG FileId,
+ OUT PFILE_INFORMATION Buffer
+ )
+
+/*++
+
+Routine Description:
+
+ This procedure returns to the user a buffer filled with file information
+
+Arguments:
+
+ FileId - Supplies the File id for the operation
+
+ Buffer - Supplies the buffer to receive the file information. Note that
+ it must be large enough to hold the full file name
+
+Return Value:
+
+ ESUCCESS is returned for all get information requests.
+
+--*/
+
+{
+ PBL_FILE_TABLE FileTableEntry;
+ ULONG i;
+
+ //
+ // Load our local variables
+ //
+
+ FileTableEntry = &BlFileTable[FileId];
+
+ //
+ // Zero out the buffer, and fill in its non-zero values
+ //
+
+ RtlZeroMemory(Buffer, sizeof(FILE_INFORMATION));
+
+ Buffer->EndingAddress.LowPart = FileTableEntry->u.CdfsFileContext.FileSize;
+
+ Buffer->CurrentPosition.LowPart = FileTableEntry->Position.LowPart;
+ Buffer->CurrentPosition.HighPart = 0;
+
+ SetFlag(Buffer->Attributes, ArcReadOnlyFile);
+
+ if (FileTableEntry->u.CdfsFileContext.IsDirectory) {
+
+ SetFlag( Buffer->Attributes, ArcDirectoryFile );
+ }
+
+ Buffer->FileNameLength = FileTableEntry->FileNameLength;
+
+ for (i = 0; i < FileTableEntry->FileNameLength; i += 1) {
+
+ Buffer->FileName[i] = FileTableEntry->FileName[i];
+ }
+
+ return ESUCCESS;
+}
+
+
+ARC_STATUS
+CdfsSetFileInformation (
+ IN ULONG FileId,
+ IN ULONG AttributeFlags,
+ IN ULONG AttributeMask
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets the file attributes of the indicated file
+
+Arguments:
+
+ FileId - Supplies the File Id for the operation
+
+ AttributeFlags - Supplies the value (on or off) for each attribute being modified
+
+ AttributeMask - Supplies a mask of the attributes being altered. All other
+ file attributes are left alone.
+
+Return Value:
+
+ EROFS is always returned in this case.
+
+--*/
+
+{
+ return EROFS;
+
+ UNREFERENCED_PARAMETER( FileId );
+ UNREFERENCED_PARAMETER( AttributeFlags );
+ UNREFERENCED_PARAMETER( AttributeMask );
+}
+
+
+ARC_STATUS
+CdfsInitialize (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the cdfs boot filesystem.
+ Currently this is a no-op.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ ESUCCESS.
+
+--*/
+
+{
+ return ESUCCESS;
+}
+
+
+//
+// Internal support routine
+//
+
+ARC_STATUS
+CdfsReadDisk(
+ IN ULONG DeviceId,
+ IN ULONG Lbo,
+ IN ULONG ByteCount,
+ IN OUT PVOID Buffer
+ )
+
+/*++
+
+Routine Description:
+
+ This routine reads in zero or more sectors from the specified device.
+
+Arguments:
+
+ DeviceId - Supplies the device id to use in the arc calls.
+
+ Lbo - Supplies the LBO to start reading from.
+
+ ByteCount - Supplies the number of bytes to read.
+
+ Buffer - Supplies a pointer to the buffer to read the bytes into.
+
+Return Value:
+
+ ESUCCESS is returned if the read operation is successful. Otherwise,
+ an unsuccessful status is returned that describes the reason for failure.
+
+--*/
+
+{
+ LARGE_INTEGER LargeLbo;
+ ARC_STATUS Status;
+ ULONG i;
+
+ //
+ // Seek to the appropriate offset on the volume
+ //
+
+ LargeLbo.LowPart = Lbo;
+ LargeLbo.HighPart = 0;
+ if ((Status = ArcSeek( DeviceId, &LargeLbo , SeekAbsolute )) != ESUCCESS) {
+
+ return Status;
+ }
+
+ //
+ // Issue the arc read request
+ //
+
+ if ((Status = ArcRead( DeviceId, Buffer, ByteCount, &i)) != ESUCCESS) {
+
+ return Status;
+ }
+
+ //
+ // Make sure we got back the amount requested
+ //
+
+ if (ByteCount != i) {
+
+ return EIO;
+ }
+
+ //
+ // Everything is fine so return success to our caller
+ //
+
+ return ESUCCESS;
+}
+
+
+//
+// Internal support routine
+//
+
+VOID
+CdfsFirstComponent(
+ IN OUT PSTRING String,
+ OUT PSTRING FirstComponent
+ )
+
+/*++
+
+Routine Description:
+
+ This routine takes an input path name and separates it into its
+ first file name component and the remaining part.
+
+Arguments:
+
+ String - Supplies the original string being dissected. On return
+ this string will now point to the remaining part.
+
+ FirstComponent - Returns the string representing the first file name
+ in the input string.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG Index;
+
+ //
+ // Copy over the string variable into the first component variable
+ //
+
+ *FirstComponent = *String;
+
+ //
+ // Now if the first character in the name is a backslash then
+ // simply skip over the backslash.
+ //
+
+ if (FirstComponent->Buffer[0] == '\\') {
+
+ FirstComponent->Buffer += 1;
+ FirstComponent->Length -= 1;
+ }
+
+ //
+ // Now search the name for a backslash
+ //
+
+ for (Index = 0; Index < FirstComponent->Length; Index += 1) {
+
+ if (FirstComponent->Buffer[Index] == '\\') {
+
+ break;
+ }
+ }
+
+ //
+ // At this point Index denotes a backslash or is equal to the length
+ // of the string. So update string to be the remaining part.
+ // Decrement the length of the first component by the approprate
+ // amount
+ //
+
+ String->Buffer = &FirstComponent->Buffer[Index];
+ String->Length = (SHORT)(FirstComponent->Length - Index);
+
+ FirstComponent->Length = (SHORT)Index;
+
+ //
+ // And return to our caller.
+ //
+
+ return;
+}
+
+
+//
+// Internal support routine
+//
+
+COMPARISON_RESULTS
+CdfsCompareNames(
+ IN PSTRING Name1,
+ IN PSTRING Name2
+ )
+
+/*++
+
+Routine Description:
+
+ This routine takes two names and compare them ignoring case. This
+ routine does not do implied dot or dbcs processing.
+
+Arguments:
+
+ Name1 - Supplies the first name to compare
+
+ Name2 - Supplies the second name to compare
+
+Return Value:
+
+ LessThan if Name1 is lexically less than Name2
+ EqualTo if Name1 is lexically equal to Name2
+ GreaterThan if Name1 is lexically greater than Name2
+
+--*/
+
+{
+ ULONG i;
+ ULONG MinimumLength;
+
+ //
+ // Compute the smallest of the two name lengths
+ //
+
+ MinimumLength = (Name1->Length < Name2->Length ? Name1->Length : Name2->Length);
+
+ //
+ // Now compare each character in the names.
+ //
+
+ for (i = 0; i < MinimumLength; i += 1) {
+
+ if (ToUpper(Name1->Buffer[i]) < ToUpper(Name2->Buffer[i])) {
+
+ return LessThan;
+ }
+
+ if (ToUpper(Name1->Buffer[i]) > ToUpper(Name2->Buffer[i])) {
+
+ return GreaterThan;
+ }
+ }
+
+ //
+ // The names compared equal up to the smallest name length so
+ // now check the name lengths
+ //
+
+ if (Name1->Length < Name2->Length) {
+
+ return LessThan;
+ }
+
+ if (Name1->Length > Name2->Length) {
+
+ return GreaterThan;
+ }
+
+ return EqualTo;
+}
+
+
+//
+// Internal support routine.
+//
+
+ARC_STATUS
+CdfsSearchDirectory(
+ IN PSTRING Name,
+ OUT PBOOLEAN IsDirectory
+ )
+
+/*++
+
+Routine Description:
+
+ This routine walks through the current directory in the Cdfs
+ context structure, looking for a match for 'Name'. We will find
+ the first non-multi-extent, non-interleave file. We will ignore
+ any version number for the file. The details about the file, if
+ found, are stored in the Cdfs context structure.
+
+Arguments:
+
+ Name - This is the name of the file to search for.
+
+ IsDirectory - Supplies the address of a boolean where we store
+ whether this is or is not a directory.
+
+Return Value:
+
+ ESUCCESS is returned if the operation is successful. Otherwise,
+ an unsuccessful status is returned that describes the reason for failure.
+
+--*/
+
+{
+ ARC_STATUS Status;
+
+ ULONG SectorOffset;
+ ULONG SectorDiskOffset;
+ ULONG DirentOffset;
+ ULONG RemainingBytes;
+
+ BOOLEAN ReadSector;
+ BOOLEAN SearchForMultiEnd;
+
+ UCHAR UnalignedBuffer[CD_SECTOR_SIZE + 256];
+
+ PUCHAR RawSector;
+
+ PRAW_DIR_REC RawDe;
+
+ COMPARISON_RESULTS ComparisonResult;
+
+ //
+ // Initialize the local variables.
+ //
+
+ RawSector = ALIGN_BUFFER( UnalignedBuffer );
+
+ SearchForMultiEnd = FALSE;
+
+ //
+ // Remember where we are within the disk, sector and directory file.
+ //
+
+ SectorOffset = CdfsStructureContext->DirSectorOffset;
+ SectorDiskOffset = CdfsStructureContext->DirDiskOffset - SectorOffset;
+ DirentOffset = 0;
+
+ ReadSector = FALSE;
+
+ //
+ // If this is the root directory, then we can return immediately.
+ //
+
+ if (Name->Length == 1
+ && *Name->Buffer == '\\') {
+
+ *IsDirectory = TRUE;
+
+ //
+ // The structure context is already filled in.
+ //
+
+ return ESUCCESS;
+ }
+
+ //
+ // Compute the remaining bytes in this sector.
+ //
+
+ RemainingBytes = CD_SECTOR_SIZE - SectorOffset;
+
+ //
+ // Loop until the directory is exhausted or a matching dirent for the
+ // target name is found.
+ //
+
+ while (TRUE) {
+
+ //
+ // If the current offset is beyond the end of the directory,
+ // raise an appropriate status.
+ //
+
+ if (DirentOffset >= CdfsStructureContext->DirSize) {
+
+ return ENOENT;
+ }
+
+ //
+ // If the remaining bytes in this sector is less than the
+ // minimum needed for a dirent, then move to the next sector.
+ //
+
+ if (RemainingBytes < MIN_DIR_REC_SIZE) {
+
+ SectorDiskOffset += CD_SECTOR_SIZE;
+ DirentOffset += RemainingBytes;
+ SectorOffset = 0;
+ RemainingBytes = CD_SECTOR_SIZE;
+ ReadSector = FALSE;
+
+ continue;
+ }
+
+ //
+ // If we have not read in the sector, do so now.
+ //
+
+ if (!ReadSector) {
+
+ Status = CdfsReadDisk( CdfsFileTableEntry->DeviceId,
+ SectorDiskOffset,
+ CD_SECTOR_SIZE,
+ RawSector );
+
+ if (Status != ESUCCESS) {
+
+ return Status;
+ }
+
+ ReadSector = TRUE;
+ }
+
+ //
+ // If the first byte of the next dirent is '\0', then we move to
+ // the next sector.
+ //
+
+ if (*(RawSector + SectorOffset) == '\0') {
+
+ SectorDiskOffset += CD_SECTOR_SIZE;
+ DirentOffset += RemainingBytes;
+ SectorOffset = 0;
+ RemainingBytes = CD_SECTOR_SIZE;
+ ReadSector = FALSE;
+
+ continue;
+ }
+
+ RawDe = (PRAW_DIR_REC) ((PUCHAR) RawSector + SectorOffset);
+
+ //
+ // If the size of this dirent extends beyond the end of this sector
+ // we abort the search.
+ //
+
+ if ((ULONG)RawDe->DirLen > RemainingBytes) {
+
+ return EINVAL;
+ }
+
+ //
+ // We have correctly found the next dirent. We first check whether
+ // we are looking for the last dirent for a multi-extent.
+ //
+
+ if (SearchForMultiEnd) {
+
+ //
+ // If this is the last of a multi-extent we change our search
+ // state.
+ //
+
+ if (!FlagOn( DE_FILE_FLAGS( CdfsStructureContext->IsIsoVol, RawDe ),
+ ISO_ATTR_MULTI )) {
+
+ SearchForMultiEnd = TRUE;
+ }
+
+ //
+ // If this is a multi-extent dirent, we change our search state.
+ //
+
+ } else if (FlagOn( DE_FILE_FLAGS( CdfsStructureContext->IsIsoVol, RawDe ),
+ ISO_ATTR_MULTI )) {
+
+ SearchForMultiEnd = TRUE;
+
+ //
+ // If this is a file match, we update the Cdfs context structure
+ // and the 'IsDirectory' flag.
+ //
+
+ } else {
+
+ ComparisonResult = CdfsFileMatch( RawDe, Name );
+
+ if (ComparisonResult == EqualTo) {
+
+ CdfsGetDirectoryInfo( RawDe,
+ CdfsStructureContext->IsIsoVol,
+ &CdfsStructureContext->DirSectorOffset,
+ &CdfsStructureContext->DirDiskOffset,
+ &CdfsStructureContext->DirSize );
+
+ *IsDirectory = FlagOn( DE_FILE_FLAGS( CdfsStructureContext->IsIsoVol, RawDe ),
+ ISO_ATTR_DIRECTORY );
+
+ return ESUCCESS;
+
+ //
+ // If we have passed this file in the directory, then
+ // exit with the appropriate error code.
+ //
+
+ } else if (ComparisonResult == GreaterThan) {
+
+ return ENOENT;
+ }
+ }
+
+ //
+ // Otherwise we simply compute the next sector offset, disk offset
+ // and file offset.
+ //
+
+ SectorOffset += RawDe->DirLen;
+ DirentOffset += RawDe->DirLen;
+ RemainingBytes -= RawDe->DirLen;
+ }
+
+ return ESUCCESS;
+}
+
+
+//
+// Internal support routine.
+//
+
+VOID
+CdfsGetDirectoryInfo(
+ IN PRAW_DIR_REC DirEntry,
+ IN BOOLEAN IsoVol,
+ OUT PULONG SectorOffset,
+ OUT PULONG DiskOffset,
+ OUT PULONG Length
+ )
+
+/*++
+
+Routine Description:
+
+ This routine takes a pointer to a raw directory structure on the disk
+ and computes the file size, disk offset and file length for the
+ directory entry.
+
+Arguments:
+
+ DirEntry - This points to raw data from the disk.
+
+ IsoVol - Boolean indicating that this is an ISO volume.
+
+ SectorOffset - This supplies the address to store the sector offset of the
+ start of the disk data.
+
+ DiskOffset - This supplies the address to store the disk offset of the
+ start of the disk data.
+
+ Length - This supplies the address to store the number of bytes in
+ the file referred by this disk directory.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // The disk offset is length of the Xar blocks added to the starting
+ // location for the file.
+ //
+
+ CopyUshort2( DiskOffset, DirEntry->FileLoc );
+ *DiskOffset *= CdfsStructureContext->LbnBlockSize;
+ *DiskOffset += (DirEntry->XarLen * CdfsStructureContext->LbnBlockSize);
+
+ //
+ // The sector offset is the least significant bytes of the disk offset.
+ //
+
+ *SectorOffset = *DiskOffset & (CD_SECTOR_SIZE - 1);
+
+ //
+ // The file size is pulled straight from the dirent. We round it
+ // to a sector size to protect us from faulty disks if this is a
+ // directory. Otherwise we use it directly from the dirent.
+ //
+
+ CopyUshort2( Length, DirEntry->DataLen );
+
+ if (FlagOn( DE_FILE_FLAGS( IsoVol, DirEntry ), ISO_ATTR_DIRECTORY )) {
+
+ *Length += (*SectorOffset + CD_SECTOR_SIZE - 1);
+ *Length &= ~(CD_SECTOR_SIZE - 1);
+ *Length -= *SectorOffset;
+ }
+
+ return;
+}
+
+
+//
+// Internal support routine.
+//
+
+COMPARISON_RESULTS
+CdfsFileMatch(
+ IN PRAW_DIR_REC DirEntry,
+ IN PSTRING FileName
+ )
+
+{
+ STRING DirentString;
+ ULONG Count;
+
+ PUCHAR StringPtr;
+
+ //
+ // We never match either '\0' or '\1'. We will return 'LessThan' in
+ // all of these cases.
+ //
+
+ if (DirEntry->FileIdLen == 1
+ && (DirEntry->FileId[0] == '\0'
+ || DirEntry->FileId[0] == '\1')) {
+
+ return LessThan;
+ }
+
+ //
+ // We assume that we can use the entire file name in the dirent.
+ //
+
+ DirentString.Length = DirEntry->FileIdLen;
+ DirentString.Buffer = DirEntry->FileId;
+
+ //
+ // We walk backwards through the dirent name to check for the
+ // existance of a ';' character. We then set the string length
+ // to this position.
+ //
+
+ StringPtr = DirentString.Buffer + DirentString.Length - 1;
+ Count = DirentString.Length;
+
+ while (Count--) {
+
+ if (*StringPtr == ';') {
+
+ DirentString.Length = (SHORT)Count;
+ break;
+ }
+
+ StringPtr--;
+ }
+
+ //
+ // We also check for a terminating '.' character and truncate it.
+ //
+
+ StringPtr = DirentString.Buffer + DirentString.Length - 1;
+ Count = DirentString.Length;
+
+ while (Count--) {
+
+ if (*StringPtr == '.') {
+
+ DirentString.Length = (SHORT)Count;
+
+ } else {
+
+ break;
+ }
+
+ StringPtr--;
+ }
+
+ //
+ // We now have the two filenames to compare. The result of this
+ // operation is simply the comparison of the two of them.
+ //
+
+ DirentString.MaximumLength = DirentString.Length;
+
+ return CdfsCompareNames( &DirentString, FileName );
+}
diff --git a/private/ntos/boot/lib/etfsboot.c b/private/ntos/boot/lib/etfsboot.c
new file mode 100644
index 000000000..c1761e5cf
--- /dev/null
+++ b/private/ntos/boot/lib/etfsboot.c
@@ -0,0 +1,1734 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ EtfsBoot.c
+
+Abstract:
+
+ This module implements the El Torito CD boot file system used by the operating
+ system loader.
+
+Author:
+
+ Steve Collins [stevec] 25-Nov-1995
+
+Revision History:
+
+--*/
+
+#if defined(ELTORITO)
+#include "bootlib.h"
+#include "cd.h"
+
+BOOTFS_INFO EtfsBootFsInfo = {L"etfs"};
+
+
+//
+// Local procedure prototypes.
+//
+
+ARC_STATUS
+EtfsReadDisk(
+ IN ULONG DeviceId,
+ IN ULONG Lbo,
+ IN ULONG ByteCount,
+ IN OUT PVOID Buffer
+ );
+
+VOID
+EtfsFirstComponent(
+ IN OUT PSTRING String,
+ OUT PSTRING FirstComponent
+ );
+
+typedef enum _COMPARISON_RESULTS {
+ LessThan = -1,
+ EqualTo = 0,
+ GreaterThan = 1
+} COMPARISON_RESULTS;
+
+COMPARISON_RESULTS
+EtfsCompareNames(
+ IN PSTRING Name1,
+ IN PSTRING Name2
+ );
+
+ARC_STATUS
+EtfsSearchDirectory(
+ IN PSTRING Name,
+ OUT PBOOLEAN IsDirectory
+ );
+
+VOID
+EtfsGetDirectoryInfo(
+ IN PRAW_DIR_REC DirEntry,
+ IN BOOLEAN IsoVol,
+ OUT PULONG SectorOffset,
+ OUT PULONG DiskOffset,
+ OUT PULONG Length
+ );
+
+COMPARISON_RESULTS
+EtfsFileMatch(
+ IN PRAW_DIR_REC DirEntry,
+ IN PSTRING FileName
+ );
+
+typedef union _USHORT2 {
+ USHORT Ushort[2];
+ ULONG ForceAlignment;
+} USHORT2, *PUSHORT2;
+
+//
+// This macro copies an unaligned src longword to an aligned dsr longword
+// accessing the source on a word boundary.
+//
+
+#define CopyUshort2(Dst,Src) { \
+ ((PUSHORT2)(Dst))->Ushort[0] = ((UNALIGNED USHORT2 *)(Src))->Ushort[0]; \
+ ((PUSHORT2)(Dst))->Ushort[1] = ((UNALIGNED USHORT2 *)(Src))->Ushort[1]; \
+ }
+
+//
+// The following macro upcases a single ascii character
+//
+
+#define ToUpper(C) ((((C) >= 'a') && ((C) <= 'z')) ? (C) - 'a' + 'A' : (C))
+
+#define SetFlag(Flags,SingleFlag) { (Flags) |= (SingleFlag); }
+
+//
+// The following macro indicate if the flag is on or off
+//
+
+#define FlagOn(Flags,SingleFlag) ((BOOLEAN)( \
+ (((Flags) & (SingleFlag)) != 0 ? TRUE : FALSE) \
+ ) \
+)
+
+
+//
+// Define global data.
+//
+// Context Pointer - This is a pointer to the context for the current file
+// operation that is active.
+//
+
+PETFS_STRUCTURE_CONTEXT EtfsStructureContext;
+
+//
+// File Descriptor - This is a pointer to the file descriptor for the current
+// file operation that is active.
+//
+
+
+PBL_FILE_TABLE EtfsFileTableEntry;
+
+//
+// File entry table - This is a structure that provides entry to the Etfs
+// file system procedures. It is exported when an Etfs file structure
+// is recognized.
+//
+
+BL_DEVICE_ENTRY_TABLE EtfsDeviceEntryTable;
+
+
+PBL_DEVICE_ENTRY_TABLE
+IsEtfsFileStructure (
+ IN ULONG DeviceId,
+ IN PVOID StructureContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines if the partition on the specified channel
+ contains an Etfs file system volume.
+
+Arguments:
+
+ DeviceId - Supplies the file table index for the device on which
+ read operations are to be performed.
+
+ StructureContext - Supplies a pointer to a Etfs file structure context.
+
+Return Value:
+
+ A pointer to the Etfs entry table is returned if the partition is
+ recognized as containing an Etfs volume. Otherwise, NULL is returned.
+
+--*/
+
+{
+ UCHAR UnalignedSector[CD_SECTOR_SIZE + 256];
+
+ PRAW_ISO_VD RawVd;
+ PRAW_DIR_REC RootDe;
+ PRAW_ET_BRVD RawBrvd;
+
+ UCHAR DescType;
+ UCHAR Version;
+
+ UCHAR BrInd;
+ UCHAR BrVersion;
+
+ BOOLEAN EtBootRec;
+ BOOLEAN IsoVol;
+
+ STRING IsoVolId;
+ STRING EtSysId;
+ STRING DiskId;
+
+ ULONG DiskOffset;
+
+ //
+ // Capture in our global variable the Etfs Structure context record
+ //
+
+ EtfsStructureContext = (PETFS_STRUCTURE_CONTEXT)StructureContext;
+ RtlZeroMemory((PVOID)EtfsStructureContext, sizeof(ETFS_STRUCTURE_CONTEXT));
+
+ //
+ // First check the Boot Record Volume Descriptor at sector 17
+ //
+
+ DiskOffset = ELTORITO_BRVD_SECTOR * CD_SECTOR_SIZE;
+
+ //
+ // Compute the properly aligned buffer for reading in cdrom
+ // sectors.
+ //
+
+ RawBrvd = ALIGN_BUFFER( UnalignedSector );
+
+ if (EtfsReadDisk( DeviceId,
+ DiskOffset,
+ CD_SECTOR_SIZE,
+ RawBrvd ) != ESUCCESS) {
+
+ return NULL;
+ }
+
+ //
+ // Initialize the string Id to match.
+ //
+
+ RtlInitString( &IsoVolId, ISO_VOL_ID );
+
+ DiskId.Length = 5;
+ DiskId.MaximumLength = 5;
+
+ //
+ // Compare the standard identifier string in the boot record volume descriptor with the Iso value.
+ //
+
+ DiskId.Buffer = RBRVD_STD_ID( RawBrvd );
+
+ IsoVol = (BOOLEAN)(EtfsCompareNames( &DiskId, &IsoVolId ) == EqualTo);
+
+ if (!IsoVol) {
+
+ return NULL;
+ }
+
+ //
+ // Get the boot record indicator and volume descriptor version number.
+ //
+
+ BrInd = RBRVD_BR_IND( RawBrvd );
+ BrVersion = RBRVD_VERSION( RawBrvd );
+
+ //
+ // Return NULL, if the version is incorrect or this isn't a boot record
+ // volume descriptor.
+ //
+
+ if (BrVersion != BRVD_VERSION_1
+ || BrInd != VD_BOOTREC) {
+
+ return NULL;
+ }
+
+ //
+ // Initialize the string Id to match.
+ //
+
+ RtlInitString( &EtSysId, ET_SYS_ID );
+
+ DiskId.Length = 23;
+ DiskId.MaximumLength = 23;
+
+ //
+ // Compare the boot system identifier in the boot record volume descriptor with the El Torito value.
+ //
+
+ DiskId.Buffer = RBRVD_SYS_ID( RawBrvd );
+
+ EtBootRec = (BOOLEAN)(EtfsCompareNames( &DiskId, &EtSysId ) == EqualTo);
+
+ if (!EtBootRec) {
+
+ return NULL;
+ }
+
+ //
+ // Now check the Primary Volume Descriptor
+ // We do this second because if it's valid we want to store values from this sector
+ // (we only allocate a single buffer for reading in a sector at a time)
+ //
+
+ RawVd = ALIGN_BUFFER( UnalignedSector );
+
+ //
+ // For El Torito the Primary Volume Descriptor must be at sector 16
+ //
+
+ DiskOffset = ELTORITO_VD_SECTOR * CD_SECTOR_SIZE;
+
+ //
+ // Check if this is a valid Primary Volume Descriptor
+ //
+
+ if (EtfsReadDisk( DeviceId,
+ DiskOffset,
+ CD_SECTOR_SIZE,
+ RawVd ) != ESUCCESS) {
+
+ return NULL;
+ }
+
+ //
+ // Initialize the string Id to match.
+ //
+
+ RtlInitString( &IsoVolId, ISO_VOL_ID );
+
+ DiskId.Length = 5;
+ DiskId.MaximumLength = 5;
+
+ //
+ // Compare the standard identifier string in the volume descriptor with the Iso value.
+ //
+
+ DiskId.Buffer = RVD_STD_ID( RawVd, TRUE );
+
+ IsoVol = (BOOLEAN)(EtfsCompareNames( &DiskId, &IsoVolId ) == EqualTo);
+
+ if (!IsoVol) {
+
+ return NULL;
+ }
+
+ //
+ // Get the volume descriptor type and volume descriptor version number.
+ //
+
+ DescType = RVD_DESC_TYPE( RawVd, IsoVol );
+ Version = RVD_VERSION( RawVd, IsoVol );
+
+ //
+ // Return NULL, if the version is incorrect or this isn't a primary
+ // volume descriptor.
+ //
+
+ if (Version != VERSION_1
+ || DescType != VD_PRIMARY) {
+
+ return NULL;
+ }
+
+ //
+ // Update the fields of the Etfs context structure that apply
+ // to the volume.
+ //
+
+ EtfsStructureContext->IsIsoVol = IsoVol;
+ EtfsStructureContext->LbnBlockSize = RVD_LB_SIZE( RawVd, IsoVol );
+ EtfsStructureContext->LogicalBlockCount = RVD_VOL_SIZE( RawVd, IsoVol );
+
+ //
+ // Get the information on the root directory and save it in
+ // the context structure.
+ //
+
+ RootDe = (PRAW_DIR_REC) (RVD_ROOT_DE( RawVd, IsoVol ));
+
+ EtfsGetDirectoryInfo( RootDe,
+ IsoVol,
+ &EtfsStructureContext->RootDirSectorOffset,
+ &EtfsStructureContext->RootDirDiskOffset,
+ &EtfsStructureContext->RootDirSize );
+
+ //
+ // Initialize the file entry table.
+ //
+
+ EtfsDeviceEntryTable.Open = EtfsOpen;
+ EtfsDeviceEntryTable.Close = EtfsClose;
+ EtfsDeviceEntryTable.Read = EtfsRead;
+ EtfsDeviceEntryTable.Seek = EtfsSeek;
+ EtfsDeviceEntryTable.Write = EtfsWrite;
+ EtfsDeviceEntryTable.GetFileInformation = EtfsGetFileInformation;
+ EtfsDeviceEntryTable.SetFileInformation = EtfsSetFileInformation;
+ EtfsDeviceEntryTable.BootFsInfo = &EtfsBootFsInfo;
+
+ //
+ // And return the address of the table to our caller.
+ //
+
+ return &EtfsDeviceEntryTable;
+}
+
+
+ARC_STATUS
+EtfsClose (
+ IN ULONG FileId
+ )
+
+/*++
+
+Routine Description:
+
+ This routine closes the file specified by the file id.
+
+Arguments:
+
+ FileId - Supplies the file table index.
+
+Return Value:
+
+ ESUCCESS if returned as the function value.
+
+--*/
+
+{
+ //
+ // Indicate that the file isn't open any longer
+ //
+
+ BlFileTable[FileId].Flags.Open = 0;
+
+ //
+ // And return to our caller
+ //
+
+ return ESUCCESS;
+}
+
+
+ARC_STATUS
+EtfsOpen (
+ IN PCHAR FileName,
+ IN OPEN_MODE OpenMode,
+ IN PULONG FileId
+ )
+
+/*++
+
+Routine Description:
+
+ This routine searches the root directory for a file matching FileName.
+ If a match is found the dirent for the file is saved and the file is
+ opened.
+
+Arguments:
+
+ FileName - Supplies a pointer to a zero terminated file name.
+
+ OpenMode - Supplies the mode of the open.
+
+ FileId - Supplies a pointer to a variable that specifies the file
+ table entry that is to be filled in if the open is successful.
+
+Return Value:
+
+ ESUCCESS is returned if the open operation is successful. Otherwise,
+ an unsuccessful status is returned that describes the reason for failure.
+
+--*/
+
+{
+ ARC_STATUS Status;
+
+ ULONG DeviceId;
+
+ STRING PathName;
+
+ STRING Name;
+ BOOLEAN IsDirectory;
+ BOOLEAN SearchSucceeded;
+
+ //
+ // Save the address of the file table entry, context area, and the device
+ // id in use.
+ //
+
+ EtfsFileTableEntry = &BlFileTable[*FileId];
+ EtfsStructureContext = (PETFS_STRUCTURE_CONTEXT)EtfsFileTableEntry->StructureContext;
+
+ DeviceId = EtfsFileTableEntry->DeviceId;
+
+ //
+ // Construct a file name descriptor from the input file name.
+ //
+
+ RtlInitString( &PathName, FileName );
+
+ //
+ // Set the starting directory to be the root directory.
+ //
+
+ EtfsStructureContext->DirSectorOffset = EtfsStructureContext->RootDirSectorOffset;
+ EtfsStructureContext->DirDiskOffset = EtfsStructureContext->RootDirDiskOffset;
+ EtfsStructureContext->DirSize = EtfsStructureContext->RootDirSize;
+
+ //
+ // While the path name has some characters in it we'll go through our
+ // loop which extracts the first part of the path name and searches
+ // the current fnode (which must be a directory) for an the entry.
+ // If what we find is a directory then we have a new directory fnode
+ // and simply continue back to the top of the loop.
+ //
+
+ IsDirectory = TRUE;
+ SearchSucceeded = TRUE;
+
+ while (PathName.Length > 0
+ && IsDirectory) {
+
+ //
+ // Extract the first component.
+ //
+
+ EtfsFirstComponent( &PathName, &Name );
+
+ //
+ // Copy the name into the filename buffer.
+ //
+
+ EtfsFileTableEntry->FileNameLength = (UCHAR) Name.Length;
+ RtlMoveMemory( EtfsFileTableEntry->FileName,
+ Name.Buffer,
+ Name.Length );
+
+ //
+ // Look to see if the file exists.
+ //
+
+ Status = EtfsSearchDirectory( &Name,
+ &IsDirectory );
+
+ if (Status == ENOENT) {
+
+ SearchSucceeded = FALSE;
+ break;
+ }
+
+ if (Status != ESUCCESS) {
+
+ return Status;
+ }
+
+ }
+
+ //
+ // If the path name length is not zero then we were trying to crack a path
+ // with an nonexistent (or non directory) name in it. For example, we tried
+ // to crack a\b\c\d and b is not a directory or does not exist (then the path
+ // name will still contain c\d).
+ //
+
+ if (PathName.Length != 0) {
+
+ return ENOTDIR;
+ }
+
+ //
+ // At this point we've cracked the name up to (an maybe including the last
+ // component). We located the last component if the SearchSucceeded flag is
+ // true, otherwise the last component does not exist. If we located the last
+ // component then this is like an open or a supersede, but not a create.
+ //
+
+ if (SearchSucceeded) {
+
+ //
+ // Check if the last component is a directory
+ //
+
+ if (IsDirectory) {
+
+ //
+ // For an existing directory the only valid open mode is OpenDirectory
+ // all other modes return an error
+ //
+
+ switch (OpenMode) {
+
+ case ArcOpenReadOnly:
+ case ArcOpenWriteOnly:
+ case ArcOpenReadWrite:
+ case ArcCreateWriteOnly:
+ case ArcCreateReadWrite:
+ case ArcSupersedeWriteOnly:
+ case ArcSupersedeReadWrite:
+
+ //
+ // If we reach here then the caller got a directory but didn't
+ // want to open a directory
+ //
+
+ return EISDIR;
+
+ case ArcOpenDirectory:
+
+ //
+ // If we reach here then the caller got a directory and wanted
+ // to open a directory.
+ //
+
+ EtfsFileTableEntry->u.EtfsFileContext.FileSize = EtfsStructureContext->DirSize;
+ EtfsFileTableEntry->u.EtfsFileContext.DiskOffset = EtfsStructureContext->DirDiskOffset;
+ EtfsFileTableEntry->u.EtfsFileContext.IsDirectory = TRUE;
+
+ EtfsFileTableEntry->Flags.Open = 1;
+ EtfsFileTableEntry->Flags.Read = 1;
+ EtfsFileTableEntry->Position.LowPart = 0;
+ EtfsFileTableEntry->Position.HighPart = 0;
+
+ return ESUCCESS;
+
+ case ArcCreateDirectory:
+
+ //
+ // If we reach here then the caller got a directory and wanted
+ // to create a new directory
+ //
+
+ return EACCES;
+ }
+ }
+
+ //
+ // If we get there then we have an existing file that is being opened.
+ // We can open existing files only read only.
+ //
+
+ switch (OpenMode) {
+
+ case ArcOpenReadOnly:
+
+ //
+ // If we reach here then the user got a file and wanted to open the
+ // file read only
+ //
+
+ EtfsFileTableEntry->u.EtfsFileContext.FileSize = EtfsStructureContext->DirSize;
+ EtfsFileTableEntry->u.EtfsFileContext.DiskOffset = EtfsStructureContext->DirDiskOffset;
+ EtfsFileTableEntry->u.EtfsFileContext.IsDirectory = FALSE;
+
+ EtfsFileTableEntry->Flags.Open = 1;
+ EtfsFileTableEntry->Flags.Read = 1;
+ EtfsFileTableEntry->Position.LowPart = 0;
+ EtfsFileTableEntry->Position.HighPart = 0;
+
+ return ESUCCESS;
+
+ case ArcOpenWriteOnly:
+ case ArcOpenReadWrite:
+ case ArcCreateWriteOnly:
+ case ArcCreateReadWrite:
+ case ArcSupersedeWriteOnly:
+ case ArcSupersedeReadWrite:
+
+ //
+ // If we reach here then we are trying to open a read only
+ // device for write.
+ //
+
+ return EROFS;
+
+ case ArcOpenDirectory:
+ case ArcCreateDirectory:
+
+ //
+ // If we reach here then the user got a file and wanted a directory
+ //
+
+ return ENOTDIR;
+ }
+ }
+
+ //
+ // If we get here the last component does not exist so we are trying to create
+ // either a new file or a directory.
+ //
+
+ switch (OpenMode) {
+
+ case ArcOpenReadOnly:
+ case ArcOpenWriteOnly:
+ case ArcOpenReadWrite:
+ case ArcOpenDirectory:
+
+ //
+ // If we reach here then the user did not get a file but wanted a file
+ //
+
+ return ENOENT;
+
+ case ArcCreateWriteOnly:
+ case ArcSupersedeWriteOnly:
+ case ArcCreateReadWrite:
+ case ArcSupersedeReadWrite:
+ case ArcCreateDirectory:
+
+ //
+ // If we get hre the user wants to create something.
+ //
+
+ return EROFS;
+ }
+
+ //
+ // If we reach here then the path name is exhausted and we didn't
+ // reach a file so return an error to our caller
+ //
+
+ return ENOENT;
+}
+
+
+ARC_STATUS
+EtfsRead (
+ IN ULONG FileId,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Transfer
+ )
+
+/*++
+
+Routine Description:
+
+ This routine reads data from the specified file.
+
+Arguments:
+
+ FileId - Supplies the file table index.
+
+ Buffer - Supplies a pointer to the buffer that receives the data
+ read.
+
+ Length - Supplies the number of bytes that are to be read.
+
+ Transfer - Supplies a pointer to a variable that receives the number
+ of bytes actually transfered.
+
+Return Value:
+
+ ESUCCESS is returned if the read operation is successful. Otherwise,
+ an unsuccessful status is returned that describes the reason for failure.
+
+--*/
+
+{
+ ARC_STATUS Status;
+
+ ULONG DeviceId;
+ ULONG DiskOffset;
+
+ //
+ // Save the address of the file table entry, context area, and the device
+ // id in use.
+ //
+
+ EtfsFileTableEntry = &BlFileTable[FileId];
+ EtfsStructureContext = (PETFS_STRUCTURE_CONTEXT)EtfsFileTableEntry->StructureContext;
+
+ DeviceId = EtfsFileTableEntry->DeviceId;
+
+ //
+ // Clear the transfer count and set the initial disk offset.
+ //
+
+ *Transfer = 0;
+
+ //
+ // Check for end of file.
+ //
+
+ //
+ // If the file position is currently at the end of file, then return
+ // a success status with no bytes read from the file. If the file
+ // plus the length of the transfer is beyond the end of file, then
+ // read only the remaining part of the file. Otherwise, read the
+ // requested number of bytes.
+ //
+
+ if (EtfsFileTableEntry->Position.LowPart ==
+ EtfsFileTableEntry->u.EtfsFileContext.FileSize) {
+ return ESUCCESS;
+
+ } else {
+ if ((EtfsFileTableEntry->Position.LowPart + Length) >=
+ EtfsFileTableEntry->u.EtfsFileContext.FileSize) {
+ Length = EtfsFileTableEntry->u.EtfsFileContext.FileSize -
+ EtfsFileTableEntry->Position.LowPart;
+ }
+ }
+
+ DiskOffset = EtfsFileTableEntry->Position.LowPart
+ + EtfsFileTableEntry->u.EtfsFileContext.DiskOffset;
+
+ //
+ // Read in runs (i.e., sectors) until the byte count goes to zero
+ //
+
+ while (Length > 0) {
+
+ ULONG CurrentRunByteCount;
+
+ //
+ // Compute the current read byte count.
+ //
+
+ if (Length > MAX_CDROM_READ) {
+
+ CurrentRunByteCount = MAX_CDROM_READ;
+
+ } else {
+
+ CurrentRunByteCount = Length;
+ }
+
+ //
+ // Read from the disk.
+ //
+
+ if ((Status = EtfsReadDisk( DeviceId,
+ DiskOffset,
+ CurrentRunByteCount,
+ Buffer)) != ESUCCESS) {
+
+ return Status;
+ }
+
+ //
+ // Update the remaining length.
+ //
+
+ Length -= CurrentRunByteCount;
+
+ //
+ // Update the current position and the number of bytes transfered
+ //
+
+ EtfsFileTableEntry->Position.LowPart += CurrentRunByteCount;
+ DiskOffset += CurrentRunByteCount;
+
+ *Transfer += CurrentRunByteCount;
+
+ //
+ // Update buffer to point to the next byte location to fill in
+ //
+
+ Buffer = (PCHAR)Buffer + CurrentRunByteCount;
+ }
+
+ //
+ // If we get here then remaining sector count is zero so we can
+ // return success to our caller
+ //
+
+ return ESUCCESS;
+}
+
+
+ARC_STATUS
+EtfsSeek (
+ IN ULONG FileId,
+ IN PLARGE_INTEGER Offset,
+ IN SEEK_MODE SeekMode
+ )
+
+/*++
+
+Routine Description:
+
+ This routine seeks to the specified position for the file specified
+ by the file id.
+
+Arguments:
+
+ FileId - Supplies the file table index.
+
+ Offset - Supplies the offset in the file to position to.
+
+ SeekMode - Supplies the mode of the seek operation.
+
+Return Value:
+
+ ESUCCESS if returned as the function value.
+
+--*/
+
+{
+ ULONG NewPosition;
+
+ //
+ // Compute the new position
+ //
+
+ if (SeekMode == SeekAbsolute) {
+
+ NewPosition = Offset->LowPart;
+
+ } else {
+
+ NewPosition = BlFileTable[FileId].Position.LowPart + Offset->LowPart;
+ }
+
+ //
+ // If the new position is greater than the file size then return
+ // an error
+ //
+
+ if (NewPosition > BlFileTable[FileId].u.EtfsFileContext.FileSize) {
+
+ return EINVAL;
+ }
+
+ //
+ // Otherwise set the new position and return to our caller
+ //
+
+ BlFileTable[FileId].Position.LowPart = NewPosition;
+
+ return ESUCCESS;
+}
+
+
+ARC_STATUS
+EtfsWrite (
+ IN ULONG FileId,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Transfer
+ )
+
+/*++
+
+Routine Description:
+
+ This routine writes data to the specified file.
+
+Arguments:
+
+ FileId - Supplies the file table index.
+
+ Buffer - Supplies a pointer to the buffer that contains the data
+ written.
+
+ Length - Supplies the number of bytes that are to be written.
+
+ Transfer - Supplies a pointer to a variable that receives the number
+ of bytes actually transfered.
+
+Return Value:
+
+ ESUCCESS is returned if the write operation is successful. Otherwise,
+ an unsuccessful status is returned that describes the reason for failure.
+
+--*/
+
+{
+ return EROFS;
+
+ UNREFERENCED_PARAMETER( FileId );
+ UNREFERENCED_PARAMETER( Buffer );
+ UNREFERENCED_PARAMETER( Length );
+ UNREFERENCED_PARAMETER( Transfer );
+}
+
+
+ARC_STATUS
+EtfsGetFileInformation (
+ IN ULONG FileId,
+ OUT PFILE_INFORMATION Buffer
+ )
+
+/*++
+
+Routine Description:
+
+ This procedure returns to the user a buffer filled with file information
+
+Arguments:
+
+ FileId - Supplies the File id for the operation
+
+ Buffer - Supplies the buffer to receive the file information. Note that
+ it must be large enough to hold the full file name
+
+Return Value:
+
+ ESUCCESS is returned for all get information requests.
+
+--*/
+
+{
+ PBL_FILE_TABLE FileTableEntry;
+ ULONG i;
+
+ //
+ // Load our local variables
+ //
+
+ FileTableEntry = &BlFileTable[FileId];
+
+ //
+ // Zero out the buffer, and fill in its non-zero values
+ //
+
+ RtlZeroMemory(Buffer, sizeof(FILE_INFORMATION));
+
+ Buffer->EndingAddress.LowPart = FileTableEntry->u.EtfsFileContext.FileSize;
+
+ Buffer->CurrentPosition.LowPart = FileTableEntry->Position.LowPart;
+ Buffer->CurrentPosition.HighPart = 0;
+
+ SetFlag(Buffer->Attributes, ArcReadOnlyFile);
+
+ if (FileTableEntry->u.EtfsFileContext.IsDirectory) {
+
+ SetFlag( Buffer->Attributes, ArcDirectoryFile );
+ }
+
+ Buffer->FileNameLength = FileTableEntry->FileNameLength;
+
+ for (i = 0; i < FileTableEntry->FileNameLength; i += 1) {
+
+ Buffer->FileName[i] = FileTableEntry->FileName[i];
+ }
+
+ return ESUCCESS;
+}
+
+
+ARC_STATUS
+EtfsSetFileInformation (
+ IN ULONG FileId,
+ IN ULONG AttributeFlags,
+ IN ULONG AttributeMask
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets the file attributes of the indicated file
+
+Arguments:
+
+ FileId - Supplies the File Id for the operation
+
+ AttributeFlags - Supplies the value (on or off) for each attribute being modified
+
+ AttributeMask - Supplies a mask of the attributes being altered. All other
+ file attributes are left alone.
+
+Return Value:
+
+ EROFS is always returned in this case.
+
+--*/
+
+{
+ return EROFS;
+
+ UNREFERENCED_PARAMETER( FileId );
+ UNREFERENCED_PARAMETER( AttributeFlags );
+ UNREFERENCED_PARAMETER( AttributeMask );
+}
+
+
+ARC_STATUS
+EtfsInitialize (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the etfs boot filesystem.
+ Currently this is a no-op.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ ESUCCESS.
+
+--*/
+
+{
+ return ESUCCESS;
+}
+
+
+//
+// Internal support routine
+//
+
+ARC_STATUS
+EtfsReadDisk(
+ IN ULONG DeviceId,
+ IN ULONG Lbo,
+ IN ULONG ByteCount,
+ IN OUT PVOID Buffer
+ )
+
+/*++
+
+Routine Description:
+
+ This routine reads in zero or more sectors from the specified device.
+
+Arguments:
+
+ DeviceId - Supplies the device id to use in the arc calls.
+
+ Lbo - Supplies the LBO (logical byte offset) to start reading from.
+
+ ByteCount - Supplies the number of bytes to read.
+
+ Buffer - Supplies a pointer to the buffer to read the bytes into.
+
+Return Value:
+
+ ESUCCESS is returned if the read operation is successful. Otherwise,
+ an unsuccessful status is returned that describes the reason for failure.
+
+--*/
+
+{
+ LARGE_INTEGER LargeLbo;
+ ARC_STATUS Status;
+ ULONG i;
+
+ //
+ // Seek to the appropriate offset on the volume
+ //
+
+ LargeLbo.LowPart = Lbo;
+ LargeLbo.HighPart = 0;
+ if ((Status = ArcSeek( DeviceId, &LargeLbo , SeekAbsolute )) != ESUCCESS) {
+
+ return Status;
+ }
+
+ //
+ // Issue the arc read request
+ //
+
+ if ((Status = ArcRead( DeviceId, Buffer, ByteCount, &i)) != ESUCCESS) {
+
+ return Status;
+ }
+
+ //
+ // Make sure we got back the amount requested
+ //
+
+ if (ByteCount != i) {
+
+ return EIO;
+ }
+
+ //
+ // Everything is fine so return success to our caller
+ //
+
+ return ESUCCESS;
+}
+
+
+//
+// Internal support routine
+//
+
+VOID
+EtfsFirstComponent(
+ IN OUT PSTRING String,
+ OUT PSTRING FirstComponent
+ )
+
+/*++
+
+Routine Description:
+
+ This routine takes an input path name and separates it into its
+ first file name component and the remaining part.
+
+Arguments:
+
+ String - Supplies the original string being dissected. On return
+ this string will now point to the remaining part.
+
+ FirstComponent - Returns the string representing the first file name
+ in the input string.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG Index;
+
+ //
+ // Copy over the string variable into the first component variable
+ //
+
+ *FirstComponent = *String;
+
+ //
+ // Now if the first character in the name is a backslash then
+ // simply skip over the backslash.
+ //
+
+ if (FirstComponent->Buffer[0] == '\\') {
+
+ FirstComponent->Buffer += 1;
+ FirstComponent->Length -= 1;
+ }
+
+ //
+ // Now search the name for a backslash
+ //
+
+ for (Index = 0; Index < FirstComponent->Length; Index += 1) {
+
+ if (FirstComponent->Buffer[Index] == '\\') {
+
+ break;
+ }
+ }
+
+ //
+ // At this point Index denotes a backslash or is equal to the length
+ // of the string. So update string to be the remaining part.
+ // Decrement the length of the first component by the approprate
+ // amount
+ //
+
+ String->Buffer = &FirstComponent->Buffer[Index];
+ String->Length = (SHORT)(FirstComponent->Length - Index);
+
+ FirstComponent->Length = (SHORT)Index;
+
+ //
+ // And return to our caller.
+ //
+
+ return;
+}
+
+
+//
+// Internal support routine
+//
+
+COMPARISON_RESULTS
+EtfsCompareNames(
+ IN PSTRING Name1,
+ IN PSTRING Name2
+ )
+
+/*++
+
+Routine Description:
+
+ This routine takes two names and compare them ignoring case. This
+ routine does not do implied dot or dbcs processing.
+
+Arguments:
+
+ Name1 - Supplies the first name to compare
+
+ Name2 - Supplies the second name to compare
+
+Return Value:
+
+ LessThan if Name1 is lexically less than Name2
+ EqualTo if Name1 is lexically equal to Name2
+ GreaterThan if Name1 is lexically greater than Name2
+
+--*/
+
+{
+ ULONG i;
+ ULONG MinimumLength;
+
+ //
+ // Compute the smallest of the two name lengths
+ //
+
+ MinimumLength = (Name1->Length < Name2->Length ? Name1->Length : Name2->Length);
+
+ //
+ // Now compare each character in the names.
+ //
+
+ for (i = 0; i < MinimumLength; i += 1) {
+
+ if (ToUpper(Name1->Buffer[i]) < ToUpper(Name2->Buffer[i])) {
+
+ return LessThan;
+ }
+
+ if (ToUpper(Name1->Buffer[i]) > ToUpper(Name2->Buffer[i])) {
+
+ return GreaterThan;
+ }
+ }
+
+ //
+ // The names compared equal up to the smallest name length so
+ // now check the name lengths
+ //
+
+ if (Name1->Length < Name2->Length) {
+
+ return LessThan;
+ }
+
+ if (Name1->Length > Name2->Length) {
+
+ return GreaterThan;
+ }
+
+ return EqualTo;
+}
+
+
+//
+// Internal support routine.
+//
+
+ARC_STATUS
+EtfsSearchDirectory(
+ IN PSTRING Name,
+ OUT PBOOLEAN IsDirectory
+ )
+
+/*++
+
+Routine Description:
+
+ This routine walks through the current directory in the Etfs
+ context structure, looking for a match for 'Name'. We will find
+ the first non-multi-extent, non-interleave file. We will ignore
+ any version number for the file. The details about the file, if
+ found, are stored in the Etfs context structure.
+
+Arguments:
+
+ Name - This is the name of the file to search for.
+
+ IsDirectory - Supplies the address of a boolean where we store
+ whether this is or is not a directory.
+
+Return Value:
+
+ ESUCCESS is returned if the operation is successful. Otherwise,
+ an unsuccessful status is returned that describes the reason for failure.
+
+--*/
+
+{
+ ARC_STATUS Status;
+
+ ULONG SectorOffset;
+ ULONG SectorDiskOffset;
+ ULONG DirentOffset;
+ ULONG RemainingBytes;
+
+ BOOLEAN ReadSector;
+ BOOLEAN SearchForMultiEnd;
+
+ UCHAR UnalignedBuffer[CD_SECTOR_SIZE + 256];
+
+ PUCHAR RawSector;
+
+ PRAW_DIR_REC RawDe;
+
+ COMPARISON_RESULTS ComparisonResult;
+
+ //
+ // Initialize the local variables.
+ //
+
+ RawSector = ALIGN_BUFFER( UnalignedBuffer );
+
+ SearchForMultiEnd = FALSE;
+
+ //
+ // Remember where we are within the disk, sector and directory file.
+ //
+
+ SectorOffset = EtfsStructureContext->DirSectorOffset;
+ SectorDiskOffset = EtfsStructureContext->DirDiskOffset - SectorOffset;
+ DirentOffset = 0;
+
+ ReadSector = FALSE;
+
+ //
+ // If this is the root directory, then we can return immediately.
+ //
+
+ if (Name->Length == 1
+ && *Name->Buffer == '\\') {
+
+ *IsDirectory = TRUE;
+
+ //
+ // The structure context is already filled in.
+ //
+
+ return ESUCCESS;
+ }
+
+ //
+ // Compute the remaining bytes in this sector.
+ //
+
+ RemainingBytes = CD_SECTOR_SIZE - SectorOffset;
+
+ //
+ // Loop until the directory is exhausted or a matching dirent for the
+ // target name is found.
+ //
+
+ while (TRUE) {
+
+ //
+ // If the current offset is beyond the end of the directory,
+ // raise an appropriate status.
+ //
+
+ if (DirentOffset >= EtfsStructureContext->DirSize) {
+
+ return ENOENT;
+ }
+
+ //
+ // If the remaining bytes in this sector is less than the
+ // minimum needed for a dirent, then move to the next sector.
+ //
+
+ if (RemainingBytes < MIN_DIR_REC_SIZE) {
+
+ SectorDiskOffset += CD_SECTOR_SIZE;
+ DirentOffset += RemainingBytes;
+ SectorOffset = 0;
+ RemainingBytes = CD_SECTOR_SIZE;
+ ReadSector = FALSE;
+
+ continue;
+ }
+
+ //
+ // If we have not read in the sector, do so now.
+ //
+
+ if (!ReadSector) {
+
+ Status = EtfsReadDisk( EtfsFileTableEntry->DeviceId,
+ SectorDiskOffset,
+ CD_SECTOR_SIZE,
+ RawSector );
+
+ if (Status != ESUCCESS) {
+
+ return Status;
+ }
+
+ ReadSector = TRUE;
+ }
+
+ //
+ // If the first byte of the next dirent is '\0', then we move to
+ // the next sector.
+ //
+
+ if (*(RawSector + SectorOffset) == '\0') {
+
+ SectorDiskOffset += CD_SECTOR_SIZE;
+ DirentOffset += RemainingBytes;
+ SectorOffset = 0;
+ RemainingBytes = CD_SECTOR_SIZE;
+ ReadSector = FALSE;
+
+ continue;
+ }
+
+ RawDe = (PRAW_DIR_REC) ((PUCHAR) RawSector + SectorOffset);
+
+ //
+ // If the size of this dirent extends beyond the end of this sector
+ // we abort the search.
+ //
+
+ if ((ULONG)RawDe->DirLen > RemainingBytes) {
+
+ return EINVAL;
+ }
+
+ //
+ // We have correctly found the next dirent. We first check whether
+ // we are looking for the last dirent for a multi-extent.
+ //
+
+ if (SearchForMultiEnd) {
+
+ //
+ // If this is the last of a multi-extent we change our search
+ // state.
+ //
+
+ if (!FlagOn( DE_FILE_FLAGS( EtfsStructureContext->IsIsoVol, RawDe ),
+ ISO_ATTR_MULTI )) {
+
+ SearchForMultiEnd = TRUE;
+ }
+
+ //
+ // If this is a multi-extent dirent, we change our search state.
+ //
+
+ } else if (FlagOn( DE_FILE_FLAGS( EtfsStructureContext->IsIsoVol, RawDe ),
+ ISO_ATTR_MULTI )) {
+
+ SearchForMultiEnd = TRUE;
+
+ //
+ // If this is a file match, we update the Etfs context structure
+ // and the 'IsDirectory' flag.
+ //
+
+ } else {
+
+ ComparisonResult = EtfsFileMatch( RawDe, Name );
+
+ if (ComparisonResult == EqualTo) {
+
+ EtfsGetDirectoryInfo( RawDe,
+ EtfsStructureContext->IsIsoVol,
+ &EtfsStructureContext->DirSectorOffset,
+ &EtfsStructureContext->DirDiskOffset,
+ &EtfsStructureContext->DirSize );
+
+ *IsDirectory = FlagOn( DE_FILE_FLAGS( EtfsStructureContext->IsIsoVol, RawDe ),
+ ISO_ATTR_DIRECTORY );
+
+ return ESUCCESS;
+
+ //
+ // If we have passed this file in the directory, then
+ // exit with the appropriate error code.
+ //
+
+ } else if (ComparisonResult == GreaterThan) {
+
+ return ENOENT;
+ }
+ }
+
+ //
+ // Otherwise we simply compute the next sector offset, disk offset
+ // and file offset.
+ //
+
+ SectorOffset += RawDe->DirLen;
+ DirentOffset += RawDe->DirLen;
+ RemainingBytes -= RawDe->DirLen;
+ }
+
+ return ESUCCESS;
+}
+
+
+//
+// Internal support routine.
+//
+
+VOID
+EtfsGetDirectoryInfo(
+ IN PRAW_DIR_REC DirEntry,
+ IN BOOLEAN IsoVol,
+ OUT PULONG SectorOffset,
+ OUT PULONG DiskOffset,
+ OUT PULONG Length
+ )
+
+/*++
+
+Routine Description:
+
+ This routine takes a pointer to a raw directory structure on the disk
+ and computes the file size, disk offset and file length for the
+ directory entry.
+
+Arguments:
+
+ DirEntry - This points to raw data from the disk.
+
+ IsoVol - Boolean indicating that this is an ISO volume.
+
+ SectorOffset - This supplies the address to store the sector offset of the
+ start of the disk data.
+
+ DiskOffset - This supplies the address to store the disk offset of the
+ start of the disk data.
+
+ Length - This supplies the address to store the number of bytes in
+ the file referred by this disk directory.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // The disk offset is length of the Xar blocks added to the starting
+ // location for the file.
+ //
+
+ CopyUshort2( DiskOffset, DirEntry->FileLoc );
+ *DiskOffset *= EtfsStructureContext->LbnBlockSize;
+ *DiskOffset += (DirEntry->XarLen * EtfsStructureContext->LbnBlockSize);
+
+ //
+ // The sector offset is the least significant bytes of the disk offset.
+ //
+
+ *SectorOffset = *DiskOffset & (CD_SECTOR_SIZE - 1);
+
+ //
+ // The file size is pulled straight from the dirent. We round it
+ // to a sector size to protect us from faulty disks if this is a
+ // directory. Otherwise we use it directly from the dirent.
+ //
+
+ CopyUshort2( Length, DirEntry->DataLen );
+
+ if (FlagOn( DE_FILE_FLAGS( IsoVol, DirEntry ), ISO_ATTR_DIRECTORY )) {
+
+ *Length += (*SectorOffset + CD_SECTOR_SIZE - 1);
+ *Length &= ~(CD_SECTOR_SIZE - 1);
+ *Length -= *SectorOffset;
+ }
+
+ return;
+}
+
+
+//
+// Internal support routine.
+//
+
+COMPARISON_RESULTS
+EtfsFileMatch(
+ IN PRAW_DIR_REC DirEntry,
+ IN PSTRING FileName
+ )
+
+{
+ STRING DirentString;
+ ULONG Count;
+
+ PUCHAR StringPtr;
+
+ //
+ // We never match either '\0' or '\1'. We will return 'LessThan' in
+ // all of these cases.
+ //
+
+ if (DirEntry->FileIdLen == 1
+ && (DirEntry->FileId[0] == '\0'
+ || DirEntry->FileId[0] == '\1')) {
+
+ return LessThan;
+ }
+
+ //
+ // We assume that we can use the entire file name in the dirent.
+ //
+
+ DirentString.Length = DirEntry->FileIdLen;
+ DirentString.Buffer = DirEntry->FileId;
+
+ //
+ // We walk backwards through the dirent name to check for the
+ // existance of a ';' character. We then set the string length
+ // to this position.
+ //
+
+ StringPtr = DirentString.Buffer + DirentString.Length - 1;
+ Count = DirentString.Length;
+
+ while (Count--) {
+
+ if (*StringPtr == ';') {
+
+ DirentString.Length = (SHORT)Count;
+ break;
+ }
+
+ StringPtr--;
+ }
+
+ //
+ // We also check for a terminating '.' character and truncate it.
+ //
+
+ StringPtr = DirentString.Buffer + DirentString.Length - 1;
+ Count = DirentString.Length;
+
+ while (Count--) {
+
+ if (*StringPtr == '.') {
+
+ DirentString.Length = (SHORT)Count;
+
+ } else {
+
+ break;
+ }
+
+ StringPtr--;
+ }
+
+ //
+ // We now have the two filenames to compare. The result of this
+ // operation is simply the comparison of the two of them.
+ //
+
+ DirentString.MaximumLength = DirentString.Length;
+
+ return EtfsCompareNames( &DirentString, FileName );
+}
+
+#endif
diff --git a/private/ntos/boot/lib/etfsboot.h b/private/ntos/boot/lib/etfsboot.h
new file mode 100644
index 000000000..a5fa72def
--- /dev/null
+++ b/private/ntos/boot/lib/etfsboot.h
@@ -0,0 +1,210 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ EtfsBoot.h
+
+Abstract:
+
+ This module defines globally used procedure and data structures used
+ by Etfs boot.
+
+Author:
+
+ Steve Collins [stevec] 25-Nov-1995
+
+Revision History:
+
+--*/
+
+#if defined(ELTORITO)
+#ifndef _ETFSBOOT_
+#define _ETFSBOOT_
+
+//
+// The following constants are values from the disk.
+//
+
+#define ELTORITO_VD_SECTOR (16)
+#define ELTORITO_BRVD_SECTOR (17)
+#define ET_SYS_ID "EL TORITO SPECIFICATION"
+#define BRVD_VERSION_1 (1)
+#define VD_BOOTREC (0)
+
+typedef struct _RAW_ET_BRVD {
+
+ UCHAR BrIndicator; // boot record indicator = 0
+ UCHAR StandardId[5]; // volume structure standard id = "CD001"
+ UCHAR Version; // descriptor version number = 1
+ UCHAR BootSysId[32]; // boot system identifier = "EL TORITO SPECIFICATION"
+ UCHAR Unused1[32]; // unused = 0
+ ULONG BootCatPtr; // absolute pointer to first sector of boot catalog
+ UCHAR Reserved[1973]; // unused = 0
+
+} RAW_ET_BRVD;
+typedef RAW_ET_BRVD *PRAW_ET_BRVD;
+
+
+//
+// The following macros are used to recover data from the different
+// volume descriptor structures.
+//
+
+#define RBRVD_BR_IND( r ) ( r->BrIndicator )
+#define RBRVD_STD_ID( r ) ( r->StandardId )
+#define RBRVD_VERSION( r ) ( r->Version )
+#define RBRVD_SYS_ID( r ) ( r->BootSysId )
+
+typedef struct _ETFS_STRUCTURE_CONTEXT {
+
+ //
+ // The following field is the sector offset of the start of
+ // directory data.
+ //
+
+ ULONG RootDirSectorOffset;
+
+ //
+ // The following field is the start of the sector containing the
+ // this directory.
+ //
+
+ ULONG RootDirDiskOffset;
+
+ //
+ // The following field is the size of the directory.
+ //
+
+ ULONG RootDirSize;
+
+ //
+ // The following field is the sector offset of the start of
+ // directory data.
+ //
+
+ ULONG DirSectorOffset;
+
+ //
+ // The following field is the start of the sector containing the
+ // this directory.
+ //
+
+ ULONG DirDiskOffset;
+
+ //
+ // The following field is the size of the directory.
+ //
+
+ ULONG DirSize;
+
+ //
+ // The following field indicates the size of the disk Logical Blocks.
+ //
+
+ ULONG LbnBlockSize;
+
+ //
+ // The following field indicates the number of logical blocks on the
+ // disk.
+ //
+
+ ULONG LogicalBlockCount;
+
+ //
+ // The following indicates whether this is an Iso or Hsg disk.
+ //
+
+ BOOLEAN IsIsoVol;
+
+} ETFS_STRUCTURE_CONTEXT, *PETFS_STRUCTURE_CONTEXT;
+
+//
+// Define Etfs file context structure.
+//
+
+typedef struct _ETFS_FILE_CONTEXT {
+
+ //
+ // The following is the disk offset of the read position for the
+ // start of the file. This may include the above number of non-file
+ // bytes.
+ //
+
+ ULONG DiskOffset;
+
+ //
+ // The following field contains the size of the file, in bytes.
+ //
+
+ ULONG FileSize;
+
+ //
+ // The following field indicates whether this is a directory.
+ //
+
+ BOOLEAN IsDirectory;
+
+} ETFS_FILE_CONTEXT, *PETFS_FILE_CONTEXT;
+
+//
+// Define file I/O prototypes.
+//
+
+ARC_STATUS
+EtfsClose (
+ IN ULONG FileId
+ );
+
+ARC_STATUS
+EtfsOpen (
+ IN PCHAR OpenPath,
+ IN OPEN_MODE OpenMode,
+ OUT PULONG FileId
+ );
+
+ARC_STATUS
+EtfsRead (
+ IN ULONG FileId,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ );
+
+ARC_STATUS
+EtfsSeek (
+ IN ULONG FileId,
+ IN PLARGE_INTEGER Offset,
+ IN SEEK_MODE SeekMode
+ );
+
+ARC_STATUS
+EtfsWrite (
+ IN ULONG FileId,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ );
+
+ARC_STATUS
+EtfsGetFileInformation (
+ IN ULONG FileId,
+ OUT PFILE_INFORMATION Buffer
+ );
+
+ARC_STATUS
+EtfsSetFileInformation (
+ IN ULONG FileId,
+ IN ULONG AttributeFlags,
+ IN ULONG AttributeMask
+ );
+
+ARC_STATUS
+EtfsInitialize(
+ VOID
+ );
+
+#endif // _ETFSBOOT_
+#endif
+
diff --git a/private/ntos/boot/lib/fatboot.c b/private/ntos/boot/lib/fatboot.c
new file mode 100644
index 000000000..a97528fca
--- /dev/null
+++ b/private/ntos/boot/lib/fatboot.c
@@ -0,0 +1,5639 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ fatboot.c
+
+Abstract:
+
+ This module implements the FAT boot file system used by the operating
+ system loader.
+
+Author:
+
+ Gary Kimura (garyki) 29-Aug-1989
+
+Revision History:
+
+--*/
+
+#include "bootlib.h"
+#include "stdio.h"
+#include "mrcf.h"
+
+BOOTFS_INFO FatBootFsInfo={L"fastfat"};
+
+//
+// Conditional debug print routine
+//
+
+#ifdef FATBOOTDBG
+
+#define FatDebugOutput(X,Y,Z) { \
+ if (BlConsoleOutDeviceId) { \
+ CHAR _b[128]; \
+ ULONG _c; \
+ sprintf(&_b[0], X, Y, Z); \
+ ArcWrite(BlConsoleOutDeviceId, &_b[0], strlen(&_b[0]), &_c); \
+ } \
+}
+
+#else
+
+#define FatDebugOutput(X,Y,Z) {NOTHING;}
+
+#endif // FATBOOTDBG
+
+
+//
+// Low level disk I/O procedure prototypes
+//
+
+ARC_STATUS
+FatDiskRead (
+ IN ULONG DeviceId,
+ IN LBO Lbo,
+ IN ULONG ByteCount,
+ IN PVOID Buffer
+ );
+
+ARC_STATUS
+FatDiskWrite (
+ IN ULONG DeviceId,
+ IN LBO Lbo,
+ IN ULONG ByteCount,
+ IN PVOID Buffer
+ );
+
+//
+// VOID
+// DiskRead (
+// IN ULONG DeviceId,
+// IN LBO Lbo,
+// IN ULONG ByteCount,
+// IN PVOID Buffer
+// IN BOOLEAN IsDoubleSpace
+// );
+//
+
+#ifdef DBLSPACE_LEGAL
+#define DiskRead(A,B,C,D,ISDBLS) { ARC_STATUS _s; \
+ if (!ISDBLS) { \
+ if ((_s = FatDiskRead(A,B,C,D)) != ESUCCESS) { return _s; } \
+ } else { \
+ ARC_STATUS DblsReadVfp(ULONG FileId, LBO Lbo, ULONG ByteCount, PUCHAR Buffer ); \
+ if ((_s = DblsReadVfp(A,B,C,(PUCHAR)D)) != ESUCCESS) { return _s; } \
+ } \
+}
+#else
+#define DiskRead(A,B,C,D,ignored) { ARC_STATUS _s; \
+ if ((_s = FatDiskRead(A,B,C,D)) != ESUCCESS) { return _s; } \
+}
+#endif // def DBLSPACE_LEGAL
+
+#define DiskWrite(A,B,C,D) { ARC_STATUS _s; \
+ if ((_s = FatDiskWrite(A,B,C,D)) != ESUCCESS) { return _s; } \
+}
+
+
+//
+// Cluster/Index routines
+//
+
+typedef enum _CLUSTER_TYPE {
+ FatClusterAvailable,
+ FatClusterReserved,
+ FatClusterBad,
+ FatClusterLast,
+ FatClusterNext
+} CLUSTER_TYPE;
+
+CLUSTER_TYPE
+FatInterpretClusterType (
+ IN PFAT_STRUCTURE_CONTEXT FatStructureContext,
+ IN FAT_ENTRY Entry
+ );
+
+ARC_STATUS
+FatLookupFatEntry (
+ IN PFAT_STRUCTURE_CONTEXT FatStructureContext,
+ IN ULONG DeviceId,
+ IN FAT_ENTRY FatIndex,
+ OUT PFAT_ENTRY FatEntry,
+ IN BOOLEAN IsDoubleSpace
+ );
+
+ARC_STATUS
+FatSetFatEntry (
+ IN PFAT_STRUCTURE_CONTEXT FatStructureContext,
+ IN ULONG DeviceId,
+ IN FAT_ENTRY FatIndex,
+ IN FAT_ENTRY FatEntry
+ );
+
+ARC_STATUS
+FatFlushFatEntries (
+ IN PFAT_STRUCTURE_CONTEXT FatStructureContext,
+ IN ULONG DeviceId
+ );
+
+LBO
+FatIndexToLbo (
+ IN PFAT_STRUCTURE_CONTEXT FatStructureContext,
+ IN FAT_ENTRY FatIndex
+ );
+
+#define LookupFatEntry(A,B,C,D,E) { ARC_STATUS _s; \
+ if ((_s = FatLookupFatEntry(A,B,C,D,E)) != ESUCCESS) { return _s; } \
+}
+
+#define SetFatEntry(A,B,C,D) { ARC_STATUS _s; \
+ if ((_s = FatSetFatEntry(A,B,C,D)) != ESUCCESS) { return _s; } \
+}
+
+#define FlushFatEntries(A,B) { ARC_STATUS _s; \
+ if ((_s = FatFlushFatEntries(A,B)) != ESUCCESS) { return _s; } \
+}
+
+
+//
+// Directory routines
+//
+
+ARC_STATUS
+FatSearchForDirent (
+ IN PFAT_STRUCTURE_CONTEXT FatStructureContext,
+ IN ULONG DeviceId,
+ IN FAT_ENTRY DirectoriesStartingIndex,
+ IN PFAT8DOT3 FileName,
+ OUT PDIRENT Dirent,
+ OUT PLBO Lbo,
+ IN BOOLEAN IsDoubleSpace
+ );
+
+ARC_STATUS
+FatCreateDirent (
+ IN PFAT_STRUCTURE_CONTEXT FatStructureContext,
+ IN ULONG DeviceId,
+ IN FAT_ENTRY DirectoriesStartingIndex,
+ IN PDIRENT Dirent,
+ OUT PLBO Lbo
+ );
+
+VOID
+FatSetDirent (
+ IN PFAT8DOT3 FileName,
+ IN OUT PDIRENT Dirent,
+ IN UCHAR Attributes
+ );
+
+#define SearchForDirent(A,B,C,D,E,F,G) { ARC_STATUS _s; \
+ if ((_s = FatSearchForDirent(A,B,C,D,E,F,G)) != ESUCCESS) { return _s; } \
+}
+
+#define CreateDirent(A,B,C,D,E) { ARC_STATUS _s; \
+ if ((_s = FatCreateDirent(A,B,C,D,E)) != ESUCCESS) { return _s; } \
+}
+
+
+//
+// Allocation and mcb routines
+//
+
+ARC_STATUS
+FatLoadMcb (
+ IN ULONG FileId,
+ IN VBO StartingVbo,
+ IN BOOLEAN IsDoubleSpace
+ );
+
+ARC_STATUS
+FatVboToLbo (
+ IN ULONG FileId,
+ IN VBO Vbo,
+ OUT PLBO Lbo,
+ OUT PULONG ByteCount,
+ IN BOOLEAN IsDoubleSpace
+ );
+
+ARC_STATUS
+FatIncreaseFileAllocation (
+ IN ULONG FileId,
+ IN ULONG ByteSize
+ );
+
+ARC_STATUS
+FatTruncateFileAllocation (
+ IN ULONG FileId,
+ IN ULONG ByteSize
+ );
+
+ARC_STATUS
+FatAllocateClusters (
+ IN PFAT_STRUCTURE_CONTEXT FatStructureContext,
+ IN ULONG DeviceId,
+ IN ULONG ClusterCount,
+ IN FAT_ENTRY Hint,
+ OUT PFAT_ENTRY AllocatedEntry
+ );
+
+#define LoadMcb(A,B,C) { ARC_STATUS _s; \
+ if ((_s = FatLoadMcb(A,B,C)) != ESUCCESS) { return _s; } \
+}
+
+#define VboToLbo(A,B,C,D) { ARC_STATUS _s; \
+ if ((_s = FatVboToLbo(A,B,C,D,FALSE)) != ESUCCESS) { return _s; } \
+}
+
+#define IncreaseFileAllocation(A,B) { ARC_STATUS _s; \
+ if ((_s = FatIncreaseFileAllocation(A,B)) != ESUCCESS) { return _s; } \
+}
+
+#define TruncateFileAllocation(A,B) { ARC_STATUS _s; \
+ if ((_s = FatTruncateFileAllocation(A,B)) != ESUCCESS) { return _s; } \
+}
+
+#define AllocateClusters(A,B,C,D,E) { ARC_STATUS _s; \
+ if ((_s = FatAllocateClusters(A,B,C,D,E)) != ESUCCESS) { return _s; } \
+}
+
+
+//
+// Miscellaneous routines
+//
+
+VOID
+FatFirstComponent (
+ IN OUT PSTRING String,
+ OUT PFAT8DOT3 FirstComponent
+ );
+
+#define AreNamesEqual(X,Y) ( \
+ ((*(X))[0]==(*(Y))[0]) && ((*(X))[1]==(*(Y))[1]) && ((*(X))[2]==(*(Y))[2]) && \
+ ((*(X))[3]==(*(Y))[3]) && ((*(X))[4]==(*(Y))[4]) && ((*(X))[5]==(*(Y))[5]) && \
+ ((*(X))[6]==(*(Y))[6]) && ((*(X))[7]==(*(Y))[7]) && ((*(X))[8]==(*(Y))[8]) && \
+ ((*(X))[9]==(*(Y))[9]) && ((*(X))[10]==(*(Y))[10]) \
+)
+
+#define ToUpper(C) ((((C) >= 'a') && ((C) <= 'z')) ? (C) - 'a' + 'A' : (C))
+
+#define FlagOn(Flags,SingleFlag) ((Flags) & (SingleFlag))
+#define BooleanFlagOn(Flags,SingleFlag) ((BOOLEAN)(((Flags) & (SingleFlag)) != 0))
+#define SetFlag(Flags,SingleFlag) { (Flags) |= (SingleFlag); }
+#define ClearFlag(Flags,SingleFlag) { (Flags) &= ~(SingleFlag); }
+
+#define FatFirstFatAreaLbo(B) ( (B)->ReservedSectors * (B)->BytesPerSector )
+
+#define Minimum(X,Y) ((X) < (Y) ? (X) : (Y))
+#define Maximum(X,Y) ((X) < (Y) ? (Y) : (X))
+
+//
+// The following types and macros are used to help unpack the packed and
+// misaligned fields found in the Bios parameter block
+//
+
+typedef union _UCHAR1 { UCHAR Uchar[1]; UCHAR ForceAlignment; } UCHAR1, *PUCHAR1;
+typedef union _UCHAR2 { UCHAR Uchar[2]; USHORT ForceAlignment; } UCHAR2, *PUCHAR2;
+typedef union _UCHAR4 { UCHAR Uchar[4]; ULONG ForceAlignment; } UCHAR4, *PUCHAR4;
+
+//
+// This macro copies an unaligned src byte to an aligned dst byte
+//
+
+#define CopyUchar1(Dst,Src) { \
+ *((UCHAR1 *)(Dst)) = *((UNALIGNED UCHAR1 *)(Src)); \
+ }
+
+//
+// This macro copies an unaligned src word to an aligned dst word
+//
+
+#define CopyUchar2(Dst,Src) { \
+ *((UCHAR2 *)(Dst)) = *((UNALIGNED UCHAR2 *)(Src)); \
+ }
+
+//
+// This macro copies an unaligned src longword to an aligned dsr longword
+//
+
+#define CopyUchar4(Dst,Src) { \
+ *((UCHAR4 *)(Dst)) = *((UNALIGNED UCHAR4 *)(Src)); \
+ }
+
+//
+// DirectoryEntry routines
+//
+
+VOID
+FatDirToArcDir (
+ IN PDIRENT FatDirent,
+ OUT PDIRECTORY_ENTRY ArcDirent
+ );
+
+
+//
+// Define global data.
+//
+
+//
+// File entry table - This is a structure that provides entry to the FAT
+// file system procedures. It is exported when a FAT file structure
+// is recognized.
+//
+
+BL_DEVICE_ENTRY_TABLE FatDeviceEntryTable;
+
+
+PBL_DEVICE_ENTRY_TABLE
+IsFatFileStructure (
+ IN ULONG DeviceId,
+ IN PVOID StructureContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines if the partition on the specified channel
+ contains a FAT file system volume.
+
+Arguments:
+
+ DeviceId - Supplies the file table index for the device on which
+ read operations are to be performed.
+
+ StructureContext - Supplies a pointer to a FAT file structure context.
+
+Return Value:
+
+ A pointer to the FAT entry table is returned if the partition is
+ recognized as containing a FAT volume. Otherwise, NULL is returned.
+
+--*/
+
+{
+ PPACKED_BOOT_SECTOR BootSector;
+ UCHAR Buffer[sizeof(PACKED_BOOT_SECTOR)+256];
+
+ PFAT_STRUCTURE_CONTEXT FatStructureContext;
+
+ FatDebugOutput("IsFatFileStructure\r\n", 0, 0);
+
+ //
+ // Clear the file system context block for the specified channel and
+ // establish a pointer to the context structure that can be used by other
+ // routines
+ //
+
+ FatStructureContext = (PFAT_STRUCTURE_CONTEXT)StructureContext;
+ RtlZeroMemory(FatStructureContext, sizeof(FAT_STRUCTURE_CONTEXT));
+
+ //
+ // Setup and read in the boot sector for the potential fat partition
+ //
+
+ BootSector = (PPACKED_BOOT_SECTOR)ALIGN_BUFFER( &Buffer[0] );
+
+ if (FatDiskRead(DeviceId, 0, sizeof(PACKED_BOOT_SECTOR), BootSector) != ESUCCESS) {
+
+ return NULL;
+ }
+
+ //
+ // Unpack the Bios parameter block
+ //
+
+ FatUnpackBios(&FatStructureContext->Bpb, &BootSector->PackedBpb);
+
+ //
+ // Check if it is fat
+ //
+
+ if ((BootSector->Jump[0] != 0xeb) &&
+ (BootSector->Jump[0] != 0xe9)) {
+
+ return NULL;
+
+ } else if ((FatStructureContext->Bpb.BytesPerSector != 128) &&
+ (FatStructureContext->Bpb.BytesPerSector != 256) &&
+ (FatStructureContext->Bpb.BytesPerSector != 512) &&
+ (FatStructureContext->Bpb.BytesPerSector != 1024)) {
+
+ return NULL;
+
+ } else if ((FatStructureContext->Bpb.SectorsPerCluster != 1) &&
+ (FatStructureContext->Bpb.SectorsPerCluster != 2) &&
+ (FatStructureContext->Bpb.SectorsPerCluster != 4) &&
+ (FatStructureContext->Bpb.SectorsPerCluster != 8) &&
+ (FatStructureContext->Bpb.SectorsPerCluster != 16) &&
+ (FatStructureContext->Bpb.SectorsPerCluster != 32) &&
+ (FatStructureContext->Bpb.SectorsPerCluster != 64) &&
+ (FatStructureContext->Bpb.SectorsPerCluster != 128)) {
+
+ return NULL;
+
+ } else if (FatStructureContext->Bpb.ReservedSectors == 0) {
+
+ return NULL;
+
+ } else if (FatStructureContext->Bpb.Fats == 0) {
+
+ return NULL;
+
+ } else if (FatStructureContext->Bpb.RootEntries == 0) {
+
+ return NULL;
+
+ } else if (((FatStructureContext->Bpb.Sectors == 0) && (FatStructureContext->Bpb.LargeSectors == 0)) ||
+ ((FatStructureContext->Bpb.Sectors != 0) && (FatStructureContext->Bpb.LargeSectors != 0))) {
+
+ return NULL;
+
+ } else if (FatStructureContext->Bpb.SectorsPerFat == 0) {
+
+ return NULL;
+
+ } else if ((FatStructureContext->Bpb.Media != 0xf0) &&
+ (FatStructureContext->Bpb.Media != 0xf8) &&
+ (FatStructureContext->Bpb.Media != 0xf9) &&
+ (FatStructureContext->Bpb.Media != 0xfc) &&
+ (FatStructureContext->Bpb.Media != 0xfd) &&
+ (FatStructureContext->Bpb.Media != 0xfe) &&
+ (FatStructureContext->Bpb.Media != 0xff)) {
+
+ return NULL;
+ }
+
+ //
+ // Initialize the file entry table and return the address of the table.
+ //
+
+ FatDeviceEntryTable.Open = FatOpen;
+ FatDeviceEntryTable.Close = FatClose;
+ FatDeviceEntryTable.Read = FatRead;
+ FatDeviceEntryTable.Seek = FatSeek;
+ FatDeviceEntryTable.Write = FatWrite;
+ FatDeviceEntryTable.GetFileInformation = FatGetFileInformation;
+ FatDeviceEntryTable.SetFileInformation = FatSetFileInformation;
+ FatDeviceEntryTable.Rename = FatRename;
+ FatDeviceEntryTable.GetDirectoryEntry = FatGetDirectoryEntry;
+ FatDeviceEntryTable.BootFsInfo = &FatBootFsInfo;
+
+
+ return &FatDeviceEntryTable;
+}
+
+ARC_STATUS
+FatClose (
+ IN ULONG FileId
+ )
+
+/*++
+
+Routine Description:
+
+ This routine closes the file specified by the file id.
+
+Arguments:
+
+ FileId - Supplies the file table index.
+
+Return Value:
+
+ ESUCCESS if returned as the function value.
+
+--*/
+
+{
+ PBL_FILE_TABLE FileTableEntry;
+ PFAT_STRUCTURE_CONTEXT FatStructureContext;
+ ULONG DeviceId;
+
+ FatDebugOutput("FatClose\r\n", 0, 0);
+
+ //
+ // Load our local variables
+ //
+
+ FileTableEntry = &BlFileTable[FileId];
+ FatStructureContext = (PFAT_STRUCTURE_CONTEXT)FileTableEntry->StructureContext;
+ DeviceId = FileTableEntry->DeviceId;
+
+ //
+ // Mark the file closed
+ //
+
+ BlFileTable[FileId].Flags.Open = 0;
+
+ //
+ // Check if the fat is dirty and flush it out if it is.
+ //
+
+ if (FatStructureContext->CachedFatDirty) {
+
+ FlushFatEntries( FatStructureContext, DeviceId );
+ }
+
+ //
+ // Check if the current mcb is for this file and if it is then zero it out.
+ // By setting the file id for the mcb to be the table size we guarantee that
+ // we've just set it to an invalid file id.
+ //
+
+ if (FatStructureContext->FileId == FileId) {
+
+ FatStructureContext->FileId = BL_FILE_TABLE_SIZE;
+ FatStructureContext->Mcb.InUse = 0;
+ }
+
+ return ESUCCESS;
+}
+
+
+ARC_STATUS
+FatGetDirectoryEntry (
+ IN ULONG FileId,
+ IN DIRECTORY_ENTRY *DirEntry,
+ IN ULONG NumberDir,
+ OUT PULONG CountDir
+ )
+
+/*++
+
+Routine Description:
+
+ This routine implements the GetDirectoryEntry operation for the
+ FAT file system.
+
+Arguments:
+
+ FileId - Supplies the file table index.
+
+ DirEntry - Supplies a pointer to a directory entry structure.
+
+ NumberDir - Supplies the number of directory entries to read.
+
+ Count - Supplies a pointer to a variable to receive the number
+ of entries read.
+
+Return Value:
+
+ ESUCCESS is returned if the read was successful, otherwise
+ an error code is returned.
+
+--*/
+
+{
+ //
+ // define local variables
+ //
+
+ ARC_STATUS Status; // ARC status
+ ULONG Count = 0; // # of bytes read
+ ULONG Position; // file position
+ PFAT_FILE_CONTEXT pContext; // FAT file context
+ ULONG RunByteCount = 0; // max sequential bytes
+ ULONG RunDirCount; // max dir entries to read per time
+ ULONG i; // general index
+ PDIRENT FatDirEnt; // directory entry pointer
+ UCHAR Buffer[ 16 * sizeof(DIRENT) + 32 ];
+ LBO Lbo;
+ BOOLEAN EofDir = FALSE; // not end of file
+
+ //
+ // initialize local variables
+ //
+
+ pContext = &BlFileTable[ FileId ].u.FatFileContext;
+ FatDirEnt = (PDIRENT)ALIGN_BUFFER( &Buffer[0] );
+
+ //
+ // if not directory entry, exit with error
+ //
+
+ if ( !FlagOn(pContext->Dirent.Attributes, FAT_DIRENT_ATTR_DIRECTORY) ) {
+
+ return EBADF;
+ }
+
+ //
+ // Initialize the output count to zero
+ //
+
+ *CountDir = 0;
+
+ //
+ // if NumberDir is zero, return ESUCCESS.
+ //
+
+ if ( !NumberDir ) {
+
+ return ESUCCESS;
+ }
+
+ //
+ // read one directory at a time.
+ //
+
+ do {
+
+ //
+ // save position
+ //
+
+ Position = BlFileTable[ FileId ].Position.LowPart;
+
+ //
+ // Lookup the corresponding Lbo and run length for the current position
+ //
+
+ if ( !RunByteCount ) {
+
+ if (Status = FatVboToLbo( FileId, Position, &Lbo, &RunByteCount, FALSE )) {
+
+ if ( Status == EINVAL ) {
+
+ break; // eof has been reached
+
+ } else {
+
+ return Status; // I/O error
+ }
+ }
+ }
+
+ //
+ // validate the # of bytes readable in sequance (exit loop if eof)
+ // the block is always multiple of a directory entry size.
+ //
+
+ if ( !(RunDirCount = Minimum( RunByteCount/sizeof(DIRENT), 16)) ) {
+
+ break;
+ }
+
+ //
+ // issue the read
+ //
+
+ if ( Status = FatDiskRead( BlFileTable[ FileId ].DeviceId,
+ Lbo,
+ RunDirCount * sizeof(DIRENT),
+ (PVOID)FatDirEnt )) {
+
+ BlFileTable[ FileId ].Position.LowPart = Position;
+ return Status;
+ }
+
+ for ( i=0; i<RunDirCount; i++ ) {
+
+ //
+ // exit from loop if logical end of directory
+ //
+
+ if ( FatDirEnt[i].FileName[0] == FAT_DIRENT_NEVER_USED ) {
+
+ EofDir = TRUE;
+ break;
+ }
+
+ //
+ // update the current position and the number of bytes transfered
+ //
+
+ BlFileTable[ FileId ].Position.LowPart += sizeof(DIRENT);
+ Lbo += sizeof(DIRENT);
+ RunByteCount -= sizeof(DIRENT);
+
+ //
+ // skip this entry if the file or directory has been erased
+ //
+
+ if ( FatDirEnt[i].FileName[0] == FAT_DIRENT_DELETED ) {
+
+ continue;
+ }
+
+ //
+ // skip this entry if this is a valume label
+ //
+
+ if (FlagOn( FatDirEnt[i].Attributes, FAT_DIRENT_ATTR_VOLUME_ID )) {
+
+ continue;
+ }
+
+ //
+ // convert FAT directory entry in ARC directory entry
+ //
+
+ FatDirToArcDir( &FatDirEnt[i], DirEntry++ );
+
+ //
+ // update pointers
+ //
+
+ if ( ++*CountDir >= NumberDir ) {
+
+ break;
+ }
+ }
+
+ } while ( !EofDir && *CountDir < NumberDir );
+
+ //
+ // all done
+ //
+
+ return *CountDir ? ESUCCESS : ENOTDIR;
+}
+
+
+ARC_STATUS
+FatGetFileInformation (
+ IN ULONG FileId,
+ OUT PFILE_INFORMATION Buffer
+ )
+
+/*++
+
+Routine Description:
+
+ This procedure returns to the user a buffer filled with file information
+
+Arguments:
+
+ FileId - Supplies the File id for the operation
+
+ Buffer - Supplies the buffer to receive the file information. Note that
+ it must be large enough to hold the full file name
+
+Return Value:
+
+ ESUCCESS is returned if the open operation is successful. Otherwise,
+ an unsuccessful status is returned that describes the reason for failure.
+
+--*/
+
+{
+ PBL_FILE_TABLE FileTableEntry;
+ UCHAR Attributes;
+ ULONG i;
+
+ FatDebugOutput("FatGetFileInformation\r\n", 0, 0);
+
+ //
+ // Load our local variables
+ //
+
+ FileTableEntry = &BlFileTable[FileId];
+ Attributes = FileTableEntry->u.FatFileContext.Dirent.Attributes;
+
+ //
+ // Zero out the buffer, and fill in its non-zero values.
+ //
+
+ RtlZeroMemory(Buffer, sizeof(FILE_INFORMATION));
+
+ Buffer->EndingAddress.LowPart = FileTableEntry->u.FatFileContext.Dirent.FileSize;
+
+ Buffer->CurrentPosition.LowPart = FileTableEntry->Position.LowPart;
+ Buffer->CurrentPosition.HighPart = 0;
+
+ if (FlagOn(Attributes, FAT_DIRENT_ATTR_READ_ONLY)) { SetFlag(Buffer->Attributes, ArcReadOnlyFile) };
+ if (FlagOn(Attributes, FAT_DIRENT_ATTR_HIDDEN)) { SetFlag(Buffer->Attributes, ArcHiddenFile) };
+ if (FlagOn(Attributes, FAT_DIRENT_ATTR_SYSTEM)) { SetFlag(Buffer->Attributes, ArcSystemFile) };
+ if (FlagOn(Attributes, FAT_DIRENT_ATTR_ARCHIVE)) { SetFlag(Buffer->Attributes, ArcArchiveFile) };
+ if (FlagOn(Attributes, FAT_DIRENT_ATTR_DIRECTORY)) { SetFlag(Buffer->Attributes, ArcDirectoryFile) };
+
+ Buffer->FileNameLength = FileTableEntry->FileNameLength;
+
+ for (i = 0; i < FileTableEntry->FileNameLength; i += 1) {
+
+ Buffer->FileName[i] = FileTableEntry->FileName[i];
+ }
+
+ return ESUCCESS;
+}
+
+
+ARC_STATUS
+FatOpen (
+ IN PCHAR FileName,
+ IN OPEN_MODE OpenMode,
+ IN PULONG FileId
+ )
+
+/*++
+
+Routine Description:
+
+ This routine searches the device for a file matching FileName.
+ If a match is found the dirent for the file is saved and the file is
+ opened.
+
+Arguments:
+
+ FileName - Supplies a pointer to a zero terminated file name.
+
+ OpenMode - Supplies the mode of the open.
+
+ FileId - Supplies a pointer to a variable that specifies the file
+ table entry that is to be filled in if the open is successful.
+
+Return Value:
+
+ ESUCCESS is returned if the open operation is successful. Otherwise,
+ an unsuccessful status is returned that describes the reason for failure.
+
+--*/
+
+{
+ PBL_FILE_TABLE FileTableEntry;
+ PFAT_STRUCTURE_CONTEXT FatStructureContext;
+ ULONG DeviceId;
+
+ FAT_ENTRY CurrentDirectoryIndex;
+ BOOLEAN SearchSucceeded;
+ BOOLEAN IsDirectory;
+ BOOLEAN IsReadOnly;
+
+ STRING PathName;
+ FAT8DOT3 Name;
+
+ FatDebugOutput("FatOpen\r\n", 0, 0);
+
+ //
+ // Load our local variables
+ //
+
+ FileTableEntry = &BlFileTable[*FileId];
+ FatStructureContext = (PFAT_STRUCTURE_CONTEXT)FileTableEntry->StructureContext;
+ DeviceId = FileTableEntry->DeviceId;
+
+ //
+ // Construct a file name descriptor from the input file name
+ //
+
+ RtlInitString( &PathName, FileName );
+
+ //
+ // While the path name has some characters in it we'll go through our loop
+ // which extracts the first part of the path name and searches the current
+ // directory for an entry. If what we find is a directory then we have to
+ // continue looping until we're done with the path name.
+ //
+
+ FileTableEntry->u.FatFileContext.DirentLbo = 0;
+ FileTableEntry->Position.LowPart = 0;
+ FileTableEntry->Position.HighPart = 0;
+
+ CurrentDirectoryIndex = 0;
+ SearchSucceeded = TRUE;
+ IsDirectory = TRUE;
+ IsReadOnly = TRUE;
+
+ if ((PathName.Buffer[0] == '\\') && (PathName.Length == 1)) {
+
+ //
+ // We are opening the root directory.
+ //
+ // N.B.: IsDirectory and SearchSucceeded are already TRUE.
+ //
+
+ PathName.Length = 0;
+
+ FileTableEntry->FileNameLength = 1;
+ FileTableEntry->FileName[0] = PathName.Buffer[0];
+
+ //
+ // Root dirent is all zeroes with a directory attribute.
+ //
+
+ RtlZeroMemory(&FileTableEntry->u.FatFileContext.Dirent, sizeof(DIRENT));
+
+ FileTableEntry->u.FatFileContext.Dirent.Attributes = FAT_DIRENT_ATTR_DIRECTORY;
+
+ FileTableEntry->u.FatFileContext.DirentLbo = 0;
+
+ IsReadOnly = FALSE;
+
+ CurrentDirectoryIndex = FileTableEntry->u.FatFileContext.Dirent.FirstClusterOfFile;
+
+ } else {
+
+ //
+ // We are not opening the root directory.
+ //
+
+ while ((PathName.Length > 0) && IsDirectory) {
+
+ ARC_STATUS Status;
+
+ //
+ // Extract the first component and search the directory for a match, but
+ // first copy the first part to the file name buffer in the file table entry
+ //
+
+ if (PathName.Buffer[0] == '\\') {
+ PathName.Buffer +=1;
+ PathName.Length -=1;
+ }
+
+ for (FileTableEntry->FileNameLength = 0;
+ (((USHORT)FileTableEntry->FileNameLength < PathName.Length) &&
+ (PathName.Buffer[FileTableEntry->FileNameLength] != '\\'));
+ FileTableEntry->FileNameLength += 1) {
+
+ FileTableEntry->FileName[FileTableEntry->FileNameLength] =
+ PathName.Buffer[FileTableEntry->FileNameLength];
+ }
+
+ FatFirstComponent( &PathName, &Name );
+
+ Status = FatSearchForDirent( FatStructureContext,
+ DeviceId,
+ CurrentDirectoryIndex,
+ &Name,
+ &FileTableEntry->u.FatFileContext.Dirent,
+ &FileTableEntry->u.FatFileContext.DirentLbo,
+ FALSE );
+
+ if (Status == ENOENT) {
+
+ SearchSucceeded = FALSE;
+ break;
+ }
+
+ if (Status != ESUCCESS) {
+
+ return Status;
+ }
+
+ //
+ // We have a match now check to see if it is a directory, and also
+ // if it is readonly
+ //
+
+ IsDirectory = BooleanFlagOn( FileTableEntry->u.FatFileContext.Dirent.Attributes,
+ FAT_DIRENT_ATTR_DIRECTORY );
+
+ IsReadOnly = BooleanFlagOn( FileTableEntry->u.FatFileContext.Dirent.Attributes,
+ FAT_DIRENT_ATTR_READ_ONLY );
+
+ if (IsDirectory) {
+
+ CurrentDirectoryIndex = FileTableEntry->u.FatFileContext.Dirent.FirstClusterOfFile;
+ }
+ }
+ }
+
+ //
+ // If the path name length is not zero then we were trying to crack a path
+ // with an nonexistent (or non directory) name in it. For example, we tried
+ // to crack a\b\c\d and b is not a directory or does not exist (then the path
+ // name will still contain c\d).
+ //
+
+ if (PathName.Length != 0) {
+
+ return ENOTDIR;
+ }
+
+ //
+ // At this point we've cracked the name up to (an maybe including the last
+ // component). We located the last component if the SearchSucceeded flag is
+ // true, otherwise the last component does not exist. If we located the last
+ // component then this is like an open or a supersede, but not a create.
+ //
+
+ if (SearchSucceeded) {
+
+ //
+ // Check if the last component is a directory
+ //
+
+ if (IsDirectory) {
+
+ //
+ // For an existing directory the only valid open mode is OpenDirectory
+ // all other modes return an error
+ //
+
+ switch (OpenMode) {
+
+ case ArcOpenReadOnly:
+ case ArcOpenWriteOnly:
+ case ArcOpenReadWrite:
+ case ArcCreateWriteOnly:
+ case ArcCreateReadWrite:
+ case ArcSupersedeWriteOnly:
+ case ArcSupersedeReadWrite:
+
+ //
+ // If we reach here then the caller got a directory but didn't
+ // want to open a directory
+ //
+
+ return EISDIR;
+
+ case ArcOpenDirectory:
+
+ //
+ // If we reach here then the caller got a directory and wanted
+ // to open a directory.
+ //
+
+ FileTableEntry->Flags.Open = 1;
+ FileTableEntry->Flags.Read = 1;
+
+ return ESUCCESS;
+
+ case ArcCreateDirectory:
+
+ //
+ // If we reach here then the caller got a directory and wanted
+ // to create a new directory
+ //
+
+ return EACCES;
+ }
+ }
+
+ //
+ // If we get there then we have an existing file that is being opened.
+ // We can open existing files through a lot of different open modes in
+ // some cases we need to check the read only part of file and/or truncate
+ // the file.
+ //
+
+ switch (OpenMode) {
+
+ case ArcOpenReadOnly:
+
+ //
+ // If we reach here then the user got a file and wanted to open the
+ // file read only
+ //
+
+ FileTableEntry->Flags.Open = 1;
+ FileTableEntry->Flags.Read = 1;
+
+ return ESUCCESS;
+
+ case ArcOpenWriteOnly:
+
+ //
+ // If we reach here then the user got a file and wanted to open the
+ // file write only
+ //
+
+ if (IsReadOnly) { return EROFS; }
+ FileTableEntry->Flags.Open = 1;
+ FileTableEntry->Flags.Write = 1;
+
+ return ESUCCESS;
+
+ case ArcOpenReadWrite:
+
+ //
+ // If we reach here then the user got a file and wanted to open the
+ // file read/write
+ //
+
+ if (IsReadOnly) { return EROFS; }
+ FileTableEntry->Flags.Open = 1;
+ FileTableEntry->Flags.Read = 1;
+ FileTableEntry->Flags.Write = 1;
+
+ return ESUCCESS;
+
+ case ArcCreateWriteOnly:
+ case ArcCreateReadWrite:
+
+ //
+ // If we reach here then the user got a file and wanted to create a new
+ // file
+ //
+
+ return EACCES;
+
+ case ArcSupersedeWriteOnly:
+
+ //
+ // If we reach here then the user got a file and wanted to supersede a
+ // file
+ //
+
+ if (IsReadOnly) { return EROFS; }
+ TruncateFileAllocation( *FileId, 0 );
+ FileTableEntry->Flags.Open = 1;
+ FileTableEntry->Flags.Read = 1;
+ FileTableEntry->Flags.Write = 1;
+
+ return ESUCCESS;
+
+ case ArcSupersedeReadWrite:
+
+ //
+ // If we reach here then the user got a file and wanted to supersede a
+ // file
+ //
+
+ if (IsReadOnly) { return EROFS; }
+ TruncateFileAllocation( *FileId, 0 );
+ FileTableEntry->Flags.Open = 1;
+ FileTableEntry->Flags.Read = 1;
+ FileTableEntry->Flags.Write = 1;
+
+ return ESUCCESS;
+
+ case ArcOpenDirectory:
+ case ArcCreateDirectory:
+
+ //
+ // If we reach here then the user got a file and wanted a directory
+ //
+
+ return ENOTDIR;
+ }
+ }
+
+ //
+ // If we get here the last component does not exist so we are trying to create
+ // either a new file or a directory.
+ //
+
+ switch (OpenMode) {
+
+ case ArcOpenReadOnly:
+ case ArcOpenWriteOnly:
+ case ArcOpenReadWrite:
+
+ //
+ // If we reach here then the user did not get a file but wanted a file
+ //
+
+ return ENOENT;
+
+ case ArcCreateWriteOnly:
+ case ArcSupersedeWriteOnly:
+
+ //
+ // If we reach here then the user did not get a file and wanted to create
+ // or supersede a file write only
+ //
+
+ RtlZeroMemory( &FileTableEntry->u.FatFileContext.Dirent, sizeof(DIRENT));
+
+ FatSetDirent( &Name, &FileTableEntry->u.FatFileContext.Dirent, 0 );
+
+ CreateDirent( FatStructureContext,
+ DeviceId,
+ CurrentDirectoryIndex,
+ &FileTableEntry->u.FatFileContext.Dirent,
+ &FileTableEntry->u.FatFileContext.DirentLbo );
+
+ FileTableEntry->Flags.Open = 1;
+ FileTableEntry->Flags.Write = 1;
+
+ return ESUCCESS;
+
+ case ArcCreateReadWrite:
+ case ArcSupersedeReadWrite:
+
+ //
+ // If we reach here then the user did not get a file and wanted to create
+ // or supersede a file read/write
+ //
+
+ RtlZeroMemory( &FileTableEntry->u.FatFileContext.Dirent, sizeof(DIRENT));
+
+ FatSetDirent( &Name, &FileTableEntry->u.FatFileContext.Dirent, 0 );
+
+ CreateDirent( FatStructureContext,
+ DeviceId,
+ CurrentDirectoryIndex,
+ &FileTableEntry->u.FatFileContext.Dirent,
+ &FileTableEntry->u.FatFileContext.DirentLbo );
+
+ FileTableEntry->Flags.Open = 1;
+ FileTableEntry->Flags.Read = 1;
+ FileTableEntry->Flags.Write = 1;
+
+ return ESUCCESS;
+
+ case ArcOpenDirectory:
+
+ //
+ // If we reach here then the user did not get a file and wanted to open
+ // an existing directory
+ //
+
+ return ENOENT;
+
+ case ArcCreateDirectory:
+
+ //
+ // If we reach here then the user did not get a file and wanted to create
+ // a new directory.
+ //
+
+ RtlZeroMemory( &FileTableEntry->u.FatFileContext.Dirent, sizeof(DIRENT));
+
+ FatSetDirent( &Name,
+ &FileTableEntry->u.FatFileContext.Dirent,
+ FAT_DIRENT_ATTR_DIRECTORY );
+
+ CreateDirent( FatStructureContext,
+ DeviceId,
+ CurrentDirectoryIndex,
+ &FileTableEntry->u.FatFileContext.Dirent,
+ &FileTableEntry->u.FatFileContext.DirentLbo );
+
+ IncreaseFileAllocation( *FileId, sizeof(DIRENT) * 2 );
+
+ {
+ DIRENT Buffer;
+ LBO Lbo;
+ ULONG Count;
+ ULONG i;
+
+ RtlZeroMemory((PVOID)&Buffer.FileName[0], sizeof(DIRENT) );
+
+ for (i = 0; i < 11; i += 1) {
+ Buffer.FileName[i] = ' ';
+ }
+ Buffer.Attributes = FAT_DIRENT_ATTR_DIRECTORY;
+
+ VboToLbo( *FileId, 0, &Lbo, &Count );
+ Buffer.FileName[0] = FAT_DIRENT_DIRECTORY_ALIAS;
+ Buffer.FirstClusterOfFile = FileTableEntry->u.FatFileContext.Dirent.FirstClusterOfFile;
+ DiskWrite( DeviceId, Lbo, sizeof(DIRENT), (PVOID)&Buffer.FileName[0] );
+
+ VboToLbo( *FileId, sizeof(DIRENT), &Lbo, &Count );
+ Buffer.FileName[1] = FAT_DIRENT_DIRECTORY_ALIAS;
+ Buffer.FirstClusterOfFile = CurrentDirectoryIndex;
+ DiskWrite( DeviceId, Lbo, sizeof(DIRENT), (PVOID)&Buffer.FileName[0] );
+ }
+
+ FileTableEntry->Flags.Open = 1;
+ FileTableEntry->Flags.Read = 1;
+
+ return ESUCCESS;
+ }
+}
+
+
+ARC_STATUS
+FatRead (
+ IN ULONG FileId,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Transfer
+ )
+
+/*++
+
+Routine Description:
+
+ This routine reads data from the specified file.
+
+Arguments:
+
+ FileId - Supplies the file table index.
+
+ Buffer - Supplies a pointer to the buffer that receives the data
+ read.
+
+ Length - Supplies the number of bytes that are to be read.
+
+ Transfer - Supplies a pointer to a variable that receives the number
+ of bytes actually transfered.
+
+Return Value:
+
+ ESUCCESS is returned if the read operation is successful. Otherwise,
+ an unsuccessful status is returned that describes the reason for failure.
+
+--*/
+
+{
+ PBL_FILE_TABLE FileTableEntry;
+ PFAT_STRUCTURE_CONTEXT FatStructureContext;
+ ULONG DeviceId;
+
+ FatDebugOutput("FatRead\r\n", 0, 0);
+
+ //
+ // Load out local variables
+ //
+
+ FileTableEntry = &BlFileTable[FileId];
+ FatStructureContext = (PFAT_STRUCTURE_CONTEXT)FileTableEntry->StructureContext;
+ DeviceId = FileTableEntry->DeviceId;
+
+ //
+ // Clear the transfer count
+ //
+
+ *Transfer = 0;
+
+ //
+ // Read in runs (i.e., bytes) until the byte count goes to zero
+ //
+
+ while (Length > 0) {
+
+ LBO Lbo;
+
+ ULONG CurrentRunByteCount;
+
+ //
+ // Lookup the corresponding Lbo and run length for the current position
+ // (i.e., Vbo).
+ //
+
+ if (FatVboToLbo( FileId, FileTableEntry->Position.LowPart, &Lbo, &CurrentRunByteCount, FALSE ) != ESUCCESS) {
+
+ return ESUCCESS;
+ }
+
+ //
+ // while there are bytes to be read in from the current run
+ // length and we haven't exhausted the request we loop reading
+ // in bytes. The biggest request we'll handle is only 32KB
+ // contiguous bytes per physical read. So we might need to loop
+ // through the run.
+ //
+
+ while ((Length > 0) && (CurrentRunByteCount > 0)) {
+
+ LONG SingleReadSize;
+
+ //
+ // Compute the size of the next physical read
+ //
+
+ SingleReadSize = Minimum(Length, 32 * 1024);
+ SingleReadSize = Minimum((ULONG)SingleReadSize, CurrentRunByteCount);
+
+ //
+ // Don't read beyond the eof
+ //
+
+ if (((ULONG)SingleReadSize + FileTableEntry->Position.LowPart) >
+ FileTableEntry->u.FatFileContext.Dirent.FileSize) {
+
+ SingleReadSize = FileTableEntry->u.FatFileContext.Dirent.FileSize -
+ FileTableEntry->Position.LowPart;
+
+ //
+ // If the readjusted read length is now zero then we're done.
+ //
+
+ if (SingleReadSize <= 0) {
+
+ return ESUCCESS;
+ }
+
+ //
+ // By also setting length here we'll make sure that this is our last
+ // read
+ //
+
+ Length = SingleReadSize;
+ }
+
+ //
+ // Issue the read
+ //
+
+ DiskRead( DeviceId, Lbo, SingleReadSize, Buffer, FALSE );
+
+ //
+ // Update the remaining length, Current run byte count
+ // and new Lbo offset
+ //
+
+ Length -= SingleReadSize;
+ CurrentRunByteCount -= SingleReadSize;
+ Lbo += SingleReadSize;
+
+ //
+ // Update the current position and the number of bytes transfered
+ //
+
+ FileTableEntry->Position.LowPart += SingleReadSize;
+ *Transfer += SingleReadSize;
+
+ //
+ // Update buffer to point to the next byte location to fill in
+ //
+
+ Buffer = (PCHAR)Buffer + SingleReadSize;
+ }
+ }
+
+ //
+ // If we get here then remaining sector count is zero so we can
+ // return success to our caller
+ //
+
+ return ESUCCESS;
+}
+
+
+ARC_STATUS
+FatRename(
+ IN ULONG FileId,
+ IN PCHAR NewFileName
+ )
+
+/*++
+
+Routine Description:
+
+ This routine renames an open file. It does no checking to
+ see if the target filename already exists. It is intended for use
+ only when dual-booting DOS on x86 machines, where it is used to
+ replace the NT MVDM CONFIG.SYS and AUTOEXEC.BAT with the native DOS
+ CONFIG.SYS and AUTOEXEC.BAT files.
+
+Arguments:
+
+ FileId - Supplies the file id of the file to be renamed
+
+ NewFileName - Supplies the new name for the file.
+
+Return Value:
+
+ ARC_STATUS
+
+--*/
+
+{
+ PBL_FILE_TABLE FileTableEntry;
+ PFAT_STRUCTURE_CONTEXT FatStructureContext;
+ ULONG DeviceId;
+ FAT8DOT3 FatName;
+ STRING String;
+
+ //
+ // Initialize our local variables
+ //
+
+ RtlInitString( &String, NewFileName );
+ FileTableEntry = &BlFileTable[FileId];
+ FatStructureContext = (PFAT_STRUCTURE_CONTEXT)FileTableEntry->StructureContext;
+ DeviceId = FileTableEntry->DeviceId;
+
+ //
+ // Modify a in-memory copy of the dirent with the new name
+ //
+
+ FatFirstComponent( &String, &FatName );
+
+ FatSetDirent( &FatName,
+ &FileTableEntry->u.FatFileContext.Dirent,
+ FileTableEntry->u.FatFileContext.Dirent.Attributes );
+
+ //
+ // Write the modified dirent to disk
+ //
+
+ DiskWrite( DeviceId,
+ FileTableEntry->u.FatFileContext.DirentLbo,
+ sizeof(DIRENT),
+ &FileTableEntry->u.FatFileContext.Dirent );
+
+ //
+ // And return to our caller
+ //
+
+ return ESUCCESS;
+}
+
+
+ARC_STATUS
+FatSeek (
+ IN ULONG FileId,
+ IN PLARGE_INTEGER Offset,
+ IN SEEK_MODE SeekMode
+ )
+
+/*++
+
+Routine Description:
+
+ This routine seeks to the specified position for the file specified
+ by the file id.
+
+Arguments:
+
+ FileId - Supplies the file table index.
+
+ Offset - Supplies the offset in the file to position to.
+
+ SeekMode - Supplies the mode of the seek operation.
+
+Return Value:
+
+ ESUCCESS is returned if the seek operation is successful. Otherwise,
+ EINVAL is returned.
+
+--*/
+
+{
+ PBL_FILE_TABLE FileTableEntry;
+ ULONG NewPosition;
+
+ FatDebugOutput("FatSeek\r\n", 0, 0);
+
+ //
+ // Load our local variables
+ //
+
+ FileTableEntry = &BlFileTable[FileId];
+
+ //
+ // Compute the new position
+ //
+
+ if (SeekMode == SeekAbsolute) {
+
+ NewPosition = Offset->LowPart;
+
+ } else {
+
+ NewPosition = FileTableEntry->Position.LowPart + Offset->LowPart;
+ }
+
+ //
+ // If the new position is greater than the file size then return
+ // an error
+ //
+
+ if (NewPosition > FileTableEntry->u.FatFileContext.Dirent.FileSize) {
+
+ return EINVAL;
+ }
+
+ //
+ // Otherwise set the new position and return to our caller
+ //
+
+ FileTableEntry->Position.LowPart = NewPosition;
+
+ return ESUCCESS;
+}
+
+
+ARC_STATUS
+FatSetFileInformation (
+ IN ULONG FileId,
+ IN ULONG AttributeFlags,
+ IN ULONG AttributeMask
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets the file attributes of the indicated file
+
+Arguments:
+
+ FileId - Supplies the File Id for the operation
+
+ AttributeFlags - Supplies the value (on or off) for each attribute being modified
+
+ AttributeMask - Supplies a mask of the attributes being altered. All other
+ file attributes are left alone.
+
+Return Value:
+
+ ESUCCESS is returned if the read operation is successful. Otherwise,
+ an unsuccessful status is returned that describes the reason for failure.
+
+--*/
+
+{
+ PBL_FILE_TABLE FileTableEntry;
+ PFAT_STRUCTURE_CONTEXT FatStructureContext;
+ ULONG DeviceId;
+ UCHAR DirentAttributes;
+ UCHAR DirentMask;
+ UCHAR DirentFlags;
+
+ FatDebugOutput("FatSetFileInformation\r\n", 0, 0);
+
+ //
+ // Load our local variables
+ //
+
+ FileTableEntry = &BlFileTable[FileId];
+ FatStructureContext = (PFAT_STRUCTURE_CONTEXT)FileTableEntry->StructureContext;
+ DeviceId = FileTableEntry->DeviceId;
+
+ DirentAttributes = FileTableEntry->u.FatFileContext.Dirent.Attributes;
+
+ //
+ // Check if this is the root directory
+ //
+
+ if (FileTableEntry->u.FatFileContext.DirentLbo == 0) {
+
+ return EACCES;
+ }
+
+ //
+ // Check if the users wishes to delete the file/directory
+ //
+
+ if (FlagOn(AttributeMask, ArcDeleteFile) && FlagOn(AttributeFlags, ArcDeleteFile)) {
+
+ //
+ // Check if the file/directory is marked read only
+ //
+
+ if (FlagOn(DirentAttributes, FAT_DIRENT_ATTR_READ_ONLY)) {
+
+ return EACCES;
+ }
+
+ //
+ // Check if this is a directory because we need to then check if the
+ // directory is empty
+ //
+
+ if (FlagOn(DirentAttributes, FAT_DIRENT_ATTR_DIRECTORY)) {
+
+ ULONG BytesPerCluster;
+ FAT_ENTRY FatEntry;
+ CLUSTER_TYPE ClusterType;
+
+ BytesPerCluster = FatBytesPerCluster( &FatStructureContext->Bpb );
+ FatEntry = FileTableEntry->u.FatFileContext.Dirent.FirstClusterOfFile;
+ ClusterType = FatInterpretClusterType( FatStructureContext, FatEntry );
+
+ //
+ // Now loop through each cluster, and compute the starting Lbo for each
+ // cluster that we encounter
+ //
+
+ while (ClusterType == FatClusterNext) {
+
+ LBO ClusterLbo;
+ ULONG Offset;
+
+ ClusterLbo = FatIndexToLbo( FatStructureContext, FatEntry );
+
+ //
+ // Now for each dirent in the cluster compute the lbo, read in the dirent
+ // and check if it is in use
+ //
+
+ for (Offset = 0; Offset < BytesPerCluster; Offset += sizeof(DIRENT)) {
+
+ DIRENT Dirent;
+
+ DiskRead( DeviceId, Offset + ClusterLbo, sizeof(DIRENT), &Dirent, FALSE );
+
+ if (Dirent.FileName[0] == FAT_DIRENT_NEVER_USED) {
+
+ break;
+ }
+
+ if ((Dirent.FileName[0] != FAT_DIRENT_DIRECTORY_ALIAS) ||
+ (Dirent.FileName[0] != FAT_DIRENT_DELETED)) {
+
+ return EACCES;
+ }
+ }
+
+ //
+ // Now that we've exhausted the current cluster we need to read
+ // in the next cluster. So locate the next fat entry in the chain
+ // and go back to the top of the while loop.
+ //
+
+ LookupFatEntry( FatStructureContext, DeviceId, FatEntry, &FatEntry, FALSE );
+
+ ClusterType = FatInterpretClusterType(FatStructureContext, FatEntry);
+ }
+ }
+
+ //
+ // At this point the file/directory can be deleted so mark the name
+ // as deleted and write it back out
+ //
+
+ FileTableEntry->u.FatFileContext.Dirent.FileName[0] = FAT_DIRENT_DELETED;
+
+ DiskWrite( DeviceId,
+ FileTableEntry->u.FatFileContext.DirentLbo,
+ sizeof(DIRENT),
+ &FileTableEntry->u.FatFileContext.Dirent );
+
+ //
+ // And then truncate any file allocation assigned to the file
+ //
+
+ TruncateFileAllocation( FileId, 0);
+
+ return ESUCCESS;
+ }
+
+ //
+ // At this point the user does not want to delete the file so we only
+ // need to modify the attributes
+ //
+
+ DirentMask = 0;
+ DirentFlags = 0;
+
+ //
+ // Build up a mask and flag byte that correspond to the bits in the dirent
+ //
+
+ if (FlagOn(AttributeMask, ArcReadOnlyFile)) { SetFlag(DirentMask, FAT_DIRENT_ATTR_READ_ONLY); }
+ if (FlagOn(AttributeMask, ArcHiddenFile)) { SetFlag(DirentMask, FAT_DIRENT_ATTR_HIDDEN); }
+ if (FlagOn(AttributeMask, ArcSystemFile)) { SetFlag(DirentMask, FAT_DIRENT_ATTR_SYSTEM); }
+ if (FlagOn(AttributeMask, ArcArchiveFile)) { SetFlag(DirentMask, FAT_DIRENT_ATTR_ARCHIVE); }
+
+ if (FlagOn(AttributeFlags, ArcReadOnlyFile)) { SetFlag(DirentFlags, FAT_DIRENT_ATTR_READ_ONLY); }
+ if (FlagOn(AttributeFlags, ArcHiddenFile)) { SetFlag(DirentFlags, FAT_DIRENT_ATTR_HIDDEN); }
+ if (FlagOn(AttributeFlags, ArcSystemFile)) { SetFlag(DirentFlags, FAT_DIRENT_ATTR_SYSTEM); }
+ if (FlagOn(AttributeFlags, ArcArchiveFile)) { SetFlag(DirentFlags, FAT_DIRENT_ATTR_ARCHIVE); }
+
+ //
+ // The new attributes is calculated via the following formula
+ //
+ // Attributes = (~Mask & OldAttributes) | (Mask & NewAttributes);
+ //
+ // After we calculate the new attribute byte we write it out.
+ //
+
+ FileTableEntry->u.FatFileContext.Dirent.Attributes = (UCHAR)((~DirentMask & DirentAttributes) |
+ (DirentMask & DirentFlags));
+
+ DiskWrite( DeviceId,
+ FileTableEntry->u.FatFileContext.DirentLbo,
+ sizeof(DIRENT),
+ &FileTableEntry->u.FatFileContext.Dirent );
+
+ return ESUCCESS;
+}
+
+
+ARC_STATUS
+FatWrite (
+ IN ULONG FileId,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Transfer
+ )
+
+/*++
+
+Routine Description:
+
+ This routine writes data to the specified file.
+
+Arguments:
+
+ FileId - Supplies the file table index.
+
+ Buffer - Supplies a pointer to the buffer that contains the data
+ written.
+
+ Length - Supplies the number of bytes that are to be written.
+
+ Transfer - Supplies a pointer to a variable that receives the number
+ of bytes actually transfered.
+
+Return Value:
+
+ ESUCCESS is returned if the write operation is successful. Otherwise,
+ an unsuccessful status is returned that describes the reason for failure.
+
+--*/
+
+{
+ PBL_FILE_TABLE FileTableEntry;
+ PFAT_STRUCTURE_CONTEXT FatStructureContext;
+ ULONG DeviceId;
+ ULONG OffsetBeyondWrite;
+
+ FatDebugOutput("FatWrite\r\n", 0, 0);
+
+ //
+ // Load our local variables
+ //
+
+ FileTableEntry = &BlFileTable[FileId];
+ FatStructureContext = (PFAT_STRUCTURE_CONTEXT)FileTableEntry->StructureContext;
+ DeviceId = FileTableEntry->DeviceId;
+
+ //
+ // Reset the file size to be the maximum of what is it now and the end of
+ // our write. We will assume that there is always enough allocation to support
+ // the file size, so we only need to increase allocation if we are increasing
+ // the file size.
+ //
+
+ OffsetBeyondWrite = FileTableEntry->Position.LowPart + Length;
+
+ if (OffsetBeyondWrite > FileTableEntry->u.FatFileContext.Dirent.FileSize) {
+
+ IncreaseFileAllocation( FileId, OffsetBeyondWrite );
+
+ FileTableEntry->u.FatFileContext.Dirent.FileSize = OffsetBeyondWrite;
+
+ DiskWrite( DeviceId,
+ FileTableEntry->u.FatFileContext.DirentLbo,
+ sizeof(DIRENT),
+ &FileTableEntry->u.FatFileContext.Dirent );
+ }
+
+ //
+ // Clear the transfer count
+ //
+
+ *Transfer = 0;
+
+ //
+ // Write out runs (i.e., bytes) until the byte count goes to zero
+ //
+
+ while (Length > 0) {
+
+ LBO Lbo;
+
+ ULONG CurrentRunByteCount;
+
+ //
+ // Lookup the corresponding Lbo and run length for the current position
+ // (i.e., Vbo).
+ //
+
+ VboToLbo( FileId, FileTableEntry->Position.LowPart, &Lbo, &CurrentRunByteCount );
+
+ //
+ // While there are bytes to be written out to the current run
+ // length and we haven't exhausted the request we loop reading
+ // in bytes. The biggest request we'll handle is only 32KB
+ // contiguous bytes per physical read. So we might need to loop
+ // through the run.
+ //
+
+ while ((Length > 0) && (CurrentRunByteCount > 0)) {
+
+ LONG SingleWriteSize;
+
+ //
+ // Compute the size of the next physical read
+ //
+
+ SingleWriteSize = Minimum(Length, 32 * 1024);
+ SingleWriteSize = Minimum((ULONG)SingleWriteSize, CurrentRunByteCount);
+
+ //
+ // Issue the Write
+ //
+
+ DiskWrite( DeviceId, Lbo, SingleWriteSize, Buffer);
+
+ //
+ // Update the remaining length, Current run byte count
+ // and new Lbo offset
+ //
+
+ Length -= SingleWriteSize;
+ CurrentRunByteCount -= SingleWriteSize;
+ Lbo += SingleWriteSize;
+
+ //
+ // Update the current position and the number of bytes transfered
+ //
+
+ FileTableEntry->Position.LowPart += SingleWriteSize;
+ *Transfer += SingleWriteSize;
+
+ //
+ // Update buffer to point to the next byte location to fill in
+ //
+
+ Buffer = (PCHAR)Buffer + SingleWriteSize;
+ }
+ }
+
+ //
+ // Check if the fat is dirty and flush it out if it is.
+ //
+
+ if (FatStructureContext->CachedFatDirty) {
+
+ FlushFatEntries( FatStructureContext, DeviceId );
+ }
+
+ //
+ // If we get here then remaining sector count is zero so we can
+ // return success to our caller
+ //
+
+ return ESUCCESS;
+}
+
+
+ARC_STATUS
+FatInitialize (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the fat boot filesystem.
+ Currently this is a no-op.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ ESUCCESS.
+
+--*/
+
+{
+ return ESUCCESS;
+}
+
+
+//
+// Internal support routine
+//
+
+ARC_STATUS
+FatDiskRead (
+ IN ULONG DeviceId,
+ IN LBO Lbo,
+ IN ULONG ByteCount,
+ IN PVOID Buffer
+ )
+
+/*++
+
+Routine Description:
+
+ This routine reads in zero or more bytes from the specified device.
+
+Arguments:
+
+ DeviceId - Supplies the device id to use in the arc calls.
+
+ Lbo - Supplies the LBO to start reading from.
+
+ ByteCount - Supplies the number of bytes to read.
+
+ Buffer - Supplies a pointer to the buffer to read the bytes into.
+
+Return Value:
+
+ ESUCCESS is returned if the read operation is successful. Otherwise,
+ an unsuccessful status is returned that describes the reason for failure.
+
+--*/
+
+{
+ LARGE_INTEGER LargeLbo;
+ ARC_STATUS Status;
+ ULONG i;
+
+ //
+ // Special case the zero byte read request
+ //
+
+ if (ByteCount == 0) {
+
+ return ESUCCESS;
+ }
+
+ //
+ // Seek to the appropriate offset on the volume
+ //
+
+ LargeLbo.LowPart = (ULONG)Lbo;
+ LargeLbo.HighPart = 0;
+
+ if ((Status = ArcSeek( DeviceId, &LargeLbo, SeekAbsolute )) != ESUCCESS) {
+
+ return Status;
+ }
+
+ //
+ // Issue the arc read request
+ //
+
+ if ((Status = ArcRead( DeviceId, Buffer, ByteCount, &i)) != ESUCCESS) {
+
+ return Status;
+ }
+
+ //
+ // Make sure we got back the amount requested
+ //
+
+ if (ByteCount != i) {
+
+ return EIO;
+ }
+
+ //
+ // Everything is fine so return success to our caller
+ //
+
+ return ESUCCESS;
+}
+
+
+//
+// Internal support routine
+//
+
+ARC_STATUS
+FatDiskWrite (
+ IN ULONG DeviceId,
+ IN LBO Lbo,
+ IN ULONG ByteCount,
+ IN PVOID Buffer
+ )
+
+/*++
+
+Routine Description:
+
+ This routine writes in zero or more bytes to the specified device.
+
+Arguments:
+
+ DeviceId - Supplies the device id to use in the arc calls.
+
+ Lbo - Supplies the LBO to start writing from.
+
+ ByteCount - Supplies the number of bytes to write.
+
+ Buffer - Supplies a pointer to the buffer of bytes to write out.
+
+Return Value:
+
+ ESUCCESS is returned if the write operation is successful. Otherwise,
+ an unsuccessful status is returned that describes the reason for failure.
+
+--*/
+
+{
+ LARGE_INTEGER LargeLbo;
+ ARC_STATUS Status;
+ ULONG i;
+
+ //
+ // Special case the zero byte write request
+ //
+
+ if (ByteCount == 0) {
+
+ return ESUCCESS;
+ }
+
+ //
+ // Seek to the appropriate offset on the volume
+ //
+
+ LargeLbo.LowPart = (ULONG) Lbo;
+ LargeLbo.HighPart = 0;
+
+ if ((Status = ArcSeek( DeviceId, &LargeLbo, SeekAbsolute )) != ESUCCESS) {
+
+ return Status;
+ }
+
+ //
+ // Issue the arc write request
+ //
+
+ if ((Status = ArcWrite( DeviceId, Buffer, ByteCount, &i)) != ESUCCESS) {
+
+ return Status;
+ }
+
+ //
+ // Make sure we wrote out the amount requested
+ //
+
+ if (ByteCount != i) {
+
+ return EIO;
+ }
+
+ //
+ // Everything is fine so return success to our caller
+ //
+
+ return ESUCCESS;
+}
+
+
+//
+// Internal support routine
+//
+
+CLUSTER_TYPE
+FatInterpretClusterType (
+ IN PFAT_STRUCTURE_CONTEXT FatStructureContext,
+ IN FAT_ENTRY Entry
+ )
+
+/*++
+
+Routine Description:
+
+ This procedure tells the caller how to interpret a fat table entry. It will
+ indicate if the fat cluster is available, reserved, bad, the last one, or another
+ fat index.
+
+Arguments:
+
+ FatStructureContext - Supplies the volume structure for the operation
+
+ DeviceId - Supplies the DeviceId for the volume being used.
+
+ Entry - Supplies the fat entry to examine.
+
+Return Value:
+
+ The type of the input fat entry is returned
+
+--*/
+
+{
+ //
+ // Check for 12 or 16 bit fat.
+ //
+
+ if (FatIndexBitSize(&FatStructureContext->Bpb) == 12) {
+
+ //
+ // For 12 bit fat check for one of the cluster types, but first
+ // make sure we only looking at 12 bits of the entry
+ //
+
+ Entry &= 0x00000fff;
+
+ if (Entry == 0x000) { return FatClusterAvailable; }
+ else if ((Entry >= 0xff0) && (Entry <= 0xff6)) { return FatClusterReserved; }
+ else if (Entry == 0xff7) { return FatClusterBad; }
+ else if ((Entry >= 0xff8) && (Entry <= 0xfff)) { return FatClusterLast; }
+ else { return FatClusterNext; }
+
+ } else {
+
+ //
+ // For 16 bit fat check for one of the cluster types, but first
+ // make sure we are only looking at 16 bits of the entry
+ //
+
+ Entry &= 0x0000ffff;
+
+ if (Entry == 0x0000) { return FatClusterAvailable; }
+ else if ((Entry >= 0xfff0) && (Entry <= 0xfff6)) { return FatClusterReserved; }
+ else if (Entry == 0xfff7) { return FatClusterBad; }
+ else if ((Entry >= 0xfff8) && (Entry <= 0xffff)) { return FatClusterLast; }
+ else { return FatClusterNext; }
+ }
+}
+
+
+//
+// Internal support routine
+//
+
+ARC_STATUS
+FatLookupFatEntry (
+ IN PFAT_STRUCTURE_CONTEXT FatStructureContext,
+ IN ULONG DeviceId,
+ IN FAT_ENTRY FatIndex,
+ OUT PFAT_ENTRY FatEntry,
+ IN BOOLEAN IsDoubleSpace
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the value stored within the fat table and the specified
+ fat index. It is semantically equivalent to doing
+
+ x = Fat[FatIndex]
+
+Arguments:
+
+ FatStrutureContext - Supplies the volume struture being used
+
+ DeviceId - Supplies the device being used
+
+ FatIndex - Supplies the index being looked up.
+
+ FatEntry - Receives the value stored at the specified fat index
+
+ IsDoubleSpace - Indicates if the search is being done on a double space volume
+
+Return Value:
+
+ ESUCCESS is returned if the operation is successful. Otherwise,
+ an unsuccessful status is returned that describes the reason for failure.
+
+--*/
+
+{
+ BOOLEAN TwelveBitFat;
+ VBO Vbo;
+
+ //****if (IsDoubleSpace) { DbgPrint("FatLookupFatEntry(%0x,%0x,%0x,%0x,%0x)\n",FatStructureContext, DeviceId, FatIndex, FatEntry, IsDoubleSpace); }
+
+ //
+ // Calculate the Vbo of the word in the fat we need and
+ // also figure out if this is a 12 or 16 bit fat
+ //
+
+ if (FatIndexBitSize( &FatStructureContext->Bpb ) == 12) {
+
+ TwelveBitFat = TRUE;
+ Vbo = (FatIndex * 3) / 2;
+
+ } else {
+
+ TwelveBitFat = FALSE;
+ Vbo = FatIndex * 2;
+ }
+
+ //
+ // Check if the Vbo we need is already in the cached fat
+ //
+
+ if ((FatStructureContext->CachedFat == NULL) ||
+ (Vbo < FatStructureContext->CachedFatVbo) ||
+ ((Vbo+1) > (FatStructureContext->CachedFatVbo + FAT_CACHE_SIZE))) {
+
+ //
+ // Set the aligned cached fat buffer in the structure context
+ //
+
+ FatStructureContext->CachedFat = ALIGN_BUFFER( &FatStructureContext->CachedFatBuffer[0] );
+
+ //
+ // As a safety net we'll flush any dirty fats that we might have cached before
+ // we turn the window
+ //
+
+ if (!IsDoubleSpace && FatStructureContext->CachedFatDirty) {
+
+ FlushFatEntries( FatStructureContext, DeviceId );
+ }
+
+ //
+ // Now set the new cached Vbo to be the Vbo of the cache sized section that
+ // we're trying to map. Each time we read in the cache we only read in
+ // cache sized and cached aligned pieces of the fat. So first compute an
+ // aligned cached fat vbo and then do the read.
+ //
+
+ FatStructureContext->CachedFatVbo = (Vbo / FAT_CACHE_SIZE) * FAT_CACHE_SIZE;
+
+ DiskRead( DeviceId,
+ FatStructureContext->CachedFatVbo + FatFirstFatAreaLbo(&FatStructureContext->Bpb),
+ FAT_CACHE_SIZE,
+ FatStructureContext->CachedFat,
+ IsDoubleSpace );
+ }
+
+ //
+ // At this point the cached fat contains the vbo we're after so simply
+ // extract the word
+ //
+
+ CopyUchar2( FatEntry,
+ &FatStructureContext->CachedFat[Vbo - FatStructureContext->CachedFatVbo] );
+
+ //
+ // Now if this is a 12 bit fat then check if the index is odd or even
+ // If it is odd then we need to shift it over 4 bits, and in all
+ // cases we need to mask out the high 4 bits.
+ //
+
+ if (TwelveBitFat) {
+
+ if ((FatIndex % 2) == 1) { *FatEntry >>= 4; }
+
+ *FatEntry &= 0x0fff;
+ }
+
+ return ESUCCESS;
+}
+
+
+//
+// Internal support routine
+//
+
+ARC_STATUS
+FatSetFatEntry(
+ IN PFAT_STRUCTURE_CONTEXT FatStructureContext,
+ IN ULONG DeviceId,
+ IN FAT_ENTRY FatIndex,
+ IN FAT_ENTRY FatEntry
+ )
+
+/*++
+
+Routine Description:
+
+ This procedure sets the data within the fat table at the specified index to
+ to the specified value. It is semantically equivalent to doing
+
+ Fat[FatIndex] = FatEntry;
+
+Arguments:
+
+ FatStructureContext - Supplies the structure context for the operation
+
+ DeviceId - Supplies the device for the operation
+
+ FatIndex - Supplies the index within the fat table to set
+
+ FatEntry - Supplies the value to store within the fat table
+
+Return Value:
+
+ ESUCCESS is returned if the operation is successful. Otherwise,
+ an unsuccessful status is returned that describes the reason for failure.
+
+--*/
+
+{
+ BOOLEAN TwelveBitFat;
+ VBO Vbo;
+
+ //
+ // Calculate the Vbo of the word in the fat we are modifying and
+ // also figure out if this is a 12 or 16 bit fat
+ //
+
+ if (FatIndexBitSize( &FatStructureContext->Bpb ) == 12) {
+
+ TwelveBitFat = TRUE;
+ Vbo = (FatIndex * 3) / 2;
+
+ } else {
+
+ TwelveBitFat = FALSE;
+ Vbo = FatIndex * 2;
+ }
+
+ //
+ // Check if the Vbo we need is already in the cached fat
+ //
+
+ if ((FatStructureContext->CachedFat == NULL) ||
+ (Vbo < FatStructureContext->CachedFatVbo) ||
+ ((Vbo+1) > (FatStructureContext->CachedFatVbo + FAT_CACHE_SIZE))) {
+
+ //
+ // Set the aligned cached fat buffer in the structure context
+ //
+
+ FatStructureContext->CachedFat = ALIGN_BUFFER( &FatStructureContext->CachedFatBuffer[0] );
+
+ //
+ // As a safety net we'll flush any dirty fats that we might have cached before
+ // we turn the window
+ //
+
+ if (FatStructureContext->CachedFatDirty) {
+
+ FlushFatEntries( FatStructureContext, DeviceId );
+ }
+
+ //
+ // Now set the new cached Vbo to be the Vbo of the cache sized section that
+ // we're trying to map. Each time we read in the cache we only read in
+ // cache sized and cached aligned pieces of the fat. So first compute an
+ // aligned cached fat vbo and then do the read.
+ //
+
+ FatStructureContext->CachedFatVbo = (Vbo / FAT_CACHE_SIZE) * FAT_CACHE_SIZE;
+
+ DiskRead( DeviceId,
+ FatStructureContext->CachedFatVbo + FatFirstFatAreaLbo(&FatStructureContext->Bpb),
+ FAT_CACHE_SIZE,
+ FatStructureContext->CachedFat,
+ FALSE );
+ }
+
+ //
+ // At this point the cached fat contains the vbo we're after. For a 16 bit
+ // fat we simply put in the fat entry. For the 12 bit fat we first need to extract
+ // the word containing the entry, modify the word, and then put it back.
+ //
+
+ if (TwelveBitFat) {
+
+ FAT_ENTRY Temp;
+
+ CopyUchar2( &Temp,
+ &FatStructureContext->CachedFat[Vbo - FatStructureContext->CachedFatVbo] );
+
+ if ((FatIndex % 2) == 0) {
+
+ FatEntry = (FAT_ENTRY)((Temp & 0xf000) | (FatEntry & 0x0fff));
+
+ } else {
+
+ FatEntry = (FAT_ENTRY)((Temp & 0x000f) | ((FatEntry << 4) & 0xfff0));
+ }
+ }
+
+ CopyUchar2( &FatStructureContext->CachedFat[Vbo - FatStructureContext->CachedFatVbo],
+ &FatEntry );
+
+ //
+ // Now that we're done we can set the fat dirty
+ //
+
+ FatStructureContext->CachedFatDirty = TRUE;
+
+ return ESUCCESS;
+}
+
+
+//
+// Internal support routine
+//
+
+ARC_STATUS
+FatFlushFatEntries (
+ IN PFAT_STRUCTURE_CONTEXT FatStructureContext,
+ IN ULONG DeviceId
+ )
+
+/*++
+
+Routine Description:
+
+ This routine flushes out any dirty cached fat entries to the volume.
+
+Arguments:
+
+ FatStructureContext - Supplies the structure context for the operation
+
+ DeviceId - Supplies the Device for the operation
+
+Return Value:
+
+ ESUCCESS is returned if the operation is successful. Otherwise,
+ an unsuccessful status is returned that describes the reason for failure.
+
+--*/
+
+{
+ ULONG BytesPerFat;
+ ULONG AmountToWrite;
+ ULONG i;
+
+ //
+ // Compute the actual number of bytes that we need to write. We do this
+ // because we don't want to overwrite beyond the fat.
+ //
+
+ BytesPerFat = FatBytesPerFat(&FatStructureContext->Bpb);
+
+ if (FatStructureContext->CachedFatVbo + FAT_CACHE_SIZE <= BytesPerFat) {
+
+ AmountToWrite = FAT_CACHE_SIZE;
+
+ } else {
+
+ AmountToWrite = BytesPerFat - FatStructureContext->CachedFatVbo;
+ }
+
+ //
+ // For each fat table on the volume we will calculate the lbo for the operation
+ // and then write out the cached fat
+ //
+
+ for (i = 0; i < FatStructureContext->Bpb.Fats; i += 1) {
+
+ ULONG Lbo;
+
+ Lbo = FatStructureContext->CachedFatVbo +
+ FatFirstFatAreaLbo(&FatStructureContext->Bpb) +
+ (i * BytesPerFat);
+
+ DiskWrite( DeviceId,
+ Lbo,
+ AmountToWrite,
+ FatStructureContext->CachedFat );
+ }
+
+ //
+ // we are all done so now mark the fat clean
+ //
+
+ FatStructureContext->CachedFatDirty = FALSE;
+
+ return ESUCCESS;
+}
+
+
+//
+// Internal support routine
+//
+
+LBO
+FatIndexToLbo (
+ IN PFAT_STRUCTURE_CONTEXT FatStructureContext,
+ IN FAT_ENTRY FatIndex
+ )
+
+/*++
+
+Routine Description:
+
+ This procedure translates a fat index into its corresponding lbo.
+
+Arguments:
+
+ FatStructureContext - Supplies the volume structure for the operation
+
+ Entry - Supplies the fat entry to examine.
+
+Return Value:
+
+ The LBO for the input fat index is returned
+
+--*/
+
+{
+ //
+ // The formula for translating an index into an lbo is to take the index subtract
+ // 2 (because index values 0 and 1 are reserved) multiply that by the bytes per
+ // cluster and add the results to the first file area lbo.
+ //
+
+ return ((FatIndex-2) * FatBytesPerCluster(&FatStructureContext->Bpb))
+ + FatFileAreaLbo(&FatStructureContext->Bpb);
+}
+
+
+//
+// Internal support routine
+//
+
+ARC_STATUS
+FatSearchForDirent (
+ IN PFAT_STRUCTURE_CONTEXT FatStructureContext,
+ IN ULONG DeviceId,
+ IN FAT_ENTRY DirectoriesStartingIndex,
+ IN PFAT8DOT3 FileName,
+ OUT PDIRENT Dirent,
+ OUT PLBO Lbo,
+ IN BOOLEAN IsDoubleSpace
+ )
+
+/*++
+
+Routine Description:
+
+ The procedure searches the indicated directory for a dirent that matches
+ the input file name.
+
+Arguments:
+
+ FatStructureContext - Supplies the structure context for the operation
+
+ DeviceId - Supplies the Device id for the operation
+
+ DirectoriesStartingIndex - Supplies the fat index of the directory we are
+ to search. A value of zero indicates that we are searching the root directory
+
+ FileName - Supplies the file name to look for. The name must have already been
+ biased by the 0xe5 transmogrification
+
+ Dirent - The caller supplies the memory for a dirent and this procedure will
+ fill in the dirent if one is located
+
+ Lbo - Receives the Lbo of the dirent if one is located
+
+ IsDoubleSpace - Indicates if the search is being done on a double space volume
+
+Return Value:
+
+ ESUCCESS is returned if the operation is successful. Otherwise,
+ an unsuccessful status is returned that describes the reason for failure.
+
+--*/
+
+{
+ PDIRENT DirentBuffer;
+ UCHAR Buffer[ 16 * sizeof(DIRENT) + 256 ];
+
+ ULONG i;
+ ULONG j;
+
+ ULONG BytesPerCluster;
+ FAT_ENTRY FatEntry;
+ CLUSTER_TYPE ClusterType;
+
+ DirentBuffer = (PDIRENT)ALIGN_BUFFER( &Buffer[0] );
+
+ //****if (IsDoubleSpace) { (*FileName)[11] = 0; DbgPrint("FatSearchForDirent(%0x,%0x,%0x,\"%11s\",%0x,%0x,%0x)\n", FatStructureContext, DeviceId, DirectoriesStartingIndex, FileName, Dirent, Lbo, IsDoubleSpace); }
+
+ //
+ // Check if this is the root directory that is being searched
+ //
+
+ if (DirectoriesStartingIndex == FAT_CLUSTER_AVAILABLE) {
+
+ VBO Vbo;
+
+ ULONG RootLbo = FatRootDirectoryLbo(&FatStructureContext->Bpb);
+ ULONG RootSize = FatRootDirectorySize(&FatStructureContext->Bpb);
+
+ //
+ // For the root directory we'll zoom down the dirents until we find
+ // a match, or run out of dirents or hit the never used dirent.
+ // The outer loop reads in 512 bytes of the directory at a time into
+ // dirent buffer.
+ //
+
+ for (Vbo = 0; Vbo < RootSize; Vbo += 16 * sizeof(DIRENT)) {
+
+ *Lbo = Vbo + RootLbo;
+
+ DiskRead( DeviceId, *Lbo, 16 * sizeof(DIRENT), DirentBuffer, IsDoubleSpace );
+
+ //
+ // The inner loop cycles through the 16 dirents that we've just read in
+ //
+
+ for (i = 0; i < 16; i += 1) {
+
+ //
+ // Check if we've found a non label match for file name, and if so
+ // then copy the buffer into the dirent and set the real lbo
+ // of the dirent and return
+ //
+
+ if (!FlagOn(DirentBuffer[i].Attributes, FAT_DIRENT_ATTR_VOLUME_ID ) &&
+ AreNamesEqual(&DirentBuffer[i].FileName, FileName)) {
+
+ for (j = 0; j < sizeof(DIRENT); j += 1) {
+
+ ((PCHAR)Dirent)[j] = ((PCHAR)DirentBuffer)[(i * sizeof(DIRENT)) + j];
+ }
+
+ *Lbo = Vbo + RootLbo + (i * sizeof(DIRENT));
+
+ return ESUCCESS;
+ }
+
+ if (DirentBuffer[i].FileName[0] == FAT_DIRENT_NEVER_USED) {
+
+ return ENOENT;
+ }
+ }
+ }
+
+ return ENOENT;
+ }
+
+ //
+ // If we get here we need to search a non-root directory. The alrogithm
+ // for doing the search is that for each cluster we read in each dirent
+ // until we find a match, or run out of clusters, or hit the never used
+ // dirent. First set some local variables and then get the cluster type
+ // of the first cluster
+ //
+
+ BytesPerCluster = FatBytesPerCluster( &FatStructureContext->Bpb );
+ FatEntry = DirectoriesStartingIndex;
+ ClusterType = FatInterpretClusterType( FatStructureContext, FatEntry );
+
+ //
+ // Now loop through each cluster, and compute the starting Lbo for each cluster
+ // that we encounter
+ //
+
+ while (ClusterType == FatClusterNext) {
+
+ LBO ClusterLbo;
+ ULONG Offset;
+
+ ClusterLbo = FatIndexToLbo( FatStructureContext, FatEntry );
+
+ //
+ // Now for each dirent in the cluster compute the lbo, read in the dirent
+ // and check for a match, the outer loop reads in 512 bytes of dirents at
+ // a time.
+ //
+
+ for (Offset = 0; Offset < BytesPerCluster; Offset += 16 * sizeof(DIRENT)) {
+
+ *Lbo = Offset + ClusterLbo;
+
+ DiskRead( DeviceId, *Lbo, 16 * sizeof(DIRENT), DirentBuffer, IsDoubleSpace );
+
+ //
+ // The inner loop cycles through the 16 dirents that we've just read in
+ //
+
+ for (i = 0; i < 16; i += 1) {
+
+ //
+ // Check if we've found a for file name, and if so
+ // then copy the buffer into the dirent and set the real lbo
+ // of the dirent and return
+ //
+
+ if (AreNamesEqual(&DirentBuffer[i].FileName, FileName)) {
+
+ for (j = 0; j < sizeof(DIRENT); j += 1) {
+
+ ((PCHAR)Dirent)[j] = ((PCHAR)DirentBuffer)[(i * sizeof(DIRENT)) + j];
+ }
+
+ *Lbo = Offset + ClusterLbo + (i * sizeof(DIRENT));
+
+ return ESUCCESS;
+ }
+
+ if (DirentBuffer[i].FileName[0] == FAT_DIRENT_NEVER_USED) {
+
+ return ENOENT;
+ }
+ }
+ }
+
+ //
+ // Now that we've exhausted the current cluster we need to read
+ // in the next cluster. So locate the next fat entry in the chain
+ // and go back to the top of the while loop.
+ //
+
+ LookupFatEntry( FatStructureContext, DeviceId, FatEntry, &FatEntry, IsDoubleSpace );
+
+ ClusterType = FatInterpretClusterType(FatStructureContext, FatEntry);
+ }
+
+ return ENOENT;
+}
+
+
+//
+// Internal support routine
+//
+
+ARC_STATUS
+FatCreateDirent (
+ IN PFAT_STRUCTURE_CONTEXT FatStructureContext,
+ IN ULONG DeviceId,
+ IN FAT_ENTRY DirectoriesStartingIndex,
+ IN PDIRENT Dirent,
+ OUT PLBO Lbo
+ )
+
+/*++
+
+Routine Description:
+
+ This procedure allocates and write out a new dirent for a data file in the
+ specified directory. It assumes that the file name does not already exist.
+
+Arguments:
+
+ FatStructureContext - Supplies the structure context for the operation
+
+ DeviceId - Supplies the device id for the operation
+
+ DirectoriesStartingIndex - Supplies the fat index of the directory we are
+ to use. A value of zero indicates that we are using the root directory
+
+ Dirent - Supplies a copy of the dirent to put out on the disk
+
+ Lbo - Recieves the Lbo of where the dirent is placed
+
+Return Value:
+
+ ESUCCESS is returned if the operation is successful. Otherwise,
+ an unsuccessful status is returned that describes the reason for failure.
+
+--*/
+
+{
+ DIRENT TemporaryDirent;
+
+ ULONG BytesPerCluster;
+ FAT_ENTRY FatEntry;
+ FAT_ENTRY PreviousEntry;
+
+ //
+ // Check if this is the root directory that is being used
+ //
+
+ if (DirectoriesStartingIndex == FAT_CLUSTER_AVAILABLE) {
+
+ VBO Vbo;
+
+ ULONG RootLbo = FatRootDirectoryLbo(&FatStructureContext->Bpb);
+ ULONG RootSize = FatRootDirectorySize(&FatStructureContext->Bpb);
+
+ //
+ // For the root directory we'll zoom down the dirents until we find
+ // a the never used (or deleted) dirent, if we never find one then the
+ // directory is full.
+ //
+
+ for (Vbo = 0; Vbo < RootSize; Vbo += sizeof(DIRENT)) {
+
+ *Lbo = Vbo + RootLbo;
+
+ DiskRead( DeviceId, *Lbo, sizeof(DIRENT), &TemporaryDirent, FALSE );
+
+ if ((TemporaryDirent.FileName[0] == FAT_DIRENT_DELETED) ||
+ (TemporaryDirent.FileName[0] == FAT_DIRENT_NEVER_USED)) {
+
+ //
+ // This dirent is free so write out the dirent, and we're done.
+ //
+
+ DiskWrite( DeviceId, *Lbo, sizeof(DIRENT), Dirent );
+
+ return ESUCCESS;
+ }
+ }
+
+ return ENOSPC;
+ }
+
+ //
+ // If we get here we need to use a non-root directory. The alrogithm
+ // for doing the work is that for each cluster we read in each dirent
+ // until we hit a never used dirent or run out of clusters. First set
+ // some local variables and then get the cluster type of the first
+ // cluster
+ //
+
+ BytesPerCluster = FatBytesPerCluster( &FatStructureContext->Bpb );
+ FatEntry = DirectoriesStartingIndex;
+
+ //
+ // Now loop through each cluster, and compute the starting Lbo for each cluster
+ // that we encounter
+ //
+
+ while (TRUE) {
+
+ LBO ClusterLbo;
+ ULONG Offset;
+
+ ClusterLbo = FatIndexToLbo( FatStructureContext, FatEntry );
+
+ //
+ // Now for each dirent in the cluster compute the lbo, read in the dirent
+ // and check if it is available.
+ //
+
+ for (Offset = 0; Offset < BytesPerCluster; Offset += sizeof(DIRENT)) {
+
+ *Lbo = Offset + ClusterLbo;
+
+ DiskRead( DeviceId, *Lbo, sizeof(DIRENT), &TemporaryDirent, FALSE );
+
+ if ((TemporaryDirent.FileName[0] == FAT_DIRENT_DELETED) ||
+ (TemporaryDirent.FileName[0] == FAT_DIRENT_NEVER_USED)) {
+
+ //
+ // This dirent is free so write out the dirent, and we're done.
+ //
+
+ DiskWrite( DeviceId, *Lbo, sizeof(DIRENT), Dirent );
+
+ return ESUCCESS;
+ }
+ }
+
+ //
+ // Now that we've exhausted the current cluster we need to read
+ // in the next cluster. So locate the next fat entry in the chain.
+ // Set previous entry to be the saved entry just in case we run off
+ // the chain and need to allocate another cluster.
+ //
+
+ PreviousEntry = FatEntry;
+
+ LookupFatEntry( FatStructureContext, DeviceId, FatEntry, &FatEntry, FALSE );
+
+ //
+ // If there isn't another cluster in the chain then we need to allocate a
+ // new cluster, and set previous entry to point to it.
+ //
+
+ if (FatInterpretClusterType(FatStructureContext, FatEntry) != FatClusterNext) {
+
+ AllocateClusters( FatStructureContext, DeviceId, 1, PreviousEntry, &FatEntry );
+
+ SetFatEntry( FatStructureContext, DeviceId, PreviousEntry, FatEntry );
+ }
+ }
+
+ return ENOSPC;
+}
+
+
+//
+// Internal support routine
+//
+
+VOID
+FatSetDirent (
+ IN PFAT8DOT3 FileName,
+ IN OUT PDIRENT Dirent,
+ IN UCHAR Attributes
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets up the dirent
+
+Arguments:
+
+ FileName - Supplies the name to store in the dirent
+
+ Dirent - Receives the current date and time
+
+ Attributes - Supplies the attributes to initialize the dirent with
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PTIME_FIELDS Time;
+ ULONG i;
+
+ for (i = 0; i < sizeof(FAT8DOT3); i+= 1) {
+
+ Dirent->FileName[i] = (*FileName)[i];
+ }
+
+ Dirent->Attributes = (UCHAR)(Attributes | FAT_DIRENT_ATTR_ARCHIVE);
+
+ Time = ArcGetTime();
+
+ Dirent->LastWriteTime.Time.DoubleSeconds = (USHORT)(Time->Second/2);
+ Dirent->LastWriteTime.Time.Minute = Time->Minute;
+ Dirent->LastWriteTime.Time.Hour = Time->Hour;
+
+ Dirent->LastWriteTime.Date.Day = Time->Day;
+ Dirent->LastWriteTime.Date.Month = Time->Month;
+ Dirent->LastWriteTime.Date.Year = (USHORT)(Time->Year - 1980);
+
+ return;
+}
+
+
+//
+// Internal support routine
+//
+
+ARC_STATUS
+FatLoadMcb (
+ IN ULONG FileId,
+ IN VBO StartingVbo,
+ IN BOOLEAN IsDoubleSpace
+ )
+
+/*++
+
+Routine Description:
+
+ This routine loads into the cached mcb table the the retrival information for
+ the starting vbo.
+
+Arguments:
+
+ FileId - Supplies the FileId for the operation
+
+ StartingVbo - Supplies the starting vbo to use when loading the mcb
+
+ IsDoubleSpace - Indicates if the operation is being done on a double space volume
+
+Return Value:
+
+ ESUCCESS is returned if the operation is successful. Otherwise,
+ an unsuccessful status is returned that describes the reason for failure.
+
+--*/
+
+{
+ PBL_FILE_TABLE FileTableEntry;
+ PFAT_STRUCTURE_CONTEXT FatStructureContext;
+ PFAT_MCB Mcb;
+ ULONG DeviceId;
+ ULONG BytesPerCluster;
+
+ FAT_ENTRY FatEntry;
+ CLUSTER_TYPE ClusterType;
+ VBO Vbo;
+
+ //****if (IsDoubleSpace) { DbgPrint("FatLoadMcb(%0x,%0x,%0x)\n", FileId, StartingVbo, IsDoubleSpace); }
+
+ //
+ // Preload some of the local variables
+ //
+
+ FileTableEntry = &BlFileTable[FileId];
+ FatStructureContext = (PFAT_STRUCTURE_CONTEXT)FileTableEntry->StructureContext;
+ Mcb = &FatStructureContext->Mcb;
+ DeviceId = FileTableEntry->DeviceId;
+ BytesPerCluster = FatBytesPerCluster(&FatStructureContext->Bpb);
+
+ if (IsDoubleSpace) { DeviceId = FileId; }
+
+ //
+ // Set the file id in the structure context, and also set the mcb to be initially
+ // empty
+ //
+
+ FatStructureContext->FileId = FileId;
+ Mcb->InUse = 0;
+ Mcb->Vbo[0] = 0;
+
+ //
+ // Check if this is the root directory. If it is then we build the single
+ // run mcb entry for the root directory.
+ //
+
+ if (FileTableEntry->u.FatFileContext.DirentLbo == 0) {
+
+ Mcb->InUse = 1;
+ Mcb->Lbo[0] = FatRootDirectoryLbo(&FatStructureContext->Bpb);
+ Mcb->Vbo[1] = FatRootDirectorySize(&FatStructureContext->Bpb);
+
+ return ESUCCESS;
+ }
+
+ //
+ // For all other files/directories we need to do some work. First get the fat
+ // entry and cluster type of the fat entry stored in the dirent
+ //
+
+ FatEntry = FileTableEntry->u.FatFileContext.Dirent.FirstClusterOfFile;
+ ClusterType = FatInterpretClusterType(FatStructureContext, FatEntry);
+
+ //
+ // Scan through the fat until we reach the vbo we're after and then build the
+ // mcb for the file
+ //
+
+ for (Vbo = BytesPerCluster; Vbo < StartingVbo; Vbo += BytesPerCluster) {
+
+ //
+ // Check if the file does not have any allocation beyond this point in which
+ // case the mcb we return is empty
+ //
+
+ if (ClusterType != FatClusterNext) {
+
+ return ESUCCESS;
+ }
+
+ LookupFatEntry( FatStructureContext, DeviceId, FatEntry, &FatEntry, IsDoubleSpace );
+
+ ClusterType = FatInterpretClusterType(FatStructureContext, FatEntry);
+ }
+
+ //
+ // We need to check again if the file does not have any allocation beyond this
+ // point in which case the mcb we return is empty
+ //
+
+ if (ClusterType != FatClusterNext) {
+
+ return ESUCCESS;
+ }
+
+ //
+ // At this point FatEntry denotes another cluster, and it happens to be the
+ // cluster we want to start loading into the mcb. So set up the first run in
+ // the mcb to be this cluster, with a size of a single cluster.
+ //
+
+ Mcb->InUse = 1;
+ Mcb->Vbo[0] = Vbo - BytesPerCluster;
+ Mcb->Lbo[0] = FatIndexToLbo( FatStructureContext, FatEntry );
+ Mcb->Vbo[1] = Vbo;
+
+ //
+ // Now we'll scan through the fat chain until we either exhaust the fat chain
+ // or we fill up the mcb
+ //
+
+ while (TRUE) {
+
+ LBO Lbo;
+
+ //
+ // Get the next fat entry and interpret its cluster type
+ //
+
+ LookupFatEntry( FatStructureContext, DeviceId, FatEntry, &FatEntry, IsDoubleSpace );
+
+ ClusterType = FatInterpretClusterType(FatStructureContext, FatEntry);
+
+ if (ClusterType != FatClusterNext) {
+
+ return ESUCCESS;
+ }
+
+ //
+ // Now calculate the lbo for this cluster and determine if it
+ // is a continuation of the previous run or a start of a new run
+ //
+
+ Lbo = FatIndexToLbo(FatStructureContext, FatEntry);
+
+ //
+ // It is a continuation if the lbo of the last run plus the current
+ // size of the run is equal to the lbo for the next cluster. If it
+ // is a contination then we only need to add a cluster amount to the
+ // last vbo to increase the run size. If it is a new run then
+ // we need to check if the run will fit, and if so then add in the
+ // new run.
+ //
+
+ if ((Mcb->Lbo[Mcb->InUse-1] + (Mcb->Vbo[Mcb->InUse] - Mcb->Vbo[Mcb->InUse-1])) == Lbo) {
+
+ Mcb->Vbo[Mcb->InUse] += BytesPerCluster;
+
+ } else {
+
+ if ((Mcb->InUse + 1) >= FAT_MAXIMUM_MCB) {
+
+ return ESUCCESS;
+ }
+
+ Mcb->InUse += 1;
+ Mcb->Lbo[Mcb->InUse-1] = Lbo;
+ Mcb->Vbo[Mcb->InUse] = Mcb->Vbo[Mcb->InUse-1] + BytesPerCluster;
+ }
+ }
+
+ return ESUCCESS;
+}
+
+
+//
+// Internal support routine
+//
+
+ARC_STATUS
+FatVboToLbo (
+ IN ULONG FileId,
+ IN VBO Vbo,
+ OUT PLBO Lbo,
+ OUT PULONG ByteCount,
+ IN BOOLEAN IsDoubleSpace
+ )
+
+/*++
+
+Routine Description:
+
+ This routine computes the run denoted by the input vbo to into its
+ corresponding lbo and also returns the number of bytes remaining in
+ the run.
+
+Arguments:
+
+ Vbo - Supplies the Vbo to match
+
+ Lbo - Recieves the corresponding Lbo
+
+ ByteCount - Receives the number of bytes remaining in the run
+
+ IsDoubleSpace - Indicates if the operation is being done on a double space volume
+
+Return Value:
+
+ ESUCCESS is returned if the operation is successful. Otherwise,
+ an unsuccessful status is returned that describes the reason for failure.
+
+--*/
+
+{
+ PFAT_STRUCTURE_CONTEXT FatStructureContext;
+ PFAT_MCB Mcb;
+ ULONG i;
+
+ //****if (IsDoubleSpace) { DbgPrint("FatVboToLbo(%0x,%0x,%0x,%0x,%0x)\n", FileId, Vbo, Lbo, ByteCount, IsDoubleSpace); }
+
+ FatStructureContext = (PFAT_STRUCTURE_CONTEXT)BlFileTable[FileId].StructureContext;
+ Mcb = &FatStructureContext->Mcb;
+
+ //
+ // Check if the mcb is for the correct file id and has the range we're asking for.
+ // If it doesn't then call load mcb to load in the right range.
+ //
+
+ if ((FileId != FatStructureContext->FileId) ||
+ (Vbo < Mcb->Vbo[0]) || (Vbo >= Mcb->Vbo[Mcb->InUse])) {
+
+ LoadMcb(FileId, Vbo, IsDoubleSpace);
+ }
+
+ //
+ // Now search for the slot where the Vbo fits in the mcb. Note that
+ // we could also do a binary search here but because the run count
+ // is probably small the extra overhead of a binary search doesn't
+ // buy us anything
+ //
+
+ for (i = 0; i < Mcb->InUse; i += 1) {
+
+ //
+ // We found our slot if the vbo we're after is less then the
+ // next mcb's vbo
+ //
+
+ if (Vbo < Mcb->Vbo[i+1]) {
+
+ //
+ // Compute the corresponding lbo which is the stored lbo plus
+ // the difference between the stored vbo and the vbo we're
+ // looking up. Also compute the byte count which is the
+ // difference between the current vbo we're looking up and
+ // the vbo for the next run.
+ //
+
+ *Lbo = Mcb->Lbo[i] + (Vbo - Mcb->Vbo[i]);
+
+ *ByteCount = Mcb->Vbo[i+1] - Vbo;
+
+ //
+ // and return success to our caller
+ //
+
+ return ESUCCESS;
+ }
+ }
+
+ //
+ // If we really reach here we have an error, most likely because the file is
+ // not large enough for the requested Vbo.
+ //
+
+ return EINVAL;
+}
+
+
+//
+// Internal support routine
+//
+
+ARC_STATUS
+FatIncreaseFileAllocation (
+ IN ULONG FileId,
+ IN ULONG ByteSize
+ )
+
+/*++
+
+Routine Description:
+
+ This procedure increases the file allocation to be at minimum the indicated
+ size.
+
+Arguments:
+
+ FileId - Supplies the file id being processed
+
+ ByteSize - Supplies the minimum byte size for file allocation
+
+Return Value:
+
+ ESUCCESS is returned if the operation is successful. Otherwise,
+ an unsuccessful status is returned that describes the reason for failure.
+
+--*/
+
+{
+ PBL_FILE_TABLE FileTableEntry;
+ PFAT_STRUCTURE_CONTEXT FatStructureContext;
+ ULONG DeviceId;
+ ULONG BytesPerCluster;
+
+ ULONG NumberOfClustersNeeded;
+ FAT_ENTRY FatEntry;
+ CLUSTER_TYPE ClusterType;
+ FAT_ENTRY PreviousEntry;
+ ULONG i;
+
+ //
+ // Preload some of the local variables
+ //
+
+ FileTableEntry = &BlFileTable[FileId];
+ FatStructureContext = (PFAT_STRUCTURE_CONTEXT)FileTableEntry->StructureContext;
+ DeviceId = FileTableEntry->DeviceId;
+ BytesPerCluster = FatBytesPerCluster(&FatStructureContext->Bpb);
+
+ //
+ // Check if this is the root directory. If it is then check if the allocation
+ // increase is already accommodated in the volume
+ //
+
+ if (FileTableEntry->u.FatFileContext.DirentLbo == 0) {
+
+ if (FatRootDirectorySize(&FatStructureContext->Bpb) >= ByteSize) {
+
+ return ESUCCESS;
+
+ } else {
+
+ return ENOSPC;
+ }
+ }
+
+ //
+ // Compute the actual number of clusters needed to satisfy the request
+ // Also get the first fat entry and its cluster type from the dirent.
+ //
+
+ NumberOfClustersNeeded = (ByteSize + BytesPerCluster - 1) / BytesPerCluster;
+
+ FatEntry = FileTableEntry->u.FatFileContext.Dirent.FirstClusterOfFile;
+ ClusterType = FatInterpretClusterType(FatStructureContext, FatEntry);
+
+ //
+ // Previous Entry is as a hint to allocate new space and to show us where
+ // the end of the current fat chain is located
+ //
+
+ PreviousEntry = 2;
+
+ //
+ // We loop for the number of clusters we need trying to go down the fat chain.
+ // When we exit i is either number of clusters in the file (if less then
+ // the number of clusters we need) or it is set equal to the number of clusters
+ // we need
+ //
+
+ for (i = 0; i < NumberOfClustersNeeded; i += 1) {
+
+ if (ClusterType != FatClusterNext) { break; }
+
+ PreviousEntry = FatEntry;
+
+ LookupFatEntry( FatStructureContext, DeviceId, PreviousEntry, &FatEntry, FALSE );
+
+ ClusterType = FatInterpretClusterType(FatStructureContext, FatEntry);
+ }
+
+ if (i >= NumberOfClustersNeeded) {
+
+ return ESUCCESS;
+ }
+
+ //
+ // At this point previous entry points to the last entry and i contains the
+ // number of clusters in the file. We now need to build up the allocation
+ //
+
+ AllocateClusters( FatStructureContext,
+ DeviceId,
+ NumberOfClustersNeeded - i,
+ PreviousEntry,
+ &FatEntry );
+
+ //
+ // We have our additional allocation, so now figure out if we need to chain off of
+ // the dirent or it we already have a few clusters in the chain and we
+ // need to munge the fat.
+ //
+
+ if (FileTableEntry->u.FatFileContext.Dirent.FirstClusterOfFile == FAT_CLUSTER_AVAILABLE) {
+
+ FileTableEntry->u.FatFileContext.Dirent.FirstClusterOfFile = FatEntry;
+
+ DiskWrite( DeviceId,
+ FileTableEntry->u.FatFileContext.DirentLbo,
+ sizeof(DIRENT),
+ &FileTableEntry->u.FatFileContext.Dirent );
+
+ } else {
+
+ SetFatEntry( FatStructureContext, DeviceId, PreviousEntry, FatEntry );
+ }
+
+ return ESUCCESS;
+}
+
+
+//
+// Internal support routine
+//
+
+ARC_STATUS
+FatTruncateFileAllocation (
+ IN ULONG FileId,
+ IN ULONG ByteSize
+ )
+
+/*++
+
+Routine Description:
+
+ This procedure decreases the file allocation to be at maximum the indicated
+ size.
+
+Arguments:
+
+ FileId - Supplies the file id being processed
+
+ ByteSize - Supplies the maximum byte size for file allocation
+
+Return Value:
+
+ ESUCCESS is returned if the operation is successful. Otherwise,
+ an unsuccessful status is returned that describes the reason for failure.
+
+--*/
+
+{
+ PBL_FILE_TABLE FileTableEntry;
+ PFAT_STRUCTURE_CONTEXT FatStructureContext;
+ ULONG DeviceId;
+ ULONG BytesPerCluster;
+
+ ULONG NumberOfClustersNeeded;
+ FAT_ENTRY FatEntry;
+ CLUSTER_TYPE ClusterType;
+ FAT_ENTRY CurrentIndex;
+ ULONG i;
+
+ //
+ // Preload some of the local variables
+ //
+
+ FileTableEntry = &BlFileTable[FileId];
+ FatStructureContext = (PFAT_STRUCTURE_CONTEXT)FileTableEntry->StructureContext;
+ DeviceId = FileTableEntry->DeviceId;
+ BytesPerCluster = FatBytesPerCluster(&FatStructureContext->Bpb);
+
+ //
+ // Check if this is the root directory. If it is then noop this request
+ //
+
+ if (FileTableEntry->u.FatFileContext.DirentLbo == 0) {
+
+ return ESUCCESS;
+ }
+
+ //
+ // Compute the actual number of clusters needed to satisfy the request
+ // Also get the first fat entry and its cluster type from the dirent
+ //
+
+ NumberOfClustersNeeded = (ByteSize + BytesPerCluster - 1) / BytesPerCluster;
+
+ FatEntry = FileTableEntry->u.FatFileContext.Dirent.FirstClusterOfFile;
+ ClusterType = FatInterpretClusterType(FatStructureContext, FatEntry);
+
+ //
+ // The current index variable is used to indicate where we extracted the current
+ // fat entry value from. It has a value of 0 we got the fat entry from the
+ // dirent.
+ //
+
+ CurrentIndex = FAT_CLUSTER_AVAILABLE;
+
+ //
+ // Now loop through the fat chain for the number of clusters needed.
+ // If we run out of the chain before we run out of clusters needed then the
+ // current allocation is already smaller than necessary.
+ //
+
+ for (i = 0; i < NumberOfClustersNeeded; i += 1) {
+
+ //
+ // If we run out of the chain before we run out of clusters needed then the
+ // current allocation is already smaller than necessary.
+ //
+
+ if (ClusterType != FatClusterNext) { return ESUCCESS; }
+
+ //
+ // Update the current index, and read in a new fat entry and interpret its
+ // type
+ //
+
+ CurrentIndex = FatEntry;
+
+ LookupFatEntry( FatStructureContext, DeviceId, CurrentIndex, &FatEntry, FALSE );
+
+ ClusterType = FatInterpretClusterType(FatStructureContext, FatEntry);
+ }
+
+ //
+ // If we get here then we've found that the current allocation is equal to or
+ // larger than what we want. It is equal if the current cluster type does not
+ // point to another cluster. The first thing we have to do is terminate the
+ // fat chain correctly. If the current index is zero then we zero out the
+ // dirent, otherwise we need to set the value to be last cluster.
+ //
+
+ if (CurrentIndex == FAT_CLUSTER_AVAILABLE) {
+
+ if (FileTableEntry->u.FatFileContext.Dirent.FirstClusterOfFile != FAT_CLUSTER_AVAILABLE) {
+
+ //
+ // By setting the dirent we set in a new date.
+ //
+
+ FatSetDirent( &FileTableEntry->u.FatFileContext.Dirent.FileName,
+ &FileTableEntry->u.FatFileContext.Dirent,
+ 0 );
+
+ FileTableEntry->u.FatFileContext.Dirent.FirstClusterOfFile = FAT_CLUSTER_AVAILABLE;
+ FileTableEntry->u.FatFileContext.Dirent.FileSize = 0;
+
+ DiskWrite( DeviceId,
+ FileTableEntry->u.FatFileContext.DirentLbo,
+ sizeof(DIRENT),
+ &FileTableEntry->u.FatFileContext.Dirent );
+ }
+
+ } else {
+
+ if (ClusterType != FatClusterLast) {
+
+ SetFatEntry( FatStructureContext, DeviceId, CurrentIndex, FAT_CLUSTER_LAST );
+ }
+ }
+
+ //
+ // Now while there are clusters left to deallocate then we need to go down the
+ // chain freeing up the clusters
+ //
+
+ while (ClusterType == FatClusterNext) {
+
+ //
+ // Read in the value at the next fat entry and interpret its cluster type
+ //
+
+ CurrentIndex = FatEntry;
+
+ LookupFatEntry( FatStructureContext, DeviceId, CurrentIndex, &FatEntry, FALSE );
+
+ ClusterType = FatInterpretClusterType(FatStructureContext, FatEntry);
+
+ //
+ // Now deallocate the cluster at the current index
+ //
+
+ SetFatEntry( FatStructureContext, DeviceId, CurrentIndex, FAT_CLUSTER_AVAILABLE );
+ }
+
+ return ESUCCESS;
+}
+
+
+//
+// Internal support routine
+//
+
+ARC_STATUS
+FatAllocateClusters (
+ IN PFAT_STRUCTURE_CONTEXT FatStructureContext,
+ IN ULONG DeviceId,
+ IN ULONG ClusterCount,
+ IN FAT_ENTRY Hint,
+ OUT PFAT_ENTRY AllocatedEntry
+ )
+
+/*++
+
+Routine Description:
+
+ This procedure allocates a new cluster, set its entry to be the last one,
+ and zeros out the cluster.
+
+Arguments:
+
+ FatStructureContext - Supplies the structure context for the operation
+
+ DeviceId - Supplies the device id for the operation
+
+ ClusterCount - Supplies the number of clusters we need to allocate
+
+ Hint - Supplies a hint to start from when looking for a free cluster
+
+ AllocatedEntry - Receives the first fat index for the new allocated cluster chain
+
+Return Value:
+
+ ESUCCESS is returned if the operation is successful. Otherwise,
+ an unsuccessful status is returned that describes the reason for failure.
+
+--*/
+
+{
+ ULONG TotalClustersInVolume;
+ ULONG BytesPerCluster;
+ UCHAR BlankBuffer[512];
+
+ FAT_ENTRY PreviousEntry;
+ ULONG CurrentClusterCount;
+ ULONG j;
+ LBO ClusterLbo;
+ ULONG i;
+
+ //
+ // Load some local variables
+ //
+
+ TotalClustersInVolume = FatNumberOfClusters(&FatStructureContext->Bpb);
+ BytesPerCluster = FatBytesPerCluster(&FatStructureContext->Bpb);
+ RtlZeroMemory((PVOID)&BlankBuffer[0], 512);
+
+ PreviousEntry = 0;
+ CurrentClusterCount = 0;
+
+ //
+ // For each cluster on the disk we'll do the following loop
+ //
+
+ for (j = 0; j < TotalClustersInVolume; j += 1) {
+
+ FAT_ENTRY EntryToExamine;
+ FAT_ENTRY FatEntry;
+
+ //
+ // Check if the current allocation is enough.
+ //
+
+ if (CurrentClusterCount >= ClusterCount) {
+
+ return ESUCCESS;
+ }
+
+ //
+ // Compute an entry to examine based on the loop iteration and our hint
+ //
+
+ EntryToExamine = (FAT_ENTRY)(((j + Hint - 2) % TotalClustersInVolume) + 2);
+
+ //
+ // Read in the prospective fat entry and check if it is available. If it
+ // is not available then continue looping.
+ //
+
+ LookupFatEntry( FatStructureContext, DeviceId, EntryToExamine, &FatEntry, FALSE );
+
+ if (FatInterpretClusterType(FatStructureContext, FatEntry) != FatClusterAvailable) {
+
+ continue;
+ }
+
+ //
+ // We have a free cluster, so put it at the end of the chain.
+ //
+
+ if (PreviousEntry == 0) {
+
+ *AllocatedEntry = EntryToExamine;
+
+ } else {
+
+ SetFatEntry( FatStructureContext, DeviceId, PreviousEntry, EntryToExamine );
+ }
+
+ SetFatEntry( FatStructureContext, DeviceId, EntryToExamine, FAT_CLUSTER_LAST );
+
+ //
+ // Now we need to go through and zero out the data in the cluster that we've
+ // just allocated. Because all clusters must be a multiple of dirents we'll
+ // do it a dirent at a time.
+ //
+
+ ClusterLbo = FatIndexToLbo( FatStructureContext, EntryToExamine );
+
+ for (i = 0; i < BytesPerCluster; i += 512) {
+
+ DiskWrite( DeviceId, ClusterLbo + i, 512, BlankBuffer );
+ }
+
+ //
+ // Before we go back to the top of the loop we need to update the
+ // previous entry so that it points to the end of the current chain and
+ // also i because we've just added another cluster.
+ //
+
+ PreviousEntry = EntryToExamine;
+ CurrentClusterCount += 1;
+ }
+
+ return ENOSPC;
+}
+
+
+//
+// Internal support routine
+//
+
+VOID
+FatFirstComponent (
+ IN OUT PSTRING String,
+ OUT PFAT8DOT3 FirstComponent
+ )
+
+/*++
+
+Routine Description:
+
+ Convert a string into fat 8.3 format and advance the input string
+ descriptor to point to the next file name component.
+
+Arguments:
+
+ InputString - Supplies a pointer to the input string descriptor.
+
+ Output8dot3 - Supplies a pointer to the converted string.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG Extension;
+ ULONG Index;
+
+ //
+ // Fill the output name with blanks.
+ //
+
+ for (Index = 0; Index < 11; Index += 1) { (*FirstComponent)[Index] = ' '; }
+
+ //
+ // Copy the first part of the file name up to eight characters and
+ // skip to the end of the name or the input string as appropriate.
+ //
+
+ for (Index = 0; Index < String->Length; Index += 1) {
+
+ if ((String->Buffer[Index] == '\\') || (String->Buffer[Index] == '.')) {
+
+ break;
+ }
+
+ if (Index < 8) {
+
+ (*FirstComponent)[Index] = (CHAR)ToUpper(String->Buffer[Index]);
+ }
+ }
+
+ //
+ // Check if the end of the string was reached, an extension was specified,
+ // or a subdirectory was specified..
+ //
+
+ if (Index < String->Length) {
+
+ if (String->Buffer[Index] == '.') {
+
+ //
+ // Skip over the extension separator and add the extension to
+ // the file name.
+ //
+
+ Index += 1;
+ Extension = 8;
+
+ while (Index < String->Length) {
+
+ if (String->Buffer[Index] == '\\') {
+
+ break;
+ }
+
+ if (Extension < 11) {
+
+ (*FirstComponent)[Extension] = (CHAR)ToUpper(String->Buffer[Index]);
+ Extension += 1;
+ }
+
+ Index += 1;
+ }
+ }
+ }
+
+ //
+ // Now we'll bias the first component by the 0xe5 factor so that all our tests
+ // to names on the disk will be ready for a straight 11 byte comparison
+ //
+
+ if ((*FirstComponent)[0] == 0xe5) {
+
+ (*FirstComponent)[0] = FAT_DIRENT_REALLY_0E5;
+ }
+
+ //
+ // Update string descriptor.
+ //
+
+ String->Buffer += Index;
+ String->Length -= (USHORT)Index;
+
+ return;
+}
+
+
+//
+// Internal support routine
+//
+
+VOID
+FatDirToArcDir (
+ IN PDIRENT FatDirent,
+ OUT PDIRECTORY_ENTRY ArcDirent
+ )
+
+/*++
+
+Routine Description:
+
+ This routine converts a FAT directory entry into an ARC
+ directory entry.
+
+Arguments:
+
+ FatDirent - supplies a pointer to a FAT directory entry.
+
+ ArcDirent - supplies a pointer to an ARC directory entry.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG i, e;
+
+ //
+ // clear info area
+ //
+
+ RtlZeroMemory( ArcDirent, sizeof(DIRECTORY_ENTRY) );
+
+ //
+ // check the directory flag
+ //
+
+ if (FlagOn( FatDirent->Attributes, FAT_DIRENT_ATTR_DIRECTORY )) {
+
+ SetFlag( ArcDirent->FileAttribute, ArcDirectoryFile );
+ }
+
+ //
+ // check the read-only flag
+ //
+
+ if (FlagOn( FatDirent->Attributes, FAT_DIRENT_ATTR_READ_ONLY )) {
+
+ SetFlag( ArcDirent->FileAttribute, ArcReadOnlyFile );
+ }
+
+ //
+ // clear name string
+ //
+
+ RtlZeroMemory( ArcDirent->FileName, 32 );
+
+ //
+ // copy first portion of file name
+ //
+
+ for (i = 0; (i < 8) && (FatDirent->FileName[i] != ' '); i += 1) {
+
+ ArcDirent->FileName[i] = FatDirent->FileName[i];
+ }
+
+ //
+ // check for an extension
+ //
+
+ if ( FatDirent->FileName[8] != ' ' ) {
+
+ //
+ // store the dot char
+ //
+
+ ArcDirent->FileName[i++] = '.';
+
+ //
+ // add the extension
+ //
+
+ for (e = 8; (e < 11) && (FatDirent->FileName[e] != ' '); e += 1) {
+
+ ArcDirent->FileName[i++] = FatDirent->FileName[e];
+ }
+ }
+
+ //
+ // set file name length before returning
+ //
+
+ ArcDirent->FileNameLength = i;
+
+ return;
+}
+
+
+#ifdef DBLSPACE_LEGAL
+
+
+/*++
+
+ The remainder of this file contains the double space additions.
+ Logically the caller see a virtual fat partition (vfp), which
+ double space implements on top of a compressed volume file (cvf).
+
+ All user reads to the Vfp are translated to a read (with possibly
+ some decompression) of the Cvf. In our implementation the Cvf
+ is just an opened file handled by FatBoot. So double space
+ can read the cvf by simply calling BlSeek/BlRead using the FileId
+ for the Cvf which is fed straight back into FatBoot.
+
+ Pictorially here is how things look:
+
+ CVF
+ +------------+
+ | |
+ | Cvf Header |
+ | |
+ +------------+
+ | |
+ | Cvf Bitmap |
+ | |
+ +------------+
+ | |
+ | Cvf Fat |
+ | Extensions |
+ VFP | |
+ +-------------+ +------------+
+ | | | |
+ | Boot Sector | | Dos Boot |
+ | and | | Sector and |
+ | Reserved | | Reserved |
+ | Area | | Area3 |
+ | | | |
+ +-------------+ +------------+
+ | | ---read---> | |
+ | First | | Dos Fat |
+ | Fat | | |
+ | | +------------+
+ |.............| +-> | |
+ | | | | Dos Root |
+ | Secondary | | | Directory |
+ | Fats | | | |
+ | | | +------------+
+ +-------------+ | | |
+ | | ---read-+ | Cvf Heap |
+ | Root | | |
+ | Directory | +-> | |
+ | | | +------------+
+ +-------------+ |
+ | | ---read-+
+ | File Area |
+ | |
+ | |
+ +-------------+
+
+ The boot file system never tries to read from the Vfp Boot and
+ Reserved Sector area or the secondary fats so none of the logic
+ needs to worry about reading those areas.
+
+--*/
+
+//
+// Low level I/O procedure prototypes for reading the Vfp. This
+// makes the Vfp look like one big partition without compression.
+// The other prototype is for reading the Cvf.
+//
+
+ARC_STATUS
+DblsReadVfp (
+ IN ULONG FileId,
+ IN LBO Lbo,
+ IN ULONG ByteCount,
+ IN PUCHAR Buffer
+ );
+
+ARC_STATUS
+DblsReadCvf (
+ IN ULONG CvfId,
+ IN LBO Lbo,
+ IN ULONG ByteCount,
+ IN PVOID Buffer
+ );
+
+#define ReadVfp(A,B,C,D) { ARC_STATUS _s; \
+ if ((_s = DblsReadVfp(A,B,C,D)) != ESUCCESS) { return _s; } \
+}
+
+#define ReadCvf(A,B,C,D) { ARC_STATUS _s; \
+ if ((_s = DblsReadCvf(A,B,C,D)) != ESUCCESS) { return _s; } \
+}
+
+//
+// The following macro is used to translate an Lbo relative to the start
+// of the file area into a cluster index.
+//
+// ULONG
+// DblsLboToIndex (
+// IN PDBLS_STRUCTURE_CONTEXT Dscb,
+// IN LBO Lbo
+// );
+//
+
+#define DblsLboToIndex(D,L) ( \
+ ((L) / (D)->VfpLayout.BytesPerCluster) + 2 \
+)
+
+//
+// LBO
+// DblsGetHeapLbo (
+// IN CVF_FAT_EXTENSIONS FatExtensions
+// );
+//
+// ULONG
+// DblsGetCompressedDataLength (
+// IN CVF_FAT_EXTENSIONS FatExtensions
+// );
+//
+// ULONG
+// DblsGetUncompressedDatalength (
+// IN CVF_FAT_EXTENSIONS FatExtensions
+// );
+//
+
+#define DblsGetHeapLbo(F) ( \
+ ((F).CvfHeapLbnMinus1 + 1) * 0x200 \
+)
+
+#define DblsGetCompressedDataLength(F) ( \
+ ((F).CompressedSectorLengthMinus1 + 1) * 0x200 \
+)
+
+#define DblsGetUncompressedDataLength(F) ( \
+ ((F).UncompressedSectorLengthMinus1 + 1) * 0x200 \
+)
+
+ULONG
+DblsMrcfDecompress (
+ PUCHAR UncompressedBuffer,
+ ULONG UncompressedLength,
+ PUCHAR CompressedBuffer,
+ ULONG CompressedLength,
+ PMRCF_DECOMPRESS WorkSpace
+ );
+
+//
+// Define global data.
+//
+
+BOOLEAN DblsBootInitialized = FALSE;
+
+//
+// File entry table - This is a structure that provides entry to the DBLS
+// file system procedures. It is exported when a FAT file structure
+// is recognized.
+//
+
+BL_DEVICE_ENTRY_TABLE DblsDeviceEntryTable;
+
+
+PBL_DEVICE_ENTRY_TABLE
+IsDblsFileStructure (
+ IN ULONG CvfId,
+ IN PVOID StructureContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines if the partition on the specified opened file
+ contains a Double Space file system volume.
+
+ This routine does minimal sanity checking because the logic being that
+ if we're being called to boot a double space system then we know what
+ we doing and any little small error (like bad signatures) shouldn't
+ necessarily keep us from booting. If the system (i.e., the disk is
+ really bad then we're not going to boot anyway.
+
+Arguments:
+
+ CvfId - Supplies the file table index for the CVF on which
+ read operations are to be performed.
+
+ StructureContext - Supplies a pointer to a DBLS file structure context.
+
+Return Value:
+
+ A pointer to the DBLS entry table is returned if the file is
+ recognized as containing a DBLS volume. Otherwise, NULL is returned.
+
+--*/
+
+{
+ PDBLS_STRUCTURE_CONTEXT Dscb;
+
+ //****DbgPrint("IsDblsFileStructure(%0x,%0x)\n", CvfId, StructureContext);
+ //****DbgWaitForEnter("Start of IsDblsFileStructure");
+
+ //
+ // Clear the file system context block.
+ //
+
+ Dscb = (PDBLS_STRUCTURE_CONTEXT)StructureContext;
+ RtlZeroMemory(&Dscb->FatStructureContext, sizeof(FAT_STRUCTURE_CONTEXT));
+
+ //
+ // Figure out the size and shape of the Cvf
+ //
+
+ {
+ ULONG CvfSize;
+ PACKED_CVF_HEADER PackedCvfHeader;
+
+ //
+ // Get the size of the Cvf. Rather than call back to get the file
+ // information we'll just incestuously know that it is stored in the
+ // Dirent field of the Fat File Context of the Cvf's file table entry.
+ //
+
+ CvfSize = BlFileTable[ CvfId ].u.FatFileContext.Dirent.FileSize;
+
+ //
+ // Read in the Cvf Header, unpack the Cvf and compute
+ // the Cvf layout
+ //
+
+ if (DblsReadCvf( CvfId, 0, sizeof(PACKED_CVF_HEADER), &PackedCvfHeader) != ESUCCESS) {
+
+ return NULL;
+ }
+
+ CvfUnpackCvfHeader( &Dscb->CvfHeader, &PackedCvfHeader );
+
+ CvfLayout( &Dscb->CvfLayout, &Dscb->CvfHeader, CvfSize );
+ }
+
+ //
+ // Figure out the size and shape of the Vfp
+ //
+
+ {
+ PACKED_BIOS_PARAMETER_BLOCK PackedBpb;
+
+ //
+ // Read in the Bpb from the Cvf and compute the
+ // Vfp layout
+ //
+
+ if (DblsReadCvf( CvfId,
+ Dscb->CvfLayout.DosBootSector.Lbo + FIELD_OFFSET(PACKED_BOOT_SECTOR, PackedBpb),
+ sizeof(PACKED_BIOS_PARAMETER_BLOCK),
+ &PackedBpb ) != ESUCCESS) {
+
+ return NULL;
+ }
+
+ FatUnpackBios( &Dscb->FatStructureContext.Bpb, &PackedBpb );
+
+ //
+ // Now setup the vfp layout fields
+ //
+
+ Dscb->VfpLayout.Fat.Lbo = Dscb->FatStructureContext.Bpb.ReservedSectors *
+ Dscb->FatStructureContext.Bpb.BytesPerSector;
+ Dscb->VfpLayout.Fat.Allocation =
+ Dscb->VfpLayout.Fat.Size = Dscb->FatStructureContext.Bpb.Fats *
+ FatBytesPerFat( &Dscb->FatStructureContext.Bpb );
+
+ Dscb->VfpLayout.RootDirectory.Lbo = FatRootDirectoryLbo( &Dscb->FatStructureContext.Bpb );
+ Dscb->VfpLayout.RootDirectory.Allocation =
+ Dscb->VfpLayout.RootDirectory.Size = FatRootDirectorySize( &Dscb->FatStructureContext.Bpb );
+
+ Dscb->VfpLayout.FileArea.Lbo = FatFileAreaLbo( &Dscb->FatStructureContext.Bpb );
+ Dscb->VfpLayout.FileArea.Allocation =
+ Dscb->VfpLayout.FileArea.Size = FatNumberOfClusters( &Dscb->FatStructureContext.Bpb ) *
+ FatBytesPerCluster( &Dscb->FatStructureContext.Bpb );
+
+ Dscb->VfpLayout.BytesPerCluster = FatBytesPerCluster( &Dscb->FatStructureContext.Bpb );
+ }
+
+ if (!DblsBootInitialized) {
+
+ DblsBootInitialized = TRUE;
+
+ //
+ // Now that we know it is a real double space partition we'll
+ // allocate some heap storage for our decompression algorithm,
+ // and also some scratch space for buffering the file data area.
+ //
+
+ Dscb->DecompressWorkSpace = BlAllocateHeap( sizeof(MRCF_DECOMPRESS) );
+ Dscb->CompressedBuffer = BlAllocateHeap( 8192 );
+ Dscb->UncompressedBuffer = BlAllocateHeap( 8192 );
+
+ //
+ // Now set up the cached fat extensions area
+ //
+
+ Dscb->CachedFatExtensionsLbo = 0;
+ Dscb->CachedFatExtensions = BlAllocateHeap( sizeof(CVF_FAT_EXTENSIONS) * 512 );
+
+ //
+ // Initialize the file entry table and return the address of the table.
+ //
+
+ DblsDeviceEntryTable.Open = DblsOpen;
+ DblsDeviceEntryTable.Close = FatClose;
+ DblsDeviceEntryTable.Read = DblsRead;
+ DblsDeviceEntryTable.Seek = FatSeek;
+ DblsDeviceEntryTable.GetFileInformation = FatGetFileInformation;
+ }
+
+ return &DblsDeviceEntryTable;
+}
+
+
+ARC_STATUS
+DblsOpen (
+ IN PCHAR FileName,
+ IN OPEN_MODE OpenMode,
+ IN PULONG FileId
+ )
+
+/*++
+
+Routine Description:
+
+ This routine searches the device for a file matching FileName. If a
+ match is found the dirent for the file is saved and the file is opened.
+
+Arguments:
+
+ FileName - Supplies a pointer to a zero terminated file name.
+
+ OpenMode - Supplies the mode of the open.
+
+ FileId - Supplies a pointer to a variable that specifies the file
+ table entry that is to be filled in if the open is successful.
+
+Return Value:
+
+ ESUCCESS is returned if the open operation is successful. Otherwise,
+ an unsuccessful status is returned that describes the reason for failure.
+
+--*/
+
+{
+ PBL_FILE_TABLE FileTableEntry;
+ PDBLS_STRUCTURE_CONTEXT DblsStructureContext;
+
+ FAT_ENTRY CurrentDirectoryIndex;
+ BOOLEAN IsDirectory;
+
+ STRING PathName;
+ FAT8DOT3 Name;
+
+ //****DbgPrint("DblsOpen(\"%s\", %0x, %0x)\n", FileName, OpenMode, *FileId);
+ //****DbgWaitForEnter("Start of DblsOpen");
+
+ //
+ // Load our local variables
+ //
+
+ FileTableEntry = &BlFileTable[*FileId];
+ DblsStructureContext = (PDBLS_STRUCTURE_CONTEXT)FileTableEntry->StructureContext;
+
+ //
+ // Indicate that no fat extensions are cached. We need to do this here
+ // because we might be openening a file on removable media and we
+ // have no volume tracking mechanism here -- don't want to use cached
+ // data from a volume that isn't currently in the drive.
+ //
+
+ DblsStructureContext->CachedFatExtensionsLbo = 0;
+
+ //
+ // Construct a file name descriptor from the input file name
+ //
+
+ RtlInitString( &PathName, FileName );
+
+ //
+ // Initialize the file table entry by zeroing out the file context, and
+ // setting the position to zero.
+ //
+
+ RtlZeroMemory(&FileTableEntry->u.FatFileContext, sizeof(FAT_FILE_CONTEXT));
+
+ FileTableEntry->Position.LowPart = 0;
+ FileTableEntry->Position.HighPart = 0;
+
+ //
+ // All of our work starts from the root directory which is denoted
+ // by an index value of zero.
+ //
+
+ CurrentDirectoryIndex = 0;
+ IsDirectory = TRUE;
+
+ //
+ // Check if the user simply wants to open the root directory
+ //
+
+ if ((PathName.Buffer[0] == '\\') && (PathName.Length == 1)) {
+
+ //
+ // We are opening the root directory. So construct
+ // a file name for it in the file table entry.
+ //
+
+ FileTableEntry->FileNameLength = 1;
+ FileTableEntry->FileName[0] = PathName.Buffer[0];
+
+ //
+ // Root dirent is all zeroes with a directory attribute.
+ // Including an LBO of zero, which we already zeroed. So
+ // all that is left to do is set the directory attribute.
+ //
+
+ FileTableEntry->u.FatFileContext.Dirent.Attributes = FAT_DIRENT_ATTR_DIRECTORY;
+
+ } else {
+
+ //
+ // We are not opening the root directory.
+ //
+ // While the path name has some characters in it we'll go through
+ // our loop which extracts the first part of the path name and
+ // searches the current directory for an entry. If what we find
+ // is a directory and we're not done cracking the path name we'll
+ // continue looping.
+ //
+
+ while ((PathName.Length > 0) && IsDirectory) {
+
+ //
+ // Extract the first component and search the directory for a
+ // match, but first skip over the backslash and copy the first
+ // part to the file name buffer in the file table entry.
+ //
+
+ if (PathName.Buffer[0] == '\\') {
+
+ PathName.Buffer +=1;
+ PathName.Length -=1;
+ }
+
+ for (FileTableEntry->FileNameLength = 0;
+ (((USHORT)FileTableEntry->FileNameLength < PathName.Length) &&
+ (PathName.Buffer[FileTableEntry->FileNameLength] != '\\'));
+ FileTableEntry->FileNameLength += 1) {
+
+ FileTableEntry->FileName[FileTableEntry->FileNameLength] =
+ PathName.Buffer[FileTableEntry->FileNameLength];
+ }
+
+ FatFirstComponent( &PathName, &Name );
+
+ SearchForDirent( &DblsStructureContext->FatStructureContext,
+ *FileId,
+ CurrentDirectoryIndex,
+ &Name,
+ &FileTableEntry->u.FatFileContext.Dirent,
+ &FileTableEntry->u.FatFileContext.DirentLbo,
+ TRUE );
+
+ //
+ // We have a match now check to see if it is a directory
+ //
+
+ if (IsDirectory = BooleanFlagOn( FileTableEntry->u.FatFileContext.Dirent.Attributes,
+ FAT_DIRENT_ATTR_DIRECTORY )) {
+
+ CurrentDirectoryIndex = FileTableEntry->u.FatFileContext.Dirent.FirstClusterOfFile;
+ }
+ }
+
+ //
+ // If the path name length is not zero then we were trying to crack a path
+ // with an nonexistent (or non directory) name in it. For example, we tried
+ // to crack a\b\c\d and b is not a directory or does not exist (then the path
+ // name will still contain c\d).
+ //
+
+ if (PathName.Length != 0) {
+
+ return ENOTDIR;
+ }
+ }
+
+ //
+ // At this point we're done cracking the path name, and the Fat file
+ // context is fully setup. Now all that is left to decide is what
+ // type open the user wants to do and if it is compatible with what
+ // we just found.
+ //
+
+ //
+ // Check if the last component is a directory
+ //
+
+ if (IsDirectory) {
+
+ //
+ // For an existing directory the only valid open mode is OpenDirectory
+ // all other modes return an error
+ //
+
+ switch (OpenMode) {
+
+ case ArcOpenDirectory:
+
+ FileTableEntry->Flags.Open = 1;
+ FileTableEntry->Flags.Read = 1;
+
+ return ESUCCESS;
+
+ case ArcOpenReadOnly:
+ case ArcOpenWriteOnly:
+ case ArcOpenReadWrite:
+ case ArcCreateWriteOnly:
+ case ArcCreateReadWrite:
+ case ArcSupersedeWriteOnly:
+ case ArcSupersedeReadWrite:
+
+ return EISDIR;
+
+ case ArcCreateDirectory:
+
+ return EACCES;
+ }
+ }
+
+ //
+ // If we get here then we have an existing file that is being opened.
+ // We can only open existing files for read access.
+ //
+
+ switch (OpenMode) {
+
+ case ArcOpenReadOnly:
+
+ FileTableEntry->Flags.Open = 1;
+ FileTableEntry->Flags.Read = 1;
+
+ {
+ //**** this is just a hack to make everything work. Don't know why but this works...
+ ULONG FileId2;
+ BlOpen(BlFileTable[BlFileTable[*FileId].DeviceId].DeviceId, "\\", ArcOpenReadOnly, &FileId2);
+ BlClose(FileId2);
+ }
+
+ return ESUCCESS;
+
+ case ArcOpenWriteOnly:
+ case ArcOpenReadWrite:
+ case ArcSupersedeWriteOnly:
+ case ArcSupersedeReadWrite:
+
+ return EROFS;
+
+ case ArcCreateWriteOnly:
+ case ArcCreateReadWrite:
+
+ return EACCES;
+
+ case ArcOpenDirectory:
+ case ArcCreateDirectory:
+
+ return ENOTDIR;
+ }
+}
+
+
+ARC_STATUS
+DblsRead (
+ IN ULONG FileId,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Transfer
+ )
+
+/*++
+
+Routine Description:
+
+ This routine reads data from the specified file.
+
+Arguments:
+
+ FileId - Supplies the file table index.
+
+ Buffer - Supplies a pointer to the buffer that receives the data
+ read.
+
+ Length - Supplies the number of bytes that are to be read.
+
+ Transfer - Supplies a pointer to a variable that receives the number
+ of bytes actually transfered.
+
+Return Value:
+
+ ESUCCESS is returned if the read operation is successful. Otherwise,
+ an unsuccessful status is returned that describes the reason for failure.
+
+--*/
+
+{
+ PBL_FILE_TABLE FileTableEntry;
+
+ //****DbgPrint("DblsRead(%0x,%0x,%0x,%0x)\n", FileId, Buffer, Length, Transfer);
+ //****DbgWaitForEnter("Start of DblsRead");
+
+ //
+ // Load the local variables
+ //
+
+ FileTableEntry = &BlFileTable[FileId];
+
+ //
+ // Clear the transfer count
+ //
+
+ *Transfer = 0;
+
+ //
+ // Read in runs (i.e., bytes) until the byte count goes to zero
+ //
+
+ while (Length > 0) {
+
+ LBO Lbo;
+ ULONG CurrentRunByteCount;
+ LONG ReadSize;
+
+ //
+ // Lookup the corresponding Lbo and run length for the current position
+ // (i.e., Vbo).
+ //
+
+ if (FatVboToLbo( FileId, FileTableEntry->Position.LowPart, &Lbo, &CurrentRunByteCount, TRUE ) != ESUCCESS) {
+
+ //****DbgPrint("DblsRead #1 %0x", *Transfer); DbgWaitForEnter("");
+ return ESUCCESS;
+ }
+
+ //
+ // Now compute the size of the next read. It will be the minimum
+ // of what the caller wants, the current run length, and the
+ // end of the file.
+ //
+
+ ReadSize = Minimum( Length, CurrentRunByteCount );
+
+ if (((ULONG)ReadSize + FileTableEntry->Position.LowPart) >
+ FileTableEntry->u.FatFileContext.Dirent.FileSize) {
+
+ ReadSize = FileTableEntry->u.FatFileContext.Dirent.FileSize -
+ FileTableEntry->Position.LowPart;
+
+ //
+ // If the readjusted read length is now zero then we're done.
+ //
+
+ if (ReadSize <= 0) {
+
+ //****DbgPrint("DblsRead #2 %0x", *Transfer); DbgWaitForEnter("");
+ return ESUCCESS;
+ }
+
+ //
+ // By also setting length here we'll make sure that this is our last
+ // read
+ //
+
+ Length = ReadSize;
+ }
+
+ //
+ // Issue the read
+ //
+
+ ReadVfp(FileId, Lbo, ReadSize, Buffer);
+
+ //
+ // Update the remaining length
+ //
+
+ Length -= ReadSize;
+
+ //
+ // Update the current position and the number of bytes transfered
+ //
+
+ FileTableEntry->Position.LowPart += ReadSize;
+ *Transfer += ReadSize;
+
+ //
+ // Update buffer to point to the next byte location to fill in
+ //
+
+ Buffer = (PCHAR)Buffer + ReadSize;
+ }
+
+ //
+ // If we get here then remaining sector count is zero so we can
+ // return success to our caller
+ //
+
+ //****DbgPrint("DblsRead #3 %0x", *Transfer); DbgWaitForEnter("");
+ return ESUCCESS;
+}
+
+
+ARC_STATUS
+DblsInitialize (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the DoubleSpace boot filesystem.
+
+ This involves setting a global flag to indicate that DoubleSpace
+ is not initialized. This causes IsDblsFileStructure to allocate
+ buffers the first time someone tries to open a DoubleSpaced file.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ ESUCCESS.
+
+--*/
+
+{
+ DblsBootInitialized = FALSE;
+
+ return ESUCCESS;
+}
+
+
+//
+// Internal support routine
+//
+
+ARC_STATUS
+DblsReadVfp (
+ IN ULONG FileId,
+ IN LBO Lbo,
+ IN ULONG ByteCount,
+ IN PUCHAR Buffer
+ )
+
+/*++
+
+Routine Description:
+
+ This routine reads in zero or more bytes from the specified Vfp.
+ It makes the Vfp look like one big partition without compression.
+
+ Because of the way booting work we know we will only be asked to
+ read from the Primary Fat, Root Directory, and File Data area.
+ And only one of the areas at a time (e.g., a request will never
+ overlap between the Root Directory and the File Data area).
+
+Arguments:
+
+ FileId - Supplies the Id for the file.
+
+ Lbo - Supplies the LBO to start reading from.
+
+ ByteCount - Supplies the number of bytes to read.
+
+ Buffer - Supplies a pointer to the buffer to read the bytes into.
+
+Return Value:
+
+ ESUCCESS is returned if the read operation is successful. Otherwise,
+ an unsuccessful status is returned that describes the reason for failure.
+
+--*/
+
+{
+ PDBLS_STRUCTURE_CONTEXT Dscb;
+ ULONG CvfId;
+
+ //****DbgPrint("DblsReadVfp(%0x,%0x,%0x,%0x)\n", FileId, Lbo, ByteCount, Buffer);
+
+ //
+ // Special case where we really don't have to read anything
+ //
+
+ if (ByteCount == 0) { return ESUCCESS; }
+
+ //
+ // Get the context structure for the double space partition, and the cvf id
+ //
+
+ Dscb = (PDBLS_STRUCTURE_CONTEXT)BlFileTable[ FileId ].StructureContext;
+ CvfId = BlFileTable[ FileId ].DeviceId;
+
+ //
+ // Check if we are starting out read in the FAT. We'll assume that
+ // if we starting reading from the FAT then we're going to complete
+ // our read from the fat.
+ //
+
+ if ((Dscb->VfpLayout.Fat.Lbo <= Lbo) && (Lbo < Dscb->VfpLayout.RootDirectory.Lbo)) {
+
+ return DblsReadCvf( CvfId,
+ Dscb->CvfLayout.DosFat.Lbo + (Lbo - Dscb->VfpLayout.Fat.Lbo),
+ ByteCount,
+ Buffer );
+ }
+
+ //
+ // Now check if we are reading from the root directory. Again if we
+ // are starting the read within this area then we'll assume we're
+ // going to only read from this area.
+ //
+
+ if ((Dscb->VfpLayout.RootDirectory.Lbo <= Lbo) && (Lbo < Dscb->VfpLayout.FileArea.Lbo)) {
+
+ return DblsReadCvf( CvfId,
+ Dscb->CvfLayout.DosRootDirectory.Lbo + (Lbo - Dscb->VfpLayout.RootDirectory.Lbo),
+ ByteCount,
+ Buffer );
+ }
+
+ //
+ // If we get here we're reading from the data area of the Vfp
+ // so we have some real work to do (i.e., decompressing data and
+ // so forth).
+ //
+
+ {
+ ULONG AmountRead;
+ ULONG RelativeOffset;
+
+ ULONG StartingClusterRelativeOffset;
+ ULONG EndingClusterRelativeOffset;
+
+ ULONG i;
+
+ //
+ // Check if the amount to read puts us beyond the File Area. We
+ // handle this by simply setting amount read to the mininum
+ // of the input byte count or the size that we are able to read.
+ //
+
+ RelativeOffset = Lbo - Dscb->VfpLayout.FileArea.Lbo;
+
+ AmountRead = Minimum( ByteCount, Dscb->VfpLayout.FileArea.Allocation - RelativeOffset );
+
+ //
+ // Compute the relative offset of our read with respect to
+ // to the start of the file area, and calculate the relative
+ // offset (from the start of the file area) of the starting
+ // cluster and ending cluster. For the starting value we take
+ // the index for the first byte and truncate it to a cluster
+ // boundary. For the ending value we take index of the last
+ // byte we write, truncate it to a cluster.
+ //
+ //
+ // Vfp
+ // +------+
+ // | | <- StartClusterRelativeOff - i(0)
+ // Buffer | |
+ // +------+ | |
+ // | | --> | .... | <- RelativeOffset ---------- Start(0)
+ // | | | |
+ // | | | |
+ // | | |------|
+ // | | | | <--------------------------- Stop(0) i(1) Start(1)
+ // | | | |
+ // | | | |
+ // | | | |
+ // | | | |
+ // | | | |
+ // | | |------|
+ // | | | | <- EndClusterRelativeOff --- Stop(1) i(2) Start(2)
+ // | | | |
+ // | | --> | .... |
+ // +------+ | | <--------------------------- Stop(2)
+ // | |
+ // | |
+ // +------+
+ //
+
+ StartingClusterRelativeOffset = RelativeOffset & ~(Dscb->VfpLayout.BytesPerCluster - 1);
+ EndingClusterRelativeOffset = (RelativeOffset + AmountRead - 1) & ~(Dscb->VfpLayout.BytesPerCluster - 1);
+
+ //
+ // The following loop considers each cluster that overlap with
+ // the user buffer. The loop index "i" is the offset within the
+ // file area of the current cluster under consideration
+ //
+
+ for (i = StartingClusterRelativeOffset;
+ i <= EndingClusterRelativeOffset;
+ i += Dscb->VfpLayout.BytesPerCluster) {
+
+ ULONG Start;
+ ULONG Stop;
+
+ CVF_FAT_EXTENSIONS FatExtension;
+
+ //
+ // Calculate the relative offsets of the overlap between the
+ // user buffer and this cluster.
+ //
+
+ Start = Maximum( RelativeOffset, i );
+ Stop = Minimum( RelativeOffset + AmountRead, i + Dscb->VfpLayout.BytesPerCluster );
+
+ //
+ // So now Start and Stop are within the same cluster and provide
+ // a boundary for our transfer. So now compute the cluster index
+ // of this cluster and read in its fat extension.
+ //
+
+ {
+ ULONG ClusterIndex;
+ LBO FatExtensionLbo;
+
+ ClusterIndex = DblsLboToIndex( Dscb, Start );
+
+ FatExtensionLbo = Dscb->CvfLayout.CvfFatExtensions.Lbo +
+ ((Dscb->CvfHeader.CvfFatFirstDataEntry + ClusterIndex) * sizeof(CVF_FAT_EXTENSIONS));
+
+ //
+ // Check if it is not already in our cache
+ //
+
+ if ((FatExtensionLbo < Dscb->CachedFatExtensionsLbo) ||
+ (FatExtensionLbo >= Dscb->CachedFatExtensionsLbo + (sizeof(CVF_FAT_EXTENSIONS) * 512))) {
+
+ ReadCvf( CvfId, FatExtensionLbo, sizeof(CVF_FAT_EXTENSIONS) * 512, Dscb->CachedFatExtensions )
+ Dscb->CachedFatExtensionsLbo = FatExtensionLbo;
+ }
+
+ FatExtension = Dscb->CachedFatExtensions[ (FatExtensionLbo - Dscb->CachedFatExtensionsLbo) / sizeof(CVF_FAT_EXTENSIONS) ];
+ }
+
+ //
+ // Now if the cluster is not is use we do not have to read in any
+ // data but can simply zero out the range in the user buffer
+ //
+
+ if (!FatExtension.IsEntryInUse) {
+
+ RtlZeroMemory( &Buffer[ Start - RelativeOffset ], Stop - Start );
+
+ } else {
+
+ ULONG CompressedDataLength;
+ ULONG UncompressedDataLength;
+ LBO ClusterLbo;
+
+ //
+ // Otherwise the cluster is in use so to make life easier we
+ // pull out the compressed and uncompressed data length and
+ // the lbo of the heap for the cluster
+ //
+
+ CompressedDataLength = DblsGetCompressedDataLength( FatExtension );
+
+ UncompressedDataLength = DblsGetUncompressedDataLength( FatExtension );
+
+ ClusterLbo = DblsGetHeapLbo( FatExtension );
+
+ //
+ // If we are reading beyond the compressed length, we already
+ // know the answer.
+ //
+
+ if (Start - i >= UncompressedDataLength) {
+
+ RtlZeroMemory( &Buffer[ Start - RelativeOffset ], Stop - Start );
+ continue;
+ }
+
+ //
+ // Now check if the data is uncompressed and our life is really
+ // easy because we only need to read in the data.
+ //
+
+ if (FatExtension.IsDataUncompressed) {
+
+ //
+ // The data is not compressed so read it straight into the
+ // caller's buffer, taking into account that we only want
+ // to read in the as much as will fit in our buffer or as much
+ // as is available.
+ //
+
+ ReadCvf( CvfId,
+ ClusterLbo + (Start - i),
+ Minimum( UncompressedDataLength + i, Stop) - Start,
+ &Buffer[ Start - RelativeOffset ] );
+
+ } else {
+
+ PUCHAR TargetBuffer;
+
+ //
+ // Read in the compressed buffer and decompressed it
+ //
+
+ ReadCvf( CvfId,
+ ClusterLbo,
+ CompressedDataLength,
+ Dscb->CompressedBuffer );
+
+ //
+ // If we can, decompress directly into the user's buffer
+ //
+
+ if ((Start == i) && ((Stop - i) >= UncompressedDataLength)) {
+
+ TargetBuffer = &Buffer[ Start - RelativeOffset ];
+
+ } else {
+
+ TargetBuffer = Dscb->UncompressedBuffer;
+ }
+
+ UncompressedDataLength = DblsMrcfDecompress( TargetBuffer,
+ UncompressedDataLength,
+ Dscb->CompressedBuffer,
+ CompressedDataLength,
+ Dscb->DecompressWorkSpace );
+
+ //
+ // At this point the uncompressed buffer is full and we
+ // need to copy the appropriate amount to data to the
+ // caller's buffer
+ //
+
+ if (TargetBuffer == Dscb->UncompressedBuffer) {
+
+ RtlCopyMemory( &Buffer[ Start - RelativeOffset ],
+ &TargetBuffer[ Start - i ],
+ Minimum(UncompressedDataLength + i, Stop) - Start );
+ }
+ }
+
+ //
+ // At this point we've copied some data into the user buffer
+ // however if the uncompressed data length is less than what we
+ // wanted to copy from this cluster then we need to zero out
+ // the end of the user buffer
+ //
+
+ if (UncompressedDataLength + i < Stop) {
+
+ RtlZeroMemory( &Buffer[ (Start - RelativeOffset) + UncompressedDataLength ],
+ Stop - (UncompressedDataLength + i) );
+ }
+ }
+ }
+ }
+
+ //
+ // And return to our caller
+ //
+
+ return ESUCCESS;
+}
+
+
+//
+// Internal support routine
+//
+
+ARC_STATUS
+DblsReadCvf (
+ IN ULONG CvfId,
+ IN LBO Lbo,
+ IN ULONG ByteCount,
+ IN PVOID Buffer
+ )
+
+/*++
+
+Routine Description:
+
+ This routine reads in zero or more bytes from the specified CVF.
+
+Arguments:
+
+ CvfId - Supplies the Id for the Cvf.
+
+ Lbo - Supplies the LBO to start reading from.
+
+ ByteCount - Supplies the number of bytes to read.
+
+ Buffer - Supplies a pointer to the buffer to read the bytes into.
+
+Return Value:
+
+ ESUCCESS is returned if the read operation is successful. Otherwise,
+ an unsuccessful status is returned that describes the reason for failure.
+
+--*/
+
+{
+ LARGE_INTEGER LargeLbo;
+ ARC_STATUS Status;
+ ULONG i;
+
+ //****DbgPrint("DblsReadCvf(%0x,%0x,%0x,%0x)\n", CvfId, Lbo, ByteCount, Buffer);
+
+ //
+ // Special case the zero byte read request
+ //
+ if (ByteCount == 0) {
+
+ return ESUCCESS;
+ }
+
+ //
+ // Seek to the appropriate offset in the Cvf
+ //
+
+ LargeLbo.LowPart = (ULONG)Lbo;
+ LargeLbo.HighPart = 0;
+
+ if ((Status = BlSeek( CvfId, &LargeLbo, SeekAbsolute )) != ESUCCESS) {
+
+ return Status;
+ }
+
+ //
+ // Issue the read request to FatBoot
+ //
+
+ if ((Status = BlRead( CvfId, Buffer, ByteCount, &i)) != ESUCCESS) {
+
+ return Status;
+ }
+
+ //
+ // Make sure we got back the amount requested
+ //
+
+ if (ByteCount != i) {
+
+ return EIO;
+ }
+
+ //
+ // Everything is fine so return success to our caller
+ //
+
+ return ESUCCESS;
+}
+
+
+#ifndef _X86_
+//
+// The following definitions and routines are used for decompressing
+// a buffer. The code is copied from Mrcf.c
+//
+
+#define wBACKPOINTERMAX (4415)
+
+typedef struct _MDSIGNATURE {
+ USHORT sigStamp;
+ USHORT sigType;
+} MDSIGNATURE, *PMDSIGNATURE;
+
+VOID
+DblsMrcfSetBitBuffer (
+ PUCHAR pb,
+ ULONG cb,
+ PMRCF_BIT_IO BitIo
+ );
+
+VOID
+DblsMrcfFillBitBuffer (
+ PMRCF_BIT_IO BitIo
+ );
+
+USHORT
+DblsMrcfReadBit (
+ PMRCF_BIT_IO BitIo
+ );
+
+USHORT
+DblsMrcfReadNBits (
+ LONG cbits,
+ PMRCF_BIT_IO BitIo
+ );
+
+
+//
+// Internal support routine
+//
+
+ULONG
+DblsMrcfDecompress (
+ PUCHAR UncompressedBuffer,
+ ULONG UncompressedLength,
+ PUCHAR CompressedBuffer,
+ ULONG CompressedLength,
+ PMRCF_DECOMPRESS WorkSpace
+ )
+
+/*++
+
+Routine Description:
+
+ This routine decompresses a buffer of StandardCompressed or MaxCompressed
+ data.
+
+Arguments:
+
+ UncompressedBuffer - buffer to receive uncompressed data
+
+ UncompressedLength - length of UncompressedBuffer
+
+ NOTE: UncompressedLength must be the EXACT length of the uncompressed
+ data, as Decompress uses this information to detect
+ when decompression is complete. If this value is
+ incorrect, Decompress may crash!
+
+ CompressedBuffer - buffer containing compressed data
+
+ CompressedLength - length of CompressedBuffer
+
+ WorkSpace - pointer to a private work area for use by this operation
+
+Return Value:
+
+ ULONG - Returns the size of the decompressed data in bytes. Returns 0 if
+ there was an error in the decompress.
+
+--*/
+
+{
+ ULONG cbMatch; // Length of match string
+ ULONG i; // Index in UncompressedBuffer to receive decoded data
+ ULONG iMatch; // Index in UncompressedBuffer of matched string
+ ULONG k; // Number of bits in length string
+ ULONG off; // Offset from i in UncompressedBuffer of match string
+ USHORT x; // Current bit being examined
+ ULONG y;
+
+ //****DbgPrint("DblsMrcfDecompress(%0x,%0x,%0x,%0x,%0x)\n", UncompressedBuffer,UncompressedLength,CompressedBuffer,CompressedLength,WorkSpace);
+
+ //
+ // Skip over the signature
+ //
+
+ CompressedLength -= sizeof(MDSIGNATURE);
+ CompressedBuffer += sizeof(MDSIGNATURE);
+
+ //
+ // Set up for decompress, start filling UncompressedBuffer at front
+ //
+
+ i = 0;
+
+ //
+ // Set statics to save parm passing
+ //
+
+ DblsMrcfSetBitBuffer(CompressedBuffer,CompressedLength,&WorkSpace->BitIo);
+
+ while (TRUE) {
+
+ y = DblsMrcfReadNBits(2,&WorkSpace->BitIo);
+
+ //
+ // Check if next 7 bits are a byte
+ // 1 if 128..255 (0x80..0xff), 2 if 0..127 (0x00..0x7f)
+ //
+
+ if (y == 1 || y == 2) {
+
+ UncompressedBuffer[i] = (UCHAR)((y == 1 ? 0x80 : 0) | DblsMrcfReadNBits(7,&WorkSpace->BitIo));
+
+ i++;
+
+ } else {
+
+ //
+ // Have match sequence
+ // Get the offset
+ //
+
+ if (y == 0) {
+
+ //
+ // next 6 bits are offset
+ //
+
+ off = DblsMrcfReadNBits(6,&WorkSpace->BitIo);
+
+ } else {
+
+ x = DblsMrcfReadBit(&WorkSpace->BitIo);
+
+ if (x == 0) {
+
+ //
+ // next 8 bits are offset-64 (0x40)
+ //
+
+ off = DblsMrcfReadNBits(8, &WorkSpace->BitIo) + 64;
+
+ } else {
+
+ //
+ // next 12 bits are offset-320 (0x140)
+ //
+
+ off = DblsMrcfReadNBits(12, &WorkSpace->BitIo) + 320;
+
+ if (off == wBACKPOINTERMAX) {
+
+ //
+ // EOS marker
+ //
+
+ if (i >= UncompressedLength) {
+
+ //
+ // Done with entire buffer
+ //
+
+ return i;
+
+ } else {
+
+ //
+ // More to do
+ // Done with a 512-byte chunk
+ //
+
+ continue;
+ }
+ }
+ }
+ }
+
+ //
+ // Get the length - logarithmically encoded
+ //
+
+ for (k=0; (x=DblsMrcfReadBit(&WorkSpace->BitIo)) == 0; k++) { NOTHING; }
+
+ if (k == 0) {
+
+ //
+ // All matches at least 2 chars long
+ //
+
+ cbMatch = 2;
+
+ } else {
+
+ cbMatch = (1 << k) + 1 + DblsMrcfReadNBits(k, &WorkSpace->BitIo);
+ }
+
+ //
+ // Copy the matched string
+ //
+
+ iMatch = i - off;
+
+ while ( (cbMatch > 0) && (i<UncompressedLength) ) {
+
+ UncompressedBuffer[i++] = UncompressedBuffer[iMatch++];
+ cbMatch--;
+ }
+ }
+ }
+}
+
+
+//
+// Internal Support Routine
+//
+
+VOID
+DblsMrcfSetBitBuffer (
+ PUCHAR pb,
+ ULONG cb,
+ PMRCF_BIT_IO BitIo
+ )
+
+/*++
+
+Routine Description:
+
+ Set statics with coded buffer pointer and length
+
+Arguments:
+
+ pb - pointer to compressed data buffer
+
+ cb - length of compressed data buffer
+
+ BitIo - Supplies a pointer to the bit buffer statics
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //****DbgPrint("DblsMrcfSetBitBuffer(%0x,%0x,%0x)\n", pb,cb,BitIo);
+
+ BitIo->pbBB = pb;
+ BitIo->cbBB = cb;
+ BitIo->cbBBInitial = cb;
+ BitIo->cbitsBB = 0;
+ BitIo->abitsBB = 0;
+}
+
+
+//
+// Internal Support Routine
+//
+
+VOID
+DblsMrcfFillBitBuffer (
+ PMRCF_BIT_IO BitIo
+ )
+
+/*++
+
+Routine Description:
+
+ Fill abitsBB from static bit buffer
+
+Arguments:
+
+ BitIo - Supplies a pointer to the bit buffer statics
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //****DbgPrint("DblsMrcfFillBitBuffer(%0x)\n", BitIo);
+
+ switch (BitIo->cbBB) {
+
+ case 0:
+
+ break;
+
+ case 1:
+
+ //
+ // Get last byte and adjust count
+ //
+
+ BitIo->cbitsBB = 8;
+ BitIo->abitsBB = *(BitIo->pbBB)++;
+ BitIo->cbBB--;
+
+ break;
+
+ default:
+
+ //
+ // Get word and adjust count
+ //
+
+ BitIo->cbitsBB = 16;
+ BitIo->abitsBB = *((USHORT *)(BitIo->pbBB))++;
+ BitIo->cbBB -= 2;
+
+ break;
+ }
+}
+
+
+//
+// Internal Support Routine
+//
+
+USHORT
+DblsMrcfReadBit (
+ PMRCF_BIT_IO BitIo
+ )
+
+/*++
+
+Routine Description:
+
+ Get next bit from bit buffer
+
+Arguments:
+
+ BitIo - Supplies a pointer to the bit buffer statics
+
+Return Value:
+
+ USHORT - Returns next bit (0 or 1)
+
+--*/
+
+{
+ USHORT bit;
+
+ //****DbgPrint("DblsMrcfReadBit(%0x)\n", BitIo);
+
+ //
+ // Check if no bits available
+ //
+
+ if ((BitIo->cbitsBB) == 0) {
+
+ DblsMrcfFillBitBuffer(BitIo);
+ }
+
+ //
+ // Decrement the bit count
+ // get the bit, remove it, and return the bit
+ //
+
+ (BitIo->cbitsBB)--;
+ bit = (BitIo->abitsBB) & 1;
+ (BitIo->abitsBB) >>= 1;
+
+ return bit;
+}
+
+
+//
+// Internal Support Routine
+//
+
+USHORT
+DblsMrcfReadNBits (
+ LONG cbits,
+ PMRCF_BIT_IO BitIo
+ )
+
+/*++
+
+Routine Description:
+
+ Get next N bits from bit buffer
+
+Arguments:
+
+ cbits - count of bits to get
+
+ BitIo - Supplies a pointer to the bit buffer statics
+
+Return Value:
+
+ USHORT - Returns next cbits bits.
+
+--*/
+
+{
+ ULONG abits; // Bits to return
+ LONG cbitsPart; // Partial count of bits
+ ULONG cshift; // Shift count
+ ULONG mask; // Mask
+
+ //****DbgPrint("DblsMrcfReadNBits(%0x,%0x)\n", cbits,BitIo);
+
+ //
+ // Largest number of bits we should read at one time is 12 bits for
+ // a 12-bit offset. The largest length field component that we
+ // read is 8 bits. If this routine were used for some other purpose,
+ // it can support up to 15 (NOT 16) bit reads, due to how the masking
+ // code works.
+ //
+
+ //
+ // No shift and no bits yet
+ //
+
+ cshift = 0;
+ abits = 0;
+
+ while (cbits > 0) {
+
+ //
+ // If not bits available get some bits
+ //
+
+ if ((BitIo->cbitsBB) == 0) {
+
+ DblsMrcfFillBitBuffer(BitIo);
+ }
+
+ //
+ // Number of bits we can read
+ //
+
+ cbitsPart = Minimum((BitIo->cbitsBB), cbits);
+
+ //
+ // Mask for bits we want, extract and store them
+ //
+
+ mask = (1 << cbitsPart) - 1;
+ abits |= ((BitIo->abitsBB) & mask) << cshift;
+
+ //
+ // Remember the next chunk of bits
+ //
+
+ cshift = cbitsPart;
+
+ //
+ // Update bit buffer, move remaining bits down and
+ // update count of bits left
+ //
+
+ (BitIo->abitsBB) >>= cbitsPart;
+ (BitIo->cbitsBB) -= cbitsPart;
+
+ //
+ // Update count of bits left to read
+ //
+
+ cbits -= cbitsPart;
+ }
+
+ //
+ // Return requested bits
+ //
+
+ return (USHORT)abits;
+}
+#endif // ndef _X86_
+
+#endif // def DBLSPACE_LEGAL
diff --git a/private/ntos/boot/lib/hpfsboot.c b/private/ntos/boot/lib/hpfsboot.c
new file mode 100644
index 000000000..84d8d3048
--- /dev/null
+++ b/private/ntos/boot/lib/hpfsboot.c
@@ -0,0 +1,1515 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ HpfsBoot.c
+
+Abstract:
+
+ This module implements the Hpfs boot file system used by the operating
+ system loader.
+
+Author:
+
+ Gary Kimura [GaryKi] 19-Jul-1991
+
+Revision History:
+
+--*/
+
+//
+// Stuff to get around the fact that we include both Fat, Hpfs, and Ntfs include
+// environments
+//
+
+#define VBO ULONG
+#define LBO ULONG
+
+#include "bootlib.h"
+
+BOOTFS_INFO HpfsBootFsInfo={L"pinball"};
+
+
+//
+// Local procedure prototypes.
+//
+
+ARC_STATUS
+HpfsReadDisk(
+ IN ULONG DeviceId,
+ IN ULONG Lbo,
+ IN ULONG ByteCount,
+ IN OUT PVOID Buffer
+ );
+
+VOID
+HpfsFirstComponent(
+ IN OUT PSTRING String,
+ OUT PSTRING FirstComponent
+ );
+
+typedef enum _COMPARISON_RESULTS {
+ LessThan = -1,
+ EqualTo = 0,
+ GreaterThan = 1
+} COMPARISON_RESULTS;
+
+COMPARISON_RESULTS
+HpfsCompareNames(
+ IN PSTRING Name1,
+ IN PSTRING Name2
+ );
+
+ARC_STATUS
+HpfsSearchDirectory(
+ IN LBN Fnode,
+ IN PSTRING Name,
+ OUT PBOOLEAN IsDirectory,
+ OUT PLBN FoundLbn,
+ OUT PULONG FileSize
+ );
+
+ARC_STATUS
+HpfsLoadMcb(
+ IN LBN Fnode,
+ IN VBN StartingVbn
+ );
+
+ARC_STATUS
+HpfsVbnToLbn(
+ IN VBN Vbn,
+ OUT PLBN Lbn,
+ OUT PULONG ByteCount
+ );
+
+//
+// The following macro upcases a single ascii character
+//
+
+#define ToUpper(C) ((((C) >= 'a') && ((C) <= 'z')) ? (C) - 'a' + 'A' : (C))
+
+//
+// The following macro indicate if the flag is on or off
+//
+
+#define FlagOn(Flags,SingleFlag) ((BOOLEAN)( \
+ (((Flags) & (SingleFlag)) != 0 ? TRUE : FALSE) \
+ ) \
+)
+
+
+//
+// Define global data.
+//
+// Context Pointer - This is a pointer to the context for the current file
+// operation that is active.
+//
+
+PHPFS_STRUCTURE_CONTEXT HpfsStructureContext;
+
+//
+// File Descriptor - This is a pointer to the file descriptor for the current
+// file operation that is active.
+//
+
+PBL_FILE_TABLE HpfsFileTableEntry;
+
+//
+// File entry table - This is a structure that provides entry to the Hpfs
+// file system procedures. It is exported when a Hpfs file structure
+// is recognized.
+//
+
+BL_DEVICE_ENTRY_TABLE HpfsDeviceEntryTable;
+
+
+PBL_DEVICE_ENTRY_TABLE
+IsHpfsFileStructure (
+ IN ULONG DeviceId,
+ IN PVOID StructureContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines if the partition on the specified channel
+ contains a Hpfs file system volume.
+
+Arguments:
+
+ DeviceId - Supplies the file table index for the device on which
+ read operations are to be performed.
+
+ StructureContext - Supplies a pointer to a Hpfs file structure context.
+
+Return Value:
+
+ A pointer to the Hpfs entry table is returned if the partition is
+ recognized as containing a Hpfs volume. Otherwise, NULL is returned.
+
+--*/
+
+{
+ ARC_STATUS Status;
+
+ UCHAR UnalignedSuperSector[SECTOR_SIZE+256];
+ UCHAR UnalignedSpareSector[SECTOR_SIZE+256];
+
+ PSUPER_SECTOR SuperSector;
+ PSPARE_SECTOR SpareSector;
+
+ //
+ // Capture in our global variable the Hpfs Structure context record
+ //
+
+ HpfsStructureContext = (PHPFS_STRUCTURE_CONTEXT)StructureContext;
+ RtlZeroMemory((PVOID)HpfsStructureContext, sizeof(HPFS_STRUCTURE_CONTEXT));
+
+ //
+ // Compute the properly aligned buffers for reading in our sectors
+ //
+
+ SuperSector = ALIGN_BUFFER(UnalignedSuperSector);
+ SpareSector = ALIGN_BUFFER(UnalignedSpareSector);
+
+ //
+ // Read in the super and sector
+ //
+
+ if ((HpfsReadDisk(DeviceId, SUPER_SECTOR_LBN * 512, 512, SuperSector) != ESUCCESS) ||
+ (HpfsReadDisk(DeviceId, SPARE_SECTOR_LBN * 512, 512, SpareSector) != ESUCCESS)) {
+
+ return NULL;
+ }
+
+ //
+ // Check the signature for both sectors.
+ //
+
+ if ((SuperSector->Signature1 != SUPER_SECTOR_SIGNATURE1) ||
+ (SuperSector->Signature2 != SUPER_SECTOR_SIGNATURE2) ||
+ (SpareSector->Signature1 != SPARE_SECTOR_SIGNATURE1) ||
+ (SpareSector->Signature2 != SPARE_SECTOR_SIGNATURE2)) {
+
+ return NULL;
+ }
+
+ //
+ // Initialize the file entry table.
+ //
+
+ HpfsDeviceEntryTable.Open = HpfsOpen;
+ HpfsDeviceEntryTable.Close = HpfsClose;
+ HpfsDeviceEntryTable.Read = HpfsRead;
+ HpfsDeviceEntryTable.Seek = HpfsSeek;
+ HpfsDeviceEntryTable.Write = HpfsWrite;
+ HpfsDeviceEntryTable.GetFileInformation = HpfsGetFileInformation;
+ HpfsDeviceEntryTable.SetFileInformation = HpfsSetFileInformation;
+ HpfsDeviceEntryTable.BootFsInfo = &HpfsBootFsInfo;
+
+ //
+ // And return the address of the table to our caller.
+ //
+
+ return &HpfsDeviceEntryTable;
+}
+
+
+ARC_STATUS
+HpfsClose (
+ IN ULONG FileId
+ )
+
+/*++
+
+Routine Description:
+
+ This routine closes the file specified by the file id.
+
+Arguments:
+
+ FileId - Supplies the file table index.
+
+Return Value:
+
+ ESUCCESS if returned as the function value.
+
+--*/
+
+{
+ //
+ // Indicate that the file isn't open any longer
+ //
+
+ BlFileTable[FileId].Flags.Open = 0;
+
+ //
+ // And return to our caller
+ //
+
+ return ESUCCESS;
+}
+
+
+ARC_STATUS
+HpfsGetFileInformation (
+ IN ULONG FileId,
+ OUT PFILE_INFORMATION Buffer
+ )
+
+/*++
+
+Routine Description:
+
+ This procedure returns to the user a buffer filled with file information
+
+Arguments:
+
+ FileId - Supplies the File id for the operation
+
+ Buffer - Supplies the buffer to receive the file information. Note that
+ it must be large enough to hold the full file name
+
+Return Value:
+
+ ESUCCESS is returned if the open operation is successful. Otherwise,
+ an unsuccessful status is returned that describes the reason for failure.
+
+--*/
+
+{
+ ULONG i;
+
+ HpfsFileTableEntry = &BlFileTable[FileId];
+
+ //
+ // Zero out the buffer, and fill in its non-zero values
+ //
+
+ RtlZeroMemory(Buffer, sizeof(FILE_INFORMATION));
+
+ Buffer->EndingAddress.LowPart = HpfsFileTableEntry->u.HpfsFileContext.FileSize;
+
+ Buffer->CurrentPosition.LowPart = HpfsFileTableEntry->Position.LowPart;
+
+ Buffer->FileNameLength = HpfsFileTableEntry->FileNameLength;
+
+ for (i = 0; i < HpfsFileTableEntry->FileNameLength; i += 1) {
+
+ Buffer->FileName[i] = HpfsFileTableEntry->FileName[i];
+ }
+
+ return ESUCCESS;
+}
+
+
+ARC_STATUS
+HpfsOpen (
+ IN PCHAR FileName,
+ IN OPEN_MODE OpenMode,
+ IN PULONG FileId
+ )
+
+/*++
+
+Routine Description:
+
+ This routine searches the root directory for a file matching FileName.
+ If a match is found the dirent for the file is saved and the file is
+ opened.
+
+Arguments:
+
+ FileName - Supplies a pointer to a zero terminated file name.
+
+ OpenMode - Supplies the mode of the open.
+
+ FileId - Supplies a pointer to a variable that specifies the file
+ table entry that is to be filled in if the open is successful.
+
+Return Value:
+
+ ESUCCESS is returned if the open operation is successful. Otherwise,
+ an unsuccessful status is returned that describes the reason for failure.
+
+--*/
+
+{
+ ARC_STATUS Status;
+
+ ULONG DeviceId;
+
+ UCHAR UnalignedSuperSector[SECTOR_SIZE+256];
+ PSUPER_SECTOR SuperSector;
+
+ LBN Fnode;
+
+ STRING PathName;
+
+ //
+ // Save the address of the file table entry, context area, and the device
+ // id in use.
+ //
+
+ HpfsFileTableEntry = &BlFileTable[*FileId];
+ HpfsStructureContext = (PHPFS_STRUCTURE_CONTEXT)HpfsFileTableEntry->StructureContext;
+
+ DeviceId = HpfsFileTableEntry->DeviceId;
+
+ //
+ // Compute the properly aligned buffers for reading in our sectors
+ //
+
+ SuperSector = ALIGN_BUFFER(UnalignedSuperSector);
+
+ //
+ // Read in the Super sector.
+ //
+
+ if ((Status = HpfsReadDisk(DeviceId, SUPER_SECTOR_LBN * 512, 512, SuperSector)) != ESUCCESS) {
+
+ return Status;
+ }
+
+ //
+ // Double check that the super sector is real
+ //
+
+ if ((SuperSector->Signature1 != SUPER_SECTOR_SIGNATURE1) ||
+ (SuperSector->Signature2 != SUPER_SECTOR_SIGNATURE2)) {
+
+ return EIO;
+ }
+
+ //
+ // Get the root fnode lbn
+ //
+
+ Fnode = SuperSector->RootDirectoryFnode;
+
+ //
+ // Construct a file name descriptor from the input file name.
+ //
+
+ RtlInitString( &PathName, FileName );
+
+ //
+ // While the path name has some characters in it we'll go through our
+ // loop which extracts the first part of the path name and searches
+ // the current fnode (which must be a directory) for an the entry.
+ // If what we find is a directory then we have a new directory fnode
+ // and simply continue back to the top of the loop.
+ //
+
+ while (PathName.Length > 0) {
+
+ STRING Name;
+ BOOLEAN IsDirectory;
+ ULONG FileSize;
+
+ //
+ // Extract the first component and search the directory for a match, but
+ // first copy the first part to the file name buffer in the file table entry
+ //
+
+ for (HpfsFileTableEntry->FileNameLength = 0;
+ (((USHORT)HpfsFileTableEntry->FileNameLength < PathName.Length) &&
+ (PathName.Buffer[HpfsFileTableEntry->FileNameLength] != '\\'));
+ HpfsFileTableEntry->FileNameLength += 1) {
+
+ HpfsFileTableEntry->FileName[HpfsFileTableEntry->FileNameLength] =
+ PathName.Buffer[HpfsFileTableEntry->FileNameLength];
+ }
+
+ HpfsFirstComponent( &PathName, &Name );
+
+ if ((Status = HpfsSearchDirectory(Fnode, &Name, &IsDirectory, &Fnode, &FileSize)) != ESUCCESS) {
+
+ return Status;
+ }
+
+ //
+ // If we didn't get back a directory then we're about to stop either
+ // with an error or with success
+ //
+
+ if (!IsDirectory) {
+
+ //
+ // if the path name still has some characters in it then the
+ // caller wanted to continue but we can't because we're not
+ // currently sitting on a directory
+ //
+
+ if (PathName.Length > 0) {
+
+ return ENOENT;
+ }
+
+ //
+ // Load in the mcb for the file, set the fnode in structure
+ // context, file size, open flags, position, and return
+ // success to our caller
+ //
+
+ if ((Status = HpfsLoadMcb(Fnode, 0)) != ESUCCESS) {
+
+ return Status;
+ }
+
+ HpfsStructureContext->Fnode = Fnode;
+
+ HpfsFileTableEntry->u.HpfsFileContext.FileSize = FileSize;
+
+ HpfsFileTableEntry->Flags.Open = 1;
+ HpfsFileTableEntry->Flags.Read = 1;
+ HpfsFileTableEntry->Position.LowPart = 0;
+ HpfsFileTableEntry->Position.HighPart = 0;
+
+ return ESUCCESS;
+ }
+ }
+
+ //
+ // If we reach here then the path name is exhausted and we didn't
+ // reach a file so return an error to our caller
+ //
+
+ return ENOENT;
+}
+
+
+ARC_STATUS
+HpfsRead (
+ IN ULONG FileId,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Transfer
+ )
+
+/*++
+
+Routine Description:
+
+ This routine reads data from the specified file.
+
+Arguments:
+
+ FileId - Supplies the file table index.
+
+ Buffer - Supplies a pointer to the buffer that receives the data
+ read.
+
+ Length - Supplies the number of bytes that are to be read.
+
+ Transfer - Supplies a pointer to a variable that receives the number
+ of bytes actually transfered.
+
+Return Value:
+
+ ESUCCESS is returned if the read operation is successful. Otherwise,
+ an unsuccessful status is returned that describes the reason for failure.
+
+--*/
+
+{
+ ARC_STATUS Status;
+
+ ULONG DeviceId;
+ ULONG RemainingSectorCount;
+
+ //
+ // Save the address of the file table entry, context area, and the device
+ // id in use.
+ //
+
+ HpfsFileTableEntry = &BlFileTable[FileId];
+ HpfsStructureContext = (PHPFS_STRUCTURE_CONTEXT)HpfsFileTableEntry->StructureContext;
+
+ DeviceId = HpfsFileTableEntry->DeviceId;
+
+ //
+ // Clear the transfer count
+ //
+
+ *Transfer = 0;
+
+ //
+ // Read in runs (i.e., sectors) until the byte count goes to zero
+ //
+
+ while (Length > 0) {
+
+ VBN Vbn;
+ LBN Lbn;
+
+ ULONG CurrentRunByteCount;
+
+ //
+ // Compute the Vbn from the current byte position and then
+ // lookup the corresponding Lbn and current run length
+ //
+
+ Vbn = HpfsFileTableEntry->Position.LowPart / 512;
+
+ if ((Status = HpfsVbnToLbn( Vbn, &Lbn, &CurrentRunByteCount )) != ESUCCESS) {
+
+ return Status;
+ }
+
+ //
+ // Now bias the run size by the offset we are into the
+ // sector
+ //
+
+ CurrentRunByteCount -= (HpfsFileTableEntry->Position.LowPart & 511);
+
+ //
+ // while there are sectors to be read in from the current run
+ // length and we haven't exhausted the request we loop reading
+ // in sectors. The biggest request we'll handle is only 64
+ // contiguous sectors per physical read. So we might need to loop
+ // through the run.
+ //
+
+ while ((Length > 0) && (CurrentRunByteCount > 0)) {
+
+ ULONG i;
+ ULONG Lbo;
+
+ //
+ // Compute the size of the next physical read
+ //
+
+ i = (Length < (64 * 512) ? Length : (64 * 512));
+ i = (i < CurrentRunByteCount ? i : CurrentRunByteCount);
+
+ //
+ // Don't read beyond the eof
+ //
+
+ if (i + HpfsFileTableEntry->Position.LowPart >=
+ HpfsFileTableEntry->u.HpfsFileContext.FileSize) {
+
+ i = HpfsFileTableEntry->u.HpfsFileContext.FileSize -
+ HpfsFileTableEntry->Position.LowPart;
+
+ if (i == 0) {
+
+ return ESUCCESS;
+ }
+
+ Length = i;
+ }
+
+ //
+ // Compute the lbo to read, and then issue the read.
+ //
+
+ Lbo = (Lbn * 512) | (HpfsFileTableEntry->Position.LowPart & 511);
+
+ if ((Status = HpfsReadDisk( DeviceId, Lbo, i, Buffer)) != ESUCCESS) {
+
+ return Status;
+ }
+
+ //
+ // Update the remaining length, Current run byte count
+ // and new Lbn offset
+ //
+
+ Length -= i;
+ CurrentRunByteCount -= i;
+
+ Lbn += i/512;
+
+ //
+ // Update the current position and the number of bytes transfered
+ //
+
+ HpfsFileTableEntry->Position.LowPart += i;
+ *Transfer += i;
+
+ //
+ // Update buffer to point to the next byte location to fill in
+ //
+
+ Buffer = (PCHAR)Buffer + i;
+ }
+ }
+
+ //
+ // If we get here then remaining sector count is zero so we can
+ // return success to our caller
+ //
+
+ return ESUCCESS;
+}
+
+
+ARC_STATUS
+HpfsSeek (
+ IN ULONG FileId,
+ IN PLARGE_INTEGER Offset,
+ IN SEEK_MODE SeekMode
+ )
+
+/*++
+
+Routine Description:
+
+ This routine seeks to the specified position for the file specified
+ by the file id.
+
+Arguments:
+
+ FileId - Supplies the file table index.
+
+ Offset - Supplies the offset in the file to position to.
+
+ SeekMode - Supplies the mode of the seek operation.
+
+Return Value:
+
+ ESUCCESS if returned as the function value.
+
+--*/
+
+{
+ ULONG NewPosition;
+
+ //
+ // Compute the new position
+ //
+
+ if (SeekMode == SeekAbsolute) {
+
+ NewPosition = Offset->LowPart;
+
+ } else {
+
+ NewPosition = BlFileTable[FileId].Position.LowPart + Offset->LowPart;
+ }
+
+ //
+ // If the new position is greater than the file size then return
+ // an error
+ //
+
+ if (NewPosition > BlFileTable[FileId].u.HpfsFileContext.FileSize) {
+
+ return EINVAL;
+ }
+
+ //
+ // Otherwise set the new position and return to our caller
+ //
+
+ BlFileTable[FileId].Position.LowPart = NewPosition;
+
+ return ESUCCESS;
+}
+
+
+ARC_STATUS
+HpfsSetFileInformation (
+ IN ULONG FileId,
+ IN ULONG AttributeFlags,
+ IN ULONG AttributeMask
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets the file attributes of the indicated file
+
+Arguments:
+
+ FileId - Supplies the File Id for the operation
+
+ AttributeFlags - Supplies the value (on or off) for each attribute being modified
+
+ AttributeMask - Supplies a mask of the attributes being altered. All other
+ file attributes are left alone.
+
+Return Value:
+
+ ESUCCESS is returned if the read operation is successful. Otherwise,
+ an unsuccessful status is returned that describes the reason for failure.
+
+--*/
+
+{
+ return EROFS;
+}
+
+
+ARC_STATUS
+HpfsWrite (
+ IN ULONG FileId,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Transfer
+ )
+
+/*++
+
+Routine Description:
+
+ This routine writes data to the specified file.
+
+Arguments:
+
+ FileId - Supplies the file table index.
+
+ Buffer - Supplies a pointer to the buffer that contains the data
+ written.
+
+ Length - Supplies the number of bytes that are to be written.
+
+ Transfer - Supplies a pointer to a variable that receives the number
+ of bytes actually transfered.
+
+Return Value:
+
+ ESUCCESS is returned if the write operation is successful. Otherwise,
+ an unsuccessful status is returned that describes the reason for failure.
+
+--*/
+
+{
+ return EROFS;
+}
+
+
+ARC_STATUS
+HpfsInitialize (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the hpfs boot filesystem.
+ Currently this is a no-op.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ ESUCCESS.
+
+--*/
+
+{
+ return ESUCCESS;
+}
+
+
+//
+// Internal support routine
+//
+
+ARC_STATUS
+HpfsReadDisk(
+ IN ULONG DeviceId,
+ IN ULONG Lbo,
+ IN ULONG ByteCount,
+ IN OUT PVOID Buffer
+ )
+
+/*++
+
+Routine Description:
+
+ This routine reads in zero or more sectors from the specified device.
+
+Arguments:
+
+ DeviceId - Supplies the device id to use in the arc calls.
+
+ Lbo - Supplies the LBO to start reading from.
+
+ ByteCount - Supplies the number of bytes to read.
+
+ Buffer - Supplies a pointer to the buffer to read the bytes into.
+
+Return Value:
+
+ ESUCCESS is returned if the read operation is successful. Otherwise,
+ an unsuccessful status is returned that describes the reason for failure.
+
+--*/
+
+{
+ LARGE_INTEGER LargeLbo;
+ ARC_STATUS Status;
+ ULONG i;
+
+ //
+ // Special case the zero byte read request
+ //
+
+ if (ByteCount == 0) {
+
+ return ESUCCESS;
+ }
+
+ //
+ // Seek to the appropriate offset on the volume
+ //
+
+ LargeLbo.LowPart = Lbo;
+ LargeLbo.HighPart = 0;
+
+ if ((Status = ArcSeek( DeviceId, &LargeLbo, SeekAbsolute )) != ESUCCESS) {
+
+ return Status;
+ }
+
+ //
+ // Issue the arc read request
+ //
+
+ if ((Status = ArcRead( DeviceId, Buffer, ByteCount, &i)) != ESUCCESS) {
+
+ return Status;
+ }
+
+ //
+ // Make sure we got back the amount requested
+ //
+
+ if (ByteCount != i) {
+
+ return EIO;
+ }
+
+ //
+ // Everything is fine so return success to our caller
+ //
+
+ return ESUCCESS;
+}
+
+
+//
+// Internal support routine
+//
+
+VOID
+HpfsFirstComponent(
+ IN OUT PSTRING String,
+ OUT PSTRING FirstComponent
+ )
+
+/*++
+
+Routine Description:
+
+ This routine takes an input path name and separates it into its
+ first file name component and the remaining part.
+
+Arguments:
+
+ String - Supplies the original string being dissected. On return
+ this string will now point to the remaining part.
+
+ FirstComponent - Returns the string representing the first file name
+ in the input string.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG Index;
+
+ //
+ // Copy over the string variable into the first component variable
+ //
+
+ *FirstComponent = *String;
+
+ //
+ // Now if the first character in the name is a backslash then
+ // simply skip over the backslash.
+ //
+
+ if (FirstComponent->Buffer[0] == '\\') {
+
+ FirstComponent->Buffer += 1;
+ FirstComponent->Length -= 1;
+ }
+
+ //
+ // Now search the name for a backslash
+ //
+
+ for (Index = 0; Index < FirstComponent->Length; Index += 1) {
+
+ if (FirstComponent->Buffer[Index] == '\\') {
+
+ break;
+ }
+ }
+
+ //
+ // At this point Index denotes a backslash or is equal to the length
+ // of the string. So update string to be the remaining part.
+ // Decrement the length of the first component by the approprate
+ // amount
+ //
+
+ String->Buffer = &FirstComponent->Buffer[Index];
+ String->Length = (SHORT)(FirstComponent->Length - Index);
+
+ FirstComponent->Length = (SHORT)Index;
+
+ //
+ // And return to our caller.
+ //
+
+ return;
+}
+
+
+//
+// Internal support routine
+//
+
+COMPARISON_RESULTS
+HpfsCompareNames(
+ IN PSTRING Name1,
+ IN PSTRING Name2
+ )
+
+/*++
+
+Routine Description:
+
+ This routine takes two names and compare them ignoring case. This
+ routine does not do implied dot or dbcs processing.
+
+Arguments:
+
+ Name1 - Supplies the first name to compare
+
+ Name2 - Supplies the second name to compare
+
+Return Value:
+
+ LessThan if Name1 is lexically less than Name2
+ EqualTo if Name1 is lexically equal to Name2
+ GreaterThan if Name1 is lexically greater than Name2
+
+--*/
+
+{
+ ULONG i;
+ ULONG MinimumLength;
+
+ //
+ // Compute the smallest of the two name lengths
+ //
+
+ MinimumLength = (Name1->Length < Name2->Length ? Name1->Length : Name2->Length);
+
+ //
+ // Now compare each character in the names.
+ //
+
+ for (i = 0; i < MinimumLength; i += 1) {
+
+ if ((UCHAR)(ToUpper(Name1->Buffer[i])) < (UCHAR)(ToUpper(Name2->Buffer[i]))) {
+
+ return LessThan;
+ }
+
+ if ((UCHAR)(ToUpper(Name1->Buffer[i])) > (UCHAR)(ToUpper(Name2->Buffer[i]))) {
+
+ return GreaterThan;
+ }
+ }
+
+ //
+ // The names compared equal up to the smallest name length so
+ // now check the name lengths
+ //
+
+ if (Name1->Length < Name2->Length) {
+
+ return LessThan;
+ }
+
+ if (Name1->Length > Name2->Length) {
+
+ return GreaterThan;
+ }
+
+ return EqualTo;
+}
+
+
+//
+// Internal support routine
+//
+
+ARC_STATUS
+HpfsSearchDirectory(
+ IN LBN Fnode,
+ IN PSTRING Name,
+ OUT PBOOLEAN IsDirectory,
+ OUT PLBN FoundLbn,
+ OUT PULONG FileSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine searches the indicated directory for a matching name
+
+Arguments:
+
+ Fnode - Supplies the fnode of the directory to search
+
+ Name - Supplies the name to search for
+
+ Directory - Recieves an indication of the found file is a directory
+ or a file.
+
+ FoundLbn - Receives the lbn of the fnode for the file/directory if
+ one is found.
+
+ FileSize - Receives the size of the file if one is found.
+
+Return Value:
+
+ ESUCCESS is returned if the operation is successful. Otherwise,
+ an unsuccessful status is returned that describes the reason for failure.
+
+--*/
+
+{
+ ARC_STATUS Status;
+
+ ULONG DeviceId;
+
+ UCHAR UnalignedFnodeSector[SECTOR_SIZE+256];
+ UCHAR UnalignedDirDiskBuffer[(SECTOR_SIZE*4)+256];
+
+ PFNODE_SECTOR FnodeSector;
+ PDIRECTORY_DISK_BUFFER DirDiskBuffer;
+
+ LBN DirDiskBufferLbn;
+
+ PPBDIRENT Dirent;
+
+ //
+ // Compute the properly aligned buffers for reading in our sectors
+ //
+
+ FnodeSector = ALIGN_BUFFER(UnalignedFnodeSector);
+ DirDiskBuffer = ALIGN_BUFFER(UnalignedDirDiskBuffer);
+
+ //
+ // Capture the device id from our global variable
+ //
+
+ DeviceId = HpfsFileTableEntry->DeviceId;
+
+ //
+ // Read in the fnode for the directory, and check that it is real
+ //
+
+ if ((Status = HpfsReadDisk(DeviceId, Fnode * 512, 512, FnodeSector)) != ESUCCESS) {
+
+ return Status;
+ }
+
+ if (FnodeSector->Signature != FNODE_SECTOR_SIGNATURE) {
+
+ return EIO;
+ }
+
+ //
+ // Now setup the lbn for the first dir disk buffer
+ //
+
+ DirDiskBufferLbn = FnodeSector->Allocation.Leaf[0].Lbn;
+
+ //
+ // the following loop is executed until we either find our entry
+ // or have gone past where it could possible be
+ //
+
+ while (TRUE) {
+
+ BOOLEAN ReadNewDirDiskBuffer;
+
+ //
+ // Read in the next dir disk buffer, and check that it is real
+ //
+
+ if ((Status = HpfsReadDisk( DeviceId,
+ DirDiskBufferLbn * 512,
+ 512 * 4,
+ DirDiskBuffer )) != ESUCCESS) {
+
+ return Status;
+ }
+
+ if (DirDiskBuffer->Signature != DIRECTORY_DISK_BUFFER_SIGNATURE) {
+
+ return EIO;
+ }
+
+ //
+ // Search each dirent in the dir disk buffer, we continue the
+ // loop until we either exit or read new dir disk buffer is set
+ // to true.
+ //
+
+ ReadNewDirDiskBuffer = FALSE;
+
+ for ( Dirent = (PPBDIRENT)GetFirstDirent( DirDiskBuffer );
+ !ReadNewDirDiskBuffer;
+ Dirent = (PPBDIRENT)GetNextDirent( Dirent )) {
+
+ STRING String;
+ COMPARISON_RESULTS CompareResults;
+
+ //
+ // Get a string for the file name in the dirent and then
+ // compare the names against each other
+ //
+
+ String.Length = Dirent->FileNameLength;
+ String.Buffer = &Dirent->FileName[0];
+
+ CompareResults = HpfsCompareNames( Name, &String );
+
+ //
+ // If the names are equal then we've found our match and we
+ // need to figure out if this is a directory, store the
+ // found fnode and return success
+ //
+
+ if (CompareResults == EqualTo) {
+
+ *IsDirectory = FlagOn(Dirent->FatFlags, FAT_DIRENT_ATTR_DIRECTORY);
+
+ *FoundLbn = Dirent->Fnode;
+ *FileSize = Dirent->FileSize;
+
+ return ESUCCESS;
+
+ //
+ // If the results is less than then we've gone too far in
+ // the current dir disk buffer. If we have a down pointer then
+ // there are other buffers to search through otherwise the
+ // name doesn't exist in the directory
+ //
+
+ } else if (CompareResults == LessThan) {
+
+ if (FlagOn(Dirent->Flags, DIRENT_BTREE_POINTER)) {
+
+ //
+ // Compute the new dir disk buffer to search and
+ // indicate to the for loop that we need to read in
+ // another dir disk buffer
+ //
+
+ DirDiskBufferLbn = GetBtreePointerInDirent( Dirent );
+
+ ReadNewDirDiskBuffer = TRUE;
+
+ } else {
+
+ //
+ // We didn't find the name in the directory
+ //
+
+ return ENOENT;
+ }
+
+ //
+ // Otherwise the result is greater than which means we need to
+ // compare against the next dirent.
+ //
+
+ } else {
+
+ NOTHING;
+ }
+ }
+ }
+}
+
+
+//
+// Internal support routine
+//
+
+ARC_STATUS
+HpfsLoadMcb(
+ IN LBN Fnode,
+ IN VBN StartingVbn
+ )
+
+/*++
+
+Routine Description:
+
+ This routine loads into our cache (i.e., structure context's boot mcb)
+ the retrieval information for the starting vbn.
+
+Arguments:
+
+ Fnode - Supplies the lbn for the fnode for the file we're reading
+
+ StartingVbn - Supplies the Vbn that we want to load
+
+Return Value:
+
+ ESUCCESS is returned if the operation is successful. Otherwise,
+ an unsuccessful status is returned that describes the reason for failure.
+
+--*/
+
+{
+ ARC_STATUS Status;
+
+ PHPFS_BOOT_MCB Mcb = &HpfsStructureContext->BootMcb;
+ ULONG DeviceId;
+
+ UCHAR UnalignedFnodeSector[SECTOR_SIZE+256];
+ UCHAR UnalignedAllocationSector[SECTOR_SIZE+256];
+
+ PFNODE_SECTOR FnodeSector;
+ PALLOCATION_SECTOR AllocationSector;
+
+ PALLOCATION_HEADER AllocationHeader;
+ PALLOCATION_LEAF Leafs;
+ PALLOCATION_NODE Nodes;
+
+ ULONG i;
+
+ //
+ // Compute the properly aligned buffers for reading in our sectors
+ //
+
+ FnodeSector = ALIGN_BUFFER(UnalignedFnodeSector);
+ AllocationSector = ALIGN_BUFFER(UnalignedAllocationSector);
+
+ //
+ // Capture the device id from our global variable
+ //
+
+ DeviceId = HpfsFileTableEntry->DeviceId;
+
+ //
+ // Read in the fnode for the file, and check that it is real
+ //
+
+ if ((Status = HpfsReadDisk(DeviceId, Fnode * 512, 512, FnodeSector)) != ESUCCESS) {
+
+ return Status;
+ }
+
+ if (FnodeSector->Signature != FNODE_SECTOR_SIGNATURE) {
+
+ return EIO;
+ }
+
+ //
+ // Setup the allocation header, leafs and nodes
+ //
+
+ AllocationHeader = &FnodeSector->AllocationHeader;
+ Leafs = &FnodeSector->Allocation.Leaf[0];
+ Nodes = &FnodeSector->Allocation.Node[0];
+
+ //
+ // While we have nodes and not leafs we need to search for the entry
+ // containing our starting vbn and then subsearch in that allocation
+ // sector
+ //
+
+ while (FlagOn(AllocationHeader->Flags, ALLOCATION_BLOCK_NODE)) {
+
+ for (i = 0; i < AllocationHeader->OccupiedCount; i += 1) {
+
+ if (StartingVbn < Nodes[i].Vbn) {
+
+ //
+ // We found a node that contains our starting vbn so
+ // read in the next allocation sector and check that
+ // it is real.
+
+ if ((Status = HpfsReadDisk( DeviceId,
+ Nodes[i].Lbn * 512,
+ 512,
+ AllocationSector )) != ESUCCESS) {
+
+ return Status;
+ }
+
+ if (AllocationSector->Signature != ALLOCATION_SECTOR_SIGNATURE) {
+
+ return EIO;
+ }
+
+ //
+ // Setup the allocation header, leafs and nodes, and then
+ // break out of the for loop and let our while loop check
+ // if we have allocation leafs or nodes.
+ //
+
+ AllocationHeader = &AllocationSector->AllocationHeader;
+ Leafs = &AllocationSector->Allocation.Leaf[0];
+ Nodes = &AllocationSector->Allocation.Node[0];
+
+ break;
+ }
+ }
+ }
+
+ //
+ // Now the allocation header indictes that we have leaf entries
+ // so we can simply load up the cached mcb. We set the in use here
+ // The most entries we'll ever preload is the maximum available in
+ // an allocation sector (i.e., 40).
+ //
+
+ Mcb->InUse = AllocationHeader->OccupiedCount;
+
+ for (i = 0; i < AllocationHeader->OccupiedCount; i += 1) {
+
+ //
+ // For each entry we set the vbn and lbn value. We also
+ // set the next vbn value to get the size of the run.
+ // This means that we'll really be double setting each vbn
+ // value (except the first and last entry) but that's okay
+ // because they better compute the same value
+ //
+
+ Mcb->Vbn[i] = Leafs[i].Vbn;
+ Mcb->Lbn[i] = Leafs[i].Lbn;
+ Mcb->Vbn[i+1] = Leafs[i].Vbn + Leafs[i].Length;
+ }
+
+ //
+ // We're all done so return success to our caller
+ //
+
+ return ESUCCESS;
+}
+
+
+//
+// Internal support routine
+//
+
+ARC_STATUS
+HpfsVbnToLbn(
+ IN VBN Vbn,
+ OUT PLBN Lbn,
+ OUT PULONG ByteCount
+ )
+
+/*++
+
+Routine Description:
+
+ This routine computes the run denoted by the input vbn to into its
+ corresponding lbn and also returns the number of bytes remaining in
+ the run. For all cases this byte count will be a multiple of 512.
+
+Arguments:
+
+ Vbn - Supplies the Vbn to match
+
+ Lbn - Recieves the corresponding Lbn
+
+ ByteCount - Receives the number of bytes remaining in the run
+
+Return Value:
+
+ ESUCCESS is returned if the operation is successful. Otherwise,
+ an unsuccessful status is returned that describes the reason for failure.
+
+--*/
+
+{
+ ARC_STATUS Status;
+
+ PHPFS_BOOT_MCB Mcb = &HpfsStructureContext->BootMcb;
+ ULONG i;
+
+ //
+ // Check if the boot mcb has the range we're asking for. If it
+ // doesn't then call load mcb to load in the right range.
+ //
+
+ if ((Vbn < Mcb->Vbn[0]) || (Vbn >= Mcb->Vbn[Mcb->InUse])) {
+
+ if ((Status = HpfsLoadMcb(HpfsStructureContext->Fnode, Vbn)) != ESUCCESS) {
+
+ return Status;
+ }
+ }
+
+ //
+ // Now search for the slot where the Vbn fits in the mcb. Note that
+ // we could also do a binary search here but because the run count
+ // is probably small the extra overhead of a binary search doesn't
+ // buy us anything
+ //
+
+ for (i = 0; i < Mcb->InUse; i += 1) {
+
+ //
+ // We found our slot if the vbn we're after is less then the
+ // next mcb's vbn
+ //
+
+ if (Vbn < Mcb->Vbn[i+1]) {
+
+ //
+ // Compute the corresponding lbn which is the stored lbn plus
+ // the difference between the stored vbn and the vbn we're
+ // looking up. Also compute the byte count which is the
+ // difference between the current vbn we're looking up and
+ // the vbn for the next run, all multiplied by 512.
+ //
+
+ *Lbn = Mcb->Lbn[i] + (Vbn - Mcb->Vbn[i]);
+
+ *ByteCount = (Mcb->Vbn[i+1] - Vbn) * 512;
+
+ //
+ // and return success to our caller
+ //
+
+ return ESUCCESS;
+ }
+ }
+
+ //
+ // If we really reach here we have an error in the mcb
+ //
+
+ return EIO;
+}
diff --git a/private/ntos/boot/lib/i386/abios.h b/private/ntos/boot/lib/i386/abios.h
new file mode 100644
index 000000000..5ce7b9419
--- /dev/null
+++ b/private/ntos/boot/lib/i386/abios.h
@@ -0,0 +1,175 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ abios.h
+
+Abstract:
+
+ This module contains the i386 ABIOS specific header file.
+
+Author:
+
+ Shie-Lin Tzong (shielint) 16-May-1991
+
+Revision History:
+
+--*/
+
+//
+// Virtual addresses of ABIOS ROM code Segments
+//
+
+#define ABIOS_ROM_C0000 0xC0000
+#define ABIOS_ROM_E0000 0xE0000
+#define ABIOS_ROM_F0000 0xF0000
+
+//
+// Function Number of ABIOS services
+//
+
+#define ABIOS_SERVICE_ABIOS_DETECTION 0
+#define ABIOS_SERVICE_MACHINE_INFOR 1
+#define ABIOS_SERVICE_INITIALIZE_SPT 2
+#define ABIOS_SERVICE_BUILD_IT 3
+#define ABIOS_SERVICE_INIT_DB_FTT 4
+#define ABIOS_GDT_SELECTOR_START 0x100
+
+typedef struct _ADDRESS {
+ USHORT LowPart;
+ union {
+ USHORT Segment;
+ USHORT Selector;
+ } HighPart;
+} ADDRESS, *PADDRESS;
+
+//
+// RAM Extentions Header definition
+//
+
+#define PATCH_FILE_BUFFER_SIZE 512
+#define PATCH_SIGNATURE 0xAA55
+#define PATCH_FILE_HEADER_SIZE sizeof(RAM_EXTENSION_HEADER)
+
+//
+// It is very important that ALL the ABIOS structures are packed.
+// So, All the structure definitions for ABIOS should be put in here.
+//
+
+#pragma pack(1) // Turn ON Packing
+
+typedef struct _RAM_EXTENSION_HEADER {
+ USHORT Signature;
+ UCHAR NumberBlocks;
+ UCHAR Model;
+ UCHAR Submodel;
+ UCHAR RomRevision;
+ USHORT DeviceId;
+ UCHAR NumberInitializationEntries;
+ UCHAR Reserved[7];
+} RAM_EXTENSION_HEADER, *PRAM_EXTENSION_HEADER;
+
+//
+// ABIOS Initialization Table definitions
+//
+
+#define INITIALIZATION_TABLE_ENTRY_SIZE 0x18
+
+typedef struct _INIT_TABLE_ENTRY {
+ USHORT DeviceId;
+ USHORT NumberLids;
+ USHORT DeviceBlockLength;
+ ULONG InitializeRoutine;
+ USHORT RequestBlockLength;
+ USHORT FttLength;
+ USHORT DataPointerLength;
+ UCHAR SecondDeviceId;
+ UCHAR Revision;
+ USHORT Reserved[3];
+} INIT_TABLE_ENTRY, *PINIT_TABLE_ENTRY;
+
+//
+// ABIOS Function Transfer Table definition
+//
+
+typedef struct _FUNCTION_TRANSFER_TABLE {
+ ULONG CommonRoutine[3];
+ USHORT FunctionCount;
+ USHORT Reserved;
+ ULONG SpecificRoutine;
+} FUNCTION_TRANSFER_TABLE, *PFUNCTION_TRANSFER_TABLE;
+
+//
+// ABIOS Commom Data Area definitions
+//
+
+typedef struct _DATA_POINTER_SECTION {
+ USHORT DataPointerLimit;
+ union {
+ ADDRESS VirtualPointer;
+ PVOID PhysicalPointer;
+ } DataPointer;
+} DATA_POINTER_SECTION, *PDATA_POINTER_SECTION;
+
+typedef struct _DB_FTT_SECTION {
+ ADDRESS DeviceBlockPointer;
+ ADDRESS FttPointer;
+} DB_FTT_SECTION, *PDB_FTT_SECTION;
+
+typedef struct _COMMON_DATA_AREA {
+ USHORT DataPointer0Offset;
+ USHORT NumberLids;
+ ULONG Reserved;
+ PDB_FTT_SECTION DbFttPointer;
+} COMMON_DATA_AREA, *PCOMMON_DATA_AREA;
+
+#pragma pack()
+
+//
+// Available GDT Entry
+//
+
+typedef struct _FREE_GDT_ENTRY {
+ struct _FREE_GDT_ENTRY *Flink;
+ ULONG BaseMid : 8;
+ ULONG Type : 5;
+ ULONG Dpl : 2;
+ ULONG Present : 1;
+ ULONG LimitHi : 4;
+ ULONG Sys : 1;
+ ULONG Reserved_0 : 1;
+ ULONG Default_Big : 1;
+ ULONG Granularity : 1;
+ ULONG BaseHi : 8;
+} FREE_GDT_ENTRY, *PFREE_GDT_ENTRY;
+
+typedef struct _MACHINE_INFORMATION {
+ UCHAR Model;
+ UCHAR Submodel;
+ UCHAR BiosRevision;
+ BOOLEAN Valid;
+} MACHINE_INFORMATION, *PMACHINE_INFORMATION;
+
+//
+// Macro to extract the high byte of a short offset
+//
+
+#define HIGHBYTE(l) ((UCHAR)(((USHORT)(l)>>8) & 0xff))
+
+//
+// Macro to extract the low byte of a short offset
+//
+
+#define LOWBYTE(l) ((UCHAR)(l))
+
+//
+// Misc definitions
+//
+
+#define END_OF_FILE 0x1A
+#define LINE_FEED 0xA
+#define CARRAGE_RETURN 0xD
+
+
diff --git a/private/ntos/boot/lib/i386/abiosc.c b/private/ntos/boot/lib/i386/abiosc.c
new file mode 100644
index 000000000..a85695d1f
--- /dev/null
+++ b/private/ntos/boot/lib/i386/abiosc.c
@@ -0,0 +1,1307 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ abiosc.c
+
+Abstract:
+
+ This module implements ABIOS support C routines for i386 NT.
+
+Author:
+
+ Shie-Lin Tzong (shielint) 7-May-1991
+
+Environment:
+
+ Boot loader privileged, FLAT mode.
+
+
+Revision History:
+
+--*/
+
+#include <bootx86.h>
+#include <memory.h>
+#include <string.h>
+#include "abios.h"
+
+//
+// NOTE The TYPE_CODE in ntos\inc\i386.h is incorrect for abios code
+// segment. So, I define a correct value here.
+//
+
+#define ABIOS_TYPE_CODE 0x1a
+
+
+extern UCHAR BootPartitionName[];
+PCOMMON_DATA_AREA CommonDataArea = NULL;
+
+static MACHINE_INFORMATION MachineInformation;
+static USHORT NumberFreeSelectors;
+static PFREE_GDT_ENTRY FreeGdtListHead;
+static PFUNCTION_TRANSFER_TABLE FuncTransferTables;
+static PUCHAR DeviceBlocks;
+static USHORT CdaSize;
+static USHORT FttsLength = 0;
+static USHORT DeviceBlocksLength = 0;
+static USHORT DataPointersLength = 0;
+static PUCHAR RamExtension = NULL;
+static ULONG GdtAddress;
+
+VOID
+ConvertFtt (
+ IN PFUNCTION_TRANSFER_TABLE FunctionTransferTable
+ );
+
+BOOLEAN
+LoadRamExtensions (
+ IN VOID
+ );
+
+USHORT
+AllocateGdtSelector (
+ VOID
+ );
+
+USHORT
+SearchGdtSelector (
+ IN ULONG BaseAddress,
+ IN USHORT Limit,
+ IN UCHAR Type
+ );
+
+USHORT
+MapVirtualAddress (
+ IN USHORT Selector,
+ IN ULONG BaseAddress,
+ IN BOOLEAN CodeSegment,
+ IN ULONG Length
+ );
+
+ARC_STATUS
+DetermineFileSize(
+ IN ULONG FileId,
+ OUT PULONG FileSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines the size of the specified file.
+
+Arguments:
+
+ FileId - Supplies the file id. Caller must ensure the fileId
+ is opened for read (at least)
+
+ FileSize - Supplies a pointer to a variable which will receive
+ the length of the file.
+
+Return Value:
+
+ Return the ARC_STATUS code.
+
+--*/
+
+{
+ ULONG Size;
+ ARC_STATUS Status;
+ UCHAR LocalBuffer[SECTOR_SIZE];
+ ULONG Count;
+ LARGE_INTEGER SeekPosition;
+
+ //
+ // Determine the length of the file by reading to the end of
+ // file.
+ //
+
+ Size = 0;
+ SeekPosition.QuadPart = 0;
+ Status = BlSeek(FileId,
+ &SeekPosition,
+ SeekAbsolute);
+ if (Status != ESUCCESS) {
+ return(Status);
+ }
+
+ do {
+ Status = BlRead(FileId, LocalBuffer, SECTOR_SIZE, &Count);
+ if (Status != ESUCCESS) {
+ return Status;
+ }
+ Size += Count;
+ } while (Count == SECTOR_SIZE);
+
+ SeekPosition.QuadPart = 0;
+ Status = BlSeek(FileId,
+ &SeekPosition,
+ SeekAbsolute);
+ *FileSize = Size;
+ return(Status);
+}
+
+BOOLEAN
+LoadRamExtensions (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This function loads ABIOS RAM extensions.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE - If the operation is success. Otherwise, a value of FALSE is
+ returned.
+
+--*/
+
+{
+ PCHAR AbiosSys = "\\ABIOS.SYS";
+ PCHAR Device80 = "multi(0)disk(0)rdisk(0)partition(1)";
+ PCHAR AbiosPartition;
+ PCHAR PatchFileList;
+ PCHAR PatchFileName, NextPatchFileName;
+ PRAM_EXTENSION_HEADER PatchFileHeader;
+ ULONG TotalPatchSize, FileSize, BytesRead;
+ ULONG DriveId, FileId;
+ ARC_STATUS Status;
+ PUCHAR PatchAddress;
+ BOOLEAN ReturnCode = TRUE;
+
+ AbiosPartition = BootPartitionName;
+
+TryAgain:
+
+ //
+ // Open ABIOS.SYS. Allocate buffer to read in ABIOS.SYS.
+ // Allocate 512 bytes for patch file header.
+ //
+
+ Status = ArcOpen(AbiosPartition, ArcOpenReadOnly, &DriveId);
+ if (Status != ESUCCESS) {
+// BlPrint("ABIOS: Couldn't open Boot Drive, status = %x\n", Status);
+ return(FALSE);
+ }
+
+ Status = BlOpen( DriveId,
+ AbiosSys,
+ ArcOpenReadOnly,
+ &FileId );
+
+ if (Status != ESUCCESS) {
+ if (strstr(AbiosPartition, "fdisk") != NULL) {
+
+ //
+ // Boot device is floppy. We need to try to read the abios.sys
+ // from c:.
+ //
+
+ AbiosPartition = Device80;
+ goto TryAgain;
+ } else {
+ goto CloseAndExit;
+ }
+ }
+
+ if ((Status = DetermineFileSize(FileId, &FileSize)) != ESUCCESS) {
+ BlPuts("ABIOS: Could not read ABIOS.sys\n");
+ BlClose(FileId);
+ ReturnCode = FALSE;
+ goto CloseAndExit;
+ }
+
+ PatchFileList = FwAllocateHeap(FileSize + 2);
+ PatchFileHeader = FwAllocateHeap(PATCH_FILE_BUFFER_SIZE);
+ if (PatchFileHeader == NULL || PatchFileList == NULL) {
+ BlClose(FileId);
+ BlPuts("ABIOS: Unable to allocate Heap for Patch.\n");
+ ReturnCode = FALSE;
+ goto CloseAndExit;
+ }
+ Status = BlRead(FileId,
+ PatchFileList,
+ FileSize,
+ &BytesRead
+ );
+
+ if (Status != ESUCCESS || BytesRead != FileSize) {
+ BlClose(FileId);
+ BlPuts("ABIOS: Error reading ABIOS.SYS.\n");
+ ReturnCode = FALSE;
+ goto CloseAndExit;
+ }
+ *(PatchFileList + FileSize) = END_OF_FILE;
+ *(PatchFileList + FileSize + 1) = END_OF_FILE;
+ BlClose(FileId); // Close ABIOS.SYS
+
+ //
+ // For each patch file listed in the abios.sys, we read in its
+ // patch header (first 512 bytes) and examine if we should load
+ // this patch. At the end of the loop, we will be able to know
+ // the global size of the ABIOS extension required.
+ //
+
+ TotalPatchSize = PATCH_FILE_HEADER_SIZE; // For the Last empty header
+
+ //
+ // Scan the name buffer; skip all the blacks, LFs, CRs and zeros.
+ //
+
+ while (*PatchFileList == LINE_FEED ||
+ *PatchFileList == CARRAGE_RETURN ||
+ *PatchFileList == ' ' ||
+ *PatchFileList == '\t' ||
+ *PatchFileList == 0) {
+ PatchFileList++;
+ }
+ NextPatchFileName = PatchFileList;
+
+ while (*NextPatchFileName != END_OF_FILE) {
+ PatchFileName = NextPatchFileName;
+
+ while (*NextPatchFileName != LINE_FEED &&
+ *NextPatchFileName != CARRAGE_RETURN &&
+ *NextPatchFileName != 0 &&
+ *NextPatchFileName != '\t' &&
+ *NextPatchFileName != ' ') {
+ NextPatchFileName++;
+ }
+ *NextPatchFileName++ = 0; // make ASCIIZ filename
+ if ((Status = BlOpen(DriveId, PatchFileName, ArcOpenReadOnly, &FileId))
+ == ESUCCESS) {
+ Status = DetermineFileSize(FileId, &FileSize);
+ if (Status == ESUCCESS) {
+ Status = BlRead(FileId,
+ (PUCHAR)PatchFileHeader,
+ PATCH_FILE_BUFFER_SIZE,
+ &BytesRead
+ );
+ if (Status == ESUCCESS &&
+ (BytesRead == PATCH_FILE_BUFFER_SIZE ||BytesRead == FileSize)) {
+
+ //
+ // Make sure the patch is for this particular machine.
+ //
+
+ if ((PatchFileHeader->Signature == PATCH_SIGNATURE) &&
+ (PatchFileHeader->Model == MachineInformation.Model ||
+ PatchFileHeader->Model == 0 ) &&
+ (PatchFileHeader->Submodel == MachineInformation.Submodel ||
+ PatchFileHeader->Submodel == 0) &&
+ (PatchFileHeader->RomRevision == MachineInformation.BiosRevision ||
+ PatchFileHeader->RomRevision == 0)) {
+
+ TotalPatchSize += (ULONG)PatchFileHeader->NumberBlocks * SECTOR_SIZE;
+ } else {
+ Status = ESUCCESS + 1;
+ }
+ } else {
+ Status = ESUCCESS + 1;
+ }
+ }
+ BlClose(FileId);
+ }
+
+ //
+ // If fails, remove the name from our patch file list.
+ //
+
+ if (Status != ESUCCESS) {
+ while (*PatchFileName != 0) {
+ *PatchFileName++= 0;
+ }
+ }
+ while (*NextPatchFileName == LINE_FEED ||
+ *NextPatchFileName == CARRAGE_RETURN ||
+ *NextPatchFileName == ' ' ||
+ *NextPatchFileName == '\t' ||
+ *NextPatchFileName == 0) {
+ NextPatchFileName++;
+ }
+ }
+
+ //
+ // If No Ram Extension To load, simply return.
+ //
+
+ if (TotalPatchSize == PATCH_FILE_HEADER_SIZE) {
+ goto CloseAndExit;
+ }
+
+ //
+ // Allocate permanent memory for RAM Extension.
+ //
+ // NOTE: The RamExtension memory MUST be identity mapped, i.e.
+ // Virtual address == Physical Address
+ //
+
+ RamExtension = (PUCHAR)FwAllocateHeapPermanent(
+ ROUND_UP(TotalPatchSize, PAGE_SIZE) >> PAGE_SHIFT
+ );
+ if (!RamExtension) {
+ BlPuts("ABIOS: Not enough memory for RAM extensions\n");
+ ReturnCode = FALSE;
+ goto CloseAndExit;
+ }
+
+ //
+ // Read in the patch files in the order in which they are listed in
+ // the ABIOS.SYS
+ //
+
+ NextPatchFileName = PatchFileList;
+ PatchAddress = RamExtension;
+ while (*NextPatchFileName != END_OF_FILE) {
+ PatchFileName = NextPatchFileName;
+
+ //
+ // Move next patch file pointer to the end of current file name
+ //
+
+ while (*NextPatchFileName != 0) {
+ NextPatchFileName++;
+ }
+
+ if ((Status = BlOpen(DriveId, PatchFileName, ArcOpenReadOnly, &FileId))
+ == ESUCCESS) {
+ Status = DetermineFileSize(FileId, &FileSize);
+ if (Status == ESUCCESS) {
+ Status = BlRead(FileId,
+ PatchAddress,
+ FileSize,
+ &BytesRead
+ );
+ }
+ if (Status == ESUCCESS && BytesRead == FileSize) {
+ PatchAddress += FileSize;
+ }
+ BlClose(FileId);
+ }
+
+ //
+ // Skip leading garbage.
+ //
+
+ while (*NextPatchFileName == LINE_FEED ||
+ *NextPatchFileName == CARRAGE_RETURN ||
+ *NextPatchFileName == ' ' ||
+ *NextPatchFileName == '\t' ||
+ *NextPatchFileName == 0) {
+ NextPatchFileName++;
+ }
+ }
+
+ //
+ // Create an empty RAM extension header to serve as the end patch.
+ //
+
+ ((PRAM_EXTENSION_HEADER)PatchAddress)->Signature = PATCH_SIGNATURE;
+ ((PRAM_EXTENSION_HEADER)PatchAddress)->NumberBlocks = 0;
+CloseAndExit:
+ BlClose(FileId);
+ return ReturnCode;
+
+}
+
+BOOLEAN
+AbiosBuildRealModeCda (
+ IN USHORT NumberInitTableEntries,
+ IN PINIT_TABLE_ENTRY InitializationTable
+ )
+
+/*++
+
+Routine Description:
+
+ This function builds Real Mode ABIOS Common Data Area. It computes
+ the sizes of CDA, Function transfer tables, and Device Blocks. Memory
+ is then allocated for these tables. ABIOS Device Block and Ftt
+ initialization routines are invoked to do the actual work.
+
+Arguments:
+
+ NumberInitTableEntry - Supplies the number of Init Table Entries.
+
+ InitializationTable - Supplies the pointer to Initialization Table.
+
+Return Value:
+
+ TRUE - If the operation is success. Otherwise, a value of FALSE is
+ returned.
+
+--*/
+
+{
+
+ USHORT i;
+ PINIT_TABLE_ENTRY InitTableEntry;
+ USHORT NumberLids = 2; // includes Lid 0 and 1
+ PUCHAR FuncTransferTable;
+ PUCHAR DeviceBlock;
+ USHORT DeviceCount;
+ PDB_FTT_SECTION CdaPointer;
+ USHORT StartingLid;
+ BOOLEAN Success;
+
+ //
+ // Determine the sizes of Common Data Area, FTTs, Device Blocks
+ // Device Blocks are aligned on double word boundary.
+ //
+
+ InitTableEntry = InitializationTable;
+
+ for (i = 1; i <= NumberInitTableEntries; i++) {
+ NumberLids += InitTableEntry->NumberLids;
+ DeviceBlocksLength += ((InitTableEntry->DeviceBlockLength + 3) & ~3) *
+ InitTableEntry->NumberLids;
+ FttsLength += (InitTableEntry->FttLength + 3) & ~3;
+ DataPointersLength += InitTableEntry->DataPointerLength;
+ InitTableEntry++;
+ }
+
+ CdaSize = (USHORT)(NumberLids * 2 * sizeof(ULONG) + DataPointersLength + 2);
+
+ //
+ // Allocate memory blocks for Common Data Area, Function Transfer Tables,
+ // and Device Blocks. Then, we zero initialize common data area.
+ //
+
+ CommonDataArea = (PCOMMON_DATA_AREA)FwAllocateHeapPermanent(
+ ROUND_UP(CdaSize, PAGE_SIZE) >> PAGE_SHIFT
+ );
+ if (!CommonDataArea) {
+ BlPuts("ABIOS: Unable to allocate memory for Common Data Area.\n");
+ return FALSE;
+ }
+ FuncTransferTables = (PFUNCTION_TRANSFER_TABLE)FwAllocateHeapPermanent(
+ ROUND_UP(FttsLength, PAGE_SIZE) >> PAGE_SHIFT
+ );
+
+ if (!FuncTransferTables) {
+ BlPuts("ABIOS: Unable to allocate memory for Function Transfer tables.\n");
+ return FALSE;
+ }
+
+ DeviceBlocks = (PUCHAR)FwAllocateHeapPermanent(
+ ROUND_UP(DeviceBlocksLength, PAGE_SIZE) >> PAGE_SHIFT
+ );
+
+ if (!DeviceBlocks) {
+ BlPuts("ABIOS: Unable to allocate memory for Device Blocks.\n");
+ return FALSE;
+ }
+
+ memset((PVOID)CommonDataArea, 0, ROUND_UP(CdaSize, PAGE_SIZE));
+
+ //
+ // For each entry of Initialization table, we set up device blocks and
+ // function transfer table pointers in the CDA. Note, the initialization
+ // loop starts from logical id 2.
+ //
+
+ CommonDataArea->DataPointer0Offset = CdaSize - (USHORT)8;
+ CommonDataArea->NumberLids = NumberLids;
+ CdaPointer = (PDB_FTT_SECTION)&CommonDataArea->DbFttPointer + 1;
+ InitTableEntry = InitializationTable;
+ FuncTransferTable = (PUCHAR)FuncTransferTables;
+ DeviceBlock = DeviceBlocks;
+
+ for (i = 1; i <= NumberInitTableEntries; i++) {
+ DeviceCount = InitTableEntry->NumberLids;
+ while (DeviceCount != 0) {
+
+ //
+ // Each Lid of the same IT entry needs individual device block but
+ // is operated by the same Ftt.
+ //
+
+ if (InitTableEntry->FttLength) {
+ CdaPointer->FttPointer.LowPart =
+ LOWWORD(FuncTransferTable);
+ CdaPointer->FttPointer.HighPart.Segment =
+ HIGHWORD(FuncTransferTable) << 12;
+ }
+
+ if (InitTableEntry->DeviceBlockLength) {
+ CdaPointer->DeviceBlockPointer.LowPart =
+ LOWWORD(DeviceBlock);
+ CdaPointer->DeviceBlockPointer.HighPart.Segment =
+ HIGHWORD(DeviceBlock) << 12;
+ DeviceBlock += (InitTableEntry->DeviceBlockLength + 3 ) & ~3;
+ }
+ DeviceCount--;
+ CdaPointer++;
+ }
+ FuncTransferTable += (InitTableEntry->FttLength + 3) & ~3;
+ InitTableEntry++;
+ }
+
+ //
+ // Now switch to real mode and for each entry of Initialization Table,
+ // the corresponding DeviceBlock and Function transfer table initialization
+ // routine is called to initialize Device blocks and FTT.
+ //
+
+ CdaPointer = (PDB_FTT_SECTION)&CommonDataArea->DbFttPointer + 1;
+ InitTableEntry = InitializationTable;
+ StartingLid = 2;
+ for (i = 1; i <= NumberInitTableEntries; i++) {
+
+ Success = (BOOLEAN)ABIOS_SERVICES(
+ ABIOS_SERVICE_INIT_DB_FTT,
+ (PUCHAR)CommonDataArea,
+ NULL,
+ NULL,
+ (PUCHAR)InitTableEntry->InitializeRoutine,
+ StartingLid,
+ InitTableEntry->NumberLids
+ );
+
+ //
+ // If initialization of the device fails, we need to invalidate
+ // the device block and function transfer table pointers.
+ //
+
+ if (!Success) {
+ DeviceCount = InitTableEntry->NumberLids;
+ while (DeviceCount != 0) {
+
+ //
+ // Each Lid of the same IT entry needs individual device
+ // block but is operated by the same Ftt.
+ //
+
+ CdaPointer->FttPointer.LowPart = 0;
+ CdaPointer->FttPointer.HighPart.Segment = 0;
+ CdaPointer->DeviceBlockPointer.LowPart = 0;
+ CdaPointer->DeviceBlockPointer.HighPart.Segment = 0;
+ CdaPointer++;
+ DeviceCount--;
+ }
+ }
+ StartingLid += InitTableEntry->NumberLids;
+ CdaPointer += InitTableEntry->NumberLids;
+ InitTableEntry++;
+ }
+}
+
+BOOLEAN
+AbiosBuildProtectedModeCda (
+ IN PINIT_TABLE_ENTRY InitializationTable
+ )
+
+/*++
+
+Routine Description:
+
+ This function builds protected Mode ABIOS Common Data Area. Basically,
+ this routine simply converts the real mode addresses in the real mode
+ Commom Data Area to protected mode addresses. To do this, the following
+ steps are performed:
+
+ . Convert each real mode device block pointer to a protected mode device
+ block pointer.
+ . Convert each real mode function transfer table pointer to a protected
+ mode function transfer table pointer.
+ . Convert each real mode function pointer within each real mode function
+ transfer table to a protected mode function pointer.
+ . Convert each real mode data pointer to a protected mode data pointer.
+
+Arguments:
+
+ InitializationTable - supplies a pointer to Initialization Table
+
+Return Value:
+
+ TRUE - If the operation is success. Otherwise, a value of FALSE is
+ returned.
+
+--*/
+
+{
+
+ PDB_FTT_SECTION CdaPointer;
+ USHORT FttLength, DbLength;
+ USHORT FttSelector, DbSelector, DpSelector;
+ ULONG FttSelectorBase, DbSelectorBase;
+ PINIT_TABLE_ENTRY InitTableEntry;
+ USHORT CurrentLid = 2, NewItEntryLid;
+ USHORT NumberDataPointers, i;
+ PDATA_POINTER_SECTION CurrentDataPointer;
+ ULONG TablePointer;
+ BOOLEAN InitializeFtt = TRUE;
+
+ CdaPointer = (PDB_FTT_SECTION)((ULONG)CommonDataArea +
+ 2 * sizeof(DB_FTT_SECTION));
+ InitTableEntry = InitializationTable;
+ FttSelectorBase = (ULONG)FuncTransferTables;
+ DbSelectorBase = (ULONG)DeviceBlocks;
+ FttSelector = AllocateGdtSelector();
+ DbSelector = AllocateGdtSelector();
+ NewItEntryLid = CurrentLid + InitTableEntry->NumberLids;
+
+ while (CurrentLid < CommonDataArea->NumberLids) {
+
+ //
+ // Convert the Function Transfer Table pointers in CDA and then
+ // convert each routine pointer in Function transfer table.
+ //
+
+ TablePointer = ((ULONG)CdaPointer->FttPointer.HighPart.Segment << 4) |
+ (ULONG)CdaPointer->FttPointer.LowPart;
+ if (TablePointer) {
+
+ //
+ // If the current table accross 64K, we need to have a new
+ // selector for it.
+ //
+
+ if (TablePointer - FttSelectorBase > 64 * 1024) {
+ FttSelector = MapVirtualAddress(FttSelector,
+ FttSelectorBase,
+ FALSE,
+ (ULONG)FttLength
+ );
+ if (FttSelector == 0) {
+ return FALSE;
+ }
+ CdaPointer->FttPointer.LowPart = 0;
+ FttsLength -= FttLength;
+ FttSelector = AllocateGdtSelector();
+ FttSelectorBase = TablePointer;
+ } else {
+ CdaPointer->FttPointer.LowPart =
+ (USHORT)(TablePointer - FttSelectorBase);
+ FttLength = (USHORT)(TablePointer - FttSelectorBase);
+ if (CurrentLid == CommonDataArea->NumberLids - (USHORT)1) {
+ FttSelector = MapVirtualAddress(FttSelector,
+ FttSelectorBase,
+ FALSE,
+ (ULONG)FttsLength
+ );
+ FttLength = 0;
+ }
+ }
+ CdaPointer->FttPointer.HighPart.Selector = FttSelector;
+ if (InitializeFtt) {
+ ConvertFtt((PFUNCTION_TRANSFER_TABLE)TablePointer);
+ InitializeFtt = FALSE;
+ }
+ }
+
+ //
+ // Convert the Device Block pointers in CDA.
+ //
+
+ TablePointer = ((ULONG)CdaPointer->DeviceBlockPointer.HighPart.Segment << 4) |
+ (ULONG)CdaPointer->DeviceBlockPointer.LowPart;
+
+ if (TablePointer) {
+
+ //
+ // If the current table accross 64K, we need to have a new
+ // selector for it.
+ //
+
+ if (TablePointer - DbSelectorBase > 64 * 1024) {
+ DbSelector = MapVirtualAddress(DbSelector,
+ DbSelectorBase,
+ FALSE,
+ (ULONG)DbLength
+ );
+ if (DbSelector == 0) {
+ return FALSE;
+ }
+ CdaPointer->DeviceBlockPointer.LowPart = 0;
+ DeviceBlocksLength -= DbLength;
+ DbSelector = AllocateGdtSelector();
+ DbSelectorBase = TablePointer;
+ } else {
+ CdaPointer->DeviceBlockPointer.LowPart =
+ (USHORT)(TablePointer - DbSelectorBase);
+ DbLength = (USHORT)(TablePointer - DbSelectorBase);
+ if (CurrentLid == CommonDataArea->NumberLids - (USHORT)1) {
+ DbSelector = MapVirtualAddress(DbSelector,
+ DbSelectorBase,
+ FALSE,
+ (ULONG)DeviceBlocksLength
+ );
+ DeviceBlocksLength = 0;
+ }
+ }
+ CdaPointer->DeviceBlockPointer.HighPart.Selector = DbSelector;
+ }
+
+ CdaPointer++;
+ CurrentLid++;
+ if (CurrentLid == NewItEntryLid) {
+ InitTableEntry++;
+ NewItEntryLid += InitTableEntry->NumberLids;
+ InitializeFtt = TRUE;
+ }
+ }
+
+ //
+ // Now check if any part of Function transfer table or Debice block
+ // need to be mapped.
+ //
+
+ if (FttsLength) {
+ FttSelector = MapVirtualAddress(FttSelector,
+ FttSelectorBase,
+ FALSE,
+ (ULONG)FttsLength
+ );
+ }
+
+ if (DeviceBlocksLength) {
+ DbSelector = MapVirtualAddress(DbSelector,
+ DbSelectorBase,
+ FALSE,
+ (ULONG)DeviceBlocksLength
+ );
+ }
+
+ //
+ // Convert each Data pointer in RealMode CDA to protected mode pointer
+ //
+
+ CurrentDataPointer = (PDATA_POINTER_SECTION)((ULONG)CommonDataArea +
+ CommonDataArea->DataPointer0Offset);
+ NumberDataPointers = *(PUSHORT)((ULONG)CurrentDataPointer +
+ sizeof(DATA_POINTER_SECTION));
+ for (i = 1; i <= NumberDataPointers; i++) {
+ DpSelector = MapVirtualAddress(
+ (USHORT)0,
+ (ULONG)CurrentDataPointer->DataPointer.PhysicalPointer,
+ FALSE,
+ (ULONG)ROUND_UP(CurrentDataPointer->DataPointerLimit + 1, PAGE_SIZE)
+ );
+ CurrentDataPointer->DataPointer.VirtualPointer.LowPart = 0;
+ CurrentDataPointer->DataPointer.VirtualPointer.HighPart.Selector =
+ DpSelector;
+ CurrentDataPointer--;
+ }
+}
+
+VOID
+ConvertFtt (
+ IN PFUNCTION_TRANSFER_TABLE FunctionTransferTable
+ )
+
+/*++
+
+Routine Description:
+
+ This function goes through each entry of Function Transfer Table
+ to convert the real mode pointer to protected mode pointer.
+
+Arguments:
+
+ FunctionTransferTable - supplies a pointer to the function transfer
+ table to be converted.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PULONG FttEntry;
+ ULONG RoutinePointer;
+ PRAM_EXTENSION_HEADER RamHeader;
+ USHORT i, Selector;
+
+ //
+ // Convert the Start, Interrupt and Timeout routine pointers to
+ // protected mode addresses.
+ //
+
+ for (i = 0; i < 3; i++) {
+
+ RoutinePointer = FunctionTransferTable->CommonRoutine[i];
+ if (RoutinePointer != 0L) {
+ RamHeader = (PRAM_EXTENSION_HEADER)((RoutinePointer >> 16) << 4);
+ if (RamHeader->Signature == PATCH_SIGNATURE) {
+ Selector = SearchGdtSelector(
+ (ULONG)RamHeader,
+ (USHORT)(RamHeader->NumberBlocks * 512 - 1),
+ (UCHAR)ABIOS_TYPE_CODE
+ );
+ if (Selector == 0) {
+ Selector = MapVirtualAddress(
+ 0,
+ (ULONG)RamHeader,
+ TRUE,
+ (ULONG)(RamHeader->NumberBlocks * 512)
+ );
+ }
+ } else {
+ Selector = SearchGdtSelector((ULONG)RamHeader,
+ (USHORT)(64 * 1024 - 1),
+ (UCHAR)ABIOS_TYPE_CODE
+ );
+ if (Selector == 0) {
+ Selector = MapVirtualAddress(
+ 0,
+ (ULONG)RamHeader,
+ TRUE,
+ (ULONG)(64 * 1024)
+ );
+ }
+ }
+ FunctionTransferTable->CommonRoutine[i] = ((ULONG)Selector << 16) |
+ (ULONG)(LOWWORD(FunctionTransferTable->CommonRoutine[i]));
+ }
+ }
+
+ //
+ // Convert Device Specific routine pointers to protected mode addresses.
+ //
+
+ FttEntry = &FunctionTransferTable->SpecificRoutine;
+ for (i = 0; i < FunctionTransferTable->FunctionCount; i++) {
+ RoutinePointer = *FttEntry;
+ if (RoutinePointer != 0L) {
+ RamHeader = (PRAM_EXTENSION_HEADER)((RoutinePointer >> 16) << 4);
+ if (RamHeader->Signature == PATCH_SIGNATURE) {
+ Selector = SearchGdtSelector((ULONG)RamHeader,
+ (USHORT)(RamHeader->NumberBlocks * 512 - 1),
+ (UCHAR)ABIOS_TYPE_CODE
+ );
+ if (Selector == 0) {
+ Selector = MapVirtualAddress(
+ 0,
+ (ULONG)RamHeader,
+ TRUE,
+ (ULONG)(RamHeader->NumberBlocks * 512) );
+ }
+ } else {
+ Selector = SearchGdtSelector((ULONG)RamHeader,
+ (USHORT)(64 * 1024 - 1),
+ (UCHAR)ABIOS_TYPE_CODE
+ );
+ if (Selector == 0) {
+ Selector = MapVirtualAddress(
+ 0,
+ (ULONG)RamHeader,
+ TRUE,
+ (ULONG)(64 * 1024)
+ );
+ }
+ }
+ *FttEntry = ((ULONG)Selector << 16) | (ULONG)(LOWWORD(*FttEntry));
+ }
+ FttEntry++;
+ }
+}
+
+VOID
+InitializeGdtFreeList (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This function initializes gdt free list by linking all the unused gdt
+ entries to a free list.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ #pragma pack(2)
+ static struct {
+ USHORT Limit;
+ ULONG Base;
+ } GdtDef;
+ #pragma pack(4)
+
+ PFREE_GDT_ENTRY GdtEntry;
+
+ //
+ // Get the current location of the GDT
+ //
+
+ _asm {
+ sgdt GdtDef;
+ }
+
+ GdtAddress = GdtDef.Base;
+ NumberFreeSelectors = 0;
+
+ GdtEntry = (PFREE_GDT_ENTRY)(GdtAddress + GdtDef.Limit + 1 -
+ sizeof(FREE_GDT_ENTRY));
+ FreeGdtListHead = (PFREE_GDT_ENTRY)0;
+ while ((ULONG)GdtEntry >= GdtAddress + ABIOS_GDT_SELECTOR_START) {
+ if (GdtEntry->Present == 0) {
+ GdtEntry->Flink = FreeGdtListHead;
+ FreeGdtListHead = GdtEntry;
+ NumberFreeSelectors++;
+ }
+ GdtEntry--;
+ }
+}
+
+USHORT
+AllocateGdtSelector (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This function allocates a gdt selector from GDT.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A Gdt selector is returned if success. Otherwise, a value of 0 is
+ returned. (Zero is an invalid selector.)
+
+--*/
+
+{
+ PFREE_GDT_ENTRY GdtEntry;
+
+ if (NumberFreeSelectors) {
+ GdtEntry = FreeGdtListHead;
+ FreeGdtListHead = GdtEntry->Flink;
+ NumberFreeSelectors--;
+ return (USHORT)((ULONG)GdtEntry - GdtAddress);
+ } else {
+ BlPuts("ABIOS: Out of Gdt Selector.\n");
+ return 0;
+ }
+}
+
+USHORT
+SearchGdtSelector (
+ IN ULONG BaseAddress,
+ IN USHORT Limit,
+ IN UCHAR Type
+ )
+
+/*++
+
+Routine Description:
+
+ This function searches the gdt table for the Gdt selector entry which
+ has the base address and limit caller specified.
+
+ N.B. This routine handles 16 bit code and data selectors ONLY, i.e.,
+ the limit is always less than 64k. The search ends at the head
+ of free Gdt list. So, this is not GENERAL PURPOSE Gdt selector
+ search routine.
+
+Arguments:
+
+ BaseAddress - the base address of the desired Gdt Selector.
+
+ Limit - The Limit of the desired Gdt Selector.
+
+ Type - Code or Data selector
+
+Return Value:
+
+ A Gdt selector is returned if sguccess. Otherwise, a value of 0 is
+ returned. (Zero is an invalid selector.)
+
+--*/
+
+{
+ PKGDTENTRY GdtEntry;
+ ULONG SelectorBase;
+
+ GdtEntry = (PKGDTENTRY)(GdtAddress + ABIOS_GDT_SELECTOR_START);
+ while (GdtEntry != (PKGDTENTRY)FreeGdtListHead) {
+ if (GdtEntry->HighWord.Bits.Pres != 0 &&
+ GdtEntry->HighWord.Bits.LimitHi == 0 &&
+ GdtEntry->LimitLow == Limit &&
+ GdtEntry->HighWord.Bits.Type == Type) {
+ SelectorBase = (ULONG)GdtEntry->BaseLow |
+ (ULONG)GdtEntry->HighWord.Bytes.BaseMid << 16 |
+ (ULONG)GdtEntry->HighWord.Bytes.BaseHi << 24;
+ if (BaseAddress == SelectorBase) {
+ return (USHORT)((ULONG)GdtEntry - GdtAddress);
+ }
+ }
+ GdtEntry++;
+ }
+ return 0;
+}
+
+USHORT
+MapVirtualAddress (
+ IN USHORT Selector,
+ IN ULONG BaseAddress,
+ IN BOOLEAN CodeSegment,
+ IN ULONG Length
+ )
+
+/*++
+
+Routine Description:
+
+ This function allocates a gdt selector, if necessary, and map the
+ specified area to the gdt selector.
+
+Arguments:
+
+ Selector - Supplies a Gdt selector to set up the mapping. If 0, caller
+ does not supply the selector. this routine will allocate one.
+
+ BaseAddress - Base address of the Gdt selector.
+
+ CodeSegment - Indicates if this is for a code segment.
+
+ Length - the length of the area to be mapped.
+
+Return Value:
+
+ ReturnedSelector - If the operation is success. Otherwise, a value of 0
+ is returned.
+
+--*/
+
+{
+ PKGDTENTRY GdtEntry;
+ USHORT ReturnedSelector;
+
+ if (Selector == 0) {
+ if ((ReturnedSelector = AllocateGdtSelector()) == 0) {
+ return 0;
+ }
+ } else {
+ ReturnedSelector = Selector;
+ }
+
+ GdtEntry = (PKGDTENTRY)(GdtAddress + ReturnedSelector);
+ GdtEntry->LimitLow = (USHORT)(Length - 1L);
+ GdtEntry->BaseLow = LOWWORD(BaseAddress);
+ GdtEntry->HighWord.Bytes.BaseMid = LOWBYTE(HIGHWORD(BaseAddress));
+ GdtEntry->HighWord.Bytes.BaseHi = HIGHBYTE(HIGHWORD(BaseAddress));
+ if (CodeSegment) {
+ GdtEntry->HighWord.Bits.Type = ABIOS_TYPE_CODE;
+ } else {
+ GdtEntry->HighWord.Bits.Type = TYPE_DATA;
+ }
+ GdtEntry->HighWord.Bits.Pres = 1;
+ GdtEntry->HighWord.Bits.Dpl = DPL_SYSTEM;
+ return ReturnedSelector;
+}
+
+VOID
+RemapAbiosSelectors (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This function goes thru each ABIOS specific GDT entry, allocates
+ virtual memory and remaps the GDT entry to the newly allocated
+ virtual address.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PKGDTENTRY GdtEntry;
+ ULONG Size;
+ ULONG SelectorBase;
+
+ GdtEntry = (PKGDTENTRY)(GdtAddress + ABIOS_GDT_SELECTOR_START);
+ while (GdtEntry != (PKGDTENTRY)FreeGdtListHead) {
+ if (GdtEntry->HighWord.Bits.Pres == 1 ) {
+ Size = ((ULONG)GdtEntry->LimitLow & 0xffff) |
+ ((ULONG)(GdtEntry->HighWord.Bits.LimitHi << 16) & 0xf0000);
+ SelectorBase = ((ULONG)GdtEntry->BaseLow & 0xffff) |
+ ((ULONG)GdtEntry->HighWord.Bytes.BaseMid << 16 ) |
+ ((ULONG)GdtEntry->HighWord.Bytes.BaseHi << 24);
+ SelectorBase |= KSEG0_BASE;
+ GdtEntry->BaseLow = (USHORT)(SelectorBase & 0xffff);
+ GdtEntry->HighWord.Bytes.BaseMid =
+ (UCHAR)((SelectorBase & 0xff0000) >> 16);
+ GdtEntry->HighWord.Bytes.BaseHi =
+ (UCHAR)((SelectorBase & 0xff000000) >> 24);
+ }
+ GdtEntry++;
+ }
+ CommonDataArea = (PCOMMON_DATA_AREA)((ULONG)CommonDataArea | KSEG0_BASE);
+}
+
+VOID
+AbiosInitDataStructures (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This function performs ABIOS initialization by invoking ABIOS external
+ service routines to do real mode initialization and finally converting
+ real mode Common Data Area to protected mode Common Data Area.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ BOOLEAN Success;
+ USHORT NumberInitTableEntries;
+ PINIT_TABLE_ENTRY InitializationTable;
+ ULONG TempULong;
+
+ //
+ // Initialize CommonDataArea to NULL
+ //
+
+ CommonDataArea = NULL;
+
+ if (MachineType != MACHINE_TYPE_MCA) {
+ return;
+ }
+
+ //
+ // Try to collect machine model, submodel
+ // and Bios revision such that we can check the validity of Ram
+ // Extensions.
+ //
+
+ TempULong = ABIOS_SERVICES(
+ ABIOS_SERVICE_MACHINE_INFOR,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ 0,
+ 0
+ );
+ MachineInformation = *(PMACHINE_INFORMATION)&TempULong;
+ if (MachineInformation.Valid == FALSE) {
+ BlPuts("ABIOS: Can not identify machine model, BIOS revision.\n");
+ } else {
+
+ //
+ // Load RAM Extensions.
+ //
+
+ LoadRamExtensions();
+ }
+
+ //
+ // Initialize System Parameter Table to get number of initialization
+ // table entries.
+ //
+
+ NumberInitTableEntries = (USHORT)ABIOS_SERVICES (
+ ABIOS_SERVICE_INITIALIZE_SPT,
+ NULL,
+ NULL,
+ RamExtension,
+ NULL,
+ 0,
+ 0
+ );
+
+ if (NumberInitTableEntries == 0) {
+ return;
+ }
+
+ //
+ // Allocate Initialization Table memory and build ABIOS Initialization
+ // Table.
+ //
+
+ InitializationTable = (PINIT_TABLE_ENTRY)FwAllocateHeap(NumberInitTableEntries *
+ INITIALIZATION_TABLE_ENTRY_SIZE);
+
+ Success = (BOOLEAN)ABIOS_SERVICES (ABIOS_SERVICE_BUILD_IT,
+ NULL,
+ (PUCHAR)InitializationTable,
+ RamExtension,
+ NULL,
+ 0,
+ 0
+ );
+
+ if (!Success) {
+// BlPuts("ABIOS: cannot build Initialization Table.\n");
+ return;
+ }
+
+ //
+ // Build Real mode ABIOS Common Data Area, Device Blocks and Function
+ // transfer tables.
+ //
+
+ Success = AbiosBuildRealModeCda (NumberInitTableEntries,
+ InitializationTable
+ );
+
+ if (!Success) {
+ BlPuts("ABIOS: cannot build real mode Common Data Area.\n");
+ return;
+ }
+
+ //
+ // Before initializing protected mode Common Data Area, we need to
+ // set up the free gdt selector list.
+ //
+
+ InitializeGdtFreeList();
+
+ //
+ // Build protected mode ABIOS Common Data Area and free Initialization
+ // Table Space.
+ //
+
+ Success = AbiosBuildProtectedModeCda(InitializationTable);
+
+ if (!Success) {
+ BlPuts("ABIOS: cannot build protected mode Common Data Area.\n");
+ return;
+ }
+}
+
+
diff --git a/private/ntos/boot/lib/i386/arcemul.c b/private/ntos/boot/lib/i386/arcemul.c
new file mode 100644
index 000000000..c3c604c67
--- /dev/null
+++ b/private/ntos/boot/lib/i386/arcemul.c
@@ -0,0 +1,1789 @@
+/*++
+
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ arcemul.c
+
+Abstract:
+
+ This module provides the x86 emulation for the Arc routines which are
+ built into the firmware on ARC machines.
+
+ N. B. This is where all the initialization of the SYSTEM_PARAMETER_BLOCK
+ takes place. If there is any non-standard hardware, some of the
+ vectors may have to be changed. This is where to do it.
+
+
+Author:
+
+ John Vert (jvert) 13-Jun-1991
+
+Environment:
+
+ x86 only
+
+Revision History:
+
+--*/
+
+#include "arccodes.h"
+#include "bootx86.h"
+#include "ntdddisk.h"
+#include "string.h"
+#include "stdio.h"
+#include "stdlib.h"
+#include "scsi.h"
+#include "scsiboot.h"
+
+#define CMOS_CONTROL_PORT ((PUCHAR)0x70)
+#define CMOS_DATA_PORT ((PUCHAR)0x71)
+#define CMOS_STATUS_B 0x0B
+#define CMOS_DAYLIGHT_BIT 1
+
+extern PCHAR MnemonicTable[];
+
+//
+// Size definitions for HardDiskInitialize()
+//
+
+#define SUPPORTED_NUMBER_OF_DISKS 32
+#define SIZE_FOR_SUPPORTED_DISK_STRUCTURE (SUPPORTED_NUMBER_OF_DISKS*sizeof(DRIVER_LOOKUP_ENTRY))
+
+
+//
+// Miniport DriverEntry typedef
+//
+
+typedef NTSTATUS
+(*PDRIVER_ENTRY) (
+ IN PVOID DriverObject,
+ IN PVOID Parameter2
+ );
+
+//
+// Private function prototypes
+//
+
+ARC_STATUS
+BlArcNotYetImplemented(
+ IN ULONG FileId
+ );
+
+PCONFIGURATION_COMPONENT
+AEComponentInfo(
+ IN PCONFIGURATION_COMPONENT Current
+ );
+
+PCONFIGURATION_COMPONENT
+FwGetChild(
+ IN PCONFIGURATION_COMPONENT Current
+ );
+
+PCHAR
+AEGetEnvironment(
+ IN PCHAR Variable
+ );
+
+PCONFIGURATION_COMPONENT
+FwGetPeer(
+ IN PCONFIGURATION_COMPONENT Current
+ );
+
+PCONFIGURATION_COMPONENT
+AEGetParent(
+ IN PCONFIGURATION_COMPONENT Current
+ );
+
+ARC_STATUS
+AEGetConfigurationData(
+ IN PVOID ConfigurationData,
+ IN PCONFIGURATION_COMPONENT Current
+ );
+
+PMEMORY_DESCRIPTOR
+AEGetMemoryDescriptor(
+ IN PMEMORY_DESCRIPTOR MemoryDescriptor OPTIONAL
+ );
+
+ARC_STATUS
+AEOpen(
+ IN PCHAR OpenPath,
+ IN OPEN_MODE OpenMode,
+ OUT PULONG FileId
+ );
+
+ARC_STATUS
+AEClose(
+ IN ULONG FileId
+ );
+
+ARC_STATUS
+AERead (
+ IN ULONG FileId,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ );
+
+ARC_STATUS
+AEReadStatus (
+ IN ULONG FileId
+ );
+
+VOID
+AEReboot(
+ VOID
+ );
+
+ARC_STATUS
+AESeek (
+ IN ULONG FileId,
+ IN PLARGE_INTEGER Offset,
+ IN SEEK_MODE SeekMode
+ );
+
+ARC_STATUS
+AEWrite (
+ IN ULONG FileId,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ );
+
+ARC_STATUS
+AEGetFileInformation(
+ IN ULONG FileId,
+ OUT PFILE_INFORMATION FileInformation
+ );
+
+PTIME_FIELDS
+AEGetTime(
+ VOID
+ );
+
+ULONG
+AEGetRelativeTime(
+ VOID
+ );
+
+ARC_STATUS
+ScsiDiskClose (
+ IN ULONG FileId
+ );
+
+ARC_STATUS
+ScsiDiskMount (
+ IN PCHAR MountPath,
+ IN MOUNT_OPERATION Operation
+ );
+
+ARC_STATUS
+ScsiDiskOpen (
+ IN PCHAR OpenPath,
+ IN OPEN_MODE OpenMode,
+ OUT PULONG FileId
+ );
+
+ARC_STATUS
+ScsiDiskRead (
+ IN ULONG FileId,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ );
+
+ARC_STATUS
+ScsiDiskSeek (
+ IN ULONG FileId,
+ IN PLARGE_INTEGER Offset,
+ IN SEEK_MODE SeekMode
+ );
+
+ARC_STATUS
+ScsiDiskWrite (
+ IN ULONG FileId,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ );
+
+VOID
+HardDiskInitialize(
+ IN OUT PVOID LookupTable,
+ IN ULONG Entries,
+ IN PVOID DeviceFoundCallback
+ );
+
+//
+// This is the x86 version of the system parameter block on the ARC machines.
+// It lives here, and any module that uses an ArcXXXX routine must declare
+// it external. Machines that have other than very plain-vanilla hardware
+// may have to replace some of the hard-wired vectors with different
+// procedures.
+//
+
+PVOID GlobalFirmwareVectors[MaximumRoutine];
+
+SYSTEM_PARAMETER_BLOCK GlobalSystemBlock =
+ {
+ 0, // Signature??
+ sizeof(SYSTEM_PARAMETER_BLOCK), // Length
+ 0, // Version
+ 0, // Revision
+ NULL, // RestartBlock
+ NULL, // DebugBlock
+ NULL, // GenerateExceptionVector
+ NULL, // TlbMissExceptionVector
+ MaximumRoutine, // FirmwareVectorLength
+ GlobalFirmwareVectors, // Pointer to vector block
+ 0, // VendorVectorLength
+ NULL // Pointer to vendor vector block
+ };
+
+
+extern BL_FILE_TABLE BlFileTable[BL_FILE_TABLE_SIZE];
+
+//
+// temptemp John Vert (jvert) 6-Sep-1991
+// Just do this until we can make our device driver interface look
+// like the ARC firmware one.
+//
+
+extern BL_DEVICE_ENTRY_TABLE ScsiDiskEntryTable;
+
+ULONG FwStallCounter;
+
+
+ARC_STATUS
+AEInitializeIo(
+ IN ULONG DriveId
+ )
+
+/*++
+
+Routine Description:
+
+ Initializes SCSI boot driver, if any. Loads ntbootdd.sys from the
+ boot partition, binds it to the osloader, and initializes it.
+
+Arguments:
+
+ DriveId - file id of the opened boot partition
+
+Return Value:
+
+ ESUCCESS - Drivers successfully initialized
+
+--*/
+
+{
+ extern ULONG ScsiPortCount;
+ extern ULONG MachineType;
+ ARC_STATUS Status;
+ PVOID Buffer;
+ PVOID ImageBase;
+ PLDR_DATA_TABLE_ENTRY DriverDataTableEntry;
+ PDRIVER_ENTRY Entry;
+ extern MEMORY_DESCRIPTOR MDArray[];
+ ULONG i;
+ ULONG ImageBasePage;
+
+ ScsiPortCount = 0;
+
+ FwStallCounter = GET_STALL_COUNT();
+ Status = BlLoadImage(DriveId,
+ MemoryFirmwarePermanent,
+ "\\NTBOOTDD.SYS",
+ TARGET_IMAGE,
+ &ImageBase);
+ if (Status != ESUCCESS) {
+ return(Status);
+ }
+
+ Status = BlAllocateDataTableEntry("NTBOOTDD.SYS",
+ "\\NTBOOTDD.SYS",
+ ImageBase,
+ &DriverDataTableEntry);
+ if (Status != ESUCCESS) {
+ return(Status);
+ }
+ //
+ // Scan the import table and bind to osloader
+ //
+ Status = BlScanOsloaderBoundImportTable(DriverDataTableEntry);
+ if (Status != ESUCCESS) {
+ return(Status);
+ }
+
+ Entry = (PDRIVER_ENTRY)DriverDataTableEntry->EntryPoint;
+
+ Status = (*Entry)(NULL,NULL);
+ if (Status == ESUCCESS) {
+ //
+ // Find the firmware's copy of the memory descriptor that
+ // contains the driver and change it from MemoryFree to
+ // MemoryFirmwareTemporary.
+ //
+ ImageBasePage = (((ULONG)ImageBase) & 0x7fffffff) >> PAGE_SHIFT;
+ i=0;
+ while ((MDArray[i].BasePage >= ImageBasePage) ||
+ (MDArray[i].BasePage + MDArray[i].PageCount < ImageBasePage)) {
+ i++;
+ }
+
+ MDArray[i].MemoryType = MemoryFirmwareTemporary;
+
+ Buffer = FwAllocateHeap(SIZE_FOR_SUPPORTED_DISK_STRUCTURE);
+ HardDiskInitialize(Buffer, SUPPORTED_NUMBER_OF_DISKS, NULL);
+ }
+ return(Status);
+}
+
+
+VOID
+BlFillInSystemParameters(
+ IN PBOOT_CONTEXT BootContextRecord
+ )
+/*++
+
+Routine Description:
+
+ This routine fills in all the fields in the Global System Parameter Block
+ that it can. This includes all the firmware vectors, the vendor-specific
+ information, and anything else that may come up.
+
+Arguments:
+
+ None.
+
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ int cnt;
+
+ //
+ // Fill in the pointers to the firmware functions which we emulate.
+ // Those which we don't emulate are stubbed by BlArcNotYetImplemented,
+ // which will print an error message if it is accidentally called.
+ //
+
+ for (cnt=0; cnt<MaximumRoutine; cnt++) {
+ GlobalFirmwareVectors[cnt]=(PVOID)BlArcNotYetImplemented;
+ }
+ GlobalFirmwareVectors[CloseRoutine] = (PVOID)AEClose;
+ GlobalFirmwareVectors[OpenRoutine] = (PVOID)AEOpen;
+ GlobalFirmwareVectors[MemoryRoutine]= (PVOID)AEGetMemoryDescriptor;
+ GlobalFirmwareVectors[SeekRoutine] = (PVOID)AESeek;
+ GlobalFirmwareVectors[ReadRoutine] = (PVOID)AERead;
+ GlobalFirmwareVectors[ReadStatusRoutine] = (PVOID)AEReadStatus;
+ GlobalFirmwareVectors[WriteRoutine] = (PVOID)AEWrite;
+ GlobalFirmwareVectors[GetFileInformationRoutine] = (PVOID)AEGetFileInformation;
+ GlobalFirmwareVectors[GetTimeRoutine] = (PVOID)AEGetTime;
+ GlobalFirmwareVectors[GetRelativeTimeRoutine] = (PVOID)AEGetRelativeTime;
+
+ GlobalFirmwareVectors[GetPeerRoutine] = (PVOID)FwGetPeer;
+ GlobalFirmwareVectors[GetChildRoutine] = (PVOID)FwGetChild;
+ GlobalFirmwareVectors[GetParentRoutine] = (PVOID)AEGetParent;
+ GlobalFirmwareVectors[GetComponentRoutine] = (PVOID)FwGetComponent;
+ GlobalFirmwareVectors[GetDataRoutine] = (PVOID)AEGetConfigurationData;
+ GlobalFirmwareVectors[GetEnvironmentRoutine] = (PVOID)AEGetEnvironment;
+
+ GlobalFirmwareVectors[RestartRoutine] = (PVOID)AEReboot;
+ GlobalFirmwareVectors[RebootRoutine] = (PVOID)AEReboot;
+
+}
+
+
+PMEMORY_DESCRIPTOR
+AEGetMemoryDescriptor(
+ IN PMEMORY_DESCRIPTOR MemoryDescriptor OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ Emulates the Arc GetMemoryDescriptor call. This must translate
+ between the memory description passed to us by the SU module and
+ the MEMORYDESCRIPTOR type defined by ARC.
+
+Arguments:
+
+ MemoryDescriptor - Supplies current memory descriptor.
+ If MemoryDescriptor==NULL, return the first memory descriptor.
+ If MemoryDescriptor!=NULL, return the next memory descriptor.
+
+Return Value:
+
+ Next memory descriptor in the list.
+ NULL if MemoryDescriptor is the last descriptor in the list.
+
+--*/
+
+{
+ extern MEMORY_DESCRIPTOR MDArray[];
+ extern ULONG NumberDescriptors;
+ PMEMORY_DESCRIPTOR Return;
+ if (MemoryDescriptor==NULL) {
+ Return=MDArray;
+ } else {
+ if((ULONG)(MemoryDescriptor-MDArray) >= (NumberDescriptors-1)) {
+ return NULL;
+ } else {
+ Return = ++MemoryDescriptor;
+ }
+ }
+ return(Return);
+
+}
+
+
+ARC_STATUS
+BlArcNotYetImplemented(
+ IN ULONG FileId
+ )
+
+/*++
+
+Routine Description:
+
+ This is a stub routine used to fill in the firmware vectors which haven't
+ been defined yet. It uses BlPrint to print a message on the screen.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ EINVAL
+
+--*/
+
+{
+ BlPrint("ERROR - Unimplemented Firmware Vector called (FID %lx)\n",
+ FileId );
+ return(EINVAL);
+}
+
+
+PCONFIGURATION_COMPONENT
+FwGetChild(
+ IN PCONFIGURATION_COMPONENT Current
+ )
+
+/*++
+
+Routine Description:
+
+ This is the arc emulation routine for GetChild. Based on the current
+ component, it returns the component's child component.
+
+Arguments:
+
+ Current - Supplies pointer to the current configuration component
+
+Return Value:
+
+ A pointer to a CONFIGURATION_COMPONENT structure OR
+ NULL - No more configuration information
+
+
+--*/
+
+{
+ PCONFIGURATION_COMPONENT_DATA CurrentEntry;
+
+ //
+ // if current component is NULL, return a pointer to first system
+ // component; otherwise return current component's child component.
+ //
+
+ if (Current) {
+ CurrentEntry = CONTAINING_RECORD(Current,
+ CONFIGURATION_COMPONENT_DATA,
+ ComponentEntry);
+ if (CurrentEntry->Child) {
+ return(&(CurrentEntry->Child->ComponentEntry));
+ } else {
+ return(NULL);
+ }
+ } else {
+ if (FwConfigurationTree) {
+ return(&(FwConfigurationTree->ComponentEntry));
+ } else {
+ return(NULL);
+ }
+ }
+
+}
+
+
+PCONFIGURATION_COMPONENT
+FwGetPeer(
+ IN PCONFIGURATION_COMPONENT Current
+ )
+
+/*++
+
+Routine Description:
+
+ This is the arc emulation routine for GetPeer. Based on the current
+ component, it returns the component's sibling.
+
+Arguments:
+
+ Current - Supplies pointer to the current configuration component
+
+Return Value:
+
+ A pointer to a CONFIGURATION_COMPONENT structure OR
+ NULL - No more configuration information
+
+
+--*/
+
+{
+ PCONFIGURATION_COMPONENT_DATA CurrentEntry;
+
+
+ if (Current) {
+ CurrentEntry = CONTAINING_RECORD(Current,
+ CONFIGURATION_COMPONENT_DATA,
+ ComponentEntry);
+ if (CurrentEntry->Sibling) {
+ return(&(CurrentEntry->Sibling->ComponentEntry));
+ } else {
+ return(NULL);
+ }
+ } else {
+ return(NULL);
+ }
+
+}
+
+
+PCONFIGURATION_COMPONENT
+AEGetParent(
+ IN PCONFIGURATION_COMPONENT Current
+ )
+
+/*++
+
+Routine Description:
+
+ This is the arc emulation routine for GetParent. Based on the current
+ component, it returns the component's parent.
+
+Arguments:
+
+ Current - Supplies pointer to the current configuration component
+
+Return Value:
+
+ A pointer to a CONFIGURATION_COMPONENT structure OR
+ NULL - No more configuration information
+
+
+--*/
+
+{
+ PCONFIGURATION_COMPONENT_DATA CurrentEntry;
+
+
+ if (Current) {
+ CurrentEntry = CONTAINING_RECORD(Current,
+ CONFIGURATION_COMPONENT_DATA,
+ ComponentEntry);
+ if (CurrentEntry->Parent) {
+ return(&(CurrentEntry->Parent->ComponentEntry));
+ } else {
+ return(NULL);
+ }
+ } else {
+ return(NULL);
+ }
+
+}
+
+
+ARC_STATUS
+AEGetConfigurationData(
+ IN PVOID ConfigurationData,
+ IN PCONFIGURATION_COMPONENT Current
+ )
+
+/*++
+
+Routine Description:
+
+ This is the arc emulation routine for GetParent. Based on the current
+ component, it returns the component's parent.
+
+Arguments:
+
+ Current - Supplies pointer to the current configuration component
+
+Return Value:
+
+ ESUCCESS - Data successfully returned.
+
+
+--*/
+
+{
+ PCONFIGURATION_COMPONENT_DATA CurrentEntry;
+
+
+ if (Current) {
+ CurrentEntry = CONTAINING_RECORD(Current,
+ CONFIGURATION_COMPONENT_DATA,
+ ComponentEntry);
+ RtlMoveMemory(ConfigurationData,
+ CurrentEntry->ConfigurationData,
+ Current->ConfigurationDataLength);
+ return(ESUCCESS);
+ } else {
+ return(EINVAL);
+ }
+
+}
+
+
+PCHAR
+AEGetEnvironment(
+ IN PCHAR Variable
+ )
+
+/*++
+
+Routine Description:
+
+ This is the arc emulation routine for ArcGetEnvironment. It returns
+ the value of the specified NVRAM environment variable.
+
+ NOTE John Vert (jvert) 23-Apr-1992
+ This particular implementation uses the Daylight Savings Bit on
+ the Real Time Clock to reflect the state of the LastKnownGood
+ environment variable. This is the only variable we support.
+
+Arguments:
+
+ Variable - Supplies the name of the environment variable to look up.
+
+Return Value:
+
+ A pointer to the specified environment variable's value, or
+ NULL if the variable does not exist.
+
+--*/
+
+{
+ UCHAR StatusByte;
+
+ if (_stricmp(Variable, "LastKnownGood") != 0) {
+ return(NULL);
+ }
+
+ //
+ // Read the Daylight Savings Bit out of the RTC to determine whether
+ // the LastKnownGood environment variable is TRUE or FALSE.
+ //
+
+ WRITE_PORT_UCHAR(CMOS_CONTROL_PORT, CMOS_STATUS_B);
+ StatusByte = READ_PORT_UCHAR(CMOS_DATA_PORT);
+ if (StatusByte & CMOS_DAYLIGHT_BIT) {
+ return("TRUE");
+ } else {
+ return(NULL);
+ }
+
+
+}
+
+
+ARC_STATUS
+AEOpen(
+ IN PCHAR OpenPath,
+ IN OPEN_MODE OpenMode,
+ OUT PULONG FileId
+ )
+
+/*++
+
+Routine Description:
+
+ Opens the file or device specified by OpenPath.
+
+Arguments:
+
+ OpenPath - Supplies a pointer to the fully-qualified path name.
+
+ OpenMode - Supplies the mode to open the file.
+ 0 - Read Only
+ 1 - Write Only
+ 2 - Read/Write
+
+ FileId - Returns the file descriptor for use with the Close, Read, Write,
+ and Seek routines
+
+Return Value:
+
+ ESUCCESS - File successfully opened.
+
+--*/
+
+{
+ ARC_STATUS Status;
+ CHAR Buffer[128];
+
+ Status = BiosConsoleOpen( OpenPath,
+ OpenMode,
+ FileId );
+
+ if (Status == ESUCCESS) {
+ return(ESUCCESS);
+ }
+
+ Status = BiosPartitionOpen( OpenPath,
+ OpenMode,
+ FileId );
+
+ if (Status == ESUCCESS) {
+ return(ESUCCESS);
+ }
+
+ //
+ // It's not the console or a BIOS partition, so let's try the SCSI
+ // driver.
+ //
+
+ //
+ // Find a free FileId
+ //
+
+ *FileId = 2;
+ while (BlFileTable[*FileId].Flags.Open == 1) {
+ *FileId += 1;
+ if (*FileId == BL_FILE_TABLE_SIZE) {
+ return(ENOENT);
+ }
+ }
+
+ strcpy(Buffer,OpenPath);
+
+ Status = ScsiDiskOpen( Buffer,
+ OpenMode,
+ FileId );
+
+ if (Status == ESUCCESS) {
+
+ //
+ // SCSI successfully opened it. For now, we stick the appropriate
+ // SCSI DeviceEntryTable into the BlFileTable. This is temporary.
+ //
+
+ BlFileTable[*FileId].Flags.Open = 1;
+ BlFileTable[*FileId].DeviceEntryTable = &ScsiDiskEntryTable;
+ return(ESUCCESS);
+ }
+
+ return(Status);
+}
+
+
+ARC_STATUS
+AESeek (
+ IN ULONG FileId,
+ IN PLARGE_INTEGER Offset,
+ IN SEEK_MODE SeekMode
+ )
+
+/*++
+
+Routine Description:
+
+ Changes the current offset of the file specified by FileId
+
+Arguments:
+
+ FileId - specifies the file on which the current offset is to
+ be changed.
+
+ Offset - New offset into file.
+
+ SeekMode - Either SeekAbsolute or SeekRelative
+ SeekEndRelative is not supported
+
+Return Value:
+
+ ESUCCESS - Operation completed succesfully
+
+ EBADF - Operation did not complete successfully.
+
+--*/
+
+{
+ return(BlFileTable[FileId].DeviceEntryTable->Seek)( FileId,
+ Offset,
+ SeekMode );
+}
+
+
+ARC_STATUS
+AEClose (
+ IN ULONG FileId
+ )
+
+/*++
+
+Routine Description:
+
+ Closes the file specified by FileId
+
+Arguments:
+
+ FileId - specifies the file to close
+
+Return Value:
+
+ ESUCCESS - Operation completed succesfully
+
+ EBADF - Operation did not complete successfully.
+
+--*/
+
+{
+
+ return(BlFileTable[FileId].DeviceEntryTable->Close)(FileId);
+
+}
+
+
+ARC_STATUS
+AEReadStatus(
+ IN ULONG FileId
+ )
+
+/*++
+
+Routine Description:
+
+ Determines if data is available on the specified device
+
+Arguments:
+
+ FileId - Specifies the device to check for data.
+
+Return Value:
+
+ ESUCCESS - At least one byte is available.
+
+ EAGAIN - No data is available
+
+--*/
+
+{
+ //
+ // Special case for console input
+ //
+
+ if (FileId == 0) {
+ return(BiosConsoleReadStatus(FileId));
+ } else {
+ return(BlArcNotYetImplemented(FileId));
+ }
+
+}
+
+
+ARC_STATUS
+AERead (
+ IN ULONG FileId,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ Reads from the specified file or device
+
+Arguments:
+
+ FileId - specifies the file to read from
+
+ Buffer - Address of buffer to hold the data that is read
+
+ Length - Maximum number of bytes to read
+
+ Count - Address of location in which to store the actual bytes read.
+
+Return Value:
+
+ ESUCCESS - Read completed successfully
+
+ !ESUCCESS - Read failed.
+
+--*/
+
+{
+ ARC_STATUS Status;
+ ULONG Limit;
+ ULONG PartCount;
+ //
+ // Special case for console input
+ //
+
+ if (FileId == 0) {
+ return(BiosConsoleRead(FileId,Buffer,Length,Count));
+ } else {
+
+ *Count = 0;
+
+ do {
+
+ if (((ULONG) Buffer & 0xffff0000) !=
+ (((ULONG) Buffer + Length) & 0xffff0000)) {
+
+ Limit = 0x10000 - ((ULONG) Buffer & 0x0000ffff);
+ } else {
+
+ Limit = Length;
+
+ }
+
+ Status = (BlFileTable[FileId].DeviceEntryTable->Read)( FileId,
+ Buffer,
+ Limit,
+ &PartCount );
+ *Count += PartCount;
+ Length -= Limit;
+ (PCHAR) Buffer += Limit;
+
+ if (Status != ESUCCESS) {
+ BlPrint("Disk I/O error: Status = %lx\n",Status);
+ return(Status);
+ }
+
+ } while (Length > 0);
+
+ return(Status);
+ }
+}
+
+
+ARC_STATUS
+AEWrite (
+ IN ULONG FileId,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ Writes to the specified file or device
+
+Arguments:
+
+ FileId - Supplies the file or device to write to
+
+ Buffer - Supplies address of the data to be written
+
+ Length - Supplies number of bytes to write
+
+ Count - Address of location in which to store the actual bytes written.
+
+Return Value:
+
+ ESUCCESS - Read completed successfully
+
+ !ESUCCESS - Read failed.
+
+--*/
+
+{
+ ARC_STATUS Status;
+ ULONG Limit;
+ ULONG PartCount;
+
+ //
+ // Special case for console output
+ //
+
+ if (FileId == 1) {
+ return(BiosConsoleWrite(FileId,Buffer,Length,Count));
+ } else {
+ *Count = 0;
+
+ do {
+
+ if (((ULONG) Buffer & 0xffff0000) !=
+ (((ULONG) Buffer + Length) & 0xffff0000)) {
+
+ Limit = 0x10000 - ((ULONG) Buffer & 0x0000ffff);
+ } else {
+
+ Limit = Length;
+
+ }
+
+ Status = (BlFileTable[FileId].DeviceEntryTable->Write)( FileId,
+ Buffer,
+ Limit,
+ &PartCount );
+ *Count += PartCount;
+ Length -= Limit;
+ (PCHAR) Buffer += Limit;
+
+ if (Status != ESUCCESS) {
+ BlPrint("AERead: Status = %lx\n",Status);
+ return(Status);
+ }
+
+ } while (Length > 0);
+
+ return(Status);
+ }
+}
+
+ARC_STATUS
+AEGetFileInformation(
+ IN ULONG FileId,
+ OUT PFILE_INFORMATION FileInformation
+ )
+{
+ return(BlFileTable[FileId].DeviceEntryTable->GetFileInformation)( FileId,
+ FileInformation);
+}
+
+
+TIME_FIELDS AETime;
+
+PTIME_FIELDS
+AEGetTime(
+ VOID
+ )
+{
+ ULONG Date,Time;
+
+ GET_DATETIME(&Date,&Time);
+
+ //
+ // Date and time are filled as as follows:
+ //
+ // Date:
+ //
+ // bits 0 - 4 : day
+ // bits 5 - 8 : month
+ // bits 9 - 31 : year
+ //
+ // Time:
+ //
+ // bits 0 - 5 : second
+ // bits 6 - 11 : minute
+ // bits 12 - 16 : hour
+ //
+
+ AETime.Second = (CSHORT)((Time & 0x0000003f) >> 0);
+ AETime.Minute = (CSHORT)((Time & 0x00000fc0) >> 6);
+ AETime.Hour = (CSHORT)((Time & 0x0001f000) >> 12);
+
+ AETime.Day = (CSHORT)((Date & 0x0000001f) >> 0);
+ AETime.Month = (CSHORT)((Date & 0x000001e0) >> 5);
+ AETime.Year = (CSHORT)((Date & 0xfffffe00) >> 9);
+
+ AETime.Milliseconds = 0; // info is not available
+ AETime.Weekday = 7; // info is not available - set out of range
+
+ return(&AETime);
+}
+
+
+ULONG
+AEGetRelativeTime(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Returns the time in seconds since some arbitrary starting point.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ Time in seconds since some arbitrary starting point.
+
+--*/
+
+{
+ ULONG TimerTicks;
+
+ TimerTicks = GET_COUNTER();
+
+ return((TimerTicks*10) / 182);
+}
+
+
+VOID
+AEReboot(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Reboots the machine.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ Does not return
+
+--*/
+
+{
+ ULONG DriveId;
+ ULONG Status;
+
+ TextGrTerminate();
+
+ //
+ // HACKHACK John Vert (jvert)
+ // Some SCSI drives get really confused and return zeroes when
+ // you use the BIOS to query their size after the AHA driver has
+ // initialized. This can completely tube OS/2 or DOS. So here
+ // we try and open both BIOS-accessible hard drives. Our open
+ // code is smart enough to retry if it gets back zeros, so hopefully
+ // this will give the SCSI drives a chance to get their act together.
+ //
+ Status = ArcOpen("multi(0)disk(0)rdisk(0)partition(0)",
+ ArcOpenReadOnly,
+ &DriveId);
+ if (Status == ESUCCESS) {
+ ArcClose(DriveId);
+ }
+
+ Status = ArcOpen("multi(0)disk(0)rdisk(1)partition(0)",
+ ArcOpenReadOnly,
+ &DriveId);
+ if (Status == ESUCCESS) {
+ ArcClose(DriveId);
+ }
+ REBOOT_PROCESSOR();
+}
+
+
+ARC_STATUS
+HardDiskPartitionOpen(
+ IN ULONG FileId,
+ IN ULONG DiskId,
+ IN UCHAR PartitionNumber
+ )
+
+/*++
+
+Routine Description:
+
+ This routine opens the specified partition and sets the partition info
+ in the FileTable at the specified index. It does not fill in the
+ Device Entry table.
+
+ It reads the partition information until the requested partition
+ is found or no more partitions are defined.
+
+Arguments:
+
+ FileId - Supplies the file id for the file table entry.
+
+ DiskId - Supplies the file id for the physical device.
+
+ PartitionNumber - Supplies the zero-based partition number
+
+Return Value:
+
+ If a valid partition is found on the hard disk, then ESUCCESS is
+ returned. Otherwise, EIO is returned.
+
+--*/
+
+{
+
+ USHORT DataBuffer[SECTOR_SIZE / sizeof(USHORT)];
+ PPARTITION_DESCRIPTOR Partition;
+ ULONG PartitionLength;
+ ULONG StartingSector;
+ ULONG VolumeOffset;
+ ARC_STATUS Status;
+ BOOLEAN PrimaryPartitionTable;
+ ULONG PartitionOffset=0;
+ ULONG PartitionIndex,PartitionCount=0;
+ ULONG Count;
+ LARGE_INTEGER SeekPosition;
+
+ BlFileTable[FileId].u.PartitionContext.DiskId=(UCHAR)DiskId;
+ BlFileTable[FileId].Position.QuadPart=0;
+
+ VolumeOffset=0;
+ PrimaryPartitionTable=TRUE;
+
+ //
+ // Change to a 1-based partition number
+ //
+ PartitionNumber++;
+
+ do {
+ SeekPosition.QuadPart = PartitionOffset * SECTOR_SIZE;
+ Status = (BlFileTable[DiskId].DeviceEntryTable->Seek)(DiskId,
+ &SeekPosition,
+ SeekAbsolute );
+ if (Status != ESUCCESS) {
+ return(Status);
+ }
+ Status = (BlFileTable[DiskId].DeviceEntryTable->Read)(DiskId,
+ DataBuffer,
+ SECTOR_SIZE,
+ &Count );
+
+ if (Status == ESUCCESS) {
+
+ //
+ // If sector zero is not a master boot record, then return failure
+ // status. Otherwise return success.
+ //
+
+ if (DataBuffer[BOOT_SIGNATURE_OFFSET] != BOOT_RECORD_SIGNATURE) {
+ BlPrint("Boot record signature %x not found (%x found)\n",
+ BOOT_RECORD_SIGNATURE,
+ DataBuffer[BOOT_SIGNATURE_OFFSET] );
+ Status = EIO;
+ break;
+ }
+
+ //
+ // Read the partition information until the four entries are
+ // checked or until we found the requested one.
+ //
+ Partition = (PPARTITION_DESCRIPTOR)&DataBuffer[PARTITION_TABLE_OFFSET];
+ for (PartitionIndex=0;
+ PartitionIndex < NUM_PARTITION_TABLE_ENTRIES;
+ PartitionIndex++,Partition++) {
+
+ //
+ // Count first the partitions in the MBR. The units
+ // inside the extended partition are counted later.
+ //
+ if ((Partition->PartitionType != PARTITION_ENTRY_UNUSED)
+ && !IsContainerPartition(Partition->PartitionType))
+ {
+ PartitionCount++; // another partition found.
+ }
+
+ //
+ // Check if the requested partition has already been found.
+ // set the partition info in the file table and return.
+ //
+ if (PartitionCount == PartitionNumber) {
+ StartingSector = (ULONG)(Partition->StartingSectorLsb0) |
+ (ULONG)(Partition->StartingSectorLsb1 << 8) |
+ (ULONG)(Partition->StartingSectorMsb0 << 16) |
+ (ULONG)(Partition->StartingSectorMsb1 << 24);
+ PartitionLength = (ULONG)(Partition->PartitionLengthLsb0) |
+ (ULONG)(Partition->PartitionLengthLsb1 << 8) |
+ (ULONG)(Partition->PartitionLengthMsb0 << 16) |
+ (ULONG)(Partition->PartitionLengthMsb1 << 24);
+ BlFileTable[FileId].u.PartitionContext.PartitionLength.QuadPart =
+ (PartitionLength << SECTOR_SHIFT);
+ BlFileTable[FileId].u.PartitionContext.StartingSector=PartitionOffset + StartingSector;
+ return ESUCCESS;
+ }
+ }
+
+ //
+ // If requested partition was not yet found.
+ // Look for an extended partition.
+ //
+ Partition = (PPARTITION_DESCRIPTOR)&DataBuffer[PARTITION_TABLE_OFFSET];
+ PartitionOffset = 0;
+ for (PartitionIndex=0;
+ PartitionIndex < NUM_PARTITION_TABLE_ENTRIES;
+ PartitionIndex++,Partition++) {
+ if (IsContainerPartition(Partition->PartitionType)) {
+ StartingSector = (ULONG)(Partition->StartingSectorLsb0) |
+ (ULONG)(Partition->StartingSectorLsb1 << 8) |
+ (ULONG)(Partition->StartingSectorMsb0 << 16) |
+ (ULONG)(Partition->StartingSectorMsb1 << 24);
+ PartitionOffset = VolumeOffset+StartingSector;
+ if (PrimaryPartitionTable) {
+ VolumeOffset = StartingSector;
+ }
+ break; // only one partition can be extended.
+ }
+ }
+ }
+ PrimaryPartitionTable=FALSE;
+ } while (PartitionOffset != 0);
+ return EBADF;
+}
+
+
+VOID
+BlpTranslateDosToArc(
+ IN PCHAR DosName,
+ OUT PCHAR ArcName
+ )
+
+/*++
+
+Routine Description:
+
+ This routine takes a DOS drive name ("A:" "B:" "C:" etc.) and translates
+ it into an ARC name. ("multi(0)disk(0)rdisk(0)partition(1)")
+
+ N.B. This will always return some sort of name suitable for passing
+ to BiosPartitionOpen. The name it constructs may not be an
+ actual partition. BiosPartitionOpen is responsible for
+ determining whether the partition actually exists.
+
+ Since no other driver should ever use ARC names beginning with
+ "multi(0)disk(0)..." this will not be a problem. (there is no
+ way this routine will construct a name that BiosPartitionOpen
+ will not open, but some other random driver will grab and
+ successfully open)
+
+Arguments:
+
+ DosName - Supplies the DOS name of the drive.
+
+ ArcName - Returns the ARC name of the drive.
+
+Return Value:
+
+--*/
+
+{
+ ARC_STATUS Status;
+ ULONG DriveId;
+ ULONG PartitionNumber;
+ ULONG PartitionCount;
+ ULONG Count;
+ USHORT DataBuffer[SECTOR_SIZE / sizeof(USHORT)];
+ PPARTITION_DESCRIPTOR Partition;
+ ULONG PartitionIndex;
+ BOOLEAN HasPrimary;
+ LARGE_INTEGER SeekPosition;
+
+ //
+ // Eliminate the easy ones first.
+ // A: is always "multi(0)disk(0)fdisk(0)partition(0)"
+ // B: is always "multi(0)disk(0)fdisk(1)partition(0)"
+ // C: is always "multi(0)disk(0)rdisk(0)partition(1)"
+ //
+
+ if (_stricmp(DosName,"A:")==0) {
+ strcpy(ArcName,"multi(0)disk(0)fdisk(0)partition(0)");
+ return;
+ }
+ if (_stricmp(DosName,"B:")==0) {
+ strcpy(ArcName,"multi(0)disk(0)fdisk(1)partition(0)");
+ return;
+ }
+ if (_stricmp(DosName,"C:")==0) {
+ strcpy(ArcName,"multi(0)disk(0)rdisk(0)partition(1)");
+ return;
+ }
+
+ //
+ // Now things get more unpleasant. If there are two drives, then
+ // D: is the primary partition on the second drive. Successive letters
+ // are the secondary partitions on the first drive, then back to the
+ // second drive when that runs out.
+ //
+ // The exception to this is when there is no primary partition on the
+ // second drive. Then, we letter the partitions on the first driver
+ // consecutively, and when those partitions run out, we letter the
+ // partitions on the second drive.
+ //
+ // I have no idea who came up with this wonderful scheme, but we have
+ // to live with it.
+ //
+
+ //
+ // Try to open the second drive. If this doesn't work, we only have
+ // one drive and life is easy.
+ //
+ Status = ArcOpen("multi(0)disk(0)rdisk(1)partition(0)",
+ ArcOpenReadOnly,
+ &DriveId );
+
+ if (Status != ESUCCESS) {
+
+ //
+ // We only have one drive, so whatever drive letter he's requesting
+ // has got to be on it.
+ //
+
+ sprintf(ArcName,
+ "multi(0)disk(0)rdisk(0)partition(%d)",
+ toupper(DosName[0]) - 'C' + 1 );
+
+ return;
+ } else {
+
+ //
+ // Now we read the partition table off the second drive, so we can
+ // tell if there is a primary partition or not.
+ //
+ SeekPosition.QuadPart = 0;
+
+ Status = ArcSeek(DriveId,
+ &SeekPosition,
+ SeekAbsolute);
+ if (Status != ESUCCESS) {
+ ArcName[0]='\0';
+ return;
+ }
+
+ Status = ArcRead(DriveId, DataBuffer, SECTOR_SIZE, &Count);
+ ArcClose(DriveId);
+
+ if (Status != ESUCCESS) {
+ ArcName[0] = '\0';
+ return;
+ }
+
+ HasPrimary = FALSE;
+
+ Partition = (PPARTITION_DESCRIPTOR)&DataBuffer[PARTITION_TABLE_OFFSET];
+ for (PartitionIndex = 0;
+ PartitionIndex < NUM_PARTITION_TABLE_ENTRIES;
+ PartitionIndex++,Partition++) {
+ if (IsRecognizedPartition(Partition->PartitionType)) {
+ HasPrimary = TRUE;
+ }
+ }
+
+ //
+ // Now we have to go through and count
+ // the partitions on the first drive. We do this by just constructing
+ // ARC names for each successive partition until one BiosPartitionOpen
+ // call fails.
+ //
+
+ PartitionCount = 0;
+ do {
+ ++PartitionCount;
+ sprintf(ArcName,
+ "multi(0)disk(0)rdisk(0)partition(%d)",
+ PartitionCount+1);
+
+ Status = BiosPartitionOpen( ArcName,
+ ArcOpenReadOnly,
+ &DriveId );
+
+ if (Status==ESUCCESS) {
+ BiosPartitionClose(DriveId);
+ }
+ } while ( Status == ESUCCESS );
+
+ PartitionNumber = toupper(DosName[0])-'C' + 1;
+
+ if (HasPrimary) {
+
+ //
+ // There is Windows NT primary partition on the second drive.
+ //
+ // If the DosName is "D:" then we know
+ // this is the first partition on the second drive.
+ //
+
+ if (_stricmp(DosName,"D:")==0) {
+ strcpy(ArcName,"multi(0)disk(0)rdisk(1)partition(1)");
+ return;
+ }
+
+ if (PartitionNumber-1 > PartitionCount) {
+ PartitionNumber -= PartitionCount;
+ sprintf(ArcName,
+ "multi(0)disk(0)rdisk(1)partition(%d)",
+ PartitionNumber );
+ } else {
+ sprintf(ArcName,
+ "multi(0)disk(0)rdisk(0)partition(%d)",
+ PartitionNumber-1);
+ }
+
+ } else {
+
+ //
+ // There is no primary partition on the second drive, so we
+ // consecutively letter the partitions on the first drive,
+ // then the second drive.
+ //
+
+ if (PartitionNumber > PartitionCount) {
+ PartitionNumber -= PartitionCount;
+ sprintf(ArcName,
+ "multi(0)disk(0)rdisk(1)partition(%d)",
+ PartitionNumber );
+ } else {
+ sprintf(ArcName,
+ "multi(0)disk(0)rdisk(0)partition(%d)",
+ PartitionNumber);
+ }
+
+ }
+
+
+ return;
+ }
+}
+
+
+VOID
+FwStallExecution(
+ IN ULONG Microseconds
+ )
+
+/*++
+
+Routine Description:
+
+ Does a busy wait for a specified number of microseconds (very approximate!)
+
+Arguments:
+
+ Microseconds - Supplies the number of microseconds to busy wait.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG FinalCount;
+
+ FinalCount = Microseconds * FwStallCounter;
+
+ _asm {
+ mov eax,FinalCount
+looptop:
+ sub eax,1
+ jnz short looptop
+ }
+}
+
+
+BOOLEAN
+FwGetPathMnemonicKey(
+ IN PCHAR OpenPath,
+ IN PCHAR Mnemonic,
+ IN PULONG Key
+ )
+
+/*++
+
+Routine Description:
+
+ This routine looks for the given Mnemonic in OpenPath.
+ If Mnemonic is a component of the path, then it converts the key
+ value to an integer wich is returned in Key.
+
+Arguments:
+
+ OpenPath - Pointer to a string that contains an ARC pathname.
+
+ Mnemonic - Pointer to a string that contains a ARC Mnemonic
+
+ Key - Pointer to a ULONG where the Key value is stored.
+
+
+Return Value:
+
+ FALSE if mnemonic is found in path and a valid key is converted.
+ TRUE otherwise.
+
+--*/
+
+{
+ return(BlGetPathMnemonicKey(OpenPath,Mnemonic,Key));
+}
+
+
+PCONFIGURATION_COMPONENT
+FwAddChild (
+ IN PCONFIGURATION_COMPONENT Component,
+ IN PCONFIGURATION_COMPONENT NewComponent,
+ IN PVOID ConfigurationData OPTIONAL
+ )
+{
+ ULONG Size;
+ PCONFIGURATION_COMPONENT_DATA NewEntry;
+ PCONFIGURATION_COMPONENT_DATA Parent;
+
+ if (Component==NULL) {
+ return(NULL);
+ }
+
+ Parent = CONTAINING_RECORD(Component,
+ CONFIGURATION_COMPONENT_DATA,
+ ComponentEntry);
+
+ Size = sizeof(CONFIGURATION_COMPONENT_DATA) +
+ NewComponent->IdentifierLength + 1;
+
+ NewEntry = FwAllocateHeap(Size);
+ if (NewEntry==NULL) {
+ return(NULL);
+ }
+
+ RtlCopyMemory(&NewEntry->ComponentEntry,
+ NewComponent,
+ sizeof(CONFIGURATION_COMPONENT));
+ NewEntry->ComponentEntry.Identifier = (PUCHAR)(NewEntry+1);
+ NewEntry->ComponentEntry.ConfigurationDataLength = 0;
+ strncpy(NewEntry->ComponentEntry.Identifier,
+ NewComponent->Identifier,
+ NewComponent->IdentifierLength);
+
+ //
+ // Add the new component as the first child of its parent.
+ //
+ NewEntry->Child = NULL;
+ NewEntry->Sibling = Parent->Child;
+ Parent->Child = NewEntry;
+
+ return(&NewEntry->ComponentEntry);
+
+}
+
+PCONFIGURATION_COMPONENT
+FwGetComponent(
+ IN PCHAR Pathname
+ )
+{
+ PCONFIGURATION_COMPONENT Component;
+ PCONFIGURATION_COMPONENT MatchComponent;
+ PCHAR PathString;
+ PCHAR MatchString;
+ PCHAR Token;
+ ULONG Key;
+
+ PathString = Pathname;
+
+ //
+ // Get the the root component.
+ //
+
+ MatchComponent = FwGetChild(NULL);
+
+ //
+ // Repeat search for each new match component.
+ //
+
+ do {
+
+ //
+ // Get the first child of the current match component.
+ //
+
+ Component = FwGetChild( MatchComponent );
+
+ //
+ // Search each child of the current match component for the next match.
+ //
+
+ while ( Component != NULL ) {
+
+ //
+ // Reset Token to be the current position on the pathname.
+ //
+
+ Token = PathString;
+
+ MatchString = MnemonicTable[Component->Type];
+
+ //
+ // Compare strings.
+ //
+
+ while (*MatchString == tolower(*Token)) {
+ MatchString++;
+ Token++;
+ }
+
+ //
+ // Strings compare if the first mismatch is the terminator for
+ // each.
+ //
+
+ if ((*MatchString == 0) && (*Token == '(')) {
+
+ //
+ // Form key.
+ //
+
+ Key = 0;
+ Token++;
+ while ((*Token != ')') && (*Token != 0)) {
+ Key = (Key * 10) + *Token++ - '0';
+ }
+
+ //
+ // If the key matches the component matches, so update
+ // pointers and break.
+ //
+
+ if (Component->Key == Key) {
+ PathString = Token + 1;
+ MatchComponent = Component;
+ break;
+ }
+ }
+
+ Component = FwGetPeer( Component );
+ }
+
+ } while ((Component != NULL) && (*PathString != 0));
+
+ return MatchComponent;
+}
+/**********************
+*
+* The following are just stubs for the MIPS firmware. They all return NULL
+*
+***********************/
+
+
+
+ARC_STATUS
+FwDeleteComponent (
+ IN PCONFIGURATION_COMPONENT Component
+ )
+{
+ return(ESUCCESS);
+}
+
diff --git a/private/ntos/boot/lib/i386/biosdrv.c b/private/ntos/boot/lib/i386/biosdrv.c
new file mode 100644
index 000000000..dc4fa9bdd
--- /dev/null
+++ b/private/ntos/boot/lib/i386/biosdrv.c
@@ -0,0 +1,2177 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ biosdrv.c
+
+Abstract:
+
+ Provides the ARC emulation routines for I/O to a device supported by
+ real-mode INT 13h BIOS calls.
+
+Author:
+
+ John Vert (jvert) 7-Aug-1991
+
+Revision History:
+
+--*/
+
+#include "arccodes.h"
+#include "bootx86.h"
+
+#include "stdlib.h"
+#include "string.h"
+
+#include "flop.h"
+
+//
+// defines for doing console I/O
+//
+#define CSI 0x95
+#define SGR_INVERSE 7
+#define SGR_NORMAL 0
+
+//
+// static data for console I/O
+//
+BOOLEAN ControlSequence=FALSE;
+BOOLEAN EscapeSequence=FALSE;
+BOOLEAN FontSelection=FALSE;
+ULONG PCount=0;
+
+#define CONTROL_SEQUENCE_MAX_PARAMETER 10
+ULONG Parameter[CONTROL_SEQUENCE_MAX_PARAMETER];
+
+#define KEY_INPUT_BUFFER_SIZE 16
+UCHAR KeyBuffer[KEY_INPUT_BUFFER_SIZE];
+ULONG KeyBufferEnd=0;
+ULONG KeyBufferStart=0;
+
+//
+// array for translating between ANSI colors and the VGA standard
+//
+UCHAR TranslateColor[] = {0,4,2,6,1,5,3,7};
+
+ARC_STATUS
+BiosDiskClose(
+ IN ULONG FileId
+ );
+
+VOID
+BiosConsoleFillBuffer(
+ IN ULONG Key
+ );
+
+//
+// Buffer for temporary storage of data read from the disk that needs
+// to end up in a location above the 1MB boundary.
+//
+// NOTE: it is very important that this buffer not cross a 64k boundary.
+//
+PUCHAR LocalBuffer=NULL;
+
+//
+// There are two sorts of things we can open in this module, disk partitions,
+// and raw disk devices. The following device entry tables are
+// used for these things.
+//
+
+BL_DEVICE_ENTRY_TABLE BiosPartitionEntryTable =
+ {
+ (PARC_CLOSE_ROUTINE)BiosPartitionClose,
+ (PARC_MOUNT_ROUTINE)BlArcNotYetImplemented,
+ (PARC_OPEN_ROUTINE)BiosPartitionOpen,
+ (PARC_READ_ROUTINE)BiosPartitionRead,
+ (PARC_READ_STATUS_ROUTINE)BlArcNotYetImplemented,
+ (PARC_SEEK_ROUTINE)BiosPartitionSeek,
+ (PARC_WRITE_ROUTINE)BiosPartitionWrite,
+ (PARC_GET_FILE_INFO_ROUTINE)BiosGetFileInfo,
+ (PARC_SET_FILE_INFO_ROUTINE)BlArcNotYetImplemented,
+ (PRENAME_ROUTINE)BlArcNotYetImplemented,
+ (PARC_GET_DIRECTORY_ENTRY_ROUTINE)BlArcNotYetImplemented,
+ (PBOOTFS_INFO)BlArcNotYetImplemented
+ };
+
+BL_DEVICE_ENTRY_TABLE BiosDiskEntryTable =
+ {
+ (PARC_CLOSE_ROUTINE)BiosDiskClose,
+ (PARC_MOUNT_ROUTINE)BlArcNotYetImplemented,
+ (PARC_OPEN_ROUTINE)BiosDiskOpen,
+ (PARC_READ_ROUTINE)BiosDiskRead,
+ (PARC_READ_STATUS_ROUTINE)BlArcNotYetImplemented,
+ (PARC_SEEK_ROUTINE)BiosPartitionSeek,
+ (PARC_WRITE_ROUTINE)BiosDiskWrite,
+ (PARC_GET_FILE_INFO_ROUTINE)BiosGetFileInfo,
+ (PARC_SET_FILE_INFO_ROUTINE)BlArcNotYetImplemented,
+ (PRENAME_ROUTINE)BlArcNotYetImplemented,
+ (PARC_GET_DIRECTORY_ENTRY_ROUTINE)BlArcNotYetImplemented,
+ (PBOOTFS_INFO)BlArcNotYetImplemented
+ };
+
+#if defined(ELTORITO)
+BL_DEVICE_ENTRY_TABLE BiosEDDSEntryTable =
+ {
+ (PARC_CLOSE_ROUTINE)BiosDiskClose,
+ (PARC_MOUNT_ROUTINE)BlArcNotYetImplemented,
+ (PARC_OPEN_ROUTINE)BiosDiskOpen,
+ (PARC_READ_ROUTINE)BiosEDDSDiskRead,
+ (PARC_READ_STATUS_ROUTINE)BlArcNotYetImplemented,
+ (PARC_SEEK_ROUTINE)BiosPartitionSeek,
+ (PARC_WRITE_ROUTINE)BlArcNotYetImplemented,
+ (PARC_GET_FILE_INFO_ROUTINE)BiosGetFileInfo,
+ (PARC_SET_FILE_INFO_ROUTINE)BlArcNotYetImplemented,
+ (PRENAME_ROUTINE)BlArcNotYetImplemented,
+ (PARC_GET_DIRECTORY_ENTRY_ROUTINE)BlArcNotYetImplemented,
+ (PBOOTFS_INFO)BlArcNotYetImplemented
+ };
+#endif
+
+ARC_STATUS
+BiosDiskClose(
+ IN ULONG FileId
+ )
+
+/*++
+
+Routine Description:
+
+ Closes the specified device
+
+Arguments:
+
+ FileId - Supplies file id of the device to be closed
+
+Return Value:
+
+ ESUCCESS - Device closed successfully
+
+ !ESUCCESS - Device was not closed.
+
+--*/
+
+{
+ if (BlFileTable[FileId].Flags.Open == 0) {
+ BlPrint("ERROR - Unopened fileid %lx closed\n",FileId);
+ }
+ BlFileTable[FileId].Flags.Open = 0;
+
+ return(ESUCCESS);
+}
+
+ARC_STATUS
+BiosPartitionClose(
+ IN ULONG FileId
+ )
+
+/*++
+
+Routine Description:
+
+ Closes the specified device
+
+Arguments:
+
+ FileId - Supplies file id of the device to be closed
+
+Return Value:
+
+ ESUCCESS - Device closed successfully
+
+ !ESUCCESS - Device was not closed.
+
+--*/
+
+{
+ if (BlFileTable[FileId].Flags.Open == 0) {
+ BlPrint("ERROR - Unopened fileid %lx closed\n",FileId);
+ }
+ BlFileTable[FileId].Flags.Open = 0;
+
+ return(BiosDiskClose((ULONG)BlFileTable[FileId].u.PartitionContext.DiskId));
+}
+
+
+ARC_STATUS
+BiosPartitionOpen(
+ IN PCHAR OpenPath,
+ IN OPEN_MODE OpenMode,
+ OUT PULONG FileId
+ )
+
+/*++
+
+Routine Description:
+
+ Opens the disk partition specified by OpenPath. This routine will open
+ floppy drives 0 and 1, and any partition on hard drive 0 or 1.
+
+Arguments:
+
+ OpenPath - Supplies a pointer to the name of the partition. If OpenPath
+ is "A:" or "B:" the corresponding floppy drive will be opened.
+ If it is "C:" or above, this routine will find the corresponding
+ partition on hard drive 0 or 1 and open it.
+
+ OpenMode - Supplies the mode to open the file.
+ 0 - Read Only
+ 1 - Write Only
+ 2 - Read/Write
+
+ FileId - Returns the file descriptor for use with the Close, Read, Write,
+ and Seek routines
+
+Return Value:
+
+ ESUCCESS - File successfully opened.
+
+--*/
+
+{
+ ARC_STATUS Status;
+ ULONG DiskFileId;
+ UCHAR PartitionNumber;
+ ULONG Controller;
+ ULONG Key;
+ BOOLEAN IsEisa = FALSE;
+
+ //
+ // BIOS devices are always "multi(0)" (except for EISA flakiness
+ // where we treat "eisa(0)..." like "multi(0)..." in floppy cases.
+ //
+ if(FwGetPathMnemonicKey(OpenPath,"multi",&Key)) {
+
+ if(FwGetPathMnemonicKey(OpenPath,"eisa", &Key)) {
+ return(EBADF);
+ } else {
+ IsEisa = TRUE;
+ }
+ }
+
+ if (Key!=0) {
+ return(EBADF);
+ }
+
+ //
+ // If we're opening a floppy drive, there are no partitions
+ // so we can just return the physical device.
+ //
+
+ if((_stricmp(OpenPath,"multi(0)disk(0)fdisk(0)partition(0)") == 0) ||
+ (_stricmp(OpenPath,"eisa(0)disk(0)fdisk(0)partition(0)" ) == 0))
+ {
+ return(BiosDiskOpen( 0, 0, FileId));
+ }
+ if((_stricmp(OpenPath,"multi(0)disk(0)fdisk(1)partition(0)") == 0) ||
+ (_stricmp(OpenPath,"eisa(0)disk(0)fdisk(1)partition(0)" ) == 0))
+ {
+ return(BiosDiskOpen( 1, 0, FileId));
+ }
+
+ if((_stricmp(OpenPath,"multi(0)disk(0)fdisk(0)") == 0) ||
+ (_stricmp(OpenPath,"eisa(0)disk(0)fdisk(0)" ) == 0))
+ {
+ return(BiosDiskOpen( 0, 0, FileId));
+ }
+ if((_stricmp(OpenPath,"multi(0)disk(0)fdisk(1)") == 0) ||
+ (_stricmp(OpenPath,"eisa(0)disk(0)fdisk(1)" ) == 0))
+ {
+ return(BiosDiskOpen( 1, 0, FileId));
+ }
+
+ //
+ // We can't handle eisa(0) cases for hard disks.
+ //
+ if(IsEisa) {
+ return(EBADF);
+ }
+
+ //
+ // We can only deal with disk controller 0
+ //
+
+ if (FwGetPathMnemonicKey(OpenPath,"disk",&Controller)) {
+ return(EBADF);
+ }
+ if ( Controller!=0 ) {
+ return(EBADF);
+ }
+
+#if defined(ELTORITO)
+ if (!FwGetPathMnemonicKey(OpenPath,"cdrom",&Key)) {
+ //
+ // Now we have a CD-ROM disk number, so we open that for raw access.
+ // Use a special bit to indicate CD-ROM, because otherwise
+ // the BiosDiskOpen routine thinks a third or greater disk is
+ // a CD-ROM.
+ //
+ return(BiosDiskOpen( Key | 0x80000000, 0, FileId ) );
+ }
+#endif
+
+ if (FwGetPathMnemonicKey(OpenPath,"rdisk",&Key)) {
+ return(EBADF);
+ }
+
+ //
+ // Now we have a disk number, so we open that for raw access.
+ // We need to add 0x80 to translate it to a BIOS number.
+ //
+
+ Status = BiosDiskOpen( 0x80 + Key,
+ 0,
+ &DiskFileId );
+
+ if (Status != ESUCCESS) {
+ return(Status);
+ }
+
+ //
+ // Find the partition number to open
+ //
+
+ if (FwGetPathMnemonicKey(OpenPath,"partition",&Key)) {
+ BiosPartitionClose(DiskFileId);
+ return(EBADF);
+ }
+
+ //
+ // If the partition number was 0, then we are opening the device
+ // for raw access, so we are already done.
+ //
+ if (Key == 0) {
+ *FileId = DiskFileId;
+ return(ESUCCESS);
+ }
+
+ //
+ // Before we open the partition, we need to find an available
+ // file descriptor.
+ //
+
+ *FileId=2;
+
+ while (BlFileTable[*FileId].Flags.Open != 0) {
+ *FileId += 1;
+ if (*FileId == BL_FILE_TABLE_SIZE) {
+ return(ENOENT);
+ }
+ }
+
+ //
+ // We found an entry we can use, so mark it as open.
+ //
+ BlFileTable[*FileId].Flags.Open = 1;
+
+ BlFileTable[*FileId].DeviceEntryTable=&BiosPartitionEntryTable;
+
+
+ //
+ // Convert to zero-based partition number
+ //
+ PartitionNumber = (UCHAR)(Key - 1);
+
+ return (HardDiskPartitionOpen( *FileId,
+ DiskFileId,
+ PartitionNumber) );
+}
+
+
+ARC_STATUS
+BiosPartitionRead (
+ IN ULONG FileId,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ Reads from the specified file
+
+ NOTE John Vert (jvert) 18-Jun-1991
+ This only supports block sector reads. Thus, everything
+ is assumed to start on a sector boundary, and every offset
+ is considered an offset from the logical beginning of the disk
+ partition.
+
+Arguments:
+
+ FileId - Supplies the file to read from
+
+ Buffer - Supplies buffer to hold the data that is read
+
+ Length - Supplies maximum number of bytes to read
+
+ Count - Returns actual bytes read.
+
+Return Value:
+
+ ESUCCESS - Read completed successfully
+
+ !ESUCCESS - Read failed.
+
+--*/
+
+{
+ ARC_STATUS Status;
+ LARGE_INTEGER PhysicalOffset;
+ ULONG DiskId;
+
+ PhysicalOffset.QuadPart = BlFileTable[FileId].Position.QuadPart +
+ SECTOR_SIZE * BlFileTable[FileId].u.PartitionContext.StartingSector;
+
+ DiskId = BlFileTable[FileId].u.PartitionContext.DiskId;
+
+ Status = (BlFileTable[DiskId].DeviceEntryTable->Seek)(DiskId,
+ &PhysicalOffset,
+ SeekAbsolute );
+
+ if (Status != ESUCCESS) {
+ return(Status);
+ }
+
+ Status = (BlFileTable[DiskId].DeviceEntryTable->Read)(DiskId,
+ Buffer,
+ Length,
+ Count );
+
+ BlFileTable[FileId].Position.QuadPart += *Count;
+
+ return(Status);
+}
+
+
+
+ARC_STATUS
+BiosPartitionSeek (
+ IN ULONG FileId,
+ IN PLARGE_INTEGER Offset,
+ IN SEEK_MODE SeekMode
+ )
+
+/*++
+
+Routine Description:
+
+ Changes the current offset of the file specified by FileId
+
+Arguments:
+
+ FileId - specifies the file on which the current offset is to
+ be changed.
+
+ Offset - New offset into file.
+
+ SeekMode - Either SeekAbsolute or SeekRelative
+ SeekEndRelative is not supported
+
+Return Value:
+
+ ESUCCESS - Operation completed succesfully
+
+ EBADF - Operation did not complete successfully.
+
+--*/
+
+{
+ switch (SeekMode) {
+ case SeekAbsolute:
+ BlFileTable[FileId].Position = *Offset;
+ break;
+ case SeekRelative:
+ BlFileTable[FileId].Position.QuadPart += Offset->QuadPart;
+ break;
+ default:
+ BlPrint("SeekMode %lx not supported\n",SeekMode);
+ return(EACCES);
+
+ }
+ return(ESUCCESS);
+
+}
+
+
+
+ARC_STATUS
+BiosPartitionWrite(
+ IN ULONG FileId,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ Writes to the specified file
+
+ NOTE John Vert (jvert) 18-Jun-1991
+ This only supports block sector reads. Thus, everything
+ is assumed to start on a sector boundary, and every offset
+ is considered an offset from the logical beginning of the disk
+ partition.
+
+Arguments:
+
+ FileId - Supplies the file to write to
+
+ Buffer - Supplies buffer with data to write
+
+ Length - Supplies number of bytes to write
+
+ Count - Returns actual bytes written.
+
+Return Value:
+
+ ESUCCESS - write completed successfully
+
+ !ESUCCESS - write failed.
+
+--*/
+
+{
+ ARC_STATUS Status;
+ LARGE_INTEGER PhysicalOffset;
+ ULONG DiskId;
+
+ PhysicalOffset.QuadPart = BlFileTable[FileId].Position.QuadPart +
+ SECTOR_SIZE * BlFileTable[FileId].u.PartitionContext.StartingSector;
+
+ DiskId = BlFileTable[FileId].u.PartitionContext.DiskId;
+
+ Status = (BlFileTable[DiskId].DeviceEntryTable->Seek)(DiskId,
+ &PhysicalOffset,
+ SeekAbsolute );
+
+ if (Status != ESUCCESS) {
+ return(Status);
+ }
+
+ Status = (BlFileTable[DiskId].DeviceEntryTable->Write)(DiskId,
+ Buffer,
+ Length,
+ Count );
+
+ if(Status == ESUCCESS) {
+ BlFileTable[FileId].Position.QuadPart += *Count;
+ }
+
+ return(Status);
+}
+
+
+
+ARC_STATUS
+BiosConsoleOpen(
+ IN PCHAR OpenPath,
+ IN OPEN_MODE OpenMode,
+ OUT PULONG FileId
+ )
+
+/*++
+
+Routine Description:
+
+ Attempts to open either the console input or output
+
+Arguments:
+
+ OpenPath - Supplies a pointer to the name of the device to open. If
+ this is either CONSOLE_INPUT_NAME or CONSOLE_OUTPUT_NAME,
+ a file descriptor is allocated and filled in.
+
+ OpenMode - Supplies the mode to open the file.
+ 0 - Read Only (CONSOLE_INPUT_NAME)
+ 1 - Write Only (CONSOLE_OUTPUT_NAME)
+
+ FileId - Returns the file descriptor for use with the Close, Read and
+ Write routines
+
+Return Value:
+
+ ESUCCESS - Console successfully opened.
+
+--*/
+
+{
+ if (_stricmp(OpenPath, CONSOLE_INPUT_NAME)==0) {
+
+ //
+ // Open the keyboard for input
+ //
+
+ if (OpenMode != ArcOpenReadOnly) {
+ return(EACCES);
+ }
+
+ *FileId = 0;
+
+ return(ESUCCESS);
+ }
+
+ if (_stricmp(OpenPath, CONSOLE_OUTPUT_NAME)==0) {
+
+ //
+ // Open the display for output
+ //
+
+ if (OpenMode != ArcOpenWriteOnly) {
+ return(EACCES);
+ }
+ *FileId = 1;
+
+ return(ESUCCESS);
+ }
+
+ return(ENOENT);
+
+}
+
+ARC_STATUS
+BiosConsoleReadStatus(
+ IN ULONG FileId
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines if there is a keypress pending
+
+Arguments:
+
+ FileId - Supplies the FileId to be read. (should always be 0 for this
+ function)
+
+Return Value:
+
+ ESUCCESS - There is a key pending
+
+ EAGAIN - There is not a key pending
+
+--*/
+
+{
+ ULONG Key;
+
+ Key = GET_KEY();
+ if (Key != 0) {
+ //
+ // We got a key, so we have to stick it back into our buffer
+ // and return ESUCCESS.
+ //
+ BiosConsoleFillBuffer(Key);
+ return(ESUCCESS);
+
+ } else {
+ //
+ // no key pending
+ //
+ return(EAGAIN);
+ }
+
+}
+
+ARC_STATUS
+BiosConsoleRead(
+ IN ULONG FileId,
+ OUT PUCHAR Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ Gets input from the keyboard.
+
+Arguments:
+
+ FileId - Supplies the FileId to be read (should always be 0 for this
+ function)
+
+ Buffer - Returns the keyboard input.
+
+ Length - Supplies the length of the buffer (in bytes)
+
+ Count - Returns the actual number of bytes read
+
+Return Value:
+
+ ESUCCESS - Keyboard read completed succesfully.
+
+--*/
+
+{
+ ULONG Key;
+
+ *Count = 0;
+
+ while (*Count < Length) {
+ if (KeyBufferEnd == KeyBufferStart) { // then buffer is presently empty
+ do {
+
+ //
+ // Poll the keyboard until input is available
+ //
+
+ Key = GET_KEY();
+ } while ( Key==0 );
+
+ BiosConsoleFillBuffer(Key);
+ }
+
+ Buffer[*Count] = KeyBuffer[KeyBufferStart];
+ KeyBufferStart = (KeyBufferStart+1) % KEY_INPUT_BUFFER_SIZE;
+
+ *Count = *Count + 1;
+ }
+ return(ESUCCESS);
+}
+
+
+
+VOID
+BiosConsoleFillBuffer(
+ IN ULONG Key
+ )
+
+/*++
+
+Routine Description:
+
+ Places input from the keyboard into the keyboard buffer, expanding the
+ special keys as appropriate.
+
+Arguments:
+
+ Key - Raw keypress value as returned by GET_KEY().
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ switch(Key) {
+ case UP_ARROW:
+ KeyBuffer[KeyBufferEnd] = ASCI_CSI_IN;
+ KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
+ KeyBuffer[KeyBufferEnd] = 'A';
+ KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
+ break;
+
+ case DOWN_ARROW:
+ KeyBuffer[KeyBufferEnd] = ASCI_CSI_IN;
+ KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
+ KeyBuffer[KeyBufferEnd] = 'B';
+ KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
+ break;
+
+ case F1_KEY:
+ KeyBuffer[KeyBufferEnd] = ASCI_CSI_IN;
+ KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
+ KeyBuffer[KeyBufferEnd] = 'O';
+ KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
+ KeyBuffer[KeyBufferEnd] = 'P';
+ KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
+ break;
+
+ case F3_KEY:
+ KeyBuffer[KeyBufferEnd] = ASCI_CSI_IN;
+ KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
+ KeyBuffer[KeyBufferEnd] = 'O';
+ KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
+ KeyBuffer[KeyBufferEnd] = 'w';
+ KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
+ break;
+
+ case F5_KEY:
+ KeyBuffer[KeyBufferEnd] = ASCI_CSI_IN;
+ KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
+ KeyBuffer[KeyBufferEnd] = 'O';
+ KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
+ KeyBuffer[KeyBufferEnd] = 't';
+ KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
+ break;
+
+ case F6_KEY:
+ KeyBuffer[KeyBufferEnd] = ASCI_CSI_IN;
+ KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
+ KeyBuffer[KeyBufferEnd] = 'O';
+ KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
+ KeyBuffer[KeyBufferEnd] = 'u';
+ KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
+ break;
+
+ default:
+ //
+ // The ASCII code is the low byte of Key
+ //
+ KeyBuffer[KeyBufferEnd] = (UCHAR)(Key & 0xff);
+ KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
+ }
+}
+
+
+
+ARC_STATUS
+BiosConsoleWrite(
+ IN ULONG FileId,
+ OUT PUCHAR Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ Outputs to the console. (In this case, the VGA display)
+
+Arguments:
+
+ FileId - Supplies the FileId to be written (should always be 1 for this
+ function)
+
+ Buffer - Supplies characters to be output
+
+ Length - Supplies the length of the buffer (in bytes)
+
+ Count - Returns the actual number of bytes written
+
+Return Value:
+
+ ESUCCESS - Console write completed succesfully.
+
+--*/
+{
+ ARC_STATUS Status;
+ PUCHAR String;
+ ULONG Index;
+ UCHAR a;
+ PUCHAR p;
+
+ //
+ // Process each character in turn.
+ //
+
+ Status = ESUCCESS;
+ String = (PUCHAR)Buffer;
+
+ for ( *Count = 0 ;
+ *Count < Length ;
+ (*Count)++, String++ ) {
+
+ //
+ // If we're in the middle of a control sequence, continue scanning,
+ // otherwise process character.
+ //
+
+ if (ControlSequence) {
+
+ //
+ // If the character is a digit, update parameter value.
+ //
+
+ if ((*String >= '0') && (*String <= '9')) {
+ Parameter[PCount] = Parameter[PCount] * 10 + *String - '0';
+ continue;
+ }
+
+ //
+ // If we are in the middle of a font selection sequence, this
+ // character must be a 'D', otherwise reset control sequence.
+ //
+
+ if (FontSelection) {
+
+ //if (*String == 'D') {
+ //
+ // //
+ // // Other fonts not implemented yet.
+ // //
+ //
+ //} else {
+ //}
+
+ ControlSequence = FALSE;
+ FontSelection = FALSE;
+ continue;
+ }
+
+ switch (*String) {
+
+ //
+ // If a semicolon, move to the next parameter.
+ //
+
+ case ';':
+
+ PCount++;
+ if (PCount > CONTROL_SEQUENCE_MAX_PARAMETER) {
+ PCount = CONTROL_SEQUENCE_MAX_PARAMETER;
+ }
+ Parameter[PCount] = 0;
+ break;
+
+ //
+ // If a 'J', erase part or all of the screen.
+ //
+
+ case 'J':
+
+ switch (Parameter[0]) {
+ case 0:
+ //
+ // Erase to end of the screen
+ //
+ TextClearToEndOfDisplay();
+ break;
+
+ case 1:
+ //
+ // Erase from the beginning of the screen
+ //
+ break;
+
+ default:
+ //
+ // Erase entire screen
+ //
+ TextClearDisplay();
+ break;
+ }
+
+ ControlSequence = FALSE;
+ break;
+
+ //
+ // If a 'K', erase part or all of the line.
+ //
+
+ case 'K':
+
+ switch (Parameter[0]) {
+
+ //
+ // Erase to end of the line.
+ //
+
+ case 0:
+ TextClearToEndOfLine();
+ break;
+
+ //
+ // Erase from the beginning of the line.
+ //
+
+ case 1:
+ TextClearFromStartOfLine();
+ break;
+
+ //
+ // Erase entire line.
+ //
+
+ default :
+ TextClearFromStartOfLine();
+ TextClearToEndOfLine();
+ break;
+ }
+
+ ControlSequence = FALSE;
+ break;
+
+ //
+ // If a 'H', move cursor to position.
+ //
+
+ case 'H':
+ TextSetCursorPosition(Parameter[1]-1, Parameter[0]-1);
+ ControlSequence = FALSE;
+ break;
+
+ //
+ // If a ' ', could be a FNT selection command.
+ //
+
+ case ' ':
+ FontSelection = TRUE;
+ break;
+
+ case 'm':
+ //
+ // Select action based on each parameter.
+ //
+
+ for ( Index = 0 ; Index <= PCount ; Index++ ) {
+ switch (Parameter[Index]) {
+
+ //
+ // Attributes off.
+ //
+
+ case 0:
+ TextSetCurrentAttribute(7);
+ break;
+
+ //
+ // High Intensity.
+ //
+
+ case 1:
+ break;
+
+ //
+ // Underscored.
+ //
+
+ case 4:
+ break;
+
+ //
+ // Reverse Video.
+ //
+
+ case 7:
+ TextSetCurrentAttribute(0x70);
+ break;
+
+ //
+ // Font selection, not implemented yet.
+ //
+
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ case 16:
+ case 17:
+ case 18:
+ case 19:
+ break;
+
+ //
+ // Foreground Color
+ //
+
+ case 30:
+ case 31:
+ case 32:
+ case 33:
+ case 34:
+ case 35:
+ case 36:
+ case 37:
+ a = TextGetCurrentAttribute();
+ a &= 0xf0;
+ a |= TranslateColor[Parameter[Index]-30];
+ TextSetCurrentAttribute(a);
+ break;
+
+ //
+ // Background Color
+ //
+
+ case 40:
+ case 41:
+ case 42:
+ case 43:
+ case 44:
+ case 45:
+ case 46:
+ case 47:
+ a = TextGetCurrentAttribute();
+ a &= 0x0f;
+ a |= TranslateColor[Parameter[Index]-40] << 4;
+ TextSetCurrentAttribute(a);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ default:
+ ControlSequence = FALSE;
+ break;
+ }
+
+ //
+ // This is not a control sequence, check for escape sequence.
+ //
+
+ } else {
+
+ //
+ // If escape sequence, check for control sequence, otherwise
+ // process single character.
+ //
+
+ if (EscapeSequence) {
+
+ //
+ // Check for '[', means control sequence, any other following
+ // character is ignored.
+ //
+
+ if (*String == '[') {
+
+ ControlSequence = TRUE;
+
+ //
+ // Initialize first parameter.
+ //
+
+ PCount = 0;
+ Parameter[0] = 0;
+ }
+ EscapeSequence = FALSE;
+
+ //
+ // This is not a control or escape sequence, process single character.
+ //
+
+ } else {
+
+ switch (*String) {
+ //
+ // Check for escape sequence.
+ //
+
+ case ASCI_ESC:
+ EscapeSequence = TRUE;
+ break;
+
+ default:
+ p = TextCharOut(String);
+ //
+ // Each pass through the loop increments String by 1.
+ // If we output a dbcs char we need to increment by
+ // one more.
+ //
+ (*Count) += (p - String) - 1;
+ String += (p - String) - 1;
+ break;
+ }
+
+ }
+ }
+ }
+ return Status;
+}
+
+
+ARC_STATUS
+BiosDiskOpen(
+ IN ULONG DriveId,
+ IN OPEN_MODE OpenMode,
+ OUT PULONG FileId
+ )
+
+/*++
+
+Routine Description:
+
+ Opens a BIOS-accessible disk for raw sector access.
+
+Arguments:
+
+ DriveId - Supplies the BIOS DriveId of the drive to open
+ 0 - Floppy 0
+ 1 - Floppy 1
+ 0x80 - Hard Drive 0
+ 0x81 - Hard Drive 1
+ 0x82 - Hard Drive 2
+ etc
+#if defined(ELTORITO)
+ High bit set and ID > 0x81 means the device is expected to be
+ a CD-ROM drive.
+#endif
+
+ OpenMode - Supplies the mode of the open
+
+ FileId - Supplies a pointer to a variable that specifies the file
+ table entry that is filled in if the open is successful.
+
+Return Value:
+
+ ESUCCESS is returned if the open operation is successful. Otherwise,
+ an unsuccessful status is returned that describes the reason for failure.
+
+--*/
+
+{
+ ULONG NumberHeads;
+ ULONG NumberSectors;
+ ULONG NumberCylinders;
+ ULONG NumberDrives;
+ ULONG Result;
+ ULONG Return;
+ PDRIVE_CONTEXT Context;
+ ULONG Retries;
+
+#if defined(ELTORITO)
+ BOOLEAN IsCd;
+
+ if(DriveId > 0x80000081) {
+ IsCd = TRUE;
+ DriveId &= 0x7fffffff;
+ } else {
+ IsCd = FALSE;
+ }
+#endif
+
+ //
+ // If we are opening Floppy 0 or Floppy 1, we want to read the BPB off
+ // the disk so we can deal with all the odd disk formats.
+ //
+ // If we are opening a hard drive, we can just call the BIOS to find out
+ // its characteristics
+ //
+ if ((DriveId==0) || (DriveId==1)) {
+ UCHAR Buffer[512];
+ PPACKED_BOOT_SECTOR BootSector;
+ BIOS_PARAMETER_BLOCK Bpb;
+
+ //
+ // Read the boot sector off the floppy and extract the cylinder,
+ // sector, and head information.
+ //
+
+ Return = MdGetPhysicalSectors( (USHORT)DriveId,
+ 0, 0, 1,
+ 1,
+ Buffer );
+ if (Return != ESUCCESS) {
+#ifdef LOADER_DEBUG
+ BlPrint("Couldn't read first sector from drive %i\n",DriveId);
+ while (!GET_KEY()) {
+ }
+#endif
+ return(EIO);
+ }
+ BootSector = (PPACKED_BOOT_SECTOR)Buffer;
+
+ FatUnpackBios(&Bpb, &(BootSector->PackedBpb));
+
+ NumberHeads = Bpb.Heads;
+ NumberSectors = Bpb.SectorsPerTrack;
+ NumberCylinders = Bpb.Sectors / (NumberSectors * NumberHeads);
+
+#ifdef FLOPPY_CACHE
+ //
+ // Cache floppy 0 if not already cached.
+ //
+ if((DriveId == 0) && !FcIsThisFloppyCached(Buffer)) {
+ FcCacheFloppyDisk(&Bpb);
+ }
+#endif
+#if defined(ELTORITO)
+ } else if (IsCd) {
+ // This is an El Torito drive
+ // Just use bogus values since CHS values are meaningless for no-emulation El Torito boot
+
+ NumberCylinders = 1;
+ NumberHeads = 1;
+ NumberSectors = 1;
+#endif
+ } else {
+ Retries=0;
+ do {
+ Return=BIOS_IO( 0x08, // BIOS Get Drive Parameters
+ (USHORT)DriveId,
+ 0,0,0,0,0 ); // Not used
+ //
+ // At this point, AH should hold our return code, and ECX should look
+ // like this:
+ // bits 31..22 - Maximum cylinder
+ // bits 21..16 - Maximum sector
+ // bits 15..8 - Maximum head
+ // bits 7..0 - Number of drives
+ //
+ _asm {
+ mov Result, ecx
+ }
+
+ //
+ // Unpack the information from ecx
+ //
+
+ NumberDrives = Result & 0xff;
+ NumberHeads = ((Result >> 8) & 0xff) + 1;
+ NumberSectors = (Result >> 16) & 0x3f;
+ NumberCylinders = ((Result >> 24) + ((Result >> 14) &0x300)) + 1;
+
+ ++Retries;
+
+ } while ( ((NumberHeads==0) || (NumberSectors==0) || (NumberCylinders==0))
+ && (Retries < 5) );
+
+
+ if ((DriveId & 0x7f) >= NumberDrives) {
+ //
+ // The requested DriveId does not exist
+ //
+ return(EIO);
+ }
+
+ if (Retries == 5) {
+ #ifdef LOADER_DEBUG
+ BlPrint("Couldn't get BIOS configuration info\n");
+ #endif
+ return(EIO);
+ }
+ }
+
+#ifdef LOADER_DEBUG
+ BlPrint("Bios info: D %lx H %lx S %lx C %lx\n",
+ DriveId,
+ NumberHeads,
+ NumberSectors,
+ NumberCylinders );
+
+ while (!GET_KEY()) {
+ }
+#endif
+
+ //
+ // Find an available FileId descriptor to open the device with
+ //
+ *FileId=2;
+
+ while (BlFileTable[*FileId].Flags.Open != 0) {
+ *FileId += 1;
+ if (*FileId == BL_FILE_TABLE_SIZE) {
+ return(ENOENT);
+ }
+ }
+
+ //
+ // We found an entry we can use, so mark it as open.
+ //
+ BlFileTable[*FileId].Flags.Open = 1;
+
+#if defined(ELTORITO)
+ if(IsCd) {
+ // We're using the Phoenix Enhanced Disk Drive Spec
+ BlFileTable[*FileId].DeviceEntryTable = &BiosEDDSEntryTable;
+ } else {
+#endif
+ BlFileTable[*FileId].DeviceEntryTable = &BiosDiskEntryTable;
+#if defined(ELTORITO)
+ }
+#endif
+
+ Context = &(BlFileTable[*FileId].u.DriveContext);
+
+ Context->Drive = DriveId;
+ Context->Cylinders = NumberCylinders;
+ Context->Heads = NumberHeads;
+ Context->Sectors = NumberSectors;
+
+ return(ESUCCESS);
+}
+
+
+ARC_STATUS
+BiospWritePartialSector(
+ IN ULONGLONG Sector,
+ IN PUCHAR Buffer,
+ IN BOOLEAN IsHead,
+ IN ULONG Bytes,
+ IN PDRIVE_CONTEXT DriveContext
+ )
+{
+ ULONG head,sector,cylinder;
+ ULONG SectorsPerCylinder,r;
+ ARC_STATUS Status;
+
+ //
+ // figure out CHS values to address the given sector
+ //
+
+ SectorsPerCylinder = DriveContext->Heads * DriveContext->Sectors;
+ cylinder = (ULONG)(Sector / SectorsPerCylinder);
+ r = (ULONG)(Sector % SectorsPerCylinder);
+ head = r / DriveContext->Sectors;
+ sector = (r % DriveContext->Sectors) + 1;
+
+ //
+ // read sector into the write buffer
+ //
+
+ Status = MdGetPhysicalSectors((USHORT)DriveContext->Drive,
+ (USHORT)head,
+ (USHORT)cylinder,
+ (USHORT)sector,
+ 1,
+ LocalBuffer
+ );
+ if(Status != ESUCCESS) {
+ return(Status);
+ }
+
+ //
+ // xfer the appropriate bytes from the user buffer to the write buffer
+ //
+
+ RtlMoveMemory(IsHead ? LocalBuffer + Bytes : LocalBuffer,
+ Buffer,
+ IsHead ? SECTOR_SIZE - Bytes : Bytes
+ );
+
+ //
+ // write the sector out
+ //
+
+ Status = MdPutPhysicalSectors((USHORT)DriveContext->Drive,
+ (USHORT)head,
+ (USHORT)cylinder,
+ (USHORT)sector,
+ 1,
+ LocalBuffer
+ );
+ return(Status);
+}
+
+
+ARC_STATUS
+BiosDiskWrite(
+ IN ULONG FileId,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ Writes sectors directly to an open physical disk.
+
+Arguments:
+
+ FileId - Supplies the file to write to
+
+ Buffer - Supplies buffer with data to write
+
+ Length - Supplies number of bytes to write
+
+ Count - Returns actual bytes written
+
+Return Value:
+
+ ESUCCESS - write completed successfully
+
+ !ESUCCESS - write failed
+
+--*/
+
+{
+ ULONGLONG HeadSector,TailSector,CurrentSector;
+ ULONG HeadOffset,TailByteCount;
+ ARC_STATUS Status;
+ ULONG BytesLeftToTransfer = Length;
+ PUCHAR UserBuffer = Buffer;
+ ULONG SectorsPerCylinder,SectorsPerTrack;
+ ULONG cylinder,head,sector,r;
+ ULONG SectorsToTransfer;
+ BOOLEAN Under1MegLine = FALSE;
+ PVOID TransferBuffer;
+
+ if (LocalBuffer==NULL) {
+ LocalBuffer = FwAllocateHeap(SCRATCH_BUFFER_SIZE);
+ if (LocalBuffer==NULL) {
+ return(ENOMEM);
+ }
+ }
+
+ HeadSector = BlFileTable[FileId].Position.QuadPart / SECTOR_SIZE;
+ HeadOffset = (ULONG)(BlFileTable[FileId].Position.QuadPart % SECTOR_SIZE);
+
+ TailSector = (BlFileTable[FileId].Position.QuadPart + Length) / SECTOR_SIZE;
+ TailByteCount = (ULONG)((BlFileTable[FileId].Position.QuadPart + Length) % SECTOR_SIZE);
+
+ CurrentSector = HeadSector;
+
+ SectorsPerTrack = BlFileTable[FileId].u.DriveContext.Sectors;
+ SectorsPerCylinder = BlFileTable[FileId].u.DriveContext.Heads
+ * SectorsPerTrack;
+
+ //
+ // special case of transfer occuring entirely within one sector
+ //
+
+ if(HeadOffset && TailByteCount && (HeadSector == TailSector)) {
+
+ cylinder = (ULONG)(CurrentSector / SectorsPerCylinder);
+ r = (ULONG)(CurrentSector % SectorsPerCylinder);
+ head = r / SectorsPerTrack;
+ sector = (r % SectorsPerTrack) + 1;
+
+ Status = MdGetPhysicalSectors((USHORT)BlFileTable[FileId].u.DriveContext.Drive,
+ (USHORT)head,
+ (USHORT)cylinder,
+ (USHORT)sector,
+ 1,
+ LocalBuffer
+ );
+
+ if(Status != ESUCCESS) {
+ return(Status);
+ }
+
+ RtlMoveMemory((PUCHAR)LocalBuffer + HeadOffset,
+ Buffer,
+ Length
+ );
+
+ Status = MdPutPhysicalSectors((USHORT)BlFileTable[FileId].u.DriveContext.Drive,
+ (USHORT)head,
+ (USHORT)cylinder,
+ (USHORT)sector,
+ 1,
+ LocalBuffer
+ );
+ if(Status != ESUCCESS) {
+ return(Status);
+ }
+
+ goto BiosWriteDone;
+ }
+
+ if(HeadOffset) {
+
+ Status = BiospWritePartialSector(HeadSector,
+ Buffer,
+ TRUE, // head, not tail
+ HeadOffset,
+ &BlFileTable[FileId].u.DriveContext
+ );
+ if(Status != ESUCCESS) {
+ return(Status);
+ }
+
+ BytesLeftToTransfer -= SECTOR_SIZE - HeadOffset;
+ UserBuffer += SECTOR_SIZE - HeadOffset;
+ CurrentSector += 1;
+ }
+
+ if(TailByteCount) {
+
+ Status = BiospWritePartialSector(TailSector,
+ (PUCHAR)Buffer + Length - TailByteCount,
+ FALSE,
+ TailByteCount,
+ &BlFileTable[FileId].u.DriveContext
+ );
+
+ if(Status != ESUCCESS) {
+ return(Status);
+ }
+
+ BytesLeftToTransfer -= TailByteCount;
+ }
+
+
+ //
+ // The following calculation is not inside the transfer loop because
+ // it is unlikely that a caller's buffer will *cross* the 1 meg line
+ // due to the PC memory map.
+ //
+
+ if((ULONG)UserBuffer + BytesLeftToTransfer <= 0x100000) {
+ Under1MegLine = TRUE;
+ }
+
+ //
+ // now handle the middle part. This is some number of whole sectors.
+ //
+
+ while(BytesLeftToTransfer) {
+
+ //
+ // Get CHS address of current sector
+ //
+
+ cylinder = (ULONG)(CurrentSector / SectorsPerCylinder);
+ r = (ULONG)(CurrentSector % SectorsPerCylinder);
+
+ head = r / SectorsPerTrack;
+ sector = (r % SectorsPerTrack) + 1;
+
+ //
+ // The number of sectors to transfer is the minimum of:
+ // - the number of sectors left in the current track
+ // - BytesLeftToTransfer / SECTOR_SIZE
+ //
+
+ SectorsToTransfer = min(SectorsPerTrack - sector + 1,BytesLeftToTransfer / SECTOR_SIZE);
+
+ //
+ // Now we'll figure out where to transfer the data from. If the
+ // caller's buffer is under the 1 meg line, we can transfer the
+ // data directly from the caller's buffer. Otherwise we'll copy the
+ // user's buffer to our local buffer and transfer from there.
+ // In the latter case we can only transfer in chunks of
+ // SCRATCH_BUFFER_SIZE because that's the size of the local buffer.
+ //
+ // Also make sure the transfer won't cross a 64k boundary.
+ //
+
+ if(Under1MegLine) {
+
+ //
+ // Check if the transfer would cross a 64k boundary. If so,
+ // use the local buffer. Otherwise use the user's buffer.
+ //
+
+ if(((ULONG)UserBuffer & 0xffff0000)
+ != (((ULONG)UserBuffer + (SectorsToTransfer * SECTOR_SIZE) - 1) & 0xffff0000))
+ {
+ TransferBuffer = LocalBuffer;
+ SectorsToTransfer = min(SectorsToTransfer,SCRATCH_BUFFER_SIZE / SECTOR_SIZE);
+
+ } else {
+
+ TransferBuffer = UserBuffer;
+ }
+ } else {
+ TransferBuffer = LocalBuffer;
+ SectorsToTransfer = min(SectorsToTransfer,SCRATCH_BUFFER_SIZE / SECTOR_SIZE);
+ }
+
+ if(TransferBuffer == LocalBuffer) {
+ RtlMoveMemory(LocalBuffer,UserBuffer,SectorsToTransfer*SECTOR_SIZE);
+ }
+
+ Status = MdPutPhysicalSectors((USHORT)BlFileTable[FileId].u.DriveContext.Drive,
+ (USHORT)head,
+ (USHORT)cylinder,
+ (USHORT)sector,
+ (USHORT)SectorsToTransfer,
+ TransferBuffer
+ );
+
+ if(Status != ESUCCESS) {
+ return(Status);
+ }
+
+ CurrentSector += SectorsToTransfer;
+ BytesLeftToTransfer -= SectorsToTransfer * SECTOR_SIZE;
+ UserBuffer += SectorsToTransfer * SECTOR_SIZE;
+ }
+
+ BiosWriteDone:
+
+ *Count = Length;
+ BlFileTable[FileId].Position.QuadPart += Length;
+ return(ESUCCESS);
+}
+
+
+ARC_STATUS
+BiosDiskRead (
+ IN ULONG FileId,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ Reads sectors directly from an open physical disk.
+
+Arguments:
+
+ FileId - Supplies the file to read from
+
+ Buffer - Supplies buffer to hold the data that is read
+
+ Length - Supplies maximum number of bytes to read
+
+ Count - Returns actual bytes read
+
+Return Value:
+
+ ESUCCESS - Read completed successfully
+
+ !ESUCCESS - Read failed
+
+--*/
+
+{
+ ULONGLONG HeadSector,TailSector,CurrentSector;
+ ULONG HeadOffset,TailByteCount;
+ ULONG BytesLeftToTransfer = Length;
+ ULONG SectorsPerTrack,SectorsPerCylinder;
+ ARC_STATUS Status;
+ PUCHAR UserBuffer = Buffer;
+ ULONG cylinder,head,sector,r;
+ ULONG SectorsToTransfer;
+ BOOLEAN Under1MegLine = FALSE;
+ PVOID TransferBuffer;
+
+
+#ifdef FLOPPY_CACHE
+ //
+ // For A:, try to satisfy the read from the cache.
+ //
+ if(!BlFileTable[FileId].u.DriveContext.Drive) {
+
+ Status = FcReadFromCache(
+ BlFileTable[FileId].Position.LowPart,
+ Length,
+ Buffer
+ );
+
+ if(Status == ESUCCESS) {
+
+ BlFileTable[FileId].Position.QuadPart += Length;
+ *Count = Length;
+
+ return(ESUCCESS);
+ }
+
+ //
+ // EINVAL means the read could not be satisfied from the cache.
+ //
+ if(Status != EINVAL) {
+ return(Status);
+ }
+ }
+#endif
+
+ if (LocalBuffer==NULL) {
+ LocalBuffer = FwAllocateHeap(SCRATCH_BUFFER_SIZE);
+ if (LocalBuffer==NULL) {
+ return(ENOMEM);
+ }
+ }
+
+ SectorsPerTrack = BlFileTable[FileId].u.DriveContext.Sectors;
+ SectorsPerCylinder = BlFileTable[FileId].u.DriveContext.Heads
+ * SectorsPerTrack;
+
+ HeadSector = BlFileTable[FileId].Position.QuadPart / SECTOR_SIZE;
+ HeadOffset = (ULONG)(BlFileTable[FileId].Position.QuadPart % SECTOR_SIZE);
+
+ TailSector = (BlFileTable[FileId].Position.QuadPart + Length) / SECTOR_SIZE;
+ TailByteCount = (ULONG)((BlFileTable[FileId].Position.QuadPart + Length) % SECTOR_SIZE);
+
+ CurrentSector = HeadSector;
+ if(HeadOffset && TailByteCount && (HeadSector == TailSector)) {
+
+ cylinder = (ULONG)(HeadSector / SectorsPerCylinder);
+ r = (ULONG)(HeadSector % SectorsPerCylinder);
+ head = r / SectorsPerTrack;
+ sector = (r % SectorsPerTrack) + 1;
+
+ Status = MdGetPhysicalSectors((USHORT)BlFileTable[FileId].u.DriveContext.Drive,
+ (USHORT)head,
+ (USHORT)cylinder,
+ (USHORT)sector,
+ 1,
+ LocalBuffer
+ );
+
+ if(Status != ESUCCESS) {
+ return(Status);
+ }
+
+ RtlMoveMemory(Buffer,LocalBuffer + HeadOffset,Length);
+ goto BiosDiskReadDone;
+ }
+
+ if(HeadOffset) {
+
+ cylinder = (ULONG)(HeadSector / SectorsPerCylinder);
+ r = (ULONG)(HeadSector % SectorsPerCylinder);
+ head = r / SectorsPerTrack;
+ sector = (r % SectorsPerTrack) + 1;
+
+ Status = MdGetPhysicalSectors((USHORT)BlFileTable[FileId].u.DriveContext.Drive,
+ (USHORT)head,
+ (USHORT)cylinder,
+ (USHORT)sector,
+ 1,
+ LocalBuffer
+ );
+
+ if(Status != ESUCCESS) {
+ return(Status);
+ }
+
+ RtlMoveMemory(Buffer,LocalBuffer + HeadOffset,SECTOR_SIZE - HeadOffset);
+
+ BytesLeftToTransfer -= SECTOR_SIZE - HeadOffset;
+ UserBuffer += SECTOR_SIZE - HeadOffset;
+ CurrentSector = HeadSector + 1;
+ }
+
+ if(TailByteCount) {
+
+ cylinder = (ULONG)(TailSector / SectorsPerCylinder);
+ r = (ULONG)(TailSector % SectorsPerCylinder);
+ head = r / SectorsPerTrack;
+ sector = (r % SectorsPerTrack) + 1;
+
+ Status = MdGetPhysicalSectors((USHORT)BlFileTable[FileId].u.DriveContext.Drive,
+ (USHORT)head,
+ (USHORT)cylinder,
+ (USHORT)sector,
+ 1,
+ LocalBuffer
+ );
+ if(Status != ESUCCESS) {
+ return(Status);
+ }
+ RtlMoveMemory((PUCHAR)Buffer+Length-TailByteCount,LocalBuffer,TailByteCount);
+
+ BytesLeftToTransfer -= TailByteCount;
+ }
+
+ //
+ // The following calculation is not inside the transfer loop because
+ // it is unlikely that a caller's buffer will *cross* the 1 meg line
+ // due to the PC memory map.
+ //
+
+ if((ULONG)UserBuffer + BytesLeftToTransfer <= 0x100000) {
+ Under1MegLine = TRUE;
+ }
+
+ //
+ // Now BytesLeftToTransfer is an integral multiple of sector size.
+ //
+
+ while(BytesLeftToTransfer) {
+
+ cylinder = (ULONG)(CurrentSector / SectorsPerCylinder);
+ r = (ULONG)(CurrentSector % SectorsPerCylinder);
+ head = r / SectorsPerTrack;
+ sector = (r % SectorsPerTrack) + 1;
+
+ //
+ // The number of sectors to transfer is the minimum of:
+ // - the number of sectors left in the current track
+ // - BytesLeftToTransfer / SECTOR_SIZE
+ //
+
+ SectorsToTransfer = min(SectorsPerTrack - sector + 1,BytesLeftToTransfer / SECTOR_SIZE);
+
+ //
+ // Now we'll figure out where to transfer the data to. If the
+ // caller's buffer is under the 1 meg line, we can transfer the
+ // data directly to the caller's buffer. Otherwise we'll transfer
+ // the data to our local buffer and copy it to the caller's buffer.
+ // In the latter case we can only transfer in chunks of
+ // SCRATCH_BUFFER_SIZE because that's the size of the local buffer.
+ //
+ // Also make sure the transfer won't cross a 64k boundary.
+ //
+
+ if(Under1MegLine) {
+
+ //
+ // Check if the transfer would cross a 64k boundary. If so,
+ // use the local buffer. Otherwise use the user's buffer.
+ //
+
+ if(((ULONG)UserBuffer & 0xffff0000)
+ != (((ULONG)UserBuffer + (SectorsToTransfer * SECTOR_SIZE) - 1) & 0xffff0000))
+ {
+ TransferBuffer = LocalBuffer;
+ SectorsToTransfer = min(SectorsToTransfer,SCRATCH_BUFFER_SIZE / SECTOR_SIZE);
+
+ } else {
+
+ TransferBuffer = UserBuffer;
+ }
+ } else {
+ TransferBuffer = LocalBuffer;
+ SectorsToTransfer = min(SectorsToTransfer,SCRATCH_BUFFER_SIZE / SECTOR_SIZE);
+ }
+
+ Status = MdGetPhysicalSectors((USHORT)BlFileTable[FileId].u.DriveContext.Drive,
+ (USHORT)head,
+ (USHORT)cylinder,
+ (USHORT)sector,
+ (USHORT)SectorsToTransfer,
+ TransferBuffer
+ );
+
+ if(Status != ESUCCESS) {
+ return(Status);
+ }
+
+ if(TransferBuffer == LocalBuffer) {
+
+ RtlMoveMemory(UserBuffer,LocalBuffer,SectorsToTransfer * SECTOR_SIZE);
+ }
+ UserBuffer += SectorsToTransfer * SECTOR_SIZE;
+ CurrentSector += SectorsToTransfer;
+ BytesLeftToTransfer -= SectorsToTransfer*SECTOR_SIZE;
+ }
+
+ BiosDiskReadDone:
+
+ *Count = Length;
+ BlFileTable[FileId].Position.QuadPart += Length;
+ return(ESUCCESS);
+}
+
+
+#if defined(ELTORITO)
+ARC_STATUS
+BiosEDDSDiskRead (
+ IN ULONG FileId,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ Reads sectors directly from an open physical disk using Phoenix Enhanced Disk Drive Spec. interface.
+
+ BUGBUG - sector size of 2048 shouldn't be used here - instead to sector size should be obtained
+ from drive context.
+
+Arguments:
+
+ FileId - Supplies the file to read from
+
+ Buffer - Supplies buffer to hold the data that is read
+
+ Length - Supplies maximum number of bytes to read
+
+ Count - Returns actual bytes read
+
+Return Value:
+
+ ESUCCESS - Read completed successfully
+
+ !ESUCCESS - Read failed
+
+--*/
+
+{
+
+ ULONGLONG StartLBA, EndLBA, CurrentLBA;
+ ULONG CurrentLBAHigh, CurrentLBALow;
+ ULONG StartOffset,EndOffset;
+ ULONG BytesLeftToTransfer = Length;
+ ARC_STATUS Status;
+ ULONG LBsToTransfer;
+ PUCHAR UserBuffer = Buffer;
+ BOOLEAN Under1MegLine = FALSE;
+ PVOID TransferBuffer;
+
+ if (LocalBuffer==NULL) {
+ LocalBuffer = FwAllocateHeap(SCRATCH_BUFFER_SIZE);
+ if (LocalBuffer==NULL) {
+ return(ENOMEM);
+ }
+ }
+
+ StartLBA = BlFileTable[FileId].Position.QuadPart / 2048;
+ StartOffset = (ULONG)(BlFileTable[FileId].Position.QuadPart % 2048);
+
+ EndLBA = (BlFileTable[FileId].Position.QuadPart + Length) / 2048;
+ EndOffset = (ULONG)((BlFileTable[FileId].Position.QuadPart + Length) % 2048);
+
+ CurrentLBA = StartLBA;
+
+ if(StartOffset && EndOffset && (StartLBA == EndLBA)) {
+ //
+ // We're starting and ending in the middle of a Logical Block - this transfers the whole thing
+ //
+
+ CurrentLBALow = (ULONG)(CurrentLBA & 0x00000000ffffffff);
+ CurrentLBAHigh = (ULONG)(CurrentLBA >> 32 & 0x00000000ffffffff);
+
+ Status = MdEddsGetPhysicalSectors((USHORT)BlFileTable[FileId].u.DriveContext.Drive,
+ (ULONG)CurrentLBALow,
+ (ULONG)CurrentLBAHigh,
+ 1,
+ LocalBuffer
+ );
+
+ if(Status != ESUCCESS) {
+ return(Status);
+ }
+
+ RtlMoveMemory(Buffer,LocalBuffer + StartOffset,Length);
+ goto BiosEDDSDiskReadDone;
+ }
+
+ if(StartOffset) {
+ //
+ // We're starting in the middle of a Logical Block, but ending in another - this transfers the first piece
+ //
+
+ CurrentLBALow = (ULONG)(CurrentLBA & 0x00000000ffffffff);
+ CurrentLBAHigh = (ULONG)(CurrentLBA >> 32 & 0x00000000ffffffff);
+
+ Status = MdEddsGetPhysicalSectors((USHORT)BlFileTable[FileId].u.DriveContext.Drive,
+ (ULONG)CurrentLBALow,
+ (ULONG)CurrentLBAHigh,
+ 1,
+ LocalBuffer
+ );
+
+ if(Status != ESUCCESS) {
+ return(Status);
+ }
+
+ RtlMoveMemory(Buffer, LocalBuffer + StartOffset, 2048 - StartOffset);
+
+ BytesLeftToTransfer -= (2048 - StartOffset);
+ UserBuffer += (2048 - StartOffset);
+ CurrentLBA = StartLBA + 1;
+ }
+
+ if(EndOffset) {
+ //
+ // We're ending in the middle of a Logical Block - this just transfers the end piece
+ //
+
+ CurrentLBALow = (ULONG)(EndLBA & 0x00000000ffffffff);
+ CurrentLBAHigh = (ULONG)(EndLBA >> 32 & 0x00000000ffffffff);
+
+ Status = MdEddsGetPhysicalSectors((USHORT)BlFileTable[FileId].u.DriveContext.Drive,
+ (ULONG)CurrentLBALow,
+ (ULONG)CurrentLBAHigh,
+ 1,
+ LocalBuffer
+ );
+ if(Status != ESUCCESS) {
+ return(Status);
+ }
+ RtlMoveMemory((PUCHAR)Buffer+Length-EndOffset, LocalBuffer, EndOffset);
+
+ BytesLeftToTransfer -= EndOffset;
+ }
+
+ //
+ // The following calculation is not inside the transfer loop because
+ // it is unlikely that a caller's buffer will *cross* the 1 meg line
+ // due to the PC memory map.
+ //
+
+ if((ULONG)UserBuffer + BytesLeftToTransfer <= 0x100000) {
+ Under1MegLine = TRUE;
+ }
+
+ //
+ // Now BytesLeftToTransfer is an integral multiple of logical blocks.
+ //
+ while(BytesLeftToTransfer) {
+
+ LBsToTransfer = BytesLeftToTransfer / 2048;
+
+ //
+ // Now we'll figure out where to transfer the data to. If the
+ // caller's buffer is under the 1 meg line, we can transfer the
+ // data directly to the caller's buffer. Otherwise we'll transfer
+ // the data to our local buffer and copy it to the caller's buffer.
+ // In the latter case we can only transfer in chunks of
+ // SCRATCH_BUFFER_SIZE because that's the size of the local buffer.
+ //
+ // Also make sure the transfer won't cross a 64k boundary.
+ //
+
+ if(Under1MegLine) {
+ //
+ // Check if the transfer would cross a 64k boundary. If so,
+ // use the local buffer. Otherwise use the user's buffer.
+ //
+
+ if(((ULONG)UserBuffer & 0xffff0000)
+ != (((ULONG)UserBuffer + (LBsToTransfer * 2048) - 1) & 0xffff0000))
+ {
+ TransferBuffer = LocalBuffer;
+ LBsToTransfer = min(LBsToTransfer, SCRATCH_BUFFER_SIZE / 2048);
+ } else {
+ TransferBuffer = UserBuffer;
+ }
+ } else {
+ TransferBuffer = LocalBuffer;
+ LBsToTransfer = min(LBsToTransfer, SCRATCH_BUFFER_SIZE / 2048);
+ }
+
+ CurrentLBALow = (ULONG)(CurrentLBA & 0x00000000ffffffff);
+ CurrentLBAHigh = (ULONG)(CurrentLBA >> 32 & 0x00000000ffffffff);
+
+ Status = MdEddsGetPhysicalSectors((USHORT)BlFileTable[FileId].u.DriveContext.Drive,
+ (ULONG)CurrentLBALow,
+ (ULONG)CurrentLBAHigh,
+ (USHORT)LBsToTransfer,
+ TransferBuffer
+ );
+
+ if(Status != ESUCCESS) {
+ return(Status);
+ }
+
+ if(TransferBuffer == LocalBuffer) {
+
+ RtlMoveMemory(UserBuffer, LocalBuffer, LBsToTransfer * 2048);
+
+ }
+ UserBuffer += LBsToTransfer * 2048;
+ CurrentLBA += LBsToTransfer;
+ BytesLeftToTransfer -= (LBsToTransfer * 2048);
+ }
+
+ BiosEDDSDiskReadDone:
+
+ *Count = Length;
+ BlFileTable[FileId].Position.QuadPart += Length;
+ return(ESUCCESS);
+}
+#endif
+
+
+ARC_STATUS
+BiosGetFileInfo(
+ IN ULONG FileId,
+ OUT PFILE_INFORMATION Finfo
+ )
+{
+ //
+ // THIS ROUTINE DOES NOT WORK FOR PARTITION 0.
+ //
+
+ PPARTITION_CONTEXT Context;
+
+ RtlZeroMemory(Finfo, sizeof(FILE_INFORMATION));
+
+ Context = &BlFileTable[FileId].u.PartitionContext;
+
+ Finfo->StartingAddress.QuadPart = Context->StartingSector;
+ Finfo->StartingAddress.QuadPart = Finfo->StartingAddress.QuadPart << (CCHAR)Context->SectorShift;
+
+ Finfo->EndingAddress.QuadPart = Finfo->StartingAddress.QuadPart + Context->PartitionLength.QuadPart;
+
+ Finfo->Type = DiskPeripheral;
+
+ return ESUCCESS;
+}
diff --git a/private/ntos/boot/lib/i386/bootfont.h b/private/ntos/boot/lib/i386/bootfont.h
new file mode 100644
index 000000000..58ebc74fc
--- /dev/null
+++ b/private/ntos/boot/lib/i386/bootfont.h
@@ -0,0 +1,106 @@
+/*++
+
+Copyright (c) 1995 Microsoft Corporation
+
+Module Name:
+
+ bootfint.h
+
+Abstract:
+
+ Header file describing the bootfont.bin file used to provide
+ dbcs support during system or setup bootstrap.
+
+Author:
+
+ tedm 11-July-1995
+
+Revision History:
+
+--*/
+
+
+//
+// Define maximum number of dbcs lead byte ranges we support.
+//
+#define MAX_DBCS_RANGE 5
+
+//
+// Define signature value.
+//
+#define BOOTFONTBIN_SIGNATURE 0x5465644d
+
+//
+// Define structure used as a header for the bootfont.bin file.
+//
+typedef struct _BOOTFONTBIN_HEADER {
+
+ //
+ // Signature. Must be BOOTFONTBIN_SIGNATURE.
+ //
+ ULONG Signature;
+
+ //
+ // Language id of the language supported by this font.
+ // This should match the language id of resources in msgs.xxx.
+ //
+ ULONG LanguageId;
+
+ //
+ // Number of sbcs characters and dbcs characters contained in the file.
+ //
+ unsigned NumSbcsChars;
+ unsigned NumDbcsChars;
+
+ //
+ // Offsets within the file to the images.
+ //
+ unsigned SbcsOffset;
+ unsigned DbcsOffset;
+
+ //
+ // Total sizes of the images.
+ //
+ unsigned SbcsEntriesTotalSize;
+ unsigned DbcsEntriesTotalSize;
+
+ //
+ // Dbcs lead byte table. Must contain a pair of 0's to indicate the end.
+ //
+ UCHAR DbcsLeadTable[(MAX_DBCS_RANGE+1)*2];
+
+ //
+ // Height values for the font.
+ // CharacterImageHeight is the height in scan lines/pixels of the
+ // font image. Each character is drawn with additional 'padding'
+ // lines on the top and bottom, whose sizes are also contained here.
+ //
+ UCHAR CharacterImageHeight;
+ UCHAR CharacterTopPad;
+ UCHAR CharacterBottomPad;
+
+ //
+ // Width values for the font. These values contain the width in pixels
+ // of a single byte character and double byte character.
+ //
+ // NOTE: CURRENTLY THE SINGLE BYTE WIDTH *MUST* BE 8 AND THE DOUBLE BYTE
+ // WIDTH *MUST* BE 16!!!
+ //
+ UCHAR CharacterImageSbcsWidth;
+ UCHAR CharacterImageDbcsWidth;
+
+} BOOTFONTBIN_HEADER, *PBOOTFONTBIN_HEADER;
+
+//
+// Images themselves follow.
+//
+// First there are SbcsCharacters entries for single-byte chars.
+// The first byte in each entry is the ascii char code. The next n bytes are
+// the image. n is dependent on the width and height of an sbcs char.
+//
+// Following these are the dbcs images. The first 2 bytes are the dbcs
+// character code (highbyte lowbyte) and the next n bytes are the image.
+// n is dependent on the width and height of a dbcs char.
+//
+// Important note: the characters must be sorted in ascending order!
+//
diff --git a/private/ntos/boot/lib/i386/bootx86.h b/private/ntos/boot/lib/i386/bootx86.h
new file mode 100644
index 000000000..70aac05af
--- /dev/null
+++ b/private/ntos/boot/lib/i386/bootx86.h
@@ -0,0 +1,414 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ booti386.h
+
+Abstract:
+
+ Header file for the x86-specific portions of the common boot library
+
+Author:
+
+ John Vert (jvert) 14-Oct-1993
+
+Revision History:
+
+--*/
+
+#include "bldrx86.h"
+#include "bootlib.h"
+
+//
+// common typedefs
+//
+
+
+typedef struct _FSCONTEXT_RECORD {
+ ULONG BootDrive;
+ PACKED_BIOS_PARAMETER_BLOCK *PackedBPB;
+} FSCONTEXT_RECORD, *PFSCONTEXT_RECORD;
+// M E M O R Y D E S C R I P T O R
+//
+// Memory Descriptor - each contiguous block of physical memory is
+// described by a Memory Descriptor. The descriptors are a table, with
+// the last entry having a BlockBase and BlockSize of zero. A pointer
+// to the beginning of this table is passed as part of the BootContext
+// Record to the OS Loader.
+//
+
+typedef struct _SU_MEMORY_DESCRIPTOR {
+ ULONG BlockBase;
+ ULONG BlockSize;
+} SU_MEMORY_DESCRIPTOR , *PSU_MEMORY_DESCRIPTOR;
+
+VOID
+InitializeMemoryDescriptors (
+ VOID
+ );
+
+
+// B O O T C O N T E X T R E C O R D
+//
+// Passed to the OS loader by the SU module or bootstrap
+// code, whatever the case. Constains all the basic machine
+// and environment information the OS loaders needs to get
+// itself going.
+//
+
+typedef struct _BOOT_CONTEXT {
+ PFSCONTEXT_RECORD FSContextPointer;
+ PEXTERNAL_SERVICES_TABLE ExternalServicesTable;
+ PSU_MEMORY_DESCRIPTOR MemoryDescriptorList;
+ ULONG MachineType;
+ ULONG OsLoaderStart;
+ ULONG OsLoaderEnd;
+ ULONG ResourceDirectory;
+ ULONG ResourceOffset;
+ ULONG OsLoaderBase;
+ ULONG OsLoaderExports;
+} BOOT_CONTEXT, *PBOOT_CONTEXT;
+//
+// Common function prototypes
+//
+VOID
+InitializeDisplaySubsystem(
+ VOID
+ );
+
+ARC_STATUS
+InitializeMemorySubsystem(
+ PBOOT_CONTEXT
+ );
+
+ARC_STATUS
+MdGetPhysicalSectors(
+ USHORT Drive,
+ USHORT HeadNumber,
+ USHORT TrackNumber,
+ USHORT SectorNumber,
+ USHORT NumberOfSectors,
+ PUCHAR PointerToBuffer
+ );
+
+#if defined(ELTORITO)
+ARC_STATUS
+MdEddsGetPhysicalSectors(
+ IN USHORT Drive,
+ IN ULONG LBALow,
+ IN ULONG LBAHigh,
+ IN USHORT NumberOfBlocks,
+ PUCHAR PointerToBuffer
+ );
+#endif
+
+ARC_STATUS
+MdPutPhysicalSectors(
+ USHORT Drive,
+ USHORT HeadNumber,
+ USHORT TrackNumber,
+ USHORT SectorNumber,
+ USHORT NumberOfSectors,
+ PUCHAR PointerToBuffer
+ );
+
+NTSTATUS
+MdResetDiskSystem(
+ USHORT Drive
+ );
+
+VOID
+MdShutoffFloppy(
+ VOID
+ );
+
+BOOLEAN
+FwGetPathMnemonicKey(
+ IN PCHAR OpenPath,
+ IN PCHAR Mnemonic,
+ IN PULONG Key
+ );
+
+PVOID
+FwAllocateHeapAligned(
+ IN ULONG Size
+ );
+
+PVOID
+FwAllocatePool(
+ IN ULONG Size
+ );
+
+PVOID
+FwAllocateHeapPermanent(
+ IN ULONG NumberPages
+ );
+
+VOID
+FwStallExecution(
+ IN ULONG Microseconds
+ );
+
+VOID
+BlGetActivePartition(
+ OUT PUCHAR PartitionName
+ );
+
+VOID
+BlFillInSystemParameters(
+ IN PBOOT_CONTEXT BootContextRecord
+ );
+
+
+//
+// PS/2 ABIOS module (in abiosc.c)
+//
+VOID
+RemapAbiosSelectors(
+ VOID
+ );
+
+//
+// global data definitions
+//
+
+extern ULONG MachineType;
+extern PCONFIGURATION_COMPONENT_DATA FwConfigurationTree;
+extern ULONG HeapUsed;
+
+
+#define HYPER_SPACE_ENTRY 768
+#define HYPER_SPACE_BEGIN 0xC0000000
+#define HYPER_PAGE_DIR 0xC0300000
+
+//
+// X86 Detection definitions
+// The size is *ALWAYS* assumed to be 64K.
+// N.B. The definition *MUST* be the same as the ones defined in
+// startup\su.inc
+//
+
+#define DETECTION_LOADED_ADDRESS 0x10000
+
+//
+// We need to allocate permanent and temporary memory for the page directory,
+// assorted page tables, and the memory descriptors before the blmemory
+// routines ever get control. So we have two private heaps, one for permanent
+// data and one for temporary data. There are two descriptors for this. The
+// permanent heap descriptor starts out as zero-length at P.A. 0x30000. The
+// temporary heap descriptor immediately follows the permanent heap in memory
+// and starts out as 128k long. As we allocate permanent pages, we increase
+// the size of the permanent heap descriptor and increase the base (thereby
+// decreasing the size) of the temporary heap descriptor)
+//
+// So the permanent heap starts at P.A. 0x30000 and grows upwards. The
+// temporary heap starts at P.A. 0x5C000 and grows downwards. This gives us
+// a total of 128k of combined permanent and temporary data.
+//
+
+//
+// Heap starting locations (in pages)
+//
+
+#define PERMANENT_HEAP_START 0x30
+#define TEMPORARY_HEAP_START 0x60
+
+//
+// Useful Macro Definitions
+//
+#define ROUND_UP(Num,Size) (((Num) + Size - 1) & ~(Size -1))
+
+typedef union _UCHAR1 {
+ UCHAR Uchar[1];
+ UCHAR ForceAlignment;
+} UCHAR1, *PUCHAR1;
+
+typedef union _UCHAR2 {
+ UCHAR Uchar[2];
+ USHORT ForceAlignment;
+} UCHAR2, *PUCHAR2;
+
+typedef union _UCHAR4 {
+ UCHAR Uchar[4];
+ ULONG ForceAlignment;
+} UCHAR4, *PUCHAR4;
+
+//
+// This macro copies an unaligned src byte to an aligned dst byte
+//
+
+#define CopyUchar1(Dst,Src) { \
+ *((UCHAR1 *)(Dst)) = *((UNALIGNED UCHAR1 *)(Src)); \
+ }
+
+//
+// This macro copies an unaligned src word to an aligned dst word
+//
+
+#define CopyUchar2(Dst,Src) { \
+ *((UCHAR2 *)(Dst)) = *((UNALIGNED UCHAR2 *)(Src)); \
+ }
+
+//
+// This macro copies an unaligned src longword to an aligned dsr longword
+//
+
+#define CopyUchar4(Dst,Src) { \
+ *((UCHAR4 *)(Dst)) = *((UNALIGNED UCHAR4 *)(Src)); \
+ }
+
+
+//
+// Global definitions for the BIOS ARC Emulation
+//
+
+//
+// Defines for the ARC name of console input and output
+//
+
+#define CONSOLE_INPUT_NAME "multi(0)key(0)keyboard(0)"
+#define CONSOLE_OUTPUT_NAME "multi(0)video(0)monitor(0)"
+
+//
+// Define special character values.
+//
+
+#define ASCI_NUL 0x00
+#define ASCI_BEL 0x07
+#define ASCI_BS 0x08
+#define ASCI_HT 0x09
+#define ASCI_LF 0x0A
+#define ASCI_VT 0x0B
+#define ASCI_FF 0x0C
+#define ASCI_CR 0x0D
+#define ASCI_ESC 0x1B
+#define ASCI_SYSRQ 0x80
+
+
+
+
+//
+// Device I/O prototypes
+//
+
+ARC_STATUS
+BiosPartitionClose(
+ IN ULONG FileId
+ );
+
+ARC_STATUS
+BiosPartitionOpen(
+ IN PCHAR OpenPath,
+ IN OPEN_MODE OpenMode,
+ OUT PULONG FileId
+ );
+
+ARC_STATUS
+BiosPartitionRead (
+ IN ULONG FileId,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ );
+
+ARC_STATUS
+BiosPartitionWrite(
+ IN ULONG FileId,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ );
+
+ARC_STATUS
+BiosPartitionSeek (
+ IN ULONG FileId,
+ IN PLARGE_INTEGER Offset,
+ IN SEEK_MODE SeekMode
+ );
+
+
+ARC_STATUS
+BiosGetFileInfo(
+ IN ULONG FileId,
+ OUT PFILE_INFORMATION Finfo
+ );
+
+ARC_STATUS
+BlArcNotYetImplemented(
+ IN ULONG FileId
+ );
+
+ARC_STATUS
+BiosConsoleOpen(
+ IN PCHAR OpenPath,
+ IN OPEN_MODE OpenMode,
+ OUT PULONG FileId
+ );
+
+ARC_STATUS
+BiosConsoleReadStatus(
+ IN ULONG FileId
+ );
+
+ARC_STATUS
+BiosConsoleRead (
+ IN ULONG FileId,
+ OUT PUCHAR Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ );
+
+ARC_STATUS
+BiosConsoleWrite (
+ IN ULONG FileId,
+ OUT PUCHAR Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ );
+
+ARC_STATUS
+BiosDiskOpen(
+ IN ULONG DriveId,
+ IN OPEN_MODE OpenMode,
+ OUT PULONG FileId
+ );
+
+ARC_STATUS
+BiosDiskRead (
+ IN ULONG FileId,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ );
+
+#if defined(ELTORITO)
+ARC_STATUS
+BiosEDDSDiskRead (
+ IN ULONG FileId,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ );
+
+BOOLEAN
+BlIsElToritoCDBoot(
+ ULONG DriveNum
+ );
+#endif
+
+ARC_STATUS
+BiosDiskWrite(
+ IN ULONG FileId,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ );
+
+ARC_STATUS
+HardDiskPartitionOpen(
+ IN ULONG FileId,
+ IN ULONG DiskId,
+ IN UCHAR PartitionNumber
+ );
diff --git a/private/ntos/boot/lib/i386/decode.inc b/private/ntos/boot/lib/i386/decode.inc
new file mode 100644
index 000000000..7bf63cb15
--- /dev/null
+++ b/private/ntos/boot/lib/i386/decode.inc
@@ -0,0 +1,515 @@
+;** Decoding macros
+;
+; These walk a state machine based on where a command (i.e., char or string)
+; begins.
+
+
+;** BitsAt - Extract from bit position n some bits
+;
+; Macro parameter:
+; n bit position to begin extract
+; cbits number of bits to extract
+; Entry: eax working data
+; esi input stream
+; edi output stream
+; Exit: eax updated so that next data begins in al
+; esi/edi updated
+; ecx contains data
+; Uses: none
+
+BitsAt macro n,cbits
+ .errnz n eq 0
+ if (n+cbits) lt 8 ; entire operation occurs in low byte
+ CopyBits cx,ax,n,cbits ; (cx) = desired bits rightmost
+ elseif (n+cbits) lt 16 ; operation consumes byte
+ CopyBits cx,ax,n,cbits ; (cx) = desired bits rightmost
+ lodsb ; (ah/al) = next input
+ xchg al,ah ; (al/ah) = next input
+ elseif (n+cbits) eq 16 ; operation consumes remainder of buffered data
+ CopyBits cx,ax,n,cbits ; (cx) = desired bits rightmost
+ lodsw ; (al/ah) = next input
+ else ; operation consumes into unbuffered data
+ mov ecx,eax
+ lodsw
+ shrd cx,ax,n
+ and ecx,(1 shl cbits)-1
+ endif
+endm
+
+
+;** CmdAt - macro that processes a command at a bit position
+;
+; Macro parameter:
+; n bit position where command is expected
+; Entry: eax working data, command begins in al
+; esi points to input stream
+; edi points to output stream
+; Exit: eax updated so that next command begins in al
+; esi/edi updated
+; EXPECTS FALL-THROUGH TO NEXT CmdAT
+; Uses: ecx, edx (not directly, but by virtue of OffsetAt, which
+; in turn calls LengthAt....)
+
+CmdAt macro n
+ local ca1
+
+ align4
+ public CmdAt&n
+CmdAt&n:
+ if n eq 7
+ ror eax,1
+ test al,11b shl 6
+ rol eax,1
+ else
+ test al,11b shl n
+ endif
+ jpo ca1
+
+ OffsetAt %(n+1)
+ align4 ; note that OffsetAt jumps away
+ca1: ; so there is no fall-through penalty
+ CharAt %(n+1)
+endm
+
+
+;** CharAt - macro that processes a character at a bit position
+;
+; Macro parameter:
+; n bit position where char is expected
+; Entry: eax working data, char may be in ah
+; esi input stream
+; edi output stream
+; Exit: eax updated so that next command begins in al
+; esi/edi updated
+; Uses: ch
+
+CharAt macro n
+ if n eq 8
+ mov al,ah ; (al) = char for output
+ XlatChr
+ CheckOffset
+ stosb ; store it
+ lodsw ; (al/ah) = next input
+ else
+ if n eq 1
+ shr eax,1 ; (al) = byte for output
+ XlatChr
+ CheckOffset
+ stosb ; store it
+ add eax,eax ; (ah) = next byte
+ lodsb ; (ah/al) = next input
+ else
+ mov ch,ah ; (ch) = saved next input
+ shr eax,n ; (al) = byte for output
+ XlatChr
+ CheckOffset
+ stosb ; store it
+ lodsb ; (al) = byte-after-next
+ mov ah,ch ; (ah/al) = next input
+ endif
+ xchg al,ah ; (al/ah) = next input
+ endif
+endm
+
+
+;** OffsetAt - Parse an offset at a bit position
+;
+; Macro parameter:
+; n bit position where offset is expected
+; Entry: cbits number of bits in offset
+; eax working data, offset may begin in ah
+; esi input stream
+; edi output stream
+; Exit: eax updated so that length begins in al
+; ecx offset
+; esi/edi updated
+; Uses: ecx
+
+OffsetAt macro n
+ local try8,try12
+
+ public OffsetAt&n
+OffsetAt&n:
+ CheckBit a,n ; does a 6-bit offset follow?
+ jnz try8 ; no, try an 8-bit offset
+ BitsAt %(n+1),6 ; yes, load it into (ecx) and go
+ Jump LengthAt,%((n+7) mod 8)
+ align4
+try8:
+ CheckBit a,%(n+1) ; does an 8-bit offset follow?
+ jnz try12 ; no, must be a 12-bit offset
+ BitsAt %(n+2),8 ; yes, load it into (ecx)
+ add ecx,MAX_6BIT_OFFSET+1 ;
+ Jump LengthAt,%((n+10) mod 8); go process the following length
+ align4
+try12:
+ BitsAt %(n+2),12 ; load 12-bit offset into (ecx)
+ add ecx,MAX_8BIT_OFFSET+1 ;
+ Jump LengthAt,%((n+14) mod 8); go process the following length
+endm
+
+
+;** LengthAt - parse off a length at a position and move the bytes
+;
+; LengthAt parses off a length (gamma-prime encoded), moves the
+; relevant string, and dispatches to the next command.
+;
+; Macro parameter:
+; n bit position to begin extract
+; Entry: eax working data
+; ecx offset for string
+; esi input stream
+; edi output stream
+; Exit: eax updated so that next data begins in al
+; esi/edi updated
+; Uses: ecx, edx
+
+LengthAt macro n
+ local try3,try5,try7,try9,tryGeneral,done,error
+
+ % ifidni <LastErrBJump>,<DecodeError>
+ LastErrBJump equ <error>
+ endif
+
+ align4
+ public LengthAt&n
+LengthAt&n:
+ jecxz error ; check for 0 offset (illegal)
+ cmp ecx,SPECIAL_EOS ; check end-of-segment offset
+ je done ; that's our EOS, so get out
+ CheckBit a,n ; is this a degenerate encoding?
+ jz try3 ; no, go for a wider encoding
+ DoMovs short,2
+ if n eq 7 ; are we finished with this byte?
+ lodsb ; (ah/al) is next input
+ xchg al,ah ; (al/ah) is next input
+ endif
+ Jump CmdAt,%((n + 1) mod 8) ; go process next command
+done:
+ mov dl,n ; DL == current state
+ jmp DecodeDone ; exit
+error:
+;; Debug_Out "MRCI32 Decompress32: bad offset in LengthAt&n"
+ jmp DecodeError
+
+ align4
+try3:
+ mov edx,ecx ; save delta
+ CheckBit a,%(n + 1) ; is this a 3-bit encoding?
+ jz try5 ; no, go for wider still
+ BitsAt %(n+2),1
+ DoMovs short,ecx,3
+ Jump CmdAt,%((n + 3) mod 8) ; go process next command
+
+ align4
+try5:
+ CheckBit a,%(n + 2) ; is this a 5-bit encoding?
+ jz try7 ; no, go test for wider STILL
+ BitsAt %(n+3),2
+ DoMovs short,ecx,5
+ Jump CmdAt,%((n + 5) mod 8) ; go process next command
+
+ align4
+try7:
+ CheckBit a,%(n + 3) ; is this a 7 bit encoding?
+ jz try9 ; no, go test for wider STILL
+ BitsAt %(n+4),3
+ DoMovs long,ecx,9
+ Jump CmdAt,%((n + 7) mod 8) ; go process next command
+
+ align4
+try9:
+ CheckBit a,%(n + 4) ; is this a 9 bit encoding?
+ jz tryGeneral ; no, go handle generically
+ BitsAt %(n+5),4
+ DoMovs long,ecx,17
+ Jump CmdAt,%((n + 9) mod 8) ; go process next command
+;
+; Length exception handling code goes here
+;
+ align4
+tryGeneral:
+ mov cl,n+5 ; CL == # of bits to eat to yield
+ if n NE 7
+ jmp LengthAbove32 ; gamma length with 5 leading zeros stripped
+ else
+;; .errnz $-GeneralLength ; assert that we'll fall through
+ endif
+endm
+
+
+DoGeneralLength macro
+ local try11,try13,try15,try17
+
+ public LengthAbove32,CopyString
+
+GeneralLength:
+ align4
+
+LengthAbove32:
+ shl eax,16 ;
+ mov ax,[esi] ; get 16 more bits
+ add cl,16 ;
+ ror eax,cl ; (eax) is filled, time to party
+;
+; Figure out the length and do a string op
+;
+try11:
+ shr eax,1 ; is it an 11-bit encoding?
+ jnc try13 ; no
+ and eax,1Fh ; mask off the numeric value
+ add eax,33 ;
+ xchg ecx,eax ; (ecx) now has string length
+ sub al,10 ; record # extra bits in this length
+;
+; At this point, (ecx) is the # of bytes to copy and (al) is the number of
+; additional bits to eat for the particular gamma length.
+;
+; Good coding practices suggest that CopyString be at the end so that the
+; other gamma decoders need not jump backwards to it, but if we assume
+; that the longer strings are marginally less common, then it is marginally
+; better to fall through on this, the smallest of the general cases.
+;
+ align4
+
+CopyString:
+ DoMovs long,ecx
+
+ mov dl,al ; (dl) == bit position in old ax
+ cmp dl,24 ; is it the max?
+ jb @F ; no
+ inc esi ; yes, need to skip 1 more whole byte
+ lodsw ; get new (ax) to restart state machine
+ sub dl,24 ; (dl) == new state
+ DecodeRestart
+
+ align4
+@@:
+ cmp dl,16 ; did we exhaust the old ax?
+ jae @F ; yes
+ dec esi ; no,
+ add dl,8 ; but we know we exhausted the low byte
+@@:
+ lodsw ; get new (ax) to restart state machine
+ sub dl,16 ; (dl) == new state
+ DecodeRestart
+
+ align4
+try13:
+ shr eax,1 ; is it an 13-bit encoding?
+ jnc try15 ; no
+ and eax,3Fh ; mask off the numeric value
+ add eax,65 ;
+ xchg ecx,eax ; (cx) now has string length
+ sub al,8 ; record # extra bits in this length
+ jmp CopyString ;
+
+ align4
+try15:
+ shr eax,1 ; is it an 15-bit encoding?
+ jnc try17 ; no
+ and eax,7Fh ; mask off the numeric value
+ add eax,129 ;
+ xchg ecx,eax ; (ecx) now has string length
+ sub al,6 ; record # extra bits in this length
+ jmp CopyString ;
+
+ align4
+try17:
+ shr eax,1 ; is it an 17-bit encoding?
+;; Debug_OutNC "MRCI32 Decompress32: invalid length"
+ jnc DecodeError ; no, ERROR
+ and eax,0FFh ; mask off the numeric value
+ add eax,257 ;
+ xchg ecx,eax ; (ecx) now has string length
+ sub al,4 ; record # extra bits in this length
+ jmp CopyString ;
+endm
+
+
+;** DoMovs - worker macro for LengthAt and DoGeneralLength
+;
+; <size> is either "short" or "long"; if short, then we don't
+; bother trying to do a movsw/movsb combo (overhead swamps benefit);
+; if long, we do.
+;
+; If <len> == 2, the offset to use is in (ecx). (edx) is trashed.
+;
+; Otherwise, the offset has been saved in (edx), and <len>
+; is the size of the string to move (normally ecx). (ecx) and (edx)
+; are trashed.
+;
+; <errjmp> is where to go if the expansion is going to overflow the
+; destination buffer. DoMovs just passes this parameter along to the
+; CheckOffset macro.
+;
+DoMovs macro size,len,extra,errjmp
+ local slower
+
+ ifidni <len>,<2>
+
+ mov edx,esi ; save (esi) in (edx)
+ mov esi,edi
+ sub esi,ecx
+ CheckOffset 2,errjmp ; check target offset
+ movsb ; don't do movsw,
+ movsb ; that doesn't handle overlap!
+ mov esi,edx ; restore (esi) from (edx)
+
+ else
+
+ ifnb <len>
+ ifdifi <len>,<ecx>
+ ifb <extra>
+ mov ecx,len
+ else
+ lea ecx,[len+extra]
+ endif
+ else
+ ifnb <extra>
+ add ecx,extra
+ endif
+ endif
+ endif
+
+ mov ebx,esi ; save (esi) in (ebx)
+ mov esi,edi ;
+ sub esi,edx ; (esi) points to string to move
+ CheckOffset ecx,errjmp ; check target offset
+
+ ifidni <size>,<short>
+ rep movsb
+ elseifidni <size>,<long>
+ cmp edx,1 ; if the offset is 1,
+ je short slower ; then overlap forces us to do movsb
+ shr ecx,1
+ rep movsw
+ adc ecx,ecx
+slower: rep movsb
+ else
+ .err <Bad DoMovs parameter: size>
+ endif
+
+ mov esi,ebx ; restore (esi) from (ebx)
+
+ endif
+endm
+
+
+;** CheckOffset - Verify offsets in ESI and EDI are ok for len bytes
+;
+; If "len" is blank, then CheckOffset simply does a 1-byte check.
+; In the event of an error in any case, it branches to DecodeError.
+;
+LastErrSJump equ <DecodeError>
+LastErrBJump equ <DecodeError>
+
+
+CheckOffset macro len,errjmp
+ local tmp,jsjmp,jbjmp
+
+IFDEF MAXDEBUG
+ cmp edi,[maxOffset]
+ jb short tmp
+ int 3
+tmp:
+ENDIF
+
+ ifnb <errjmp>
+ ErrSJump equ <errjmp>
+ else
+ ErrSJump catstr LastErrSJump
+ LastErrSJump equ <jsjmp>
+ endif
+
+ ifb <len>
+ dec ebp ; space remaining in destination buffer?
+ else
+ sub ebp,len ; space remaining in destination buffer?
+ endif
+
+;; Debug_OutS "MRCI32 Decompress32: target buffer overflow"
+
+jsjmp: js ErrSJump
+
+IFDEF INLINE_LOWER_BOUND_CHECKING
+;
+; In-line bounds checking is disabled in favor of an invalid page fault
+; handler. To use this code, be aware that EBX cannot be used by the
+; decoding macros above (and it currently is!)
+;
+ ifnb <len>
+ ifnb <errjmp>
+ ErrBJump equ <errjmp>
+ else
+ ErrBJump catstr LastErrBJump
+ LastErrBJump equ <jbjmp>
+ endif
+
+ cmp esi,ebx ; have we ventured before start of dest. buffer?
+
+;; Debug_OutB "MRCI32 Decompress32: target buffer underflow"
+
+jbjmp: jb ErrBJump
+ endif
+
+ENDIF ;INLINE_LOWER_BOUND_CHECKING
+
+endm
+
+
+;* Misc. macros
+
+Jump macro lab,tag
+ jmp lab&tag
+endm
+
+
+XlatChr macro ch
+ ror al,1
+ xor al,80h
+endm
+
+
+align4 macro
+;
+; BUGBUG: This actually slowed down the real-mode decompressor, so some
+; time will need to be spent verifying this is a real win... -JP
+;
+ align 4
+endm
+
+
+CheckBit macro reg,bit
+ if bit lt 8
+ test reg&l,(1 shl bit)
+ else
+ test reg&h,(1 shl (bit-8))
+ endif
+endm
+
+
+CopyBits macro dst,src,n,cbits
+ shld dst,src,16-n
+ and e&dst,(1 shl cbits)-1
+endm
+
+
+;
+; AX has the remaining bits, DL has the next state
+;
+DecodeRestart macro
+
+IFDEF DEBUG
+ cmp dl,8
+;; Debug_OutAE "MRCI32 Decompress32: bad decode state in DL"
+ENDIF
+ movzx edx,dl
+ jmp aCmdAt[edx*4] ; go to correct state handler
+endm
+
+
+IFDEF MAXDEBUG
+ public maxOffset
+maxOffset dd -1 ; handy for getting control at a specific point
+ENDIF
diff --git a/private/ntos/boot/lib/i386/disp_gr.c b/private/ntos/boot/lib/i386/disp_gr.c
new file mode 100644
index 000000000..453d35daa
--- /dev/null
+++ b/private/ntos/boot/lib/i386/disp_gr.c
@@ -0,0 +1,1146 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ disp_gr.c
+
+Abstract:
+
+ This file was created from \private\windows\setup\textmode\splib\ixdispj.c.
+ This file contains routines to display MBCS characters to the Graphics
+ VRAM.
+
+Author:
+
+ v-junm (Compaq Japan)
+ hideyukn
+ tedm
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+--*/
+
+#include "bootx86.h"
+#include "displayp.h"
+#include "bootfont.h"
+
+//
+// Physical video attributes.
+//
+#define VIDEO_BUFFER_VA 0xa0000
+#define VIDEO_BYTES_PER_SCAN_LINE 80
+#define VIDEO_WIDTH_PIXELS 640
+#define VIDEO_HEIGHT_SCAN_LINES 480
+#define VIDEO_SIZE_BYTES (VIDEO_BYTES_PER_SCAN_LINE*VIDEO_HEIGHT_SCAN_LINES)
+
+PUCHAR GrVp = (PUCHAR)VIDEO_BUFFER_VA;
+
+//
+// Screen width and height in half-character cells
+// and macro to determine total number of characters
+// displayed on the screen at once.
+//
+unsigned ScreenWidthCells,ScreenHeightCells;
+#define SCREEN_SIZE_CELLS (ScreenWidthCells*ScreenHeightCells)
+
+//
+// Globals:
+//
+// CharacterCellHeight is the number of scan lines total in a character.
+// It includes any top or bottom fill lines.
+//
+// CharacterImageHeight is the number of scan lines in the image of a character.
+// This is dependent on the font. Characters may be padded top and bottom.
+//
+// NOTE: All of this code assumes the font's single-byte characters are 8 bits wide
+// and the font's double-byte characters are 16 bits wide!
+//
+unsigned CharacterCellHeight;
+unsigned CharacterImageHeight;
+unsigned CharacterTopPad;
+unsigned CharacterBottomPad;
+
+#define VIDEO_BYTES_PER_TEXT_ROW (VIDEO_BYTES_PER_SCAN_LINE*CharacterCellHeight)
+
+//
+// Values describing the number of each type of character in the font,
+// and pointers to the base of the glyphs.
+//
+unsigned SbcsCharCount;
+unsigned DbcsCharCount;
+PUCHAR SbcsImages;
+PUCHAR DbcsImages;
+
+//
+// Values to be passed to GrDisplayMBCSChar
+//
+#define SBCSWIDTH 8
+#define DBCSWIDTH 16
+
+//
+// Lead byte table. Read from bootfont.bin.
+//
+UCHAR LeadByteTable[2*(MAX_DBCS_RANGE+1)];
+
+
+VOID
+GrDisplayMBCSChar(
+ IN PUCHAR image,
+ IN unsigned width,
+ IN UCHAR top,
+ IN UCHAR bottom
+ );
+
+BOOLEAN
+GrIsDBCSLeadByte(
+ IN UCHAR c
+ );
+
+PUCHAR
+GrGetDBCSFontImage(
+ USHORT Code
+ );
+
+PUCHAR
+GrGetSBCSFontImage(
+ UCHAR Code
+ );
+
+
+VOID
+GrWriteSBCSChar(
+ IN UCHAR c
+ )
+
+/*++
+
+Routine Description:
+
+ Displays a character at the current cursor position. ONLY SBCS
+ characters can be displayed using this routine.
+
+Arguments:
+
+ c - character to display.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ unsigned u;
+ PUCHAR pImage;
+ UCHAR temp;
+
+ switch(c) {
+
+ case '\n':
+ if(TextRow == (ScreenHeightCells-1)) {
+ TextGrScrollDisplay();
+ TextSetCursorPosition(0,TextRow);
+ } else {
+ TextSetCursorPosition(0,TextRow+1);
+ }
+ break;
+
+ case '\r':
+ break; // ignore
+
+ case '\t':
+ temp = ' ';
+ u = 8 - (TextColumn % 8);
+ while(u--) {
+ TextGrCharOut(&temp);
+ }
+ TextSetCursorPosition(TextColumn+u,TextRow);
+ break;
+
+ default:
+ //
+ // Assume it's a valid SBCS character.
+ // Get font image for SBCS char.
+ //
+ pImage = GrGetSBCSFontImage(c);
+
+ //
+ // Display the SBCS char. Check for special graphics characters.
+ // Add top and bottom extra pixels accordingly (otherwise the grids
+ // don't connect properly, because of top and bottom spacing).
+ //
+ // BUGBUG (tedm) this whole thing needs a better implementation
+ //
+ if ( c == 0x2 || c == 0x1 || c == 0x16 )
+ GrDisplayMBCSChar( pImage, SBCSWIDTH, 0x00, 0x24 );
+ else if ( c == 0x4 || c == 0x3 || c == 0x15 )
+ GrDisplayMBCSChar( pImage, SBCSWIDTH, 0x24, 0x00 );
+ else if ( c == 0x5 || c == 10 || c == 0x17 || c == 0x19 )
+ GrDisplayMBCSChar( pImage, SBCSWIDTH, 0x24, 0x24 );
+ else
+ GrDisplayMBCSChar( pImage, SBCSWIDTH, 0x00, 0x00 );
+ }
+}
+
+
+VOID
+GrDisplayMBCSChar(
+ IN PUCHAR image,
+ IN unsigned width,
+ IN UCHAR top,
+ IN UCHAR bottom
+ )
+
+/*++
+
+Routine Description:
+
+ Displays a DBCS or a SBCS character at the current cursor
+ position.
+
+Arguments:
+
+ image - SBCS or DBCS font image.
+ width - Width in bits of character image (must be SBCSWIDTH pr DBCSWIDTH).
+ top - Character to fill the top extra character line(s).
+ bottom- Character to fill the bottom extra character line(s).
+
+Return Value:
+
+ FALSE if image points to NULL,
+ else TRUE.
+
+--*/
+
+{
+ unsigned i;
+ PUCHAR VpOld = GrVp;
+
+ //
+ // Validate parameter
+ //
+ if(image == NULL) {
+ return;
+ }
+
+ //
+ // There are TOP_EXTRA lines at the top that we need to skip (background color).
+ //
+ for(i=0; i<CharacterTopPad; i++) {
+
+ //
+ // If DBCS char, we need to clear 2 bytes.
+ //
+ if(width == DBCSWIDTH) {
+ *GrVp++ = top;
+ }
+ *GrVp++ = top;
+
+ //
+ // Position pointer at next scan line
+ // for the font image.
+ //
+ GrVp += VIDEO_BYTES_PER_SCAN_LINE - (width/SBCSWIDTH);
+ }
+
+ //
+ // Display full height of DBCS or SBCS char.
+ //
+ for(i=0; i<CharacterImageHeight; i++) {
+
+ //
+ // If DBCS char, need to display 2 bytes,
+ // so display first byte here.
+ //
+ if(width == DBCSWIDTH) {
+ *GrVp++ = *image++;
+ }
+
+ //
+ // Display 2nd byte of DBCS char or the
+ // first and only byte of SBCS char.
+ //
+ *GrVp++ = *image++;
+
+ //
+ // Increment GrVP to display location of
+ // next row of font image.
+ //
+ GrVp += VIDEO_BYTES_PER_SCAN_LINE - (width/SBCSWIDTH);
+ }
+
+ //
+ // There are BOT_EXTRA lines at the bottom that we need to fill with the
+ // background color.
+ //
+ for(i=0; i<CharacterBottomPad; i++) {
+
+ //
+ // If DBCS char, need to clear 2 bytes
+ //
+ if(width == DBCSWIDTH) {
+ *GrVp++ = bottom;
+ }
+ *GrVp++ = bottom;
+
+ //
+ // Position pointer at next scan line
+ // for the font image.
+ //
+ GrVp += VIDEO_BYTES_PER_SCAN_LINE - (width/SBCSWIDTH);
+ }
+
+ //
+ // Increment cursor and video pointer
+ //
+ if(width == DBCSWIDTH) {
+ TextSetCursorPosition(TextColumn+2,TextRow);
+ } else {
+ TextSetCursorPosition(TextColumn+1,TextRow);
+ }
+}
+
+
+unsigned
+GrWriteMBCSString(
+ IN PUCHAR String,
+ IN unsigned MaxChars
+ )
+
+/*++
+
+Routine Description:
+
+ Displays a mixed byte string at the current cursor
+ position.
+
+Arguments:
+
+ String - supplies pointer to asciz string.
+
+ MaxBytes - supplies the maximum number of characters to be written.
+
+Return Value:
+
+ Number of bytes written.
+
+--*/
+
+{
+ PCHAR pImage;
+ USHORT DBCSChar;
+ unsigned BytesWritten;
+
+ BytesWritten = 0;
+
+ //
+ // While string is not NULL,
+ // get font image and display it.
+ //
+ while(*String && MaxChars--) {
+
+ //
+ // Determine if char is SBCS or DBCS, get the correct font image,
+ // and display it.
+ //
+ if(GrIsDBCSLeadByte(*String)) {
+ DBCSChar = *String++ << 8;
+ DBCSChar = DBCSChar | *String++;
+ pImage = GrGetDBCSFontImage(DBCSChar);
+ GrDisplayMBCSChar(pImage,DBCSWIDTH,0x00,0x00);
+ BytesWritten++;
+ } else {
+ GrWriteSBCSChar(*String++);
+ }
+ BytesWritten++;
+ }
+
+ return(BytesWritten);
+}
+
+
+BOOLEAN
+GrIsDBCSLeadByte(
+ IN UCHAR c
+ )
+
+/*++
+
+Routine Description:
+
+ Checks to see if a char is a DBCS leadbyte.
+
+Arguments:
+
+ c - char to check if leadbyte or not.
+
+Return Value:
+
+ TRUE - Leadbyte.
+ FALSE - Non-Leadbyte.
+
+--*/
+
+{
+ int i;
+
+ //
+ // Check to see if char is in leadbyte range.
+ // BUGBUG: If (CHAR)(0) is a valid leadbyte,
+ // this routine will fail.
+ //
+
+ for(i=0; LeadByteTable[i]; i+=2) {
+ if((LeadByteTable[i] <= c) && (LeadByteTable[i+1] >= c)) {
+ return(TRUE);
+ }
+ }
+
+ return(FALSE);
+}
+
+
+PUCHAR
+GrGetDBCSFontImage(
+ USHORT Code
+ )
+
+/*++
+
+Routine Description:
+
+ Gets the font image for DBCS char.
+
+Arguments:
+
+ Code - DBCS char code.
+
+Return Value:
+
+ Pointer to font image, or else NULL.
+
+--*/
+
+{
+ int Min,Max,Mid;
+ int Multiplier;
+ int Index;
+ USHORT code;
+
+ Min = 0;
+ Max = DbcsCharCount;
+ Multiplier = (2*CharacterImageHeight) + 2;
+
+ //
+ // Do a binary search for the image.
+ // Format of table:
+ // First 2 bytes contain the DBCS char code.
+ // Next bytes are the char image.
+ //
+ while(Max >= Min) {
+ Mid = (Max + Min) / 2;
+ Index = Mid*Multiplier;
+ code = (DbcsImages[Index] << 8) | DbcsImages[Index+1];
+
+ if(Code == code) {
+ return(DbcsImages+Index+2);
+ }
+
+ if(Code < code) {
+ Max = Mid - 1;
+ } else {
+ Min = Mid + 1;
+ }
+ }
+
+ //
+ // ERROR: No image found.
+ //
+ return(NULL);
+}
+
+
+PUCHAR
+GrGetSBCSFontImage(
+ UCHAR Code
+ )
+
+/*++
+
+Routine Description:
+
+ Gets the font image for SBCS char.
+
+Arguments:
+
+ Code - SBCS char code.
+
+Return Value:
+
+ Pointer to font image, or else NULL.
+
+--*/
+
+{
+ int Max,Min,Mid;
+ int Multiplier;
+ int Index;
+
+ Min = 0;
+ Max = SbcsCharCount;
+ Multiplier = CharacterImageHeight + 1;
+
+ //
+ // Do a binary search for the image.
+ // Format of table:
+ // First byte contain the SBCS char code.
+ // Next bytes are the char image.
+ //
+ while(Max >= Min) {
+ Mid = (Max + Min) / 2;
+ Index = Mid*Multiplier;
+
+ if(Code == SbcsImages[Index]) {
+ return(SbcsImages+Index+1);
+ }
+
+ if(Code < SbcsImages[Index]) {
+ Max = Mid - 1;
+ } else {
+ Min = Mid + 1;
+ }
+ }
+
+ //
+ // ERROR: No image found.
+ //
+ return(NULL);
+}
+
+
+//
+// Need to turn off optimization for this
+// routine. Since the write and read to
+// GVRAM seem useless to the compiler.
+//
+
+#pragma optimize( "", off )
+
+VOID
+TextGrSetCurrentAttribute(
+ IN UCHAR Attribute
+ )
+
+/*++
+
+Routine Description:
+
+ Sets the attribute by setting up various VGA registers.
+ The comments only say what registers are set to what, so
+ to understand the logic, follow the code while looking at
+ Figure 5-5 of PC&PS/2 Video Systems by Richard Wilton.
+ The book is published by Microsoft Press.
+
+Arguments:
+
+ Attribute - New attribute to set to.
+ Attribute:
+ High nibble - background attribute.
+ Low nibble - foreground attribute.
+
+Return Value:
+
+ Nothing.
+
+--*/
+
+{
+ UCHAR temp;
+
+ //
+ // Address of GVRAM off the screen.
+ //
+
+ PUCHAR OffTheScreen = (PUCHAR)(0xa9600);
+
+ union WordOrByte {
+ struct Word { unsigned short ax; } x;
+ struct Byte { unsigned char al, ah; } h;
+ } regs;
+
+ //
+ // Reset Data Rotate/Function Select
+ // regisger.
+ //
+
+ outpw( 0x3ce, 0x3 ); // Need to reset Data Rotate/Function Select.
+
+ //
+ // Set Enable Set/Reset to
+ // all (0f).
+ //
+
+ outpw( 0x3ce, 0xf01 );
+
+ //
+ // Put background color into Set/Reset register.
+ // This is done to put the background color into
+ // the latches later.
+ //
+
+ regs.x.ax = (unsigned short)(Attribute & 0x0f0) << 4;
+ outpw( 0x3ce, regs.x.ax ); // Put BLUE color in Set/Reset register.
+
+ //
+ // Put Set/Reset register value into GVRAM
+ // off the screen.
+ //
+
+ *OffTheScreen = temp;
+
+ //
+ // Read from screen, so the latches will be
+ // updated with the background color.
+ //
+
+ temp = *OffTheScreen;
+
+ //
+ // Set Data Rotate/Function Select register
+ // to be XOR.
+ //
+
+ outpw( 0x3ce, 0x1803 );
+
+ //
+ // XOR the foreground and background color and
+ // put it in Set/Reset register.
+ //
+
+ regs.h.ah = (Attribute >> 4) ^ (Attribute & 0x0f);
+ regs.h.al = 0;
+ outpw( 0x3ce, regs.x.ax );
+
+ //
+ // Put Inverse(~) of the XOR of foreground and
+ // ground attribute into Enable Set/Reset register.
+ //
+
+ regs.x.ax = ~regs.x.ax & 0x0f01;
+ outpw( 0x3ce, regs.x.ax );
+}
+
+//
+// Turn optimization on again.
+//
+
+#pragma optimize( "", on )
+
+
+VOID
+TextGrPositionCursor(
+ USHORT Row,
+ USHORT Column
+ )
+
+/*++
+
+Routine Description:
+
+ Sets the position of the soft cursor. That is, it doesn't move the
+ hardware cursor but sets the location of the next write to the
+ screen.
+
+Arguments:
+
+ Row - Row coordinate of where character is to be written.
+
+ Column - Column coordinate of where character is to be written.
+
+Returns:
+
+ Nothing.
+
+--*/
+
+{
+ if(Row >= ScreenHeightCells) {
+ Row = ScreenHeightCells-1;
+ }
+
+ if(Column >= ScreenWidthCells) {
+ Column = ScreenWidthCells-1;
+ }
+
+ GrVp = (PUCHAR)VIDEO_BUFFER_VA + (Row * VIDEO_BYTES_PER_TEXT_ROW) + Column;
+}
+
+
+VOID
+TextGrStringOut(
+ IN PUCHAR String
+ )
+{
+ GrWriteMBCSString(String,(unsigned)(-1));
+}
+
+
+PUCHAR
+TextGrCharOut(
+ PUCHAR pc
+ )
+
+/*++
+
+Routine Description:
+
+ Writes a character on the display at the current position.
+ Newlines and tabs are interpreted and acted upon.
+
+Arguments:
+
+ pc - pointer to mbcs character to write.
+
+Returns:
+
+ pointer to next character
+
+--*/
+
+{
+ return(pc + GrWriteMBCSString(pc,1));
+}
+
+
+VOID
+TextGrFillAttribute(
+ IN UCHAR Attribute,
+ IN ULONG Length
+ )
+
+/*++
+
+Routine Description:
+
+ Changes the screen attribute starting at the current cursor position.
+ The cursor is not moved.
+
+Arguments:
+
+ Attribute - Supplies the new attribute
+
+ Length - Supplies the length of the area to change (in bytes)
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UCHAR OldAttribute;
+ unsigned i;
+ ULONG x,y;
+ PUCHAR pImage;
+
+ //
+ // Save the current attribute and set the attribute to the
+ // character desired by the caller.
+ //
+ TextGetCursorPosition(&x,&y);
+ OldAttribute = TextCurrentAttribute;
+ TextSetCurrentAttribute(Attribute);
+
+ //
+ // Dirty hack: just write spaces into the area requested by the caller.
+ //
+ pImage = GrGetSBCSFontImage(' ');
+ for(i=0; i<Length; i++) {
+ GrDisplayMBCSChar(pImage,SBCSWIDTH,0x00,0x00);
+ }
+
+ //
+ // Restore the current attribute.
+ //
+ TextSetCurrentAttribute(OldAttribute);
+ TextSetCursorPosition(x,y);
+}
+
+
+VOID
+TextGrClearToEndOfLine(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Clears from the current cursor position to the end of the line
+ by writing blanks with the current video attribute.
+ The cursor position is not changed.
+
+Arguments:
+
+ None
+
+Returns:
+
+ Nothing
+
+--*/
+
+{
+ unsigned u;
+ ULONG OldX,OldY;
+ UCHAR temp;
+
+ //
+ // Fill with blanks up to char before cursor position.
+ //
+ temp = ' ';
+ TextGetCursorPosition(&OldX,&OldY);
+ for(u=TextColumn; u<ScreenWidthCells; u++) {
+ TextGrCharOut(&temp);
+ }
+ TextSetCursorPosition(OldX,OldY);
+}
+
+
+VOID
+TextGrClearFromStartOfLine(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Clears from the start of the line to the current cursor position
+ by writing blanks with the current video attribute.
+ The cursor position is not changed.
+
+Arguments:
+
+ None
+
+Returns:
+
+ Nothing
+
+--*/
+
+{
+ unsigned u;
+ ULONG OldX,OldY;
+ UCHAR temp = ' ';
+
+ //
+ // Fill with blanks up to char before cursor position.
+ //
+ TextGetCursorPosition(&OldX,&OldY);
+ TextSetCursorPosition(0,OldY);
+ for(u=0; u<TextColumn; u++) {
+ TextGrCharOut(&temp);
+ }
+ TextSetCursorPosition(OldX,OldY);
+}
+
+
+VOID
+TextGrClearToEndOfDisplay(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Clears from the current cursor position to the end of the video
+ display by writing blanks with the current video attribute.
+ The cursor position is not changed.
+
+Arguments:
+
+ None
+
+Returns:
+
+ Nothing
+
+--*/
+{
+ USHORT x,y;
+ PUCHAR p;
+
+ //
+ // Clear current line
+ //
+ TextGrClearToEndOfLine();
+
+ //
+ // Clear the remaining lines
+ //
+ p = (PUCHAR)VIDEO_BUFFER_VA + ((TextRow+1)*VIDEO_BYTES_PER_TEXT_ROW);
+
+ for(y=TextRow+1; y<ScreenHeightCells; y++) {
+
+ for(x=0; x<VIDEO_BYTES_PER_TEXT_ROW; x++) {
+
+ *p++ = 0;
+ }
+ }
+}
+
+
+VOID
+TextGrClearDisplay(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Clears the text-mode video display by writing blanks with
+ the current video attribute over the entire display.
+
+Arguments:
+
+ None
+
+Returns:
+
+ Nothing
+
+--*/
+
+{
+ unsigned i;
+
+ //
+ // Clear screen.
+ //
+ for(i=0; i<VIDEO_SIZE_BYTES; i++) {
+ ((PUCHAR)VIDEO_BUFFER_VA)[i] = 0x00;
+ }
+}
+
+
+VOID
+TextGrScrollDisplay(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Scrolls the display up one line. The cursor position is not changed.
+
+Arguments:
+
+ None
+
+Returns:
+
+ Nothing
+
+--*/
+
+{
+ PUCHAR Source,Dest;
+ unsigned n,i;
+ ULONG OldX,OldY;
+ UCHAR temp = ' ';
+
+ Source = (PUCHAR)(VIDEO_BUFFER_VA) + VIDEO_BYTES_PER_TEXT_ROW;
+ Dest = (PUCHAR)VIDEO_BUFFER_VA;
+
+ n = VIDEO_BYTES_PER_TEXT_ROW * (ScreenHeightCells-1);
+
+ for(i=0; i<n; i++) {
+ *Dest++ = *Source++;
+ }
+
+ //
+ // Write blanks in the bottom line, using the current attribute.
+ //
+ TextGetCursorPosition(&OldX,&OldY);
+
+ TextSetCursorPosition(0,ScreenHeightCells-1);
+ for(i=0; i<ScreenWidthCells; i++) {
+ TextGrCharOut(&temp);
+ }
+
+ TextSetCursorPosition(OldX,OldY);
+}
+
+
+UCHAR GrGraphicsChars[GraphicsCharMax] = { 1,2,3,4,5,6 };
+
+UCHAR
+TextGrGetGraphicsChar(
+ IN GraphicsChar WhichOne
+ )
+{
+ return(GrGraphicsChars[WhichOne]);
+}
+
+
+VOID
+TextGrInitialize(
+ IN ULONG DiskId
+ )
+{
+ ULONG FileId;
+ ARC_STATUS Status;
+ PUCHAR FontImage;
+ ULONG BytesRead;
+ BOOTFONTBIN_HEADER FileHeader;
+ LARGE_INTEGER SeekOffset;
+ ULONG SbcsSize,DbcsSize;
+
+ //
+ // Attempt to open bootfont.bin. If this fails, then boot in single-byte charset mode.
+ //
+ Status = BlOpen(DiskId,"\\BOOTFONT.BIN",ArcOpenReadOnly,&FileId);
+ if(Status != ESUCCESS) {
+ goto clean0;
+ }
+
+ //
+ // Read in the file header and check some values.
+ // We enforce the width of 8/16 here. If this is changed code all over the
+ // rest of this module must also be changed.
+ //
+ Status = BlRead(FileId,&FileHeader,sizeof(BOOTFONTBIN_HEADER),&BytesRead);
+ if((Status != ESUCCESS)
+ || (BytesRead != sizeof(BOOTFONTBIN_HEADER))
+ || (FileHeader.Signature != BOOTFONTBIN_SIGNATURE)
+ || (FileHeader.CharacterImageSbcsWidth != 8)
+ || (FileHeader.CharacterImageDbcsWidth != 16)
+ ) {
+ goto clean1;
+ }
+
+ //
+ // Calculate the amount of memory needed to hold the sbcs and dbcs
+ // character entries. Each sbcs entry is 1 byte for the ascii value
+ // followed by n bytes for the image itself. We assume a width of 8 pixels.
+ // For dbcs chars each entry is 2 bytes for the codepoint and n bytes
+ // for the image itself. We assume a width of 16 pixels.
+ //
+ // Also perform further validation on the file by comparing the sizes
+ // given in the header against a size we calculate.
+ //
+ SbcsSize = FileHeader.NumSbcsChars * (FileHeader.CharacterImageHeight + 1);
+ DbcsSize = FileHeader.NumDbcsChars * ((2 * FileHeader.CharacterImageHeight) + 2);
+
+ if((SbcsSize != FileHeader.SbcsEntriesTotalSize)
+ || (DbcsSize != FileHeader.DbcsEntriesTotalSize)) {
+ goto clean1;
+ }
+
+ //
+ // Allocate memory to hold the font. We use FwAllocatePool() because
+ // that routine uses a separate heap that was inititialized before the
+ // high-level Bl memory system was initialized, and thus is safe.
+ //
+ FontImage = FwAllocatePool(SbcsSize+DbcsSize);
+ if(!FontImage) {
+ goto clean1;
+ }
+
+ //
+ // The entries get read into the base of the region we carved out.
+ // The dbcs images get read in immediately after that.
+ //
+ SbcsImages = FontImage;
+ DbcsImages = SbcsImages + FileHeader.SbcsEntriesTotalSize;
+
+ //
+ // Read in the sbcs entries.
+ //
+ SeekOffset.HighPart = 0;
+ SeekOffset.LowPart = FileHeader.SbcsOffset;
+ if((BlSeek(FileId,&SeekOffset,SeekAbsolute) != ESUCCESS)
+ || (BlRead(FileId,SbcsImages,FileHeader.SbcsEntriesTotalSize,&BytesRead) != ESUCCESS)
+ || (BytesRead != FileHeader.SbcsEntriesTotalSize)) {
+ goto clean2;
+ }
+
+ //
+ // Read in the dbcs entries.
+ //
+ SeekOffset.HighPart = 0;
+ SeekOffset.LowPart = FileHeader.DbcsOffset;
+ if((BlSeek(FileId,&SeekOffset,SeekAbsolute) != ESUCCESS)
+ || (BlRead(FileId,DbcsImages,FileHeader.DbcsEntriesTotalSize,&BytesRead) != ESUCCESS)
+ || (BytesRead != FileHeader.DbcsEntriesTotalSize)) {
+ goto clean2;
+ }
+
+ //
+ // We're done with the file now.
+ //
+ BlClose(FileId);
+
+ //
+ // Set up various values used for displaying the font.
+ //
+ DbcsLangId = FileHeader.LanguageId;
+ CharacterImageHeight = FileHeader.CharacterImageHeight;
+ CharacterTopPad = FileHeader.CharacterTopPad;
+ CharacterBottomPad = FileHeader.CharacterBottomPad;
+ CharacterCellHeight = CharacterImageHeight + CharacterTopPad + CharacterBottomPad;
+ SbcsCharCount = FileHeader.NumSbcsChars;
+ DbcsCharCount = FileHeader.NumDbcsChars;
+ ScreenWidthCells = VIDEO_WIDTH_PIXELS / FileHeader.CharacterImageSbcsWidth;
+ ScreenHeightCells = VIDEO_HEIGHT_SCAN_LINES / CharacterCellHeight;
+
+ RtlMoveMemory(LeadByteTable,FileHeader.DbcsLeadTable,(MAX_DBCS_RANGE+1)*2);
+
+ //
+ // Switch the display into 640x480 graphics mode and clear it.
+ // We're done.
+ //
+ HW_CURSOR(0x80000000,0x12);
+ TextClearDisplay();
+ return;
+
+clean2:
+ //
+ // Want to free the memory we allocated but there's no routine to do it
+ //
+ //FwFreePool();
+clean1:
+ //
+ // Close the font file.
+ //
+ BlClose(FileId);
+clean0:
+ return;
+}
+
+
+VOID
+TextGrTerminate(
+ VOID
+ )
+{
+ if(DbcsLangId) {
+ DbcsLangId = 0;
+ //
+ // This command switches the display into 80x25 text mode.
+ //
+ HW_CURSOR(0x80000000,0x3);
+ }
+ TextClearDisplay();
+}
diff --git a/private/ntos/boot/lib/i386/disp_tm.c b/private/ntos/boot/lib/i386/disp_tm.c
new file mode 100644
index 000000000..d690b2f64
--- /dev/null
+++ b/private/ntos/boot/lib/i386/disp_tm.c
@@ -0,0 +1,441 @@
+/*++
+
+Copyright (c) 1995 Microsoft Corporation
+
+Module Name:
+
+ disp_tm.c
+
+Author:
+
+ Ted Miller 6-July-1995
+
+Abstract:
+
+ This routine contains low-level routines to operate on a
+ CGA-style text mode video buffer.
+
+ It collects up various other bits and pieces that were written by
+ others and once contained in other source files.
+
+--*/
+
+#include "bootx86.h"
+#include "displayp.h"
+
+//
+// Standard cga 80x25 text mode's video buffer address,
+// resolution, etc.
+//
+#define VIDEO_BUFFER_VA 0xb8000
+#define VIDEO_ROWS 25
+#define VIDEO_COLUMNS 80
+#define VIDEO_BYTES_PER_ROW (VIDEO_COLUMNS*2)
+
+//
+// Various globals to track location on screen, attribute, etc.
+//
+PUCHAR Vp = (PUCHAR)VIDEO_BUFFER_VA;
+
+
+VOID
+TextTmPositionCursor(
+ USHORT Row,
+ USHORT Column
+ )
+
+/*++
+
+Routine Description:
+
+ Sets the position of the soft cursor. That is, it doesn't move the
+ hardware cursor but sets the location of the next write to the
+ screen.
+
+Arguments:
+
+ Row - Row coordinate of where character is to be written.
+
+ Column - Column coordinate of where character is to be written.
+
+Returns:
+
+ Nothing.
+
+--*/
+
+{
+ if(Row >= VIDEO_ROWS) {
+ Row = VIDEO_ROWS-1;
+ }
+
+ if(Column >= VIDEO_COLUMNS) {
+ Column = VIDEO_COLUMNS-1;
+ }
+
+ Vp = (PUCHAR)(VIDEO_BUFFER_VA + (Row * VIDEO_BYTES_PER_ROW) + (2 * Column));
+}
+
+
+VOID
+TextTmStringOut(
+ IN PUCHAR String
+ )
+{
+ PUCHAR p = String;
+
+ while(*p) {
+ p = TextTmCharOut(p);
+ }
+}
+
+
+PUCHAR
+TextTmCharOut(
+ PUCHAR pc
+ )
+
+/*++
+
+Routine Description:
+
+ Writes a character on the display at the current position.
+ Newlines and tabs are interpreted and acted upon.
+
+Arguments:
+
+ c - pointer to character to write
+
+Returns:
+
+ Pointer to next char in string
+
+--*/
+
+
+
+{
+ unsigned u;
+ UCHAR c;
+ UCHAR temp;
+
+ c = *pc;
+
+ switch (c) {
+ case '\n':
+ if(TextRow == (VIDEO_ROWS-1)) {
+ TextTmScrollDisplay();
+ TextSetCursorPosition(0,TextRow);
+ } else {
+ TextSetCursorPosition(0,TextRow+1);
+ }
+ break;
+
+ case '\r':
+ //
+ // ignore
+ //
+ break;
+
+ case '\t':
+ temp = ' ';
+ u = 8 - (TextColumn % 8);
+ while(u--) {
+ TextTmCharOut(&temp);
+ }
+ TextSetCursorPosition(TextColumn+u,TextRow);
+ break;
+
+ default :
+ *Vp++ = c;
+ *Vp++ = TextCurrentAttribute;
+ TextSetCursorPosition(TextColumn+1,TextRow);
+ }
+
+ return(pc+1);
+}
+
+
+VOID
+TextTmFillAttribute(
+ IN UCHAR Attribute,
+ IN ULONG Length
+ )
+
+/*++
+
+Routine Description:
+
+ Changes the screen attribute starting at the current cursor position.
+ The cursor is not moved.
+
+Arguments:
+
+ Attribute - Supplies the new attribute
+
+ Length - Supplies the length of the area to change (in bytes)
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PUCHAR Temp;
+
+ Temp = Vp+1;
+
+ while((Vp+1+Length*2) > Temp) {
+ *Temp++ = (UCHAR)Attribute;
+ Temp++;
+ }
+}
+
+
+VOID
+TextTmClearToEndOfLine(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Clears from the current cursor position to the end of the line
+ by writing blanks with the current video attribute.
+ The cursor position is not changed.
+
+Arguments:
+
+ None
+
+Returns:
+
+ Nothing
+
+--*/
+
+{
+ PUSHORT p;
+ unsigned u;
+
+ //
+ // Calculate address of current cursor position
+ //
+ p = (PUSHORT)((PUCHAR)VIDEO_BUFFER_VA + (TextRow*VIDEO_BYTES_PER_ROW)) + TextColumn;
+
+ //
+ // Fill with blanks up to end of line.
+ //
+ for(u=TextColumn; u<VIDEO_COLUMNS; u++) {
+ *p++ = (TextCurrentAttribute << 8) + ' ';
+ }
+}
+
+
+VOID
+TextTmClearFromStartOfLine(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Clears from the start of the line to the current cursor position
+ by writing blanks with the current video attribute.
+ The cursor position is not changed.
+
+Arguments:
+
+ None
+
+Returns:
+
+ Nothing
+
+--*/
+
+{
+ PUSHORT p;
+ unsigned u;
+
+ //
+ // Calculate address of start of line in video buffer
+ //
+ p = (PUSHORT)((PUCHAR)VIDEO_BUFFER_VA + (TextRow*VIDEO_BYTES_PER_ROW));
+
+ //
+ // Fill with blanks up to char before cursor position.
+ //
+ for(u=0; u<TextColumn; u++) {
+ *p++ = (TextCurrentAttribute << 8) + ' ';
+ }
+}
+
+
+VOID
+TextTmClearToEndOfDisplay(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Clears from the current cursor position to the end of the video
+ display by writing blanks with the current video attribute.
+ The cursor position is not changed.
+
+Arguments:
+
+ None
+
+Returns:
+
+ Nothing
+
+--*/
+{
+ USHORT x,y;
+ PUSHORT p;
+
+ //
+ // Clear current line
+ //
+ TextTmClearToEndOfLine();
+
+ //
+ // Clear the remaining lines
+ //
+ p = (PUSHORT)((PUCHAR)VIDEO_BUFFER_VA + ((TextRow+1)*VIDEO_BYTES_PER_ROW));
+
+ for(y=TextRow+1; y<VIDEO_ROWS; y++) {
+
+ for(x=0; x<VIDEO_COLUMNS; x++) {
+
+ *p++ =(TextCurrentAttribute << 8) + ' ';
+ }
+ }
+}
+
+
+VOID
+TextTmClearDisplay(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Clears the text-mode video display by writing blanks with
+ the current video attribute over the entire display.
+
+Arguments:
+
+ None
+
+Returns:
+
+ Nothing
+
+--*/
+
+{
+ unsigned u;
+
+ //
+ // Write blanks in the current attribute to the entire screen.
+ //
+ for(u=0; u<VIDEO_ROWS*VIDEO_COLUMNS; u++) {
+ ((PUSHORT)VIDEO_BUFFER_VA)[u] = (TextCurrentAttribute << 8) + ' ';
+ }
+}
+
+
+VOID
+TextTmScrollDisplay(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Scrolls the display up one line. The cursor position is not changed.
+
+Arguments:
+
+ None
+
+Returns:
+
+ Nothing
+
+--*/
+
+{
+ PUSHORT Sp,Dp;
+ USHORT i,j,c;
+
+ Dp = (PUSHORT) VIDEO_BUFFER_VA;
+ Sp = (PUSHORT) (VIDEO_BUFFER_VA + VIDEO_BYTES_PER_ROW);
+
+ //
+ // Move each row up one row
+ //
+ for(i=0 ; i < (USHORT)(VIDEO_ROWS-1) ; i++) {
+ for(j=0; j < (USHORT)VIDEO_COLUMNS; j++) {
+ *Dp++ = *Sp++;
+ }
+ }
+
+ //
+ // Write blanks in the bottom line, using the attribute
+ // from the leftmost char on the bottom line on the screen.
+ //
+ c = (*Dp & (USHORT)0xff00) + (USHORT)' ';
+
+ for(i=0; i < (USHORT)VIDEO_COLUMNS; ++i) {
+ *Dp++ = c;
+ }
+}
+
+
+VOID
+TextTmSetCurrentAttribute(
+ IN UCHAR Attribute
+ )
+
+/*++
+
+Routine Description:
+
+ Noop.
+
+Arguments:
+
+ Attribute - New attribute to set to.
+
+Return Value:
+
+ Nothing.
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER(Attribute);
+}
+
+
+CHAR TmGraphicsChars[GraphicsCharMax] = { 'É','»','È','¼','º','Í' };
+
+UCHAR
+TextTmGetGraphicsChar(
+ IN GraphicsChar WhichOne
+ )
+{
+ return((UCHAR)TmGraphicsChars[WhichOne]);
+}
diff --git a/private/ntos/boot/lib/i386/display.c b/private/ntos/boot/lib/i386/display.c
new file mode 100644
index 000000000..d34ad173a
--- /dev/null
+++ b/private/ntos/boot/lib/i386/display.c
@@ -0,0 +1,659 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ display.c
+
+Author:
+
+ Thomas Parslow [TomP] Feb-13-1991
+ Reworked substantially in Tokyo 7-July-95 (tedm)
+
+Abstract:
+
+ This file contains an interface to the screen that is independent
+ of the screen type actually being written to. It is layered on top
+ of modules pecific to vga text mode and vga graphics mode.
+
+--*/
+
+
+#include "bootx86.h"
+#include "displayp.h"
+
+
+#define ZLEN_SHORT(x) ((x < 0x10) + (x < 0x100) + (x < 0x1000))
+#define ZLEN_LONG(x) ((x < 0x10) + (x < 0x100) + (x < 0x1000) + \
+ (x < 0x10000) + (x < 0x100000)+(x < 0x1000000)+(x < 0x10000000))
+
+//
+// Current screen position.
+//
+USHORT TextColumn = 0;
+USHORT TextRow = 0;
+
+//
+// Current text attribute
+//
+UCHAR TextCurrentAttribute = 0x07; // start with white on black.
+
+//
+// Internal routines
+//
+VOID
+puti(
+ LONG
+ );
+
+VOID
+putx(
+ ULONG
+ );
+
+VOID
+putu(
+ ULONG
+ );
+
+VOID
+pTextCharOut(
+ IN UCHAR c
+ );
+
+VOID
+putwS(
+ PUNICODE_STRING String
+ );
+
+
+VOID
+BlPrint(
+ PCHAR cp,
+ ...
+ )
+
+/*++
+
+Routine Description:
+
+ Standard printf function with a subset of formating features supported.
+
+ Currently handles
+
+ %d, %ld - signed short, signed long
+ %u, %lu - unsigned short, unsigned long
+ %c, %s - character, string
+ %x, %lx - unsigned print in hex, unsigned long print in hex
+
+ Does not do:
+
+ - field width specification
+ - floating point.
+
+Arguments:
+
+ cp - pointer to the format string, text string.
+
+Returns:
+
+ Nothing
+
+--*/
+
+{
+ USHORT b,c,w,len;
+ PUCHAR ap;
+ ULONG l;
+
+ //
+ // Cast a pointer to the first word on the stack
+ //
+ ap = (PUCHAR)&cp + sizeof(PCHAR);
+
+ //
+ // Process the arguments using the descriptor string
+ //
+ while(b = *cp++) {
+ if(b == '%') {
+
+ c = *cp++;
+
+ switch (c) {
+
+ case 'd':
+ puti((long)*((int *)ap));
+ ap += sizeof(int);
+ break;
+
+ case 's':
+ TextStringOut(*((PCHAR *)ap));
+ ap += sizeof(char *);
+ break;
+
+ case 'c':
+ //
+ // Does not handle dbcs chars
+ //
+ pTextCharOut(*((char *)ap));
+ ap += sizeof(int);
+ break;
+
+ case 'x':
+ w = *((USHORT *)ap);
+ len = (USHORT)ZLEN_SHORT(w);
+ while(len--) pTextCharOut('0');
+ putx((ULONG)*((USHORT *)ap));
+ ap += sizeof(int);
+ break;
+
+ case 'u':
+ putu((ULONG)*((USHORT *)ap));
+ ap += sizeof(int);
+ break;
+
+ case 'w':
+ c = *cp++;
+ switch (c) {
+ case 'S':
+ case 'Z':
+ putwS(*((PUNICODE_STRING *)ap));
+ ap += sizeof(PUNICODE_STRING);
+ break;
+ }
+ break;
+
+ case 'l':
+ c = *cp++;
+
+ switch(c) {
+
+ case '0':
+ break;
+
+ case 'u':
+ putu(*((ULONG *)ap));
+ ap += sizeof(long);
+ break;
+
+ case 'x':
+ l = *((ULONG *)ap);
+ len = (USHORT)ZLEN_LONG(l);
+ while(len--) pTextCharOut('0');
+ putx(*((ULONG *)ap));
+ ap += sizeof(long);
+ break;
+
+ case 'd':
+ puti(*((ULONG *)ap));
+ ap += sizeof(long);
+ break;
+ }
+ break;
+
+ default :
+ pTextCharOut((char)b);
+ pTextCharOut((char)c);
+ }
+ } else {
+ //
+ // Could be a double-byte char.
+ //
+ cp = TextCharOut(cp-1);
+ }
+ }
+}
+
+
+VOID
+putwS(
+ PUNICODE_STRING String
+ )
+
+/*++
+
+Routine Description:
+
+ Writes unicode string to the display at the current cursor position.
+
+Arguments:
+
+ String - pointer to unicode string to display
+
+Returns:
+
+ Nothing
+
+--*/
+
+{
+ ULONG i;
+
+ for(i=0; i < String->Length/sizeof(WCHAR); i++) {
+ pTextCharOut((UCHAR)String->Buffer[i]);
+ }
+}
+
+
+VOID
+putx(
+ ULONG x
+ )
+
+/*++
+
+Routine Description:
+
+ Writes hex long to the display at the current cursor position.
+
+Arguments:
+
+ x - ulong to write
+
+Returns:
+
+ Nothing
+
+--*/
+
+{
+ ULONG j;
+
+ if(x/16) {
+ putx(x/16);
+ }
+
+ if((j=x%16) > 9) {
+ pTextCharOut((UCHAR)(j+'A'-10));
+ } else {
+ pTextCharOut((UCHAR)(j+'0'));
+ }
+}
+
+
+VOID
+puti(
+ LONG i
+ )
+
+/*++
+
+Routine Description:
+
+ Writes a long integer on the display at the current cursor position.
+
+Arguments:
+
+ i - the integer to write to the display.
+
+Returns:
+
+ Nothing
+
+--*/
+
+{
+ if(i<0) {
+ i = -i;
+ pTextCharOut('-');
+ }
+
+ if(i/10) {
+ puti(i/10);
+ }
+
+ pTextCharOut((UCHAR)((i%10)+'0'));
+}
+
+
+VOID
+putu(
+ ULONG u
+ )
+
+/*++
+
+Routine Description:
+
+ Write an unsigned long to display
+
+Arguments:
+
+ u - unsigned
+
+Returns:
+
+ Nothing
+
+--*/
+
+{
+ if(u/10) {
+ putu(u/10);
+ }
+ pTextCharOut((UCHAR)((u%10)+'0'));
+
+}
+
+
+VOID
+pTextCharOut(
+ IN UCHAR c
+ )
+{
+ if(DbcsLangId) {
+ //
+ // Single-byte only
+ //
+ TextGrCharOut(&c);
+ } else {
+ TextTmCharOut(&c);
+ }
+}
+
+
+PUCHAR
+TextCharOut(
+ IN PUCHAR pc
+ )
+{
+ if(DbcsLangId) {
+ return(TextGrCharOut(pc));
+ } else {
+ return(TextTmCharOut(pc));
+ }
+}
+
+
+VOID
+TextStringOut(
+ IN PUCHAR String
+ )
+{
+ if(DbcsLangId) {
+ TextGrStringOut(String);
+ } else {
+ TextTmStringOut(String);
+ }
+}
+
+
+VOID
+TextClearToEndOfLine(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Clears from the current cursor position to the end of the line
+ by writing blanks with the current video attribute.
+
+Arguments:
+
+ None
+
+Returns:
+
+ Nothing
+
+
+--*/
+
+{
+ if(DbcsLangId) {
+ TextGrClearToEndOfLine();
+ } else {
+ TextTmClearToEndOfLine();
+ }
+}
+
+
+VOID
+TextClearFromStartOfLine(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Clears from the start of the line to the current cursor position
+ by writing blanks with the current video attribute.
+ The cursor position is not changed.
+
+Arguments:
+
+ None
+
+Returns:
+
+ Nothing
+
+--*/
+
+{
+ if(DbcsLangId) {
+ TextGrClearFromStartOfLine();
+ } else {
+ TextTmClearFromStartOfLine();
+ }
+}
+
+
+VOID
+TextClearToEndOfDisplay(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Clears from the current cursor position to the end of the video
+ display by writing blanks with the current video attribute.
+ The cursor position is not changed.
+
+Arguments:
+
+ None
+
+Returns:
+
+ Nothing
+
+--*/
+
+{
+ if(DbcsLangId) {
+ TextGrClearToEndOfDisplay();
+ } else {
+ TextTmClearToEndOfDisplay();
+ }
+}
+
+
+VOID
+TextClearDisplay(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Clears the video display and positions the cursor
+ at the upper left corner of the screen (0,0).
+
+Arguments:
+
+ None
+
+Returns:
+
+ Nothing
+
+--*/
+
+{
+ if(DbcsLangId) {
+ TextGrClearDisplay();
+ } else {
+ TextTmClearDisplay();
+ }
+ TextSetCursorPosition(0,0);
+}
+
+
+VOID
+TextSetCursorPosition(
+ IN ULONG X,
+ IN ULONG Y
+ )
+
+/*++
+
+Routine Description:
+
+ Moves the location of the software cursor to the specified X,Y position
+ on screen.
+
+Arguments:
+
+ X - Supplies the X-position of the cursor
+
+ Y - Supplies the Y-position of the cursor
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ TextColumn = (USHORT)X;
+ TextRow = (USHORT)Y;
+
+ if(DbcsLangId) {
+ TextGrPositionCursor((USHORT)Y,(USHORT)X);
+ } else {
+ TextTmPositionCursor((USHORT)Y,(USHORT)X);
+ }
+}
+
+
+VOID
+TextGetCursorPosition(
+ OUT PULONG X,
+ OUT PULONG Y
+ )
+
+/*++
+
+Routine Description:
+
+ Gets the position of the soft cursor.
+
+Arguments:
+
+ X - Receives column coordinate of where character would be written.
+
+ Y - Receives row coordinate of where next character would be written.
+
+Returns:
+
+ Nothing.
+
+--*/
+
+{
+ *X = (ULONG)TextColumn;
+ *Y = (ULONG)TextRow;
+}
+
+
+VOID
+TextSetCurrentAttribute(
+ IN UCHAR Attribute
+ )
+
+/*++
+
+Routine Description:
+
+ Sets the character attribute to be used for subsequent text display.
+
+Arguments:
+
+Returns:
+
+ Nothing.
+
+--*/
+
+{
+ TextCurrentAttribute = Attribute;
+
+ if(DbcsLangId) {
+ TextGrSetCurrentAttribute(Attribute);
+ } else {
+ TextTmSetCurrentAttribute(Attribute);
+ }
+}
+
+
+UCHAR
+TextGetCurrentAttribute(
+ VOID
+ )
+{
+ return(TextCurrentAttribute);
+}
+
+VOID
+TextFillAttribute(
+ IN UCHAR Attribute,
+ IN ULONG Length
+ )
+
+/*++
+
+Routine Description:
+
+ Changes the screen attribute starting at the current cursor position.
+ The cursor is not moved.
+
+Arguments:
+
+ Attribute - Supplies the new attribute
+
+ Length - Supplies the length of the area to change (in bytes)
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ if(DbcsLangId) {
+ TextGrFillAttribute(Attribute,Length);
+ } else {
+ TextTmFillAttribute(Attribute,Length);
+ }
+}
+
+
+UCHAR
+TextGetGraphicsCharacter(
+ IN GraphicsChar WhichOne
+ )
+{
+ return((WhichOne < GraphicsCharMax)
+ ? (DbcsLangId ? TextGrGetGraphicsChar(WhichOne) : TextTmGetGraphicsChar(WhichOne))
+ : ' ');
+}
+
+
diff --git a/private/ntos/boot/lib/i386/displayp.h b/private/ntos/boot/lib/i386/displayp.h
new file mode 100644
index 000000000..672be6d6f
--- /dev/null
+++ b/private/ntos/boot/lib/i386/displayp.h
@@ -0,0 +1,154 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ displayp.h
+
+Abstract:
+
+ Private header file for display routines.
+
+Author:
+
+ Ted Miller (tedm) 7-July-1995
+
+Revision History:
+
+--*/
+
+//
+// NOTICE
+//
+// Under no circumstances is anyone besides display.c to call these routines
+// directly. This would break DBCS display for Far Eastern locales.
+//
+
+//
+// Globals
+//
+extern USHORT TextColumn;
+extern USHORT TextRow;
+extern UCHAR TextCurrentAttribute;
+
+//
+// Vga text mode stuff
+//
+VOID
+TextTmScrollDisplay(
+ VOID
+ );
+
+VOID
+TextTmClearDisplay(
+ VOID
+ );
+
+VOID
+TextTmClearToEndOfDisplay(
+ VOID
+ );
+
+VOID
+TextTmClearFromStartOfLine(
+ VOID
+ );
+
+VOID
+TextTmClearToEndOfLine(
+ VOID
+ );
+
+VOID
+TextTmFillAttribute(
+ IN UCHAR Attribute,
+ IN ULONG Length
+ );
+
+PUCHAR
+TextTmCharOut(
+ PUCHAR pc
+ );
+
+VOID
+TextTmStringOut(
+ IN PUCHAR String
+ );
+
+VOID
+TextTmPositionCursor(
+ USHORT Row,
+ USHORT Column
+ );
+
+VOID
+TextTmSetCurrentAttribute(
+ IN UCHAR Attribute
+ );
+
+UCHAR
+TextTmGetGraphicsChar(
+ IN GraphicsChar WhichOne
+ );
+
+//
+// Vga graphics mode stuff
+//
+
+VOID
+TextGrScrollDisplay(
+ VOID
+ );
+
+VOID
+TextGrClearDisplay(
+ VOID
+ );
+
+VOID
+TextGrClearToEndOfDisplay(
+ VOID
+ );
+
+VOID
+TextGrClearFromStartOfLine(
+ VOID
+ );
+
+VOID
+TextGrClearToEndOfLine(
+ VOID
+ );
+
+VOID
+TextGrFillAttribute(
+ IN UCHAR Attribute,
+ IN ULONG Length
+ );
+
+PUCHAR
+TextGrCharOut(
+ PUCHAR pc
+ );
+
+VOID
+TextGrStringOut(
+ IN PUCHAR String
+ );
+
+VOID
+TextGrPositionCursor(
+ USHORT Row,
+ USHORT Column
+ );
+
+VOID
+TextGrSetCurrentAttribute(
+ IN UCHAR Attribute
+ );
+
+UCHAR
+TextGrGetGraphicsChar(
+ IN GraphicsChar WhichOne
+ );
diff --git a/private/ntos/boot/lib/i386/driverld.c b/private/ntos/boot/lib/i386/driverld.c
new file mode 100644
index 000000000..1845cd4d7
--- /dev/null
+++ b/private/ntos/boot/lib/i386/driverld.c
@@ -0,0 +1,92 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ driverld.c
+
+Abstract:
+
+ This module implements the loading and initializing of boot drivers
+ used by NTLDR.
+
+Author:
+
+ John Vert (jvert) 16-Jan-1992
+
+Revision History:
+
+--*/
+#include "arccodes.h"
+#include "bootx86.h"
+
+
+BOOLEAN
+BlpLoadAndInitializeBootDriver(
+ IN PCHAR DriverDevice,
+ IN PCHAR DriverPath
+ )
+
+/*++
+
+Routine Description:
+
+ Loads a boot driver into memory, relocates it, binds it, and initializes
+ it.
+
+Arguments:
+
+ DriverDevice - Supplies the name of the device to load the driver from.
+
+ DriverPath - Supplies the fully qualified pathname of the boot driver.
+
+Return Value:
+
+--*/
+
+{
+ ULONG DeviceId;
+ ULONG FileId;
+ ARC_STATUS Status;
+ PVOID ImageBase;
+ PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor;
+ ULONG ImportTableSize;
+
+ Status = ArcOpen(DriverDevice, ArcOpenReadOnly, &DeviceId);
+ if (Status != ESUCCESS) {
+ return(FALSE);
+ }
+
+ Status = BlLoadImage( DeviceId,
+ MemoryFirmwareTemporary,
+ DriverPath,
+ TARGET_IMAGE,
+ &ImageBase );
+
+ if (Status != ESUCCESS) {
+ ArcClose(DeviceId);
+ return(FALSE);
+ } else {
+ BlPrint("%s successfully loaded at %lx\n",
+ DriverPath,
+ ImageBase);
+ while (!GET_KEY()) {
+ }
+ }
+
+ ImportDescriptor =
+ (PIMAGE_IMPORT_DESCRIPTOR)RtlImageDirectoryEntryToData(ImageBase,
+ TRUE,
+ IMAGE_DIRECTORY_ENTRY_IMPORT,
+ &ImportTableSize);
+
+ Status = BlpScanImportAddressTable(0x80000,
+ ImageBase,
+ (PIMAGE_THUNK_DATA)((ULONG)ScanEntry->DllBase +
+ (ULONG)ImportDescriptor->FirstThunk));
+ if (Status != ESUCCESS) {
+ return(Status);
+ }
+
+}
diff --git a/private/ntos/boot/lib/i386/entry.c b/private/ntos/boot/lib/i386/entry.c
new file mode 100644
index 000000000..4dada52f3
--- /dev/null
+++ b/private/ntos/boot/lib/i386/entry.c
@@ -0,0 +1,482 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ entry.c
+
+Abstract:
+
+ x86-specific startup for setupldr
+
+Author:
+
+ John Vert (jvert) 14-Oct-1993
+
+Revision History:
+
+--*/
+#include "bootx86.h"
+#include "stdio.h"
+#include "flop.h"
+
+//
+// Prototypes for Internal Routines
+//
+
+VOID
+DoGlobalInitialization(
+ PBOOT_CONTEXT
+ );
+
+#if defined(ELTORITO)
+BOOLEAN ElToritoCDBoot = FALSE;
+#endif
+
+//
+// Global context pointers. These are passed to us by the SU module or
+// the bootstrap code.
+//
+
+PCONFIGURATION_COMPONENT_DATA FwConfigurationTree = NULL;
+PEXTERNAL_SERVICES_TABLE ExternalServicesTable;
+UCHAR BootPartitionName[80];
+ULONG FwHeapUsed = 0;
+ULONG MachineType = 0;
+ULONG OsLoaderBase;
+ULONG OsLoaderExports;
+extern PUCHAR BlpResourceDirectory;
+extern PUCHAR BlpResourceFileOffset;
+
+VOID
+NtProcessStartup(
+ IN PBOOT_CONTEXT BootContextRecord
+ )
+/*++
+
+Routine Description:
+
+ Main entry point for setup loader. Control is transferred here by the
+ start-up (SU) module.
+
+Arguments:
+
+ BootContextRecord - Supplies the boot context, particularly the
+ ExternalServicesTable.
+
+Returns:
+
+ Does not return. Control eventually passed to the kernel.
+
+
+--*/
+{
+ ARC_STATUS Status;
+
+ //
+ // Initialize the boot loader's video
+ //
+
+ DoGlobalInitialization(BootContextRecord);
+
+ BlFillInSystemParameters(BootContextRecord);
+
+ if (BootContextRecord->FSContextPointer->BootDrive == 0) {
+
+ //
+ // Boot was from A:
+ //
+
+ strcpy(BootPartitionName,"multi(0)disk(0)fdisk(0)");
+
+ //
+ // To get around an apparent bug on the BIOS of some MCA machines
+ // (specifically the NCR 386sx/MC20 w/ BIOS version 1.04.00 (3421),
+ // Phoenix BIOS 1.02.07), whereby the first int13 to floppy results
+ // in a garbage buffer, reset drive 0 here.
+ //
+
+ GET_SECTOR(0,0,0,0,0,0,NULL);
+
+#if defined(ELTORITO)
+ } else if (BlIsElToritoCDBoot(BootContextRecord->FSContextPointer->BootDrive)) {
+
+ //
+ // Boot was from El Torito CD
+ //
+
+ sprintf(BootPartitionName, "multi(0)disk(0)cdrom(%u)", BootContextRecord->FSContextPointer->BootDrive);
+ ElToritoCDBoot = TRUE;
+#endif
+
+ } else {
+
+ //
+ // Find the partition we have been booted from. Note that this
+ // is *NOT* necessarily the active partition. If the system has
+ // Boot Mangler installed, it will be the active partition, and
+ // we have to go figure out what partition we are actually on.
+ //
+ BlGetActivePartition(BootPartitionName);
+
+ }
+
+ //
+ // Initialize the memory descriptor list, the OS loader heap, and the
+ // OS loader parameter block.
+ //
+
+ Status = BlMemoryInitialize();
+ if (Status != ESUCCESS) {
+ BlPrint("Couldn't initialize memory\n");
+ while (1) {
+ }
+ }
+
+ //
+ // Initialize the OS loader I/O system.
+ //
+
+ Status = BlIoInitialize();
+ if (Status != ESUCCESS) {
+ BlPrint("Couldn't initialize I/O\n");
+ }
+
+ //
+ // Call off to regular startup code
+ //
+ BlStartup(BootPartitionName);
+
+ //
+ // we should never get here!
+ //
+ do {
+ GET_KEY();
+ } while ( 1 );
+
+}
+
+BOOLEAN
+BlDetectHardware(
+ IN ULONG DriveId,
+ IN PCHAR LoadOptions
+ )
+
+/*++
+
+Routine Description:
+
+ Loads and runs NTDETECT.COM to populate the ARC configuration tree.
+ NTDETECT is assumed to reside in the root directory.
+
+Arguments:
+
+ DriveId - Supplies drive id where NTDETECT is located.
+
+ LoadOptions - Supplies Load Options string to ntdetect.
+
+Return Value:
+
+ TRUE - NTDETECT successfully run.
+
+ FALSE - Error
+
+--*/
+
+{
+ ARC_STATUS Status;
+ PCONFIGURATION_COMPONENT_DATA TempFwTree;
+ ULONG TempFwHeapUsed;
+ extern BOOLEAN FwDescriptorsValid;
+ ULONG FileSize;
+ ULONG DetectFileId;
+ FILE_INFORMATION FileInformation;
+ PUCHAR DetectionBuffer;
+ PUCHAR Options;
+ UCHAR Buffer[100];
+ LARGE_INTEGER SeekPosition;
+ ULONG Read;
+
+ //
+ // Now check if we have ntdetect.com in the root directory, if yes,
+ // we will load it to predefined location and transfer control to
+ // it.
+ //
+
+#if defined(ELTORITO)
+ if (ElToritoCDBoot) {
+ // we assume ntdetect.com is in the i386 directory
+ Status = BlOpen( DriveId,
+ "\\i386\\ntdetect.com",
+ ArcOpenReadOnly,
+ &DetectFileId );
+ } else {
+#endif
+ Status = BlOpen( DriveId,
+ "\\ntdetect.com",
+ ArcOpenReadOnly,
+ &DetectFileId );
+#if defined(ELTORITO)
+ }
+#endif
+
+ DetectionBuffer = (PUCHAR)DETECTION_LOADED_ADDRESS;
+
+ if (Status != ESUCCESS) {
+#if DBG
+ BlPrint("Error opening NTDETECT.COM, status = %x\n", Status);
+ BlPrint("Press any key to continue\n");
+ while (!GET_KEY()) {
+ }
+#endif
+ return(FALSE);
+ }
+
+ //
+ // Determine the length of the ntdetect.com file
+ //
+
+ Status = BlGetFileInformation(DetectFileId, &FileInformation);
+ if (Status != ESUCCESS) {
+ BlClose(DetectFileId);
+#if DBG
+ BlPrint("Error getting NTDETECT.COM file information, status = %x\n", Status);
+ BlPrint("Press any key to continue\n");
+ while (!GET_KEY()) {
+ }
+#endif
+ return(FALSE);
+ }
+
+ FileSize = FileInformation.EndingAddress.LowPart;
+ if (FileSize == 0) {
+ BlClose(DetectFileId);
+#if DBG
+ BlPrint("Error: size of NTDETECT.COM is zero.\n");
+ BlPrint("Press any key to continue\n");
+ while (!GET_KEY()) {
+ }
+#endif
+ return(FALSE);
+ }
+
+ SeekPosition.QuadPart = 0;
+ Status = BlSeek(DetectFileId,
+ &SeekPosition,
+ SeekAbsolute);
+ if (Status != ESUCCESS) {
+ BlClose(DetectFileId);
+#if DBG
+ BlPrint("Error seeking to start of NTDETECT.COM file\n");
+ BlPrint("Press any key to continue\n");
+ while (!GET_KEY()) {
+ }
+#endif
+ return(FALSE);
+ }
+ Status = BlRead( DetectFileId,
+ DetectionBuffer,
+ FileSize,
+ &Read );
+
+ BlClose(DetectFileId);
+ if (Status != ESUCCESS) {
+#if DBG
+ BlPrint("Error reading from NTDETECT.COM\n");
+ BlPrint("Read %lx bytes\n",Read);
+ BlPrint("Press any key to continue\n");
+ while (!GET_KEY()) {
+ }
+#endif
+ return(FALSE);
+ }
+
+ //
+ // We need to pass NTDETECT pointers < 1Mb, so
+ // use local storage off the stack. (which is
+ // always < 1Mb.
+ //
+
+ if (LoadOptions) {
+ strcpy(Buffer, LoadOptions);
+ Options = Buffer;
+ } else {
+ Options = NULL;
+ }
+ DETECT_HARDWARE((ULONG)(TEMPORARY_HEAP_START - 0x10) * PAGE_SIZE,
+ (ULONG)0x10000, // Heap Size
+ (PVOID)&TempFwTree,
+ (PULONG)&TempFwHeapUsed,
+ (PCHAR)Options,
+ (ULONG)(LoadOptions ? strlen(LoadOptions) : 0)
+ );
+ FwConfigurationTree = TempFwTree;
+ FwHeapUsed = TempFwHeapUsed;
+ FwDescriptorsValid = FALSE;
+
+ return(TRUE);
+}
+
+
+VOID
+DoGlobalInitialization(
+ IN PBOOT_CONTEXT BootContextRecord
+ )
+
+/*++
+
+Routine Description
+
+ This routine calls all of the subsytem initialization routines.
+
+
+Arguments:
+
+ None
+
+Returns:
+
+ Nothing
+
+--*/
+
+{
+ ARC_STATUS Status;
+
+ Status = InitializeMemorySubsystem(BootContextRecord);
+ if (Status != ESUCCESS) {
+ BlPrint("InitializeMemory failed %lx\n",Status);
+ while (1) {
+ }
+ }
+ ExternalServicesTable=BootContextRecord->ExternalServicesTable;
+ MachineType = BootContextRecord->MachineType;
+
+ //
+ // Turn the cursor off
+ //
+
+ HW_CURSOR(0,127);
+
+ BlpResourceDirectory = (PUCHAR)(BootContextRecord->ResourceDirectory);
+ BlpResourceFileOffset = (PUCHAR)(BootContextRecord->ResourceOffset);
+
+ OsLoaderBase = BootContextRecord->OsLoaderBase;
+ OsLoaderExports = BootContextRecord->OsLoaderExports;
+
+ InitializeMemoryDescriptors ();
+}
+
+
+VOID
+BlGetActivePartition(
+ OUT PUCHAR BootPartitionName
+ )
+
+/*++
+
+Routine Description:
+
+ Determine the ARC name for the partition NTLDR was started from
+
+Arguments:
+
+ BootPartitionName - Supplies a buffer where the ARC name of the
+ partition will be returned.
+
+Return Value:
+
+ Name of the partition is in BootPartitionName.
+
+ Must always succeed.
+--*/
+
+{
+ UCHAR SectorBuffer[512];
+ UCHAR NameBuffer[80];
+ ARC_STATUS Status;
+ ULONG FileId;
+ ULONG Count;
+ int i;
+
+ //
+ // The method we use is to open each partition on the first drive
+ // and read in its boot sector. Then we compare that to the boot
+ // sector that we used to boot from (at physical address 0x7c00.
+ // If they are the same, we've found it. If we run out of partitions,
+ // just try partition 1
+ //
+ i=1;
+ do {
+ sprintf(NameBuffer, "multi(0)disk(0)rdisk(0)partition(%u)",i);
+ Status = ArcOpen(NameBuffer,ArcOpenReadOnly,&FileId);
+ if (Status != ESUCCESS) {
+ //
+ // we've run out of partitions, return the default.
+ //
+ i=1;
+ break;
+ } else {
+ //
+ // Read in the first 512 bytes
+ //
+ Status = ArcRead(FileId, SectorBuffer, 512, &Count);
+ ArcClose(FileId);
+ if (Status==ESUCCESS) {
+
+ //
+ // only need to compare the first 36 bytes
+ // Jump instr. == 3 bytes
+ // Oem field == 8 bytes
+ // BPB == 25 bytes
+ //
+
+ if (memcmp(SectorBuffer, (PVOID)0x7c00, 36)==0) {
+ //
+ // we have found a match.
+ //
+ break;
+ }
+ }
+ }
+
+ ++i;
+ } while ( TRUE );
+
+ sprintf(BootPartitionName, "multi(0)disk(0)rdisk(0)partition(%u)",i);
+ return;
+}
+
+#if defined(ELTORITO)
+
+BOOLEAN
+BlIsElToritoCDBoot(
+ ULONG DriveNum
+ )
+{
+ if (LocalBuffer == NULL) {
+ LocalBuffer = FwAllocateHeap(SCRATCH_BUFFER_SIZE);
+ if (LocalBuffer==NULL) {
+ return(FALSE);
+ }
+ }
+
+ // Note, even though args are short, they are pushed on the stack with
+ // 32bit alignment so the effect on the stack seen by the 16bit real
+ // mode code is the same as if we were pushing longs here.
+ //
+ // GET_ELTORITO_STATUS is 0 if we are in emulation mode
+
+ if (DriveNum > 0x81) {
+ if (!GET_ELTORITO_STATUS(LocalBuffer, DriveNum)) {
+ return(TRUE);
+ } else {
+ return(FALSE);
+ }
+ } else {
+ return(FALSE);
+ }
+}
+#endif
+
diff --git a/private/ntos/boot/lib/i386/flop.h b/private/ntos/boot/lib/i386/flop.h
new file mode 100644
index 000000000..5f49e5013
--- /dev/null
+++ b/private/ntos/boot/lib/i386/flop.h
@@ -0,0 +1,38 @@
+
+//
+// Optimize this constant so we are guaranteed to be able to transfer
+// a whole track at a time from a 1.44 meg disk (sectors/track = 18 = 9K)
+//
+#define SCRATCH_BUFFER_SIZE 9216
+
+//
+// Buffer for temporary storage of data read from the disk that needs
+// to end up in a location above the 1MB boundary.
+//
+// NOTE: it is very important that this buffer not cross a 64k boundary.
+//
+extern PUCHAR LocalBuffer;
+
+
+
+BOOLEAN
+FcIsThisFloppyCached(
+ IN PUCHAR Buffer
+ );
+
+VOID
+FcCacheFloppyDisk(
+ PBIOS_PARAMETER_BLOCK Bpb
+ );
+
+VOID
+FcUncacheFloppyDisk(
+ VOID
+ );
+
+ARC_STATUS
+FcReadFromCache(
+ IN ULONG Offset,
+ IN ULONG Length,
+ OUT PUCHAR Buffer
+ );
diff --git a/private/ntos/boot/lib/i386/flopcach.c b/private/ntos/boot/lib/i386/flopcach.c
new file mode 100644
index 000000000..9ef2a0865
--- /dev/null
+++ b/private/ntos/boot/lib/i386/flopcach.c
@@ -0,0 +1,316 @@
+#include "arccodes.h"
+#include "bootx86.h"
+#include "flop.h"
+
+#ifdef FLOPPY_CACHE
+
+//#define FLOPPY_CACHE_DEBUG
+#ifdef FLOPPY_CACHE_DEBUG
+#define DBGOUT(x) BlPrint x
+#else
+#define DBGOUT(x)
+#endif
+
+
+#define MAX_FLOPPY_LEN 1474560
+
+UCHAR CachedDiskImage[MAX_FLOPPY_LEN];
+UCHAR CachedDiskBadSectorMap[(MAX_FLOPPY_LEN/512)];
+UCHAR CachedDiskCylinderMap[80];
+USHORT CachedDiskBytesPerSector;
+USHORT CachedDiskSectorsPerTrack;
+USHORT CachedDiskSectorsPerCylinder;
+USHORT CachedDiskBytesPerTrack;
+ULONG CachedDiskLastSector;
+
+BOOLEAN DiskInCache = FALSE;
+
+
+VOID
+FcpCacheOneCylinder(
+ IN USHORT Cylinder
+ )
+{
+ PUCHAR pCache;
+ unsigned track,sector;
+ ULONG AbsoluteSector;
+ ARC_STATUS Status;
+ unsigned retry;
+
+ //
+ // Calculate the location in the cache image where this cylinder should go.
+ //
+ AbsoluteSector = Cylinder * CachedDiskSectorsPerCylinder;
+ pCache = CachedDiskImage + (AbsoluteSector * CachedDiskBytesPerSector);
+
+ //
+ // Read track 0 and 1 of this cylinder.
+ //
+ for(track=0; track<2; track++) {
+
+ DBGOUT(("FcCacheFloppyDisk: Cylinder %u head %u: ",Cylinder,track));
+
+ retry = 0;
+
+ do {
+
+ Status = GET_SECTOR(
+ 2, // int13 request = read
+ 0, // disk number (a:)
+ (USHORT)track, // head (0 or 1)
+ Cylinder, // track (usually 0-79)
+ 1, // sector number (1-based)
+ CachedDiskSectorsPerTrack, // number of sectors to read
+ LocalBuffer // buffer
+ );
+
+ if(Status) {
+ retry++;
+ RESET_DISK(0,0,0,0,0,0,0);
+ }
+
+ } while(Status && (retry <= 3));
+
+ if(Status) {
+
+ DBGOUT(("Error!\n"));
+
+ //
+ // One or more sectors in the track were bad -- read individually.
+ //
+ for(sector=1; sector<=CachedDiskSectorsPerTrack; sector++) {
+
+ DBGOUT((" Sector %u: ",sector));
+
+ retry = 0;
+
+ do {
+
+ Status = GET_SECTOR(
+ 2, // int13 request = read
+ 0, // disk number (a:)
+ (USHORT)track, // head (0 or 1)
+ Cylinder, // cylinder (usually 0-79)
+ (USHORT)sector, // sector number (1-based)
+ 1, // number of sectors to read
+ LocalBuffer // buffer
+ );
+
+ if(Status) {
+ retry++;
+ RESET_DISK(0,0,0,0,0,0,0);
+ }
+
+ } while(Status && (retry <= 2));
+
+ if(Status) {
+
+ //
+ // Sector is bad.
+ //
+ CachedDiskBadSectorMap[AbsoluteSector] = TRUE;
+
+ DBGOUT(("bad\n"));
+
+ } else {
+
+ //
+ // Sector is good. Transfer the data into the cache buffer.
+ //
+ RtlMoveMemory(pCache,LocalBuffer,CachedDiskBytesPerSector);
+
+ DBGOUT(("OK\n"));
+ }
+
+ //
+ // Advance to the next sector in the cache buffer.
+ //
+ pCache += CachedDiskBytesPerSector;
+ AbsoluteSector++;
+ }
+
+ } else {
+ //
+ // Transfer the whole track we just successfully read
+ // into the cached disk buffer.
+ //
+ RtlMoveMemory(pCache,LocalBuffer,CachedDiskBytesPerTrack);
+ pCache += CachedDiskBytesPerTrack;
+ AbsoluteSector += CachedDiskSectorsPerTrack;
+
+ DBGOUT(("OK\n"));
+ }
+ }
+
+ CachedDiskCylinderMap[Cylinder] = TRUE;
+}
+
+
+BOOLEAN
+FcIsThisFloppyCached(
+ IN PUCHAR Buffer
+ )
+{
+ if(!DiskInCache) {
+ return(FALSE);
+ }
+
+ //
+ // Compare the first 512 bytes of the cached disk
+ // to the buffer passed in. If they are equal,
+ // then the disk is already cached.
+ //
+ if(RtlCompareMemory(CachedDiskImage,Buffer,512) == 512) {
+ return(TRUE);
+ }
+
+ //
+ // Disk is not cached.
+ //
+ return(FALSE);
+}
+
+
+VOID
+FcUncacheFloppyDisk(
+ VOID
+ )
+{
+ DiskInCache = FALSE;
+}
+
+
+VOID
+FcCacheFloppyDisk(
+ PBIOS_PARAMETER_BLOCK Bpb
+ )
+{
+ //
+ // Indicate that the cache is invalid.
+ //
+ DiskInCache = FALSE;
+
+ //
+ // Sanity check the bpb.
+ // Ensure it's a standard 1.2 meg or 1.44 meg disk.
+ //
+ if((Bpb->Heads != 2) || (Bpb->BytesPerSector != 512)
+ || ((Bpb->SectorsPerTrack != 15) && (Bpb->SectorsPerTrack != 18))
+ || ((Bpb->Sectors != 2880) && (Bpb->Sectors != 2400)))
+ {
+ DBGOUT(("FcCacheFloppyDisk: floppy not standard 1.2 or 1.44 meg disk\n"));
+ return;
+ }
+
+ //
+ // Grab a buffer under the 1 meg line.
+ // The buffer must be big enough to hold one whole track of
+ // a 1.44 meg floppy.
+ //
+
+ if(LocalBuffer == NULL) {
+ LocalBuffer = FwAllocateHeap(18 * 512);
+ if(LocalBuffer == NULL) {
+ DBGOUT(("FcCacheFloppyDisk: Couldn't allocate local buffer\n"));
+ return;
+ }
+ }
+
+ DBGOUT(("FcCacheFloppyDisk: LocalBuffer @ %lx\n",LocalBuffer));
+
+ //
+ // The disk is one we can cache. Indicate that a disk is cached
+ // and mark all sectors good and all tracks not present.
+ //
+ DiskInCache = TRUE;
+ RtlZeroMemory(CachedDiskBadSectorMap,sizeof(CachedDiskBadSectorMap));
+ RtlZeroMemory(CachedDiskCylinderMap,sizeof(CachedDiskCylinderMap));
+ CachedDiskSectorsPerTrack = Bpb->SectorsPerTrack;
+ CachedDiskSectorsPerCylinder = Bpb->Heads * Bpb->SectorsPerTrack;
+ CachedDiskBytesPerSector = Bpb->BytesPerSector;
+
+ //
+ // Calculate the number of bytes in a Track on the floppy.
+ //
+ CachedDiskBytesPerTrack = CachedDiskSectorsPerTrack * Bpb->BytesPerSector;
+
+ //
+ // Calculate the number of tracks.
+ //
+ CachedDiskLastSector = Bpb->Sectors-1;
+
+ DBGOUT(("FcCacheFloppyDisk: Caching disk, %u sectors per track\n",CachedDiskSectorsPerTrack));
+
+ FcpCacheOneCylinder(0);
+}
+
+
+
+ARC_STATUS
+FcReadFromCache(
+ IN ULONG Offset,
+ IN ULONG Length,
+ OUT PUCHAR Buffer
+ )
+{
+ ULONG FirstSector,LastSector,Sector;
+ ULONG FirstCyl,LastCyl,cyl;
+
+ if(!Length) {
+ return(ESUCCESS);
+ }
+
+ if(!DiskInCache) {
+ return(EINVAL);
+ }
+
+ //
+ // Determine the first sector in the transfer.
+ //
+ FirstSector = Offset / 512;
+
+ //
+ // Determine and validate the last sector in the transfer.
+ //
+ LastSector = FirstSector + ((Length-1)/512);
+
+ if(LastSector > CachedDiskLastSector) {
+ return(E2BIG);
+ }
+
+ //
+ // Determine the first and last cylinders involved in the transfer.
+ //
+ FirstCyl = FirstSector / CachedDiskSectorsPerCylinder;
+ LastCyl = LastSector / CachedDiskSectorsPerCylinder;
+
+ //
+ // Make sure all these cylinders are cached.
+ //
+ for(cyl=FirstCyl; cyl<=LastCyl; cyl++) {
+ if(!CachedDiskCylinderMap[cyl]) {
+ FcpCacheOneCylinder((USHORT)cyl);
+ }
+ }
+
+ //
+ // Determine if any of the sectors in the transfer range
+ // are marked bad in the sector map.
+ //
+ // If so, return an i/o error.
+ //
+ for(Sector=FirstSector; Sector<=LastSector; Sector++) {
+ if(CachedDiskBadSectorMap[Sector]) {
+ return(EIO);
+ }
+ }
+
+ //
+ // Transfer the data into the caller's buffer.
+ //
+ RtlMoveMemory(Buffer,CachedDiskImage+Offset,Length);
+
+ return(ESUCCESS);
+}
+
+#endif // def FLOPPY_CACHE
diff --git a/private/ntos/boot/lib/i386/ixbusdat.c b/private/ntos/boot/lib/i386/ixbusdat.c
new file mode 100644
index 000000000..f79521615
--- /dev/null
+++ b/private/ntos/boot/lib/i386/ixbusdat.c
@@ -0,0 +1,535 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ ixbusdat.c
+
+Abstract:
+
+ This module contains the IoXxx routines for the NT I/O system that
+ are hardware dependent. Were these routines not hardware dependent,
+ they would reside in the iosubs.c module.
+
+Author:
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "bootx86.h"
+#include "arc.h"
+#include "ixfwhal.h"
+#include "eisa.h"
+#include "mca.h"
+#include "ntconfig.h"
+
+ULONG
+HalpGetCmosData(
+ IN ULONG BusNumber,
+ IN ULONG SlotNumber,
+ IN PVOID Buffer,
+ IN ULONG Length
+ );
+
+ULONG
+HalpGetPosData(
+ IN ULONG BusNumber,
+ IN ULONG SlotNumber,
+ IN PVOID Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+ );
+
+ULONG
+HalpGetEisaData(
+ IN ULONG BusNumber,
+ IN ULONG SlotNumber,
+ IN PVOID Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+ );
+
+ULONG
+HalpGetPCIData(
+ IN ULONG BusNumber,
+ IN ULONG SlotNumber,
+ IN PVOID Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+ );
+
+ULONG
+HalpSetPCIData(
+ IN ULONG BusNumber,
+ IN ULONG SlotNumber,
+ IN PVOID Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+ );
+
+NTSTATUS
+HalpAssignPCISlotResources (
+ IN ULONG BusNumber,
+ IN ULONG Slot,
+ IN OUT PCM_RESOURCE_LIST *AllocatedResources
+ );
+
+/*
+ *
+ * Router functions. Routes each call to specific handler
+ *
+ */
+
+
+ULONG
+HalGetBusData(
+ IN BUS_DATA_TYPE BusDataType,
+ IN ULONG BusNumber,
+ IN ULONG SlotNumber,
+ IN PVOID Buffer,
+ IN ULONG Length
+ )
+{
+ return HalGetBusDataByOffset (BusDataType,BusNumber,SlotNumber,Buffer,0,Length);
+}
+
+ULONG
+HalGetBusDataByOffset (
+ IN BUS_DATA_TYPE BusDataType,
+ IN ULONG BusNumber,
+ IN ULONG Slot,
+ IN PVOID Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ Dispatcher for GetBusData
+
+--*/
+{
+ switch (BusDataType) {
+ case Cmos:
+ if (Offset != 0) {
+ return 0;
+ }
+
+ return HalpGetCmosData(BusNumber, Slot, Buffer, Length);
+
+ case Pos:
+ return HalpGetPosData(BusNumber, Slot, Buffer, Offset, Length);
+
+ case EisaConfiguration:
+ return HalpGetEisaData(BusNumber, Slot, Buffer, Offset, Length);
+
+ case PCIConfiguration:
+ return HalpGetPCIData(BusNumber, Slot, Buffer, Offset, Length);
+ }
+ return 0;
+}
+
+ULONG
+HalSetBusData(
+ IN BUS_DATA_TYPE BusDataType,
+ IN ULONG BusNumber,
+ IN ULONG SlotNumber,
+ IN PVOID Buffer,
+ IN ULONG Length
+ )
+{
+ return HalSetBusDataByOffset (BusDataType,BusNumber,SlotNumber,Buffer,0,Length);
+}
+
+ULONG
+HalSetBusDataByOffset(
+ IN BUS_DATA_TYPE BusDataType,
+ IN ULONG BusNumber,
+ IN ULONG Slot,
+ IN PVOID Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ Dispatcher for SetBusData
+
+--*/
+{
+ switch (BusDataType) {
+ case PCIConfiguration:
+ return HalpSetPCIData(BusNumber, Slot, Buffer, Offset, Length);
+ }
+ return 0;
+}
+
+
+NTSTATUS
+HalAssignSlotResources (
+ IN PUNICODE_STRING RegistryPath,
+ IN PUNICODE_STRING DriverClassName OPTIONAL,
+ IN PDRIVER_OBJECT DriverObject,
+ IN PDEVICE_OBJECT DeviceObject OPTIONAL,
+ IN INTERFACE_TYPE BusType,
+ IN ULONG BusNumber,
+ IN ULONG SlotNumber,
+ IN OUT PCM_RESOURCE_LIST *AllocatedResources
+ )
+/*++
+
+Routine Description:
+
+ Dispatcher for AssignSlotResources
+
+--*/
+{
+ switch (BusType) {
+ case PCIBus:
+ return HalpAssignPCISlotResources (
+ BusNumber,
+ SlotNumber,
+ AllocatedResources
+ );
+ default:
+ break;
+ }
+ return STATUS_NOT_FOUND;
+}
+
+
+
+
+
+/**
+ **
+ ** Standard PC bus functions
+ **
+ **/
+
+
+
+BOOLEAN
+HalTranslateBusAddress(
+ IN INTERFACE_TYPE InterfaceType,
+ IN ULONG BusNumber,
+ IN PHYSICAL_ADDRESS BusAddress,
+ IN OUT PULONG AddressSpace,
+ OUT PPHYSICAL_ADDRESS TranslatedAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This function translates a bus-relative address space and address into
+ a system physical address.
+
+Arguments:
+
+ BusNumber - Supplies the bus number. This is ignored on
+ standard x86 systems
+
+ BusAddress - Supplies the bus-relative address
+
+ AddressSpace - Supplies the address space number.
+ Returns the host address space number.
+
+ AddressSpace == 0 => I/O space
+ AddressSpace == 1 => memory space
+
+ TranslatedAddress - Pointer to a physical_address.
+
+Return Value:
+
+ System physical address corresponding to the supplied bus relative
+ address and bus address number.
+
+--*/
+
+{
+ TranslatedAddress->HighPart = 0;
+ TranslatedAddress->LowPart = BusAddress.LowPart;
+ return(TRUE);
+}
+
+ULONG
+HalpGetPosData (
+ IN ULONG BusNumber,
+ IN ULONG SlotNumber,
+ IN PVOID Buffer,
+ IN ULONG DOffset,
+ IN ULONG Length
+ )
+/*--
+
+Arguments:
+
+ BusDataType - Supplies the type of bus.
+
+ BusNumber - Indicates which bus.
+
+ Buffer - Supplies the space to store the data.
+
+ Length - Supplies a count in bytes of the maximum amount to return.
+
+Return Value:
+
+ Returns the amount of data stored into the buffer.
+
+--*/
+{
+ PVOID McaRegisterBase = 0;
+ ULONG Index = 0;
+ PUCHAR DataBuffer = Buffer;
+ ULONG DataLength = 0;
+ PUCHAR PosBase;
+ ULONG Offset;
+
+ if (DOffset != 0 || MachineType != MACHINE_TYPE_MCA) {
+ return 0;
+ }
+
+ PosBase = (PUCHAR) &((PMCA_CONTROL) McaRegisterBase)->Pos;
+
+ //
+ // Place the specified adapter into setup mode.
+ //
+
+ WRITE_PORT_UCHAR((PVOID) &((PMCA_CONTROL) McaRegisterBase)->AdapterSetup,
+ (UCHAR) ( MCA_ADAPTER_SETUP_ON | SlotNumber ));
+
+ while (DataLength < Length && DataLength < 6) {
+ DataBuffer[DataLength] = READ_PORT_UCHAR( PosBase + DataLength );
+ DataLength++;
+ }
+
+ while (DataLength < Length) {
+
+ WRITE_PORT_UCHAR((PVOID) &((PPROGRAMMABLE_OPTION_SELECT)
+ PosBase)->SubaddressExtensionLsb, (UCHAR) Index);
+
+ WRITE_PORT_UCHAR((PVOID) &((PPROGRAMMABLE_OPTION_SELECT)
+ PosBase)->SubaddressExtensionMsb, (UCHAR) (Index >> 8));
+
+ DataBuffer[Index + 6] = READ_PORT_UCHAR(
+ (PVOID) &((PPROGRAMMABLE_OPTION_SELECT)PosBase)->OptionSelectData2);
+
+ DataLength++;
+
+ if (DataLength < Length) {
+ Offset = DataLength + ((Length - DataLength) / 2);
+ DataBuffer[Offset] = READ_PORT_UCHAR(
+ (PVOID) &((PPROGRAMMABLE_OPTION_SELECT)PosBase)->OptionSelectData3);
+ DataLength++;
+ Index++;
+ }
+ }
+
+ //
+ // Disable adapter setup.
+ //
+
+ WRITE_PORT_UCHAR((PVOID) &((PMCA_CONTROL) McaRegisterBase)->AdapterSetup,
+ (UCHAR) ( MCA_ADAPTER_SETUP_OFF ));
+}
+
+ULONG
+HalpGetEisaData (
+ IN ULONG BusNumber,
+ IN ULONG SlotNumber,
+ IN PVOID Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+ )
+/*--
+
+Arguments:
+
+ BusDataType - Supplies the type of bus.
+
+ BusNumber - Indicates which bus.
+
+ Buffer - Supplies the space to store the data.
+
+ Length - Supplies a count in bytes of the maximum amount to return.
+
+Return Value:
+
+ Returns the amount of data stored into the buffer.
+
+--*/
+{
+
+ ULONG DataLength = 0;
+ ULONG i;
+ ULONG TotalDataSize;
+ ULONG SlotDataSize;
+ ULONG PartialCount;
+ ULONG Index = 0;
+ PUCHAR DataBuffer = Buffer;
+ PCONFIGURATION_COMPONENT_DATA ConfigData;
+ PCM_EISA_SLOT_INFORMATION SlotInformation;
+ PCM_PARTIAL_RESOURCE_LIST Descriptor;
+ PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialResource;
+ BOOLEAN Found = FALSE;
+
+ if (MachineType != MACHINE_TYPE_EISA) {
+ return 0;
+ }
+
+ ConfigData = KeFindConfigurationEntry(
+ FwConfigurationTree,
+ AdapterClass,
+ EisaAdapter,
+ NULL
+ );
+
+ if (ConfigData == NULL) {
+ DbgPrint("HalGetBusData: KeFindConfigurationEntry failed\n");
+ return(0);
+ }
+
+ Descriptor = ConfigData->ConfigurationData;
+ PartialResource = Descriptor->PartialDescriptors;
+ PartialCount = Descriptor->Count;
+
+ for (i = 0; i < PartialCount; i++) {
+
+ //
+ // Do each partial Resource
+ //
+
+ switch (PartialResource->Type) {
+ case CmResourceTypeNull:
+ case CmResourceTypePort:
+ case CmResourceTypeInterrupt:
+ case CmResourceTypeMemory:
+ case CmResourceTypeDma:
+
+ //
+ // We dont care about these.
+ //
+
+ PartialResource++;
+
+ break;
+
+ case CmResourceTypeDeviceSpecific:
+
+ //
+ // Bingo!
+ //
+
+ TotalDataSize = PartialResource->u.DeviceSpecificData.DataSize;
+
+ SlotInformation = (PCM_EISA_SLOT_INFORMATION)
+ ((PUCHAR)PartialResource +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
+
+ while (((LONG)TotalDataSize) > 0) {
+
+ if (SlotInformation->ReturnCode == EISA_EMPTY_SLOT) {
+
+ SlotDataSize = sizeof(CM_EISA_SLOT_INFORMATION);
+
+ } else {
+
+ SlotDataSize = sizeof(CM_EISA_SLOT_INFORMATION) +
+ SlotInformation->NumberFunctions *
+ sizeof(CM_EISA_FUNCTION_INFORMATION);
+ }
+
+ if (SlotDataSize > TotalDataSize) {
+
+ //
+ // Something is wrong again
+ //
+
+ DbgPrint("HalGetBusData: SlotDataSize > TotalDataSize\n");
+
+ return(0);
+
+ }
+
+ if (SlotNumber != 0) {
+
+ SlotNumber--;
+
+ SlotInformation = (PCM_EISA_SLOT_INFORMATION)
+ ((PUCHAR)SlotInformation + SlotDataSize);
+
+ TotalDataSize -= SlotDataSize;
+
+ continue;
+
+ }
+
+ //
+ // This is our slot
+ //
+
+ Found = TRUE;
+ break;
+
+ }
+
+ //
+ // End loop
+ //
+
+ i = PartialCount;
+
+ break;
+
+ default:
+
+#if DBG
+ DbgPrint("Bad Data in registry!\n");
+#endif
+
+ return(0);
+
+ }
+
+ }
+
+ if (Found) {
+
+ //
+ // As a hack if the length is zero then the buffer points to a
+ // PVOID where the pointer to the data should be stored. This is
+ // done in the loader because we quickly run out of heap scaning
+ // all of the EISA configuration data.
+ //
+
+ if (Length == 0) {
+
+ //
+ // Return the pointer to the mini-port driver.
+ //
+
+ *((PVOID *)Buffer) = SlotInformation;
+ return(SlotDataSize);
+ }
+
+ i = Length + Offset;
+ if (i > SlotDataSize) {
+ i = SlotDataSize;
+ }
+
+ DataLength = i - Offset;
+ RtlMoveMemory(Buffer, ((PUCHAR) SlotInformation + Offset), DataLength);
+ }
+
+ return(DataLength);
+}
diff --git a/private/ntos/boot/lib/i386/ixcmos.asm b/private/ntos/boot/lib/i386/ixcmos.asm
new file mode 100644
index 000000000..80e3f5cc5
--- /dev/null
+++ b/private/ntos/boot/lib/i386/ixcmos.asm
@@ -0,0 +1,172 @@
+ title "Cmos Access Routines"
+;++
+;
+; Copyright (c) 1992 NCR Corporation
+;
+; Module Name:
+;
+; mccmos.asm
+;
+; Abstract:
+;
+; Procedures necessary to access CMOS/ECMOS information.
+;
+; Author:
+;
+; David Risner (o-ncrdr) 20 Apr 1992
+;
+; Revision History:
+;
+;--
+
+.386p
+ .xlist
+;include ks386.inc
+;include mac386.inc
+include callconv.inc
+ .list
+
+; extrn _HalpSystemHardwareLock:DWORD
+
+ subttl "HalpGetCmosData"
+_TEXT SEGMENT DWORD PUBLIC 'CODE'
+ ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+;++
+;
+; CMOS space read and write functions.
+;
+;--
+
+CmosAddressPort equ 70H
+CmosDataPort equ 71H
+
+ECmosAddressLsbPort equ 74H
+ECmosAddressMsbPort equ 75H
+ECmosDataPort equ 76H
+
+;++
+;
+; ULONG
+; HalpGetCmosData(
+; IN ULONG SourceLocation
+; IN ULONG SourceAddress
+; IN ULONG ReturnBuffer
+; IN PUCHAR ByteCount
+; )
+;
+; This routine reads the requested number of bytes from CMOS/ECMOS and
+; stores the data read into the supplied buffer in system memory. If
+; the requested data amount exceeds the allowable extent of the source
+; location, the return data is truncated.
+;
+; Arguments:
+;
+; SourceLocation : where data is to be read from CMOS or ECMOS
+; 0 - CMOS, 1 - ECMOS
+;
+; SourceAddress : address in CMOS/ECMOS where data is to be read from
+;
+; ReturnBuffer : address in system memory for return data
+;
+; ByteCount : number of bytes to be read
+;
+; Returns:
+;
+; Number of byte actually read.
+;
+;--
+
+SourceLocation equ 2*4[ebp]
+SourceAddress equ 3*4[ebp]
+ReturnBuffer equ 4*4[ebp]
+ByteCount equ 5*4[ebp]
+
+cPublicProc _HalpGetCmosData,4
+
+ push ebp
+ mov ebp, esp
+ push ebx
+ push edi
+
+ ;
+ ; NOTE: The spinlock is needed even in the UP case, because
+ ; the resource is also used in an interrupt handler (profiler).
+ ; If we own the spinlock in this routine, and we service
+ ; the profiler interrupt (which will wait for the spinlock forever),
+ ; then we have a hosed system.
+ ;
+Hgcd01:
+ cli
+; lea eax, _HalpSystemHardwareLock
+; ACQUIRE_SPINLOCK eax, Hgcd90
+
+ xor edx, edx ; initialize return data length
+ mov ecx, ByteCount
+
+ or ecx, ecx ; validate requested byte count
+ jz HalpGetCmosDataExit ; if no work to do, exit
+
+ mov edx, SourceAddress
+ mov edi, ReturnBuffer
+
+ mov eax, SourceLocation ; cmos or extended cmos?
+ cmp eax, 1 ; BUGBUG - Why???
+ je ECmosReadByte
+ cmp eax, 0
+ jne HalpGetCmosDataExit
+
+ align 4
+CmosReadByte:
+
+ cmp edx, 0ffH ; validate cmos source address
+ ja HalpGetCmosDataExit ; if out of range, exit
+ mov al, dl
+ out CmosAddressPort, al
+ in al, CmosDataPort
+ mov [edi], al
+ inc edx
+ inc edi
+ dec ecx
+ jnz CmosReadByte
+ jmp SHORT HalpGetCmosDataExit
+
+ align 4
+ECmosReadByte:
+
+
+ cmp edx,0ffffH ; validate ecmos source address
+ ja HalpGetCmosDataExit ; if out of range, exit
+ mov al, dl
+ out ECmosAddressLsbPort, al
+ mov al, dh
+ out ECmosAddressMsbPort, al
+ in al, ECmosDataPort
+ mov [edi], al
+ inc edx
+ inc edi
+ dec ecx
+ jnz ECmosReadByte
+
+HalpGetCmosDataExit:
+
+; lea eax, _HalpSystemHardwareLock
+; RELEASE_SPINLOCK eax
+ mov eax, edx ; return bytes read
+
+ pop edi
+ pop ebx
+ pop ebp
+
+ stdRET _HalpGetCmosData
+
+;Hgcd90:
+; sti
+; SPIN_ON_SPINLOCK eax, <Hgcd01>
+
+stdENDP _HalpGetCmosData
+
+
+_TEXT ends
+
+ end
diff --git a/private/ntos/boot/lib/i386/ixfwhal.h b/private/ntos/boot/lib/i386/ixfwhal.h
new file mode 100644
index 000000000..cdd75ca9c
--- /dev/null
+++ b/private/ntos/boot/lib/i386/ixfwhal.h
@@ -0,0 +1,147 @@
+/*++ BUILD Version: 0001 // Increment this if a change has global effects
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ ixfwhal.h
+
+Abstract:
+
+ This header file defines the private Hardware Architecture Layer (HAL)
+ Intel x86 specific interfaces, defines and structures.
+
+Author:
+
+ Jeff Havens (jhavens) 20-Jun-91
+
+
+Revision History:
+
+--*/
+
+#ifndef _IXHALP_
+#define _IXHALP_
+
+
+//
+// The MAXIMUM_MAP_BUFFER_SIZE defines the maximum map buffers which the system
+// will allocate for devices which require phyically contigous buffers.
+//
+
+#define MAXIMUM_MAP_BUFFER_SIZE 0x1000000
+
+//
+// Define the initial buffer allocation size for a map buffers.
+//
+
+#define INITIAL_MAP_BUFFER_SIZE 0x20000
+
+//
+// Define the incremental buffer allocation for a map buffers.
+//
+
+#define INCREMENT_MAP_BUFFER_SIZE 0x10000
+
+//
+// Define the maximum number of map registers that can be requested at one time
+// if actual map registers are required for the transfer.
+//
+
+#define MAXIMUM_ISA_MAP_REGISTER 16
+
+//
+// Define the maximum physical address which can be handled by an Isa card.
+//
+
+#define MAXIMUM_PHYSICAL_ADDRESS 0x01000000
+
+//
+// Define adapter object structure.
+//
+
+typedef struct _ADAPTER_OBJECT {
+ CSHORT Type;
+ CSHORT Size;
+ ULONG MapRegistersPerChannel;
+ PVOID AdapterBaseVa;
+ PVOID MapRegisterBase;
+ ULONG NumberOfMapRegisters;
+ UCHAR ChannelNumber;
+ UCHAR AdapterNumber;
+ UCHAR AdapterMode;
+ UCHAR ExtendedModeFlags;
+ USHORT DmaPortAddress;
+ BOOLEAN NeedsMapRegisters;
+ BOOLEAN IsaDevice;
+ BOOLEAN MasterDevice;
+ BOOLEAN Width16Bits;
+ BOOLEAN AdapterInUse;
+ PUCHAR PagePort;
+} ADAPTER_OBJECT;
+
+//
+// Define map register translation entry structure.
+//
+
+typedef struct _TRANSLATION_ENTRY {
+ PVOID VirtualAddress;
+ ULONG PhysicalAddress;
+ ULONG Index;
+} TRANSLATION_ENTRY, *PTRANSLATION_ENTRY;
+
+//
+// Define External data structures.
+//
+
+//
+// Some devices require a phyicially contiguous data buffers for DMA transfers.
+// Map registers are used give the appearance that all data buffers are
+// contiguous. In order to pool all of the map registers a master
+// adapter object is used. This object is allocated and saved internal to this
+// file. It contains a bit map for allocation of the registers and a queue
+// for requests which are waiting for more map registers. This object is
+// allocated during the first request to allocate an adapter which requires
+// map registers.
+//
+// In this system, the map registers are translation entries which point to
+// map buffers. Map buffers are physically contiguous and have physical memory
+// addresses less than 0x01000000. All of the map registers are allocated
+// initialially; however, the map buffers are allocated base in the number of
+// adapters which are allocated.
+//
+// If the master adapter is NULL in the adapter object then device does not
+// require any map registers.
+//
+
+extern PADAPTER_OBJECT MasterAdapterObject;
+
+extern POBJECT_TYPE IoAdapterObjectType;
+
+extern BOOLEAN LessThan16Mb;
+
+//
+// Define function prototypes.
+//
+
+BOOLEAN
+HalpGrowMapBuffers(
+ PADAPTER_OBJECT AdapterObject,
+ ULONG Amount
+ );
+
+PADAPTER_OBJECT
+IopAllocateAdapter(
+ IN ULONG MapRegistersPerChannel,
+ IN PVOID AdapterBaseVa,
+ IN PVOID MapRegisterBase
+ );
+
+VOID
+HalpInitializeDisplay(
+ IN PUSHORT VideoBufferAddress
+ );
+
+#endif // _IXHALP_
+
+
diff --git a/private/ntos/boot/lib/i386/ixhwsup.c b/private/ntos/boot/lib/i386/ixhwsup.c
new file mode 100644
index 000000000..cd619ffe3
--- /dev/null
+++ b/private/ntos/boot/lib/i386/ixhwsup.c
@@ -0,0 +1,2007 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ ixhwsup.c
+
+Abstract:
+
+ This module contains the IoXxx routines for the NT I/O system that
+ are hardware dependent. Were these routines not hardware dependent,
+ they would reside in the iosubs.c module.
+
+Author:
+
+ Darryl E. Havens (darrylh) 11-Apr-1990
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "bootx86.h"
+#include "arc.h"
+#include "ixfwhal.h"
+#include "eisa.h"
+#include "mca.h"
+#include "ntconfig.h"
+
+PVOID HalpEisaControlBase;
+
+//
+// Define save area for ESIA adapter objects.
+//
+
+PADAPTER_OBJECT HalpEisaAdapter[8];
+
+VOID
+HalpCopyBufferMap(
+ IN PMDL Mdl,
+ IN PTRANSLATION_ENTRY TranslationEntry,
+ IN PVOID CurrentVa,
+ IN ULONG Length,
+ IN BOOLEAN WriteToDevice
+ );
+
+ULONG
+IoMapTransferMca(
+ IN PADAPTER_OBJECT AdapterObject,
+ IN PMDL Mdl,
+ IN PVOID MapRegisterBase,
+ IN PVOID CurrentVa,
+ IN OUT PULONG Length,
+ IN BOOLEAN WriteToDevice
+ );
+
+PADAPTER_OBJECT
+HalGetAdapterMca(
+ IN PDEVICE_DESCRIPTION DeviceDescriptor,
+ OUT PULONG NumberOfMapRegisters
+ );
+
+
+VOID
+HalpCopyBufferMap(
+ IN PMDL Mdl,
+ IN PTRANSLATION_ENTRY TranslationEntry,
+ IN PVOID CurrentVa,
+ IN ULONG Length,
+ IN BOOLEAN WriteToDevice
+ )
+
+/*++
+
+Routine Description:
+
+ This routine copies the speicific data between the user's buffer and the
+ map register buffer. First a the user buffer is mapped if necessary, then
+ the data is copied. Finally the user buffer will be unmapped if
+ neccessary.
+
+Arguments:
+
+ Mdl - Pointer to the MDL that describes the pages of memory that are
+ being read or written.
+
+ TranslationEntry - The address of the base map register that has been
+ allocated to the device driver for use in mapping the transfer.
+
+ CurrentVa - Current virtual address in the buffer described by the MDL
+ that the transfer is being done to or from.
+
+ Length - The length of the transfer. This determines the number of map
+ registers that need to be written to map the transfer.
+
+ WriteToDevice - Boolean value that indicates whether this is a write
+ to the device from memory (TRUE), or vice versa.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PCCHAR bufferAddress;
+ BOOLEAN mapped;
+
+ //
+ // Check to see if the buffer needs to be mapped.
+ //
+
+ if ((Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA) == 0) {
+
+ //
+ // Map the buffer into system space.
+ //
+
+ bufferAddress = MmGetMdlVirtualAddress(Mdl);
+ mapped = TRUE;
+
+ } else {
+
+ bufferAddress = Mdl->MappedSystemVa;
+ mapped = FALSE;
+ }
+
+ //
+ // Calculate the actual start of the buffer based on the system VA and
+ // the current VA.
+ //
+
+ bufferAddress += (PCCHAR) CurrentVa - (PCCHAR) MmGetMdlVirtualAddress(Mdl);
+
+ //
+ // Copy the data between the user buffer and map buffer
+ //
+
+ if (WriteToDevice) {
+
+ RtlMoveMemory( TranslationEntry->VirtualAddress, bufferAddress, Length);
+
+ } else {
+
+ RtlMoveMemory(bufferAddress, TranslationEntry->VirtualAddress, Length);
+
+ }
+
+}
+
+PADAPTER_OBJECT
+HalGetAdapter(
+ IN PDEVICE_DESCRIPTION DeviceDescriptor,
+ OUT PULONG NumberOfMapRegisters
+ )
+
+/*++
+
+Routine Description:
+
+ This function returns the appropriate adapter object for the device defined
+ in the device description structure. This code works for Isa and Eisa
+ systems.
+
+Arguments:
+
+ DeviceDescriptor - Supplies a description of the deivce.
+
+ NumberOfMapRegisters - Returns the maximum number of map registers which
+ may be allocated by the device driver.
+
+Return Value:
+
+ A pointer to the requested adpater object or NULL if an adapter could not
+ be created.
+
+--*/
+
+{
+ PADAPTER_OBJECT adapterObject;
+ PVOID adapterBaseVa;
+ ULONG channelNumber;
+ ULONG controllerNumber;
+ DMA_EXTENDED_MODE extendedMode;
+ UCHAR adapterMode;
+ ULONG numberOfMapRegisters;
+ BOOLEAN useChannel;
+ ULONG maximumLength;
+
+ if (MachineType == MACHINE_TYPE_MCA) {
+
+ return (HalGetAdapterMca(DeviceDescriptor, NumberOfMapRegisters));
+ }
+
+ //
+ // Determine if the the channel number is important. Master cards on
+ // Eisa and Mca do not use a channel number.
+ //
+
+ if (DeviceDescriptor->InterfaceType != Isa &&
+ DeviceDescriptor->Master) {
+
+ useChannel = FALSE;
+ } else {
+
+ useChannel = TRUE;
+ }
+
+ //
+ // Support for ISA local bus machines:
+ // If the driver is a Master but really does not want a channel since it
+ // is using the local bus DMA, just don't use an ISA channel.
+ //
+
+ if (DeviceDescriptor->InterfaceType == Isa &&
+ DeviceDescriptor->DmaChannel > 7) {
+
+ useChannel = FALSE;
+ }
+
+ //
+ // Limit the maximum length to 2 GB this is done so that the BYTES_TO_PAGES
+ // macro works correctly.
+ //
+
+ maximumLength = DeviceDescriptor->MaximumLength & 0x7fffffff;
+
+ //
+ // Channel 4 cannot be used since it is used for chaining. Return null if
+ // it is requested.
+ //
+
+ if (DeviceDescriptor->DmaChannel == 4 && useChannel &&
+ DeviceDescriptor->InterfaceType != MicroChannel) {
+ return(NULL);
+ }
+
+ //
+ // Determine the number of map registers for this device.
+ //
+
+ if (DeviceDescriptor->ScatterGather && DeviceDescriptor->InterfaceType == Eisa) {
+
+ //
+ // Since the device support scatter/Gather then map registers are not
+ // required.
+ //
+
+ numberOfMapRegisters = 0;
+
+ } else {
+
+ //
+ // Determine the number of map registers required based on the maximum
+ // transfer length, up to a maximum number.
+ //
+
+ numberOfMapRegisters = BYTES_TO_PAGES(maximumLength)
+ + 1;
+ numberOfMapRegisters = numberOfMapRegisters > MAXIMUM_ISA_MAP_REGISTER ?
+ MAXIMUM_ISA_MAP_REGISTER : numberOfMapRegisters;
+
+ }
+
+ //
+ // Set the channel number number.
+ //
+
+ channelNumber = DeviceDescriptor->DmaChannel & 0x03;
+
+ //
+ // Set the adapter base address to the Base address register and controller
+ // number.
+ //
+
+ if (!(DeviceDescriptor->DmaChannel & 0x04)) {
+
+ controllerNumber = 1;
+ adapterBaseVa = (PVOID) &((PEISA_CONTROL) HalpEisaControlBase)->Dma1BasePort;
+
+ } else {
+
+ controllerNumber = 2;
+ adapterBaseVa = &((PEISA_CONTROL) HalpEisaControlBase)->Dma2BasePort;
+
+ }
+
+ //
+ // Determine if a new adapter object is necessary. If so then allocate it.
+ //
+
+ if (useChannel && HalpEisaAdapter[DeviceDescriptor->DmaChannel] != NULL) {
+
+ adapterObject = HalpEisaAdapter[DeviceDescriptor->DmaChannel];
+
+ } else {
+
+ //
+ // Allocate an adapter object.
+ //
+
+ adapterObject = (PADAPTER_OBJECT) IopAllocateAdapter(
+ numberOfMapRegisters,
+ adapterBaseVa,
+ NULL
+ );
+
+ if (adapterObject == NULL) {
+
+ return(NULL);
+
+ }
+
+ if (useChannel) {
+
+ HalpEisaAdapter[DeviceDescriptor->DmaChannel] = adapterObject;
+
+ }
+
+ //
+ // We never need map registers.
+ //
+
+ adapterObject->NeedsMapRegisters = FALSE;
+
+ //
+ // Set the maximum number of map registers for this channel bus on
+ // the number requested and the type of device.
+ //
+
+ if (numberOfMapRegisters) {
+
+ //
+ // The speicified number of registers are actually allowed to be
+ // allocated.
+ //
+
+ adapterObject->MapRegistersPerChannel = numberOfMapRegisters;
+
+ } else {
+
+ //
+ // No real map registers were allocated. If this is a master
+ // device, then the device can have as may registers as it wants.
+ //
+
+
+ if (DeviceDescriptor->Master) {
+
+ adapterObject->MapRegistersPerChannel = BYTES_TO_PAGES(
+ maximumLength
+ )
+ + 1;
+
+ } else {
+
+ //
+ // The device only gets one register. It must call
+ // IoMapTransfer repeatedly to do a large transfer.
+ //
+
+ adapterObject->MapRegistersPerChannel = 1;
+ }
+ }
+ }
+
+ *NumberOfMapRegisters = adapterObject->MapRegistersPerChannel;
+
+ //
+ // If the channel number is not used then we are finished. The rest of
+ // the work deals with channels.
+ //
+
+ if (!useChannel) {
+ return(adapterObject);
+ }
+
+ //
+ // Setup the pointers to all the random registers.
+ //
+
+ adapterObject->ChannelNumber = (UCHAR) channelNumber;
+
+ if (controllerNumber == 1) {
+
+ switch ((UCHAR)channelNumber) {
+
+ case 0:
+ adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel0;
+ break;
+
+ case 1:
+ adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel1;
+ break;
+
+ case 2:
+ adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel2;
+ break;
+
+ case 3:
+ adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel3;
+ break;
+ }
+
+ //
+ // Set the adapter number.
+ //
+
+ adapterObject->AdapterNumber = 1;
+
+ //
+ // Save the extended mode register address.
+ //
+
+ adapterBaseVa =
+ &((PEISA_CONTROL) HalpEisaControlBase)->Dma1ExtendedModePort;
+
+ } else {
+
+ switch (channelNumber) {
+ case 1:
+ adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel5;
+ break;
+
+ case 2:
+ adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel6;
+ break;
+
+ case 3:
+ adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel7;
+ break;
+ }
+
+ //
+ // Set the adapter number.
+ //
+
+ adapterObject->AdapterNumber = 2;
+
+ //
+ // Save the extended mode register address.
+ //
+ adapterBaseVa =
+ &((PEISA_CONTROL) HalpEisaControlBase)->Dma2ExtendedModePort;
+
+ }
+
+ adapterObject->Width16Bits = FALSE;
+
+ if (MachineType == MACHINE_TYPE_EISA) {
+
+ //
+ // Initialzie the extended mode port.
+ //
+
+ *((PUCHAR) &extendedMode) = 0;
+ extendedMode.ChannelNumber = (UCHAR)channelNumber;
+
+ switch (DeviceDescriptor->DmaSpeed) {
+ case Compatible:
+ extendedMode.TimingMode = COMPATIBLITY_TIMING;
+ break;
+
+ case TypeA:
+ extendedMode.TimingMode = TYPE_A_TIMING;
+ break;
+
+ case TypeB:
+ extendedMode.TimingMode = TYPE_B_TIMING;
+ break;
+
+ case TypeC:
+ extendedMode.TimingMode = BURST_TIMING;
+ break;
+
+ default:
+ return(NULL);
+
+ }
+
+ switch (DeviceDescriptor->DmaWidth) {
+ case Width8Bits:
+ extendedMode.TransferSize = BY_BYTE_8_BITS;
+ break;
+
+ case Width16Bits:
+ extendedMode.TransferSize = BY_BYTE_16_BITS;
+
+ //
+ // Note Width16bits should not be set here because there is no need
+ // to shift the address and the transfer count.
+ //
+
+ break;
+
+ case Width32Bits:
+ extendedMode.TransferSize = BY_BYTE_32_BITS;
+ break;
+
+ default:
+ return(NULL);
+
+ }
+
+ WRITE_PORT_UCHAR( adapterBaseVa, *((PUCHAR) &extendedMode));
+
+ } else if (!DeviceDescriptor->Master) {
+
+
+ switch (DeviceDescriptor->DmaWidth) {
+ case Width8Bits:
+
+ //
+ // The channel must use controller 1.
+ //
+
+ if (controllerNumber != 1) {
+ return(NULL);
+ }
+
+ break;
+
+ case Width16Bits:
+
+ //
+ // The channel must use controller 2.
+ //
+
+ if (controllerNumber != 2) {
+ return(NULL);
+ }
+
+ adapterObject->Width16Bits = TRUE;
+ break;
+
+ default:
+ return(NULL);
+
+ }
+ }
+
+
+ //
+ // Determine if this is an Isa adapter.
+ //
+
+ if (DeviceDescriptor->InterfaceType == Isa) {
+
+ adapterObject->IsaDevice = TRUE;
+
+ }
+
+ //
+ // Initialize the adapter mode register value to the correct parameters,
+ // and save them in the adapter object.
+ //
+
+ adapterMode = 0;
+ ((PDMA_EISA_MODE) &adapterMode)->Channel = adapterObject->ChannelNumber;
+
+ adapterObject->MasterDevice = FALSE;
+
+ if (DeviceDescriptor->Master) {
+
+ adapterObject->MasterDevice = TRUE;
+
+ ((PDMA_EISA_MODE) &adapterMode)->RequestMode = CASCADE_REQUEST_MODE;
+
+ //
+ // Set the mode, and enable the request.
+ //
+
+ if (adapterObject->AdapterNumber == 1) {
+
+ //
+ // This request is for DMA controller 1
+ //
+
+ PDMA1_CONTROL dmaControl;
+
+ dmaControl = adapterObject->AdapterBaseVa;
+
+ WRITE_PORT_UCHAR( &dmaControl->Mode, adapterMode );
+
+ //
+ // Unmask the DMA channel.
+ //
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->SingleMask,
+ (UCHAR) (DMA_CLEARMASK | adapterObject->ChannelNumber)
+ );
+
+ } else {
+
+ //
+ // This request is for DMA controller 1
+ //
+
+ PDMA2_CONTROL dmaControl;
+
+ dmaControl = adapterObject->AdapterBaseVa;
+
+ WRITE_PORT_UCHAR( &dmaControl->Mode, adapterMode );
+
+ //
+ // Unmask the DMA channel.
+ //
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->SingleMask,
+ (UCHAR) (DMA_CLEARMASK | adapterObject->ChannelNumber)
+ );
+
+ }
+
+ } else if (DeviceDescriptor->DemandMode) {
+
+ ((PDMA_EISA_MODE) &adapterMode)->RequestMode = DEMAND_REQUEST_MODE;
+
+ } else {
+
+ ((PDMA_EISA_MODE) &adapterMode)->RequestMode = SINGLE_REQUEST_MODE;
+
+ }
+
+ if (DeviceDescriptor->AutoInitialize) {
+
+ ((PDMA_EISA_MODE) &adapterMode)->AutoInitialize = 1;
+
+ }
+
+ adapterObject->AdapterMode = adapterMode;
+
+ return(adapterObject);
+}
+
+NTSTATUS
+IoAllocateAdapterChannel(
+ IN PADAPTER_OBJECT AdapterObject,
+ IN PDEVICE_OBJECT DeviceObject,
+ IN ULONG NumberOfMapRegisters,
+ IN PDRIVER_CONTROL ExecutionRoutine,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates the adapter channel specified by the adapter object.
+ This is accomplished by placing the device object of the driver that wants
+ to allocate the adapter on the adapter's queue. If the queue is already
+ "busy", then the adapter has already been allocated, so the device object
+ is simply placed onto the queue and waits until the adapter becomes free.
+
+ Once the adapter becomes free (or if it already is), then the driver's
+ execution routine is invoked.
+
+ Also, a number of map registers may be allocated to the driver by specifying
+ a non-zero value for NumberOfMapRegisters. If this is the case, then the
+ base address of the allocated map registers in the adapter is also passed
+ to the driver's execution routine.
+
+Arguments:
+
+ AdapterObject - Pointer to the adapter control object to allocate to the
+ driver.
+
+ DeviceObject - Pointer to the driver's device object that represents the
+ device allocating the adapter.
+
+ NumberOfMapRegisters - The number of map registers that are to be allocated
+ from the channel, if any.
+
+ ExecutionRoutine - The address of the driver's execution routine that is
+ invoked once the adapter channel (and possibly map registers) have been
+ allocated.
+
+ Context - An untyped longword context parameter passed to the driver's
+ execution routine.
+
+Return Value:
+
+ Returns STATUS_SUCESS unless too many map registers are requested.
+
+Notes:
+
+ Note that this routine MUST be invoked at DISPATCH_LEVEL or above.
+
+--*/
+
+{
+ IO_ALLOCATION_ACTION action;
+
+ //
+ // Make sure the adapter if free.
+ //
+
+ if (AdapterObject->AdapterInUse) {
+ DbgPrint("IoAllocateAdapterChannel: Called while adapter in use.\n");
+ }
+
+ //
+ // Make sure there are enough map registers.
+ //
+
+ if (NumberOfMapRegisters > AdapterObject->MapRegistersPerChannel) {
+
+ DbgPrint("IoAllocateAdapterChannel: Out of map registers.\n");
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ action = ExecutionRoutine( DeviceObject,
+ DeviceObject->CurrentIrp,
+ AdapterObject->MapRegisterBase,
+ Context );
+
+ //
+ // If the driver wishes to keep the map registers then
+ // increment the current base and decrease the number of existing map
+ // registers.
+ //
+
+ if (action == DeallocateObjectKeepRegisters &&
+ AdapterObject->MapRegisterBase != NULL) {
+
+ AdapterObject->MapRegistersPerChannel -= NumberOfMapRegisters;
+ (PTRANSLATION_ENTRY) AdapterObject->MapRegisterBase +=
+ NumberOfMapRegisters;
+
+ } else if (action == KeepObject) {
+
+ AdapterObject->AdapterInUse = TRUE;
+
+ }
+
+ return(STATUS_SUCCESS);
+}
+
+VOID
+IoFreeAdapterChannel(
+ IN PADAPTER_OBJECT AdapterObject
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is invoked to deallocate the specified adapter object.
+ Any map registers that were allocated are also automatically deallocated.
+ No checks are made to ensure that the adapter is really allocated to
+ a device object. However, if it is not, then kernel will bugcheck.
+
+ If another device is waiting in the queue to allocate the adapter object
+ it will be pulled from the queue and its execution routine will be
+ invoked.
+
+Arguments:
+
+ AdapterObject - Pointer to the adapter object to be deallocated.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ AdapterObject->AdapterInUse = FALSE;
+}
+
+PHYSICAL_ADDRESS
+IoMapTransfer(
+ IN PADAPTER_OBJECT AdapterObject,
+ IN PMDL Mdl,
+ IN PVOID MapRegisterBase,
+ IN PVOID CurrentVa,
+ IN OUT PULONG Length,
+ IN BOOLEAN WriteToDevice
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is invoked to set up the map registers in the DMA controller
+ to allow a transfer to or from a device.
+
+Arguments:
+
+ AdapterObject - Pointer to the adapter object representing the DMA
+ controller channel that has been allocated.
+
+ Mdl - Pointer to the MDL that describes the pages of memory that are
+ being read or written.
+
+ MapRegisterBase - The address of the base map register that has been
+ allocated to the device driver for use in mapping the transfer.
+
+ CurrentVa - Current virtual address in the buffer described by the MDL
+ that the transfer is being done to or from.
+
+ Length - Supplies the length of the transfer. This determines the
+ number of map registers that need to be written to map the transfer.
+ Returns the length of the transfer which was actually mapped.
+
+ WriteToDevice - Boolean value that indicates whether this is a write
+ to the device from memory (TRUE), or vice versa.
+
+Return Value:
+
+ Returns the logical address that should be used bus master controllers.
+
+--*/
+
+{
+ BOOLEAN useBuffer;
+ ULONG transferLength;
+ ULONG logicalAddress;
+ PULONG pageFrame;
+ PUCHAR bytePointer;
+ UCHAR adapterMode;
+ UCHAR dataByte;
+ PTRANSLATION_ENTRY translationEntry;
+ BOOLEAN masterDevice;
+ PHYSICAL_ADDRESS ReturnAddress;
+
+ if (MachineType == MACHINE_TYPE_MCA) {
+
+ ReturnAddress.QuadPart = IoMapTransferMca(AdapterObject,
+ Mdl,
+ MapRegisterBase,
+ CurrentVa,
+ Length,
+ WriteToDevice);
+ return (ReturnAddress);
+ }
+
+ masterDevice = AdapterObject == NULL || AdapterObject->MasterDevice ?
+ TRUE : FALSE;
+
+ translationEntry = MapRegisterBase;
+ transferLength = *Length;
+
+ //
+ // Determine if the data transfer needs to use the map buffer.
+ //
+
+ if (translationEntry && !masterDevice &&
+ ADDRESS_AND_SIZE_TO_SPAN_PAGES(CurrentVa, transferLength) > 1) {
+
+ logicalAddress = translationEntry->PhysicalAddress;
+ useBuffer = TRUE;
+
+ } else {
+
+ //
+ // The transfer can only be done for one page.
+ //
+
+ transferLength = PAGE_SIZE - BYTE_OFFSET(CurrentVa);
+ pageFrame = (PULONG)(Mdl+1);
+ pageFrame += ((ULONG) CurrentVa - (ULONG) Mdl->StartVa) / PAGE_SIZE;
+ logicalAddress = (*pageFrame << PAGE_SHIFT) + BYTE_OFFSET(CurrentVa);
+
+ //
+ // If the buffer is contigous and does not cross a 64 K bountry then
+ // just extend the buffer.
+ //
+
+ while( transferLength < *Length ){
+
+ if (*pageFrame + 1 != *(pageFrame + 1) ||
+ *pageFrame & ~0x0ffff != *(pageFrame + 1) & ~0x0ffff) {
+ break;
+ }
+
+ transferLength += PAGE_SIZE;
+ pageFrame++;
+
+ }
+
+ transferLength = transferLength > *Length ? *Length : transferLength;
+
+ useBuffer = FALSE;
+ }
+
+ //
+ // Check to see if this device has any map registers allocated. If it
+ // does, then it must require memory to be at less than 16 MB. If the
+ // logical address is greater than 16MB then map registers must be used
+ //
+
+ if (translationEntry && logicalAddress >= MAXIMUM_PHYSICAL_ADDRESS) {
+
+ logicalAddress = (translationEntry + translationEntry->Index)->
+ PhysicalAddress;
+ useBuffer = TRUE;
+
+ }
+
+ //
+ // Return the length.
+ //
+
+ *Length = transferLength;
+
+ //
+ // Copy the data if necessary.
+ //
+
+ if (useBuffer && WriteToDevice) {
+
+ HalpCopyBufferMap(
+ Mdl,
+ translationEntry + translationEntry->Index,
+ CurrentVa,
+ *Length,
+ WriteToDevice
+ );
+
+ }
+
+ //
+ // If there are map registers, then update the index to indicate
+ // how many have been used.
+ //
+
+ if (translationEntry) {
+
+ translationEntry->Index += ADDRESS_AND_SIZE_TO_SPAN_PAGES(
+ CurrentVa,
+ transferLength
+ );
+
+ }
+
+ //
+ // If no adapter was specificed then there is no more work to do so
+ // return.
+ //
+
+ if (masterDevice) {
+
+ //
+ // We only support 32 bits, but the return is 64. Just
+ // zero extend
+ //
+
+ ReturnAddress.QuadPart = logicalAddress;
+ return(ReturnAddress);
+ }
+
+ //
+ // Determine the mode based on the transfer direction.
+ //
+
+ adapterMode = AdapterObject->AdapterMode;
+ ((PDMA_EISA_MODE) &adapterMode)->TransferType = (UCHAR) (WriteToDevice ?
+ WRITE_TRANSFER : READ_TRANSFER);
+
+ ReturnAddress.QuadPart = logicalAddress;
+ bytePointer = (PUCHAR) &logicalAddress;
+
+ if (AdapterObject->Width16Bits) {
+
+ //
+ // If this is a 16 bit transfer then adjust the length and the address
+ // for the 16 bit DMA mode.
+ //
+
+ transferLength >>= 1;
+
+ //
+ // In 16 bit DMA mode the low 16 bits are shifted right one and the
+ // page register value is unchanged. So save the page register value
+ // and shift the logical address then restore the page value.
+ //
+
+ dataByte = bytePointer[2];
+ logicalAddress >>= 1;
+ bytePointer[2] = dataByte;
+
+ }
+
+ //
+ // Determine the controller number based on the Adapter number.
+ //
+
+ if (AdapterObject->AdapterNumber == 1) {
+
+ //
+ // This request is for DMA controller 1
+ //
+
+ PDMA1_CONTROL dmaControl;
+
+ dmaControl = AdapterObject->AdapterBaseVa;
+
+ WRITE_PORT_UCHAR( &dmaControl->ClearBytePointer, 0 );
+
+ WRITE_PORT_UCHAR( &dmaControl->Mode, adapterMode );
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseAddress,
+ bytePointer[0]
+ );
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseAddress,
+ bytePointer[1]
+ );
+
+ WRITE_PORT_UCHAR(
+ ((PUCHAR) &((PEISA_CONTROL) HalpEisaControlBase)->DmaPageLowPort) +
+ (ULONG)AdapterObject->PagePort,
+ bytePointer[2]
+ );
+
+#if 0
+ //
+ // Write the high page register with zero value. This enable a special mode
+ // which allows ties the page register and base count into a single 24 bit
+ // address register.
+ //
+
+ WRITE_PORT_UCHAR(
+ ((PUCHAR) &((PEISA_CONTROL) HalpEisaControlBase)->DmaPageHighPort) +
+ (ULONG)AdapterObject->PagePort,
+ 0
+ );
+#endif
+
+ //
+ // Notify DMA chip of the length to transfer.
+ //
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseCount,
+ (UCHAR) ((transferLength - 1) & 0xff)
+ );
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseCount,
+ (UCHAR) ((transferLength - 1) >> 8)
+ );
+
+
+ //
+ // Set the DMA chip to read or write mode; and unmask it.
+ //
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->SingleMask,
+ (UCHAR) (DMA_CLEARMASK | AdapterObject->ChannelNumber)
+ );
+
+ } else {
+
+ //
+ // This request is for DMA controller 2
+ //
+
+ PDMA2_CONTROL dmaControl;
+
+ dmaControl = AdapterObject->AdapterBaseVa;
+
+ WRITE_PORT_UCHAR( &dmaControl->ClearBytePointer, 0 );
+
+ WRITE_PORT_UCHAR( &dmaControl->Mode, adapterMode );
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseAddress,
+ bytePointer[0]
+ );
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseAddress,
+ bytePointer[1]
+ );
+
+ WRITE_PORT_UCHAR(
+ ((PUCHAR) &((PEISA_CONTROL) HalpEisaControlBase)->DmaPageLowPort) +
+ (ULONG)AdapterObject->PagePort,
+ bytePointer[2]
+ );
+#if 0
+
+ //
+ // Write the high page register with zero value. This enable a special mode
+ // which allows ties the page register and base count into a single 24 bit
+ // address register.
+ //
+
+ WRITE_PORT_UCHAR(
+ ((PUCHAR) &((PEISA_CONTROL) HalpEisaControlBase)->DmaPageHighPort) +
+ (ULONG)AdapterObject->PagePort,
+ 0
+ );
+
+#endif
+ //
+ // Notify DMA chip of the length to transfer.
+ //
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseCount,
+ (UCHAR) ((transferLength - 1) & 0xff)
+ );
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseCount,
+ (UCHAR) ((transferLength - 1) >> 8)
+ );
+
+
+ //
+ // Set the DMA chip to read or write mode; and unmask it.
+ //
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->SingleMask,
+ (UCHAR) (DMA_CLEARMASK | AdapterObject->ChannelNumber)
+ );
+
+ }
+
+ return(ReturnAddress);
+}
+
+BOOLEAN
+IoFlushAdapterBuffers(
+ IN PADAPTER_OBJECT AdapterObject,
+ IN PMDL Mdl,
+ IN PVOID MapRegisterBase,
+ IN PVOID CurrentVa,
+ IN ULONG Length,
+ IN BOOLEAN WriteToDevice
+ )
+
+/*++
+
+Routine Description:
+
+ This routine flushes the DMA adpater object buffers. For the Jazz system
+ its clears the enable flag which aborts the dma.
+
+Arguments:
+
+ AdapterObject - Pointer to the adapter object representing the DMA
+ controller channel.
+
+ Mdl - A pointer to a Memory Descriptor List (MDL) that maps the locked-down
+ buffer to/from which the I/O occured.
+
+ MapRegisterBase - A pointer to the base of the map registers in the adapter
+ or DMA controller.
+
+ CurrentVa - The current virtual address in the buffer described the the Mdl
+ where the I/O operation occurred.
+
+ Length - Supplies the length of the transfer.
+
+ WriteToDevice - Supplies a BOOLEAN value that indicates the direction of
+ the data transfer was to the device.
+
+Return Value:
+
+ TRUE - No errors are detected so the transfer must succeed.
+
+--*/
+
+{
+ PTRANSLATION_ENTRY translationEntry;
+ PULONG pageFrame;
+ ULONG transferLength;
+ ULONG partialLength;
+ BOOLEAN masterDevice;
+ BOOLEAN mapped = FALSE;
+
+ masterDevice = AdapterObject == NULL || AdapterObject->MasterDevice ?
+ TRUE : FALSE;
+
+ translationEntry = MapRegisterBase;
+
+ //
+ // Clear the index of used buffers.
+ //
+
+ if (translationEntry) {
+
+ translationEntry->Index = 0;
+ }
+
+ //
+ // Determine if the data needs to be copied to the orginal buffer.
+ // This only occurs if the data tranfer is from the device, the
+ // MapReisterBase is not NULL and the transfer spans a page.
+ //
+
+ if (!WriteToDevice && translationEntry) {
+
+ //
+ // If this is not a master device, then just transfer the buffer.
+ //
+
+ if (ADDRESS_AND_SIZE_TO_SPAN_PAGES(CurrentVa, Length) > 1 &&
+ !masterDevice) {
+
+ HalpCopyBufferMap(
+ Mdl,
+ translationEntry,
+ CurrentVa,
+ Length,
+ WriteToDevice
+ );
+
+ } else {
+
+ //
+ // Cycle through the pages of the transfer to determine if there
+ // are any which need to be copied back.
+ //
+
+ transferLength = PAGE_SIZE - BYTE_OFFSET(CurrentVa);
+ partialLength = transferLength;
+ pageFrame = (PULONG)(Mdl+1);
+ pageFrame += ((ULONG) CurrentVa - (ULONG) Mdl->StartVa) / PAGE_SIZE;
+
+ while( transferLength <= Length ){
+
+ if (*pageFrame >= BYTES_TO_PAGES(MAXIMUM_PHYSICAL_ADDRESS)) {
+
+ //
+ // Check to see that the MDL is mapped in system space.
+ // If is not mapped, then map it. This ensures that the
+ // buffer will only have to be mapped at most once per I/O.
+ //
+
+ if ((Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA) == 0) {
+
+ Mdl->MappedSystemVa = MmGetMdlVirtualAddress(Mdl);
+ Mdl->MdlFlags |= MDL_MAPPED_TO_SYSTEM_VA;
+ mapped = TRUE;
+
+ }
+
+ HalpCopyBufferMap(
+ Mdl,
+ translationEntry,
+ CurrentVa,
+ partialLength,
+ WriteToDevice
+ );
+
+ }
+
+ (PCCHAR) CurrentVa += partialLength;
+ partialLength = PAGE_SIZE;
+
+ //
+ // Note that transferLength indicates the amount which will be
+ // transfered after the next loop; thus, it is updated with the
+ // new partial length.
+ //
+
+ transferLength += partialLength;
+ pageFrame++;
+ translationEntry++;
+ }
+
+ //
+ // Process the any remaining residue.
+ //
+
+ partialLength = Length - transferLength + partialLength;
+ if (partialLength && *pageFrame >= BYTES_TO_PAGES(MAXIMUM_PHYSICAL_ADDRESS)) {
+
+ HalpCopyBufferMap(
+ Mdl,
+ translationEntry,
+ CurrentVa,
+ partialLength,
+ WriteToDevice
+ );
+
+ }
+ }
+
+ }
+
+
+ //
+ // If this is a master device, then there is nothing more to do so return
+ // TRUE.
+ //
+
+ if (masterDevice) {
+
+ return(TRUE);
+
+ }
+
+ //
+ // Mask the DMA request line so that DMA requests cannot occur.
+ //
+
+ if (AdapterObject->AdapterNumber == 1) {
+
+ //
+ // This request is for DMA controller 1
+ //
+
+ PDMA1_CONTROL dmaControl;
+
+ dmaControl = AdapterObject->AdapterBaseVa;
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->SingleMask,
+ (UCHAR) (DMA_SETMASK | AdapterObject->ChannelNumber)
+ );
+
+ } else {
+
+ //
+ // This request is for DMA controller 2
+ //
+
+ PDMA2_CONTROL dmaControl;
+
+ dmaControl = AdapterObject->AdapterBaseVa;
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->SingleMask,
+ (UCHAR) (DMA_SETMASK | AdapterObject->ChannelNumber)
+ );
+
+ }
+
+ return TRUE;
+}
+
+VOID
+IoFreeMapRegisters(
+ PADAPTER_OBJECT AdapterObject,
+ PVOID MapRegisterBase,
+ ULONG NumberOfMapRegisters
+ )
+/*++
+
+Routine Description:
+
+ This routine deallocates the map registers for the adapter. If there are
+ any queued adapter waiting for an attempt is made to allocate the next
+ entry.
+
+Arguments:
+
+ AdapterObject - The adapter object to where the map register should be
+ returned.
+
+ MapRegisterBase - The map register base of the registers to be deallocated.
+
+ NumberOfMapRegisters - The number of registers to be deallocated.
+
+Return Value:
+
+ None
+
+--+*/
+{
+ PTRANSLATION_ENTRY translationEntry;
+
+ //
+ // Determine if this was the last allocation from the adapter. If is was
+ // then free the map registers by restoring the map register base and the
+ // channel count; otherwise the registers are lost. This handles the
+ // normal case.
+ //
+
+ translationEntry = AdapterObject->MapRegisterBase;
+ translationEntry -= NumberOfMapRegisters;
+
+ if (translationEntry == MapRegisterBase) {
+
+ //
+ // The last allocated registers are being freed.
+ //
+
+ AdapterObject->MapRegisterBase = (PVOID) translationEntry;
+ AdapterObject->MapRegistersPerChannel += NumberOfMapRegisters;
+ }
+}
+
+PHYSICAL_ADDRESS
+MmGetPhysicalAddress (
+ IN PVOID BaseAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This function returns the corresponding physical address for a
+ valid virtual address.
+
+Arguments:
+
+ BaseAddress - Supplies the virtual address for which to return the
+ physical address.
+
+Return Value:
+
+ Returns the corresponding physical address.
+
+Environment:
+
+ Kernel mode. Any IRQL level.
+
+--*/
+
+{
+ PHYSICAL_ADDRESS PhysicalAddress;
+
+ PhysicalAddress.HighPart = 0;
+ PhysicalAddress.LowPart = (ULONG)BaseAddress & ~KSEG0_BASE;
+
+ return(PhysicalAddress);
+}
+
+PVOID
+MmAllocateNonCachedMemory (
+ IN ULONG NumberOfBytes
+ )
+
+/*++
+
+Routine Description:
+
+ This function allocates a range of noncached memory in
+ the non-paged portion of the system address space.
+
+ This routine is designed to be used by a driver's initialization
+ routine to allocate a noncached block of virtual memory for
+ various device specific buffers.
+
+Arguments:
+
+ NumberOfBytes - Supplies the number of bytes to allocate.
+
+Return Value:
+
+ NULL - the specified request could not be satisfied.
+
+ NON-NULL - Returns a pointer (virtual address in the nonpaged portion
+ of the system) to the allocated phyiscally contiguous
+ memory.
+
+Environment:
+
+ Kernel mode, IRQL of APC_LEVEL or below.
+
+--*/
+
+{
+ PVOID BaseAddress;
+
+ //
+ // Allocated the memory.
+ //
+
+ BaseAddress = FwAllocateHeap(NumberOfBytes);
+ return BaseAddress;
+}
+//
+// Define save area for MCA adapter objects. Allocate 1 extra slot for
+// bus masters (MAX_DMA_CHANNEL_NUMBER is zero-based).
+//
+
+PADAPTER_OBJECT HalpMCAAdapter[MAX_MCA_DMA_CHANNEL_NUMBER + 1 + 1];
+
+
+PADAPTER_OBJECT
+HalGetAdapterMca(
+ IN PDEVICE_DESCRIPTION DeviceDescriptor,
+ OUT PULONG NumberOfMapRegisters
+ )
+
+/*++
+
+Routine Description:
+
+ This function returns the appropriate adapter object for the device defined
+ in the device description structure. This code works for MCA systems.
+
+Arguments:
+
+ DeviceDescriptor - Supplies a description of the deivce.
+
+ NumberOfMapRegisters - Returns the maximum number of map registers which
+ may be allocated by the device driver.
+
+Return Value:
+
+ A pointer to the requested adpater object or NULL if an adapter could not
+ be created.
+
+--*/
+
+{
+ PADAPTER_OBJECT adapterObject;
+ ULONG channelNumber;
+ ULONG numberOfMapRegisters;
+ ULONG maximumLength;
+
+ //
+ // Limit the maximum length to 2 GB this is done so that the BYTES_TO_PAGES
+ // macro works correctly.
+ //
+
+ maximumLength = DeviceDescriptor->MaximumLength & 0x7fffffff;
+
+ //
+ // Determine the number of map registers for this device.
+ //
+
+ if (DeviceDescriptor->ScatterGather) {
+
+ //
+ // Since the device support scatter/Gather then map registers are not
+ // required.
+ //
+
+ numberOfMapRegisters = 0;
+
+ } else {
+
+ //
+ // Determine the number of map registers required based on the maximum
+ // transfer length, up to a maximum number.
+ //
+
+ numberOfMapRegisters = BYTES_TO_PAGES(maximumLength)
+ + 1;
+ numberOfMapRegisters = numberOfMapRegisters > MAXIMUM_ISA_MAP_REGISTER ?
+ MAXIMUM_ISA_MAP_REGISTER : numberOfMapRegisters;
+
+ //
+ // If the device is not a master and does scatter/gather then it only
+ // needs one map register.
+ //
+
+ if (DeviceDescriptor->ScatterGather && !DeviceDescriptor->Master) {
+
+ numberOfMapRegisters = 1;
+ }
+ }
+
+ //
+ // Set the channel number. If bus master, set channel to max system
+ // DMA channel + 1.
+ //
+
+ if ( DeviceDescriptor->Master) {
+
+ channelNumber = MAX_MCA_DMA_CHANNEL_NUMBER + 1;
+
+ } else {
+
+ channelNumber = DeviceDescriptor->DmaChannel;
+
+ } // if
+
+ //
+ // Determine if a new adapter object is necessary. If so then allocate it.
+ //
+
+ if (HalpMCAAdapter[channelNumber] != NULL) {
+
+ adapterObject = HalpMCAAdapter[ channelNumber];
+
+ } else {
+
+ //
+ // Allocate an adapter object.
+ //
+
+ //
+ // bugbug- need to pass in MCA base address instead of 0.
+ //
+
+ adapterObject = (PADAPTER_OBJECT) IopAllocateAdapter(
+ numberOfMapRegisters,
+ (PVOID) 0,
+ NULL
+ );
+
+ if (adapterObject == NULL) {
+
+ return(NULL);
+
+ }
+
+ HalpMCAAdapter[channelNumber] = adapterObject;
+
+
+ adapterObject->NeedsMapRegisters = FALSE;
+
+ //
+ // Set the maximum number of map registers for this channel bus on
+ // the number requested and the type of device.
+ //
+
+ if (numberOfMapRegisters) {
+
+ //
+ // The specified number of registers are actually allowed to be
+ // allocated.
+ //
+
+ adapterObject->MapRegistersPerChannel = numberOfMapRegisters;
+
+
+ } else {
+
+ //
+ // No real map registers were allocated. If this is a master
+ // device, then the device can have as may registers as it wants.
+ //
+
+ if (DeviceDescriptor->Master) {
+
+ adapterObject->MapRegistersPerChannel = BYTES_TO_PAGES(
+ maximumLength
+ )
+ + 1;
+
+ } else {
+
+ //
+ // The device only gets one register. It must call
+ // IoMapTransfer repeatedly to do a large transfer.
+ //
+
+ adapterObject->MapRegistersPerChannel = 1;
+ }
+ }
+ }
+
+ *NumberOfMapRegisters = adapterObject->MapRegistersPerChannel;
+
+ //
+ // If this is the adapter object for bus master devices,
+ // exit here since there is no additional work to do.
+ //
+
+ if (DeviceDescriptor->Master) {
+
+ adapterObject->MasterDevice = TRUE;
+ return(adapterObject);
+
+ }
+
+ adapterObject->MasterDevice = FALSE;
+
+ //
+ // set up channel number.
+ //
+
+ adapterObject->ChannelNumber = (UCHAR) channelNumber;
+
+ //
+ // initialize MCA Extended DMA Mode flags.
+ //
+
+ *((PUCHAR) &adapterObject->ExtendedModeFlags) = 0;
+
+ //
+ // set up PIO address if necessary.
+ //
+
+ if ( DeviceDescriptor->DmaPort) {
+
+ (*(PDMA_EXTENDED_MODE_MCA)&adapterObject->ExtendedModeFlags).ProgrammedIo = DMA_EXT_USE_PIO;
+ adapterObject->DmaPortAddress = (USHORT) DeviceDescriptor->DmaPort;
+ }
+
+ //
+ // indicate data transfer operation for DMA.
+ //
+
+ (*(PDMA_EXTENDED_MODE_MCA)&adapterObject->ExtendedModeFlags).DmaOpcode = DMA_EXT_DATA_XFER;
+
+ switch (DeviceDescriptor->DmaWidth) {
+ case Width8Bits:
+ (*(PDMA_EXTENDED_MODE_MCA)&adapterObject->ExtendedModeFlags).DmaWidth = DMA_EXT_WIDTH_8_BIT;
+ break;
+
+ case Width16Bits:
+ (*(PDMA_EXTENDED_MODE_MCA)&adapterObject->ExtendedModeFlags).DmaWidth = DMA_EXT_WIDTH_16_BIT;
+ break;
+
+ default:
+ return(NULL);
+
+ } // switch
+
+ return(adapterObject);
+}
+
+
+ULONG
+IoMapTransferMca(
+ IN PADAPTER_OBJECT AdapterObject,
+ IN PMDL Mdl,
+ IN PVOID MapRegisterBase,
+ IN PVOID CurrentVa,
+ IN OUT PULONG Length,
+ IN BOOLEAN WriteToDevice
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is invoked to set up the map registers in the DMA controller
+ to allow a transfer to or from a device.
+
+Arguments:
+
+ AdapterObject - Pointer to the adapter object representing the DMA
+ controller channel that has been allocated.
+
+ Mdl - Pointer to the MDL that describes the pages of memory that are
+ being read or written.
+
+ MapRegisterBase - The address of the base map register that has been
+ allocated to the device driver for use in mapping the transfer.
+
+ CurrentVa - Current virtual address in the buffer described by the MDL
+ that the transfer is being done to or from.
+
+ Length - Supplies the length of the transfer. This determines the
+ number of map registers that need to be written to map the transfer.
+ Returns the length of the transfer which was actually mapped.
+
+ WriteToDevice - Boolean value that indicates whether this is a write
+ to the device from memory (TRUE), or vice versa.
+
+Return Value:
+
+ Returns the logical address that should be used bus master controllers.
+
+--*/
+
+{
+ BOOLEAN useBuffer;
+ ULONG transferLength;
+ ULONG logicalAddress;
+ ULONG returnAddress;
+ PULONG pageFrame;
+ PUCHAR bytePointer;
+ PTRANSLATION_ENTRY translationEntry;
+ BOOLEAN masterDevice;
+ PMCA_DMA_CONTROLLER dmaControl;
+ UCHAR channelNumber;
+ ULONG pageOffset;
+
+ masterDevice = AdapterObject == NULL || AdapterObject->MasterDevice ?
+ TRUE : FALSE;
+
+ translationEntry = MapRegisterBase;
+ transferLength = *Length;
+ pageOffset = BYTE_OFFSET(CurrentVa);
+
+ //
+ // Determine if the data transfer needs to use the map buffer.
+ //
+
+ if (translationEntry && !masterDevice &&
+ ADDRESS_AND_SIZE_TO_SPAN_PAGES(CurrentVa, transferLength) > 1) {
+
+ logicalAddress = translationEntry->PhysicalAddress + pageOffset;
+ useBuffer = TRUE;
+
+ } else {
+
+ //
+ // The transfer can only be done for one page.
+ //
+
+ transferLength = PAGE_SIZE - pageOffset;
+ pageFrame = (PULONG)(Mdl+1);
+ pageFrame += ((ULONG) CurrentVa - (ULONG) Mdl->StartVa) / PAGE_SIZE;
+ logicalAddress = (*pageFrame << PAGE_SHIFT) + pageOffset;
+
+ //
+ // If the buffer is contigous then extend the buffer.
+ //
+
+ while( transferLength < *Length ){
+
+ if (*pageFrame + 1 != *(pageFrame + 1) ) {
+ break;
+ }
+
+ transferLength += PAGE_SIZE;
+ pageFrame++;
+
+ }
+
+ transferLength = transferLength > *Length ? *Length : transferLength;
+
+ useBuffer = FALSE;
+ }
+
+ //
+ // Check to see if this device has any map registers allocated. If it
+ // does, then it must require memory to be at less than 16 MB. If the
+ // logical address is greater than 16MB then map registers must be used
+ //
+
+ if (translationEntry && logicalAddress >= MAXIMUM_PHYSICAL_ADDRESS) {
+
+ logicalAddress = (translationEntry + translationEntry->Index)->
+ PhysicalAddress + pageOffset;
+ useBuffer = TRUE;
+
+ }
+
+ //
+ // Return the length.
+ //
+
+ *Length = transferLength;
+
+ //
+ // Copy the data if necessary.
+ //
+
+ if (useBuffer && WriteToDevice) {
+
+ HalpCopyBufferMap(
+ Mdl,
+ translationEntry + translationEntry->Index,
+ CurrentVa,
+ *Length,
+ WriteToDevice
+ );
+
+ }
+
+ //
+ // If there are map registers, then update the index to indicate
+ // how many have been used.
+ //
+
+ if (translationEntry) {
+
+ translationEntry->Index += ADDRESS_AND_SIZE_TO_SPAN_PAGES(
+ CurrentVa,
+ transferLength
+ );
+
+ }
+
+ //
+ // If no adapter was specificed, or device is bus master, then there
+ // is no more work to do so return.
+ //
+
+ if (masterDevice) {
+
+ return(logicalAddress);
+
+ }
+
+ //
+ // Device will use system DMA.
+ //
+
+ returnAddress = logicalAddress;
+ bytePointer = (PUCHAR) &logicalAddress;
+
+ //
+ // Set up the Microchannel system DMA controller
+ //
+
+ dmaControl = (PMCA_DMA_CONTROLLER)
+ &( (PMCA_CONTROL) (AdapterObject->AdapterBaseVa))->
+ ExtendedDmaBasePort[0];
+ channelNumber = AdapterObject->ChannelNumber;
+
+ //
+ // set the mask bit
+ //
+
+ WRITE_PORT_UCHAR( &dmaControl->DmaFunctionLsb,
+ (UCHAR) ( SET_MASK_BIT | channelNumber));
+
+ //
+ // set mode register
+ //
+
+ WRITE_PORT_UCHAR( &dmaControl->DmaFunctionLsb,
+ (UCHAR) ( WRITE_MODE | channelNumber));
+
+ //
+ // Set up for read or write, appropriately
+ //
+
+ if ( WriteToDevice) {
+
+ WRITE_PORT_UCHAR( &dmaControl->DmaFunctionData,
+ (UCHAR) (*((PUCHAR) &AdapterObject->
+ ExtendedModeFlags)
+ | (UCHAR) DMA_MODE_READ));
+
+ } else {
+
+ WRITE_PORT_UCHAR( &dmaControl->DmaFunctionData,
+ (UCHAR) ( *((PUCHAR) &AdapterObject->
+ ExtendedModeFlags)
+ | DMA_MODE_WRITE));
+ }
+
+ //
+ // if there is a DMA Programmed I/O address, set it up
+ //
+
+ if ((*(PDMA_EXTENDED_MODE_MCA)&AdapterObject->ExtendedModeFlags).ProgrammedIo) {
+
+ //
+ // set up I/O base address
+ //
+
+ WRITE_PORT_UCHAR( &dmaControl->DmaFunctionLsb,
+ (UCHAR) ( WRITE_IO_ADDRESS | channelNumber));
+
+ WRITE_PORT_UCHAR( &dmaControl->DmaFunctionData,
+ (UCHAR) AdapterObject->DmaPortAddress);
+
+ WRITE_PORT_UCHAR( &dmaControl->DmaFunctionData,
+ (UCHAR) ( AdapterObject->DmaPortAddress >> 8));
+
+ }
+
+ //
+ // set the DMA transfer count
+ //
+
+ WRITE_PORT_UCHAR( &dmaControl->DmaFunctionLsb,
+ (UCHAR) ( WRITE_TRANSFER_COUNT | channelNumber));
+
+ //
+ // adjust transfer count for 16-bit transfers as required.
+ //
+
+ if ((*(PDMA_EXTENDED_MODE_MCA)&AdapterObject->ExtendedModeFlags).DmaWidth == DMA_EXT_WIDTH_16_BIT ) {
+ transferLength >>= 1;
+ }
+
+ WRITE_PORT_UCHAR( &dmaControl->DmaFunctionData,
+ (UCHAR) ( transferLength - 1));
+
+ WRITE_PORT_UCHAR( &dmaControl->DmaFunctionData,
+ (UCHAR) ( ( transferLength - 1) >> 8));
+
+ //
+ // set the DMA transfer start address
+ //
+
+ WRITE_PORT_UCHAR( &dmaControl->DmaFunctionLsb,
+ (UCHAR) ( WRITE_MEMORY_ADDRESS | channelNumber));
+
+ WRITE_PORT_UCHAR( &dmaControl->DmaFunctionData,
+ (UCHAR) logicalAddress);
+
+ WRITE_PORT_UCHAR( &dmaControl->DmaFunctionData,
+ (UCHAR) (logicalAddress >> 8));
+
+ WRITE_PORT_UCHAR( &dmaControl->DmaFunctionData,
+ (UCHAR) (logicalAddress >> 16));
+
+ //
+ // clear the mask bit
+ //
+
+ WRITE_PORT_UCHAR( &dmaControl->DmaFunctionLsb,
+ (UCHAR) ( CLEAR_MASK_BIT | channelNumber));
+
+ return(returnAddress);
+}
diff --git a/private/ntos/boot/lib/i386/ixpcibus.c b/private/ntos/boot/lib/i386/ixpcibus.c
new file mode 100644
index 000000000..b273eb10a
--- /dev/null
+++ b/private/ntos/boot/lib/i386/ixpcibus.c
@@ -0,0 +1,1381 @@
+/*++
+
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ ixpcidat.c
+
+Abstract:
+
+ Get/Set bus data routines for the PCI bus
+
+Author:
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "bootx86.h"
+#include "arc.h"
+#include "ixfwhal.h"
+#include "ntconfig.h"
+
+#include "pci.h"
+
+//extern WCHAR rgzMultiFunctionAdapter[];
+//extern WCHAR rgzConfigurationData[];
+//extern WCHAR rgzIdentifier[];
+//extern WCHAR rgzPCIIdentifier[];
+
+//
+// Hal specific PCI bus structures
+//
+
+typedef struct tagPCIPBUSDATA {
+ union {
+ struct {
+ PULONG Address;
+ ULONG Data;
+ } Type1;
+ struct {
+ PUCHAR CSE;
+ PUCHAR Forward;
+ ULONG Base;
+ } Type2;
+ } Config;
+
+} PCIPBUSDATA, *PPCIPBUSDATA;
+
+#define PciBitIndex(Dev,Fnc) (Fnc*32 + Dev);
+#define PCI_CONFIG_TYPE(PciData) ((PciData)->HeaderType & ~PCI_MULTIFUNCTION)
+
+#define BUSHANDLER _BUSHANDLER
+#define PBUSHANDLER _PBUSHANDLER
+
+// thunk for NtLdr
+typedef struct {
+ ULONG NoBuses;
+ ULONG BusNumber;
+ PVOID BusData;
+ PCIPBUSDATA theBusData;
+} BUSHANDLER, *PBUSHANDLER;
+
+#define HalpPCIPin2Line(bus,rbus,slot,pcidata)
+#define HalpPCILine2Pin(bus,rbus,slot,pcidata,pcidata2)
+#define ExAllocatePool(a,l) FwAllocatePool(l)
+// thunk for NtLdr
+
+
+typedef ULONG (*FncConfigIO) (
+ IN PPCIPBUSDATA BusData,
+ IN PVOID State,
+ IN PUCHAR Buffer,
+ IN ULONG Offset
+ );
+
+typedef VOID (*FncSync) (
+ IN PBUSHANDLER BusHandler,
+ IN PCI_SLOT_NUMBER Slot,
+ IN PKIRQL Irql,
+ IN PVOID State
+ );
+
+typedef VOID (*FncReleaseSync) (
+ IN PBUSHANDLER BusHandler,
+ IN KIRQL Irql
+ );
+
+typedef struct {
+ FncSync Synchronize;
+ FncReleaseSync ReleaseSynchronzation;
+ FncConfigIO ConfigRead[3];
+ FncConfigIO ConfigWrite[3];
+} CONFIG_HANDLER, *PCONFIG_HANDLER;
+
+
+//
+// Prototypes
+//
+
+ULONG
+HalpGetPCIData (
+ IN ULONG BusNumber,
+ IN PCI_SLOT_NUMBER SlotNumber,
+ IN PVOID Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+ );
+
+ULONG
+HalpSetPCIData (
+ IN ULONG BusNumber,
+ IN PCI_SLOT_NUMBER SlotNumber,
+ IN PVOID Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+ );
+
+extern ULONG
+HalpGetPCIInterruptVector (
+ IN PBUSHANDLER BusHandler,
+ IN PBUSHANDLER RootHandler,
+ IN ULONG BusInterruptLevel,
+ IN ULONG BusInterruptVector,
+ OUT PKIRQL Irql,
+ OUT PKAFFINITY Affinity
+ );
+
+NTSTATUS
+HalpAdjustPCIResourceList (
+ IN PBUSHANDLER BusHandler,
+ IN PBUSHANDLER RootHandler,
+ IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList
+ );
+
+NTSTATUS
+HalpAssignPCISlotResources (
+ IN ULONG BusNumber,
+ IN ULONG SlotNumber,
+ IN OUT PCM_RESOURCE_LIST *AllocatedResources
+ );
+
+VOID
+HalpInitializePciBuses (
+ VOID
+ );
+
+//VOID
+//HalpPCIPin2Line (
+// IN PBUSHANDLER BusHandler,
+// IN PBUSHANDLER RootHandler,
+// IN PCI_SLOT_NUMBER Slot,
+// IN PPCI_COMMON_CONFIG PciData
+// );
+//
+//VOID
+//HalpPCILine2Pin (
+// IN PBUSHANDLER BusHandler,
+// IN PBUSHANDLER RootHandler,
+// IN PCI_SLOT_NUMBER SlotNumber,
+// IN PPCI_COMMON_CONFIG PciNewData,
+// IN PPCI_COMMON_CONFIG PciOldData
+// );
+
+BOOLEAN
+HalpValidPCISlot (
+ IN PBUSHANDLER BusHandler,
+ IN PCI_SLOT_NUMBER Slot
+ );
+
+VOID
+HalpReadPCIConfig (
+ IN PBUSHANDLER BusHandler,
+ IN PCI_SLOT_NUMBER Slot,
+ IN PVOID Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+ );
+
+
+VOID
+HalpWritePCIConfig (
+ IN PBUSHANDLER BusHandler,
+ IN PCI_SLOT_NUMBER Slot,
+ IN PVOID Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+ );
+
+PBUSHANDLER
+HalpGetPciBusHandler (
+ IN ULONG BusNumber
+ );
+
+//-------------------------------------------------
+
+VOID HalpPCISynchronizeType1 (
+ IN PBUSHANDLER BusHandler,
+ IN PCI_SLOT_NUMBER Slot,
+ IN PKIRQL Irql,
+ IN PVOID State
+ );
+
+VOID HalpPCIReleaseSynchronzationType1 (
+ IN PBUSHANDLER BusHandler,
+ IN KIRQL Irql
+ );
+
+ULONG HalpPCIReadUlongType1 (
+ IN PPCIPBUSDATA BusData,
+ IN PVOID State,
+ IN PUCHAR Buffer,
+ IN ULONG Offset
+ );
+
+ULONG HalpPCIReadUcharType1 (
+ IN PPCIPBUSDATA BusData,
+ IN PVOID State,
+ IN PUCHAR Buffer,
+ IN ULONG Offset
+ );
+
+ULONG HalpPCIReadUshortType1 (
+ IN PPCIPBUSDATA BusData,
+ IN PVOID State,
+ IN PUCHAR Buffer,
+ IN ULONG Offset
+ );
+
+ULONG HalpPCIWriteUlongType1 (
+ IN PPCIPBUSDATA BusData,
+ IN PVOID State,
+ IN PUCHAR Buffer,
+ IN ULONG Offset
+ );
+
+ULONG HalpPCIWriteUcharType1 (
+ IN PPCIPBUSDATA BusData,
+ IN PVOID State,
+ IN PUCHAR Buffer,
+ IN ULONG Offset
+ );
+
+ULONG HalpPCIWriteUshortType1 (
+ IN PPCIPBUSDATA BusData,
+ IN PVOID State,
+ IN PUCHAR Buffer,
+ IN ULONG Offset
+ );
+
+VOID HalpPCISynchronizeType2 (
+ IN PBUSHANDLER BusHandler,
+ IN PCI_SLOT_NUMBER Slot,
+ IN PKIRQL Irql,
+ IN PVOID State
+ );
+
+VOID HalpPCIReleaseSynchronzationType2 (
+ IN PBUSHANDLER BusHandler,
+ IN KIRQL Irql
+ );
+
+ULONG HalpPCIReadUlongType2 (
+ IN PPCIPBUSDATA BusData,
+ IN PVOID State,
+ IN PUCHAR Buffer,
+ IN ULONG Offset
+ );
+
+ULONG HalpPCIReadUcharType2 (
+ IN PPCIPBUSDATA BusData,
+ IN PVOID State,
+ IN PUCHAR Buffer,
+ IN ULONG Offset
+ );
+
+ULONG HalpPCIReadUshortType2 (
+ IN PPCIPBUSDATA BusData,
+ IN PVOID State,
+ IN PUCHAR Buffer,
+ IN ULONG Offset
+ );
+
+ULONG HalpPCIWriteUlongType2 (
+ IN PPCIPBUSDATA BusData,
+ IN PVOID State,
+ IN PUCHAR Buffer,
+ IN ULONG Offset
+ );
+
+ULONG HalpPCIWriteUcharType2 (
+ IN PPCIPBUSDATA BusData,
+ IN PVOID State,
+ IN PUCHAR Buffer,
+ IN ULONG Offset
+ );
+
+ULONG HalpPCIWriteUshortType2 (
+ IN PPCIPBUSDATA BusData,
+ IN PVOID State,
+ IN PUCHAR Buffer,
+ IN ULONG Offset
+ );
+
+
+#define DISABLE_INTERRUPTS() //_asm { cli }
+#define ENABLE_INTERRUPTS() //_asm { sti }
+
+
+//
+// Globals
+//
+
+ULONG PCIMaxDevice;
+BUSHANDLER PCIBusHandler;
+
+CONFIG_HANDLER PCIConfigHandlers = {
+ HalpPCISynchronizeType1,
+ HalpPCIReleaseSynchronzationType1,
+ {
+ HalpPCIReadUlongType1, // 0
+ HalpPCIReadUcharType1, // 1
+ HalpPCIReadUshortType1 // 2
+ },
+ {
+ HalpPCIWriteUlongType1, // 0
+ HalpPCIWriteUcharType1, // 1
+ HalpPCIWriteUshortType1 // 2
+ }
+};
+
+CONFIG_HANDLER PCIConfigHandlersType2 = {
+ HalpPCISynchronizeType2,
+ HalpPCIReleaseSynchronzationType2,
+ {
+ HalpPCIReadUlongType2, // 0
+ HalpPCIReadUcharType2, // 1
+ HalpPCIReadUshortType2 // 2
+ },
+ {
+ HalpPCIWriteUlongType2, // 0
+ HalpPCIWriteUcharType2, // 1
+ HalpPCIWriteUshortType2 // 2
+ }
+};
+
+UCHAR PCIDeref[4][4] = { {0,1,2,2},{1,1,1,1},{2,1,2,2},{1,1,1,1} };
+
+
+VOID
+HalpPCIConfig (
+ IN PBUSHANDLER BusHandler,
+ IN PCI_SLOT_NUMBER Slot,
+ IN PUCHAR Buffer,
+ IN ULONG Offset,
+ IN ULONG Length,
+ IN FncConfigIO *ConfigIO
+ );
+
+
+VOID
+HalpInitializePciBus (
+ VOID
+ )
+{
+ PPCI_REGISTRY_INFO PCIRegInfo;
+ PPCIPBUSDATA BusData;
+ PBUSHANDLER Bus;
+ PCONFIGURATION_COMPONENT_DATA ConfigData;
+ PCM_PARTIAL_RESOURCE_LIST Desc;
+ PCM_PARTIAL_RESOURCE_DESCRIPTOR PDesc;
+ ULONG i;
+ ULONG HwType;
+
+ Bus = &PCIBusHandler;
+ PCIBusHandler.BusData = &PCIBusHandler.theBusData;
+
+ PCIRegInfo = NULL; // not found
+ ConfigData = NULL; // start at begining
+ do {
+ ConfigData = KeFindConfigurationNextEntry (
+ FwConfigurationTree,
+ AdapterClass,
+ MultiFunctionAdapter,
+ NULL,
+ &ConfigData
+ );
+
+ if (ConfigData == NULL) {
+ // PCI info not found
+ return ;
+ }
+
+ if (ConfigData->ComponentEntry.Identifier == NULL ||
+ _stricmp (ConfigData->ComponentEntry.Identifier, "PCI") != 0) {
+ continue;
+ }
+
+ PCIRegInfo = NULL;
+ Desc = ConfigData->ConfigurationData;
+ PDesc = Desc->PartialDescriptors;
+ for (i = 0; i < Desc->Count; i++) {
+ if (PDesc->Type == CmResourceTypeDeviceSpecific) {
+ PCIRegInfo = (PPCI_REGISTRY_INFO) (PDesc+1);
+ break;
+ }
+ PDesc++;
+ }
+ } while (!PCIRegInfo) ;
+
+ //
+ // PCIRegInfo describes the system's PCI support as indicated
+ // by the BIOS.
+ //
+
+ HwType = PCIRegInfo->HardwareMechanism & 0xf;
+
+ switch (HwType) {
+ case 1:
+ // this is the default case
+ PCIMaxDevice = PCI_MAX_DEVICES;
+ break;
+
+ //
+ // Type2 does not work MP, nor does the default type2
+ // support more the 0xf device slots
+ //
+
+ case 2:
+ RtlMoveMemory (&PCIConfigHandlers,
+ &PCIConfigHandlersType2,
+ sizeof (PCIConfigHandlersType2));
+ PCIMaxDevice = 0x10;
+ break;
+
+ default:
+ // unsupport type
+ PCIRegInfo->NoBuses = 0;
+ }
+
+ PCIBusHandler.NoBuses = PCIRegInfo->NoBuses;
+ if (PCIRegInfo->NoBuses) {
+
+ BusData = (PPCIPBUSDATA) Bus->BusData;
+ switch (HwType) {
+ case 1:
+ BusData->Config.Type1.Address = PCI_TYPE1_ADDR_PORT;
+ BusData->Config.Type1.Data = PCI_TYPE1_DATA_PORT;
+ break;
+
+ case 2:
+ BusData->Config.Type2.CSE = PCI_TYPE2_CSE_PORT;
+ BusData->Config.Type2.Forward = PCI_TYPE2_FORWARD_PORT;
+ BusData->Config.Type2.Base = PCI_TYPE2_ADDRESS_BASE;
+ break;
+ }
+ }
+}
+
+
+PBUSHANDLER
+HalpGetPciBusHandler (
+ IN ULONG BusNumber
+ )
+{
+ if (PCIBusHandler.BusData == NULL) {
+ HalpInitializePciBus ();
+ }
+
+ if (BusNumber > PCIBusHandler.NoBuses) {
+ return NULL;
+ }
+
+ PCIBusHandler.BusNumber = BusNumber;
+ return &PCIBusHandler;
+}
+
+
+ULONG
+HalpGetPCIData (
+ IN ULONG BusNumber,
+ IN PCI_SLOT_NUMBER Slot,
+ IN PUCHAR Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ The function returns the Pci bus data for a device.
+
+Arguments:
+
+ BusNumber - Indicates which bus.
+
+ VendorSpecificDevice - The VendorID (low Word) and DeviceID (High Word)
+
+ Buffer - Supplies the space to store the data.
+
+ Length - Supplies a count in bytes of the maximum amount to return.
+
+Return Value:
+
+ Returns the amount of data stored into the buffer.
+
+ If this PCI slot has never been set, then the configuration information
+ returned is zeroed.
+
+
+--*/
+{
+ PBUSHANDLER BusHandler;
+ PPCI_COMMON_CONFIG PciData;
+ UCHAR iBuffer[PCI_COMMON_HDR_LENGTH];
+ PPCIPBUSDATA BusData;
+ ULONG Len;
+
+ BusHandler = HalpGetPciBusHandler (BusNumber);
+ if (!BusHandler) {
+ return 0;
+ }
+
+ if (Length > sizeof (PCI_COMMON_CONFIG)) {
+ Length = sizeof (PCI_COMMON_CONFIG);
+ }
+
+ Len = 0;
+ PciData = (PPCI_COMMON_CONFIG) iBuffer;
+
+ if (Offset >= PCI_COMMON_HDR_LENGTH) {
+ //
+ // The user did not request any data from the common
+ // header. Verify the PCI device exists, then continue
+ // in the device specific area.
+ //
+
+ HalpReadPCIConfig (BusHandler, Slot, PciData, 0, sizeof(ULONG));
+
+ if (PciData->VendorID == PCI_INVALID_VENDORID) {
+ return 0;
+ }
+
+ } else {
+
+ //
+ // Caller requested at least some data within the
+ // common header. Read the whole header, effect the
+ // fields we need to and then copy the user's requested
+ // bytes from the header
+ //
+
+ //
+ // Read this PCI devices slot data
+ //
+
+ Len = PCI_COMMON_HDR_LENGTH;
+ HalpReadPCIConfig (BusHandler, Slot, PciData, 0, Len);
+
+ if (PciData->VendorID == PCI_INVALID_VENDORID ||
+ PCI_CONFIG_TYPE (PciData) != 0) {
+ PciData->VendorID = PCI_INVALID_VENDORID;
+ Len = 2; // only return invalid id
+ }
+
+ //
+ // Has this PCI device been configured?
+ //
+
+ BusData = (PPCIPBUSDATA) BusHandler->BusData;
+ HalpPCIPin2Line (BusHandler, RootHandler, Slot, PciData);
+
+ //
+ // Copy whatever data overlaps into the callers buffer
+ //
+
+ if (Len < Offset) {
+ // no data at caller's buffer
+ return 0;
+ }
+
+ Len -= Offset;
+ if (Len > Length) {
+ Len = Length;
+ }
+
+ RtlMoveMemory(Buffer, iBuffer + Offset, Len);
+
+ Offset += Len;
+ Buffer += Len;
+ Length -= Len;
+ }
+
+ if (Length) {
+ if (Offset >= PCI_COMMON_HDR_LENGTH) {
+ //
+ // The remaining Buffer comes from the Device Specific
+ // area - put on the kitten gloves and read from it.
+ //
+ // Specific read/writes to the PCI device specific area
+ // are guarenteed:
+ //
+ // Not to read/write any byte outside the area specified
+ // by the caller. (this may cause WORD or BYTE references
+ // to the area in order to read the non-dword aligned
+ // ends of the request)
+ //
+ // To use a WORD access if the requested length is exactly
+ // a WORD long & WORD aligned.
+ //
+ // To use a BYTE access if the requested length is exactly
+ // a BYTE long.
+ //
+
+ HalpReadPCIConfig (BusHandler, Slot, Buffer, Offset, Length);
+ Len += Length;
+ }
+ }
+
+ return Len;
+}
+
+ULONG
+HalpSetPCIData (
+ IN ULONG BusNumber,
+ IN PCI_SLOT_NUMBER Slot,
+ IN PUCHAR Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ The function returns the Pci bus data for a device.
+
+Arguments:
+
+
+ VendorSpecificDevice - The VendorID (low Word) and DeviceID (High Word)
+
+ Buffer - Supplies the space to store the data.
+
+ Length - Supplies a count in bytes of the maximum amount to return.
+
+Return Value:
+
+ Returns the amount of data stored into the buffer.
+
+--*/
+{
+ PBUSHANDLER BusHandler;
+ PPCI_COMMON_CONFIG PciData, PciData2;
+ UCHAR iBuffer[PCI_COMMON_HDR_LENGTH];
+ UCHAR iBuffer2[PCI_COMMON_HDR_LENGTH];
+ PPCIPBUSDATA BusData;
+ ULONG Len;
+
+ BusHandler = HalpGetPciBusHandler (BusNumber);
+ if (!BusHandler) {
+ return 0;
+ }
+
+ if (Length > sizeof (PCI_COMMON_CONFIG)) {
+ Length = sizeof (PCI_COMMON_CONFIG);
+ }
+
+ Len = 0;
+ PciData = (PPCI_COMMON_CONFIG) iBuffer;
+ PciData2 = (PPCI_COMMON_CONFIG) iBuffer2;
+
+ if (Offset >= PCI_COMMON_HDR_LENGTH) {
+ //
+ // The user did not request any data from the common
+ // header. Verify the PCI device exists, then continue in
+ // the device specific area.
+ //
+
+ HalpReadPCIConfig (BusHandler, Slot, PciData, 0, sizeof(ULONG));
+
+ if (PciData->VendorID == PCI_INVALID_VENDORID) {
+ return 0;
+ }
+
+ } else {
+
+ //
+ // Caller requested to set at least some data within the
+ // common header.
+ //
+
+ Len = PCI_COMMON_HDR_LENGTH;
+ HalpReadPCIConfig (BusHandler, Slot, PciData, 0, Len);
+ if (PciData->VendorID == PCI_INVALID_VENDORID ||
+ PCI_CONFIG_TYPE (PciData) != 0) {
+
+ // no device, or header type unkown
+ return 0;
+ }
+
+ //
+ // Set this device as configured
+ //
+
+ BusData = (PPCIPBUSDATA) BusHandler->BusData;
+ //
+ // Copy COMMON_HDR values to buffer2, then overlay callers changes.
+ //
+
+ RtlMoveMemory (iBuffer2, iBuffer, Len);
+
+ Len -= Offset;
+ if (Len > Length) {
+ Len = Length;
+ }
+
+ RtlMoveMemory (iBuffer2+Offset, Buffer, Len);
+
+ // in case interrupt line or pin was editted
+ HalpPCILine2Pin (BusHandler, RootHandler, Slot, PciData2, PciData);
+
+ //
+ // Set new PCI configuration
+ //
+
+ HalpWritePCIConfig (BusHandler, Slot, iBuffer2+Offset, Offset, Len);
+
+ Offset += Len;
+ Buffer += Len;
+ Length -= Len;
+ }
+
+ if (Length) {
+ if (Offset >= PCI_COMMON_HDR_LENGTH) {
+ //
+ // The remaining Buffer comes from the Device Specific
+ // area - put on the kitten gloves and write it
+ //
+ // Specific read/writes to the PCI device specific area
+ // are guarenteed:
+ //
+ // Not to read/write any byte outside the area specified
+ // by the caller. (this may cause WORD or BYTE references
+ // to the area in order to read the non-dword aligned
+ // ends of the request)
+ //
+ // To use a WORD access if the requested length is exactly
+ // a WORD long & WORD aligned.
+ //
+ // To use a BYTE access if the requested length is exactly
+ // a BYTE long.
+ //
+
+ HalpWritePCIConfig (BusHandler, Slot, Buffer, Offset, Length);
+ Len += Length;
+ }
+ }
+
+ return Len;
+}
+
+VOID
+HalpReadPCIConfig (
+ IN PBUSHANDLER BusHandler,
+ IN PCI_SLOT_NUMBER Slot,
+ IN PVOID Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+ )
+{
+ if (!HalpValidPCISlot (BusHandler, Slot)) {
+ //
+ // Invalid SlotID return no data
+ //
+
+ RtlFillMemory (Buffer, Length, (UCHAR) -1);
+ return ;
+ }
+
+ HalpPCIConfig (BusHandler, Slot, (PUCHAR) Buffer, Offset, Length,
+ PCIConfigHandlers.ConfigRead);
+}
+
+VOID
+HalpWritePCIConfig (
+ IN PBUSHANDLER BusHandler,
+ IN PCI_SLOT_NUMBER Slot,
+ IN PVOID Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+ )
+{
+ if (!HalpValidPCISlot (BusHandler, Slot)) {
+ //
+ // Invalid SlotID do nothing
+ //
+ return ;
+ }
+
+ HalpPCIConfig (BusHandler, Slot, (PUCHAR) Buffer, Offset, Length,
+ PCIConfigHandlers.ConfigWrite);
+}
+
+BOOLEAN
+HalpValidPCISlot (
+ IN PBUSHANDLER BusHandler,
+ IN PCI_SLOT_NUMBER Slot
+ )
+{
+ PCI_SLOT_NUMBER Slot2;
+ UCHAR HeaderType;
+ ULONG i;
+
+ if (Slot.u.bits.Reserved != 0) {
+ return FALSE;
+ }
+
+ if (Slot.u.bits.DeviceNumber >= PCIMaxDevice) {
+ return FALSE;
+ }
+
+ if (Slot.u.bits.FunctionNumber == 0) {
+ return TRUE;
+ }
+
+ //
+ // Non zero function numbers are only supported if the
+ // device has the PCI_MULTIFUNCTION bit set in it's header
+ //
+
+ i = Slot.u.bits.DeviceNumber;
+
+ //
+ // Read DeviceNumber, Function zero, to determine if the
+ // PCI supports multifunction devices
+ //
+
+ Slot2 = Slot;
+ Slot2.u.bits.FunctionNumber = 0;
+
+ HalpReadPCIConfig (
+ BusHandler,
+ Slot2,
+ &HeaderType,
+ FIELD_OFFSET (PCI_COMMON_CONFIG, HeaderType),
+ sizeof (UCHAR)
+ );
+
+ if (!(HeaderType & PCI_MULTIFUNCTION) || HeaderType == 0xFF) {
+ // this device doesn't exists or doesn't support MULTIFUNCTION types
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+VOID
+HalpPCIConfig (
+ IN PBUSHANDLER BusHandler,
+ IN PCI_SLOT_NUMBER Slot,
+ IN PUCHAR Buffer,
+ IN ULONG Offset,
+ IN ULONG Length,
+ IN FncConfigIO *ConfigIO
+ )
+{
+ KIRQL OldIrql;
+ ULONG i;
+ UCHAR State[20];
+ PPCIPBUSDATA BusData;
+
+ BusData = (PPCIPBUSDATA) BusHandler->BusData;
+ PCIConfigHandlers.Synchronize (BusHandler, Slot, &OldIrql, State);
+
+ while (Length) {
+ i = PCIDeref[Offset % sizeof(ULONG)][Length % sizeof(ULONG)];
+ i = ConfigIO[i] (BusData, State, Buffer, Offset);
+
+ Offset += i;
+ Buffer += i;
+ Length -= i;
+ }
+
+ PCIConfigHandlers.ReleaseSynchronzation (BusHandler, OldIrql);
+}
+
+VOID HalpPCISynchronizeType1 (
+ IN PBUSHANDLER BusHandler,
+ IN PCI_SLOT_NUMBER Slot,
+ IN PKIRQL Irql,
+ IN PPCI_TYPE1_CFG_BITS PciCfg1
+ )
+{
+ //
+ // Initialize PciCfg1
+ //
+
+ PciCfg1->u.AsULONG = 0;
+ PciCfg1->u.bits.BusNumber = BusHandler->BusNumber;
+ PciCfg1->u.bits.DeviceNumber = Slot.u.bits.DeviceNumber;
+ PciCfg1->u.bits.FunctionNumber = Slot.u.bits.FunctionNumber;
+ PciCfg1->u.bits.Enable = TRUE;
+
+ //
+ // Synchronize with PCI type1 config space
+ //
+
+ //KeAcquireSpinLock (&HalpPCIConfigLock, Irql);
+}
+
+VOID HalpPCIReleaseSynchronzationType1 (
+ IN PBUSHANDLER BusHandler,
+ IN KIRQL Irql
+ )
+{
+ PCI_TYPE1_CFG_BITS PciCfg1;
+ PPCIPBUSDATA BusData;
+
+ //
+ // Disable PCI configuration space
+ //
+
+ PciCfg1.u.AsULONG = 0;
+ BusData = (PPCIPBUSDATA) BusHandler->BusData;
+ WRITE_PORT_ULONG (BusData->Config.Type1.Address, PciCfg1.u.AsULONG);
+
+ //
+ // Release spinlock
+ //
+
+ //KeReleaseSpinLock (&HalpPCIConfigLock, Irql);
+}
+
+
+ULONG
+HalpPCIReadUcharType1 (
+ IN PPCIPBUSDATA BusData,
+ IN PPCI_TYPE1_CFG_BITS PciCfg1,
+ IN PUCHAR Buffer,
+ IN ULONG Offset
+ )
+{
+ ULONG i;
+
+ i = Offset % sizeof(ULONG);
+ PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG);
+ WRITE_PORT_ULONG (BusData->Config.Type1.Address, PciCfg1->u.AsULONG);
+ *Buffer = READ_PORT_UCHAR ((PUCHAR) (BusData->Config.Type1.Data + i));
+ return sizeof (UCHAR);
+}
+
+ULONG
+HalpPCIReadUshortType1 (
+ IN PPCIPBUSDATA BusData,
+ IN PPCI_TYPE1_CFG_BITS PciCfg1,
+ IN PUCHAR Buffer,
+ IN ULONG Offset
+ )
+{
+ ULONG i;
+
+ i = Offset % sizeof(ULONG);
+ PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG);
+ WRITE_PORT_ULONG (BusData->Config.Type1.Address, PciCfg1->u.AsULONG);
+ *((PUSHORT) Buffer) = READ_PORT_USHORT ((PUSHORT) (BusData->Config.Type1.Data + i));
+ return sizeof (USHORT);
+}
+
+ULONG
+HalpPCIReadUlongType1 (
+ IN PPCIPBUSDATA BusData,
+ IN PPCI_TYPE1_CFG_BITS PciCfg1,
+ IN PUCHAR Buffer,
+ IN ULONG Offset
+ )
+{
+ PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG);
+ WRITE_PORT_ULONG (BusData->Config.Type1.Address, PciCfg1->u.AsULONG);
+ *((PULONG) Buffer) = READ_PORT_ULONG ((PULONG) BusData->Config.Type1.Data);
+ return sizeof (ULONG);
+}
+
+
+ULONG
+HalpPCIWriteUcharType1 (
+ IN PPCIPBUSDATA BusData,
+ IN PPCI_TYPE1_CFG_BITS PciCfg1,
+ IN PUCHAR Buffer,
+ IN ULONG Offset
+ )
+{
+ ULONG i;
+
+ i = Offset % sizeof(ULONG);
+ PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG);
+ WRITE_PORT_ULONG (BusData->Config.Type1.Address, PciCfg1->u.AsULONG);
+ WRITE_PORT_UCHAR ((PUCHAR) (BusData->Config.Type1.Data + i), *Buffer);
+ return sizeof (UCHAR);
+}
+
+ULONG
+HalpPCIWriteUshortType1 (
+ IN PPCIPBUSDATA BusData,
+ IN PPCI_TYPE1_CFG_BITS PciCfg1,
+ IN PUCHAR Buffer,
+ IN ULONG Offset
+ )
+{
+ ULONG i;
+
+ i = Offset % sizeof(ULONG);
+ PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG);
+ WRITE_PORT_ULONG (BusData->Config.Type1.Address, PciCfg1->u.AsULONG);
+ WRITE_PORT_USHORT ((PUSHORT) (BusData->Config.Type1.Data + i), *((PUSHORT) Buffer));
+ return sizeof (USHORT);
+}
+
+ULONG
+HalpPCIWriteUlongType1 (
+ IN PPCIPBUSDATA BusData,
+ IN PPCI_TYPE1_CFG_BITS PciCfg1,
+ IN PUCHAR Buffer,
+ IN ULONG Offset
+ )
+{
+ PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG);
+ WRITE_PORT_ULONG (BusData->Config.Type1.Address, PciCfg1->u.AsULONG);
+ WRITE_PORT_ULONG ((PULONG) BusData->Config.Type1.Data, *((PULONG) Buffer));
+ return sizeof (ULONG);
+}
+
+
+VOID HalpPCISynchronizeType2 (
+ IN PBUSHANDLER BusHandler,
+ IN PCI_SLOT_NUMBER Slot,
+ IN PKIRQL Irql,
+ IN PPCI_TYPE2_ADDRESS_BITS PciCfg2Addr
+ )
+{
+ PCI_TYPE2_CSE_BITS PciCfg2Cse;
+ PPCIPBUSDATA BusData;
+
+ BusData = (PPCIPBUSDATA) BusHandler->BusData;
+
+ //
+ // Initialize Cfg2Addr
+ //
+
+ PciCfg2Addr->u.AsUSHORT = 0;
+ PciCfg2Addr->u.bits.Agent = (USHORT) Slot.u.bits.DeviceNumber;
+ PciCfg2Addr->u.bits.AddressBase = (USHORT) BusData->Config.Type2.Base;
+
+ //
+ // Synchronize with type2 config space - type2 config space
+ // remaps 4K of IO space, so we can not allow other I/Os to occur
+ // while using type2 config space, hence the disable_interrupts.
+ //
+
+ //KeAcquireSpinLock (&HalpPCIConfigLock, Irql);
+ //DISABLE_INTERRUPTS (); // is not MP safe
+
+ PciCfg2Cse.u.AsUCHAR = 0;
+ PciCfg2Cse.u.bits.Enable = TRUE;
+ PciCfg2Cse.u.bits.FunctionNumber = (UCHAR) Slot.u.bits.FunctionNumber;
+ PciCfg2Cse.u.bits.Key = 0xff;
+
+ //
+ // Select bus & enable type 2 configuration space
+ //
+
+ WRITE_PORT_UCHAR (BusData->Config.Type2.Forward, (UCHAR) BusHandler->BusNumber);
+ WRITE_PORT_UCHAR (BusData->Config.Type2.CSE, PciCfg2Cse.u.AsUCHAR);
+}
+
+
+VOID HalpPCIReleaseSynchronzationType2 (
+ IN PBUSHANDLER BusHandler,
+ IN KIRQL Irql
+ )
+{
+ PCI_TYPE2_CSE_BITS PciCfg2Cse;
+ PPCIPBUSDATA BusData;
+
+ //
+ // disable PCI configuration space
+ //
+
+ BusData = (PPCIPBUSDATA) BusHandler->BusData;
+
+ PciCfg2Cse.u.AsUCHAR = 0;
+ WRITE_PORT_UCHAR (BusData->Config.Type2.CSE, PciCfg2Cse.u.AsUCHAR);
+
+ //
+ // Restore interrupts, release spinlock
+ //
+
+ //ENABLE_INTERRUPTS ();
+ //KeReleaseSpinLock (&HalpPCIConfigLock, Irql);
+}
+
+
+ULONG
+HalpPCIReadUcharType2 (
+ IN PPCIPBUSDATA BusData,
+ IN PPCI_TYPE2_ADDRESS_BITS PciCfg2Addr,
+ IN PUCHAR Buffer,
+ IN ULONG Offset
+ )
+{
+ PciCfg2Addr->u.bits.RegisterNumber = (USHORT) Offset;
+ *Buffer = READ_PORT_UCHAR ((PUCHAR) PciCfg2Addr->u.AsUSHORT);
+ return sizeof (UCHAR);
+}
+
+ULONG
+HalpPCIReadUshortType2 (
+ IN PPCIPBUSDATA BusData,
+ IN PPCI_TYPE2_ADDRESS_BITS PciCfg2Addr,
+ IN PUCHAR Buffer,
+ IN ULONG Offset
+ )
+{
+ PciCfg2Addr->u.bits.RegisterNumber = (USHORT) Offset;
+ *((PUSHORT) Buffer) = READ_PORT_USHORT ((PUSHORT) PciCfg2Addr->u.AsUSHORT);
+ return sizeof (USHORT);
+}
+
+ULONG
+HalpPCIReadUlongType2 (
+ IN PPCIPBUSDATA BusData,
+ IN PPCI_TYPE2_ADDRESS_BITS PciCfg2Addr,
+ IN PUCHAR Buffer,
+ IN ULONG Offset
+ )
+{
+ PciCfg2Addr->u.bits.RegisterNumber = (USHORT) Offset;
+ *((PULONG) Buffer) = READ_PORT_ULONG ((PULONG) PciCfg2Addr->u.AsUSHORT);
+ return sizeof(ULONG);
+}
+
+
+ULONG
+HalpPCIWriteUcharType2 (
+ IN PPCIPBUSDATA BusData,
+ IN PPCI_TYPE2_ADDRESS_BITS PciCfg2Addr,
+ IN PUCHAR Buffer,
+ IN ULONG Offset
+ )
+{
+ PciCfg2Addr->u.bits.RegisterNumber = (USHORT) Offset;
+ WRITE_PORT_UCHAR ((PUCHAR) PciCfg2Addr->u.AsUSHORT, *Buffer);
+ return sizeof (UCHAR);
+}
+
+ULONG
+HalpPCIWriteUshortType2 (
+ IN PPCIPBUSDATA BusData,
+ IN PPCI_TYPE2_ADDRESS_BITS PciCfg2Addr,
+ IN PUCHAR Buffer,
+ IN ULONG Offset
+ )
+{
+ PciCfg2Addr->u.bits.RegisterNumber = (USHORT) Offset;
+ WRITE_PORT_USHORT ((PUSHORT) PciCfg2Addr->u.AsUSHORT, *((PUSHORT) Buffer));
+ return sizeof (USHORT);
+}
+
+ULONG
+HalpPCIWriteUlongType2 (
+ IN PPCIPBUSDATA BusData,
+ IN PPCI_TYPE2_ADDRESS_BITS PciCfg2Addr,
+ IN PUCHAR Buffer,
+ IN ULONG Offset
+ )
+{
+ PciCfg2Addr->u.bits.RegisterNumber = (USHORT) Offset;
+ WRITE_PORT_ULONG ((PULONG) PciCfg2Addr->u.AsUSHORT, *((PULONG) Buffer));
+ return sizeof(ULONG);
+}
+
+NTSTATUS
+HalpAssignPCISlotResources (
+ IN ULONG BusNumber,
+ IN ULONG Slot,
+ IN OUT PCM_RESOURCE_LIST *pAllocatedResources
+ )
+/*++
+
+Routine Description:
+
+ Reads the targeted device to determine it's required resources.
+ Calls IoAssignResources to allocate them.
+ Sets the targeted device with it's assigned resoruces
+ and returns the assignments to the caller.
+
+Arguments:
+
+Return Value:
+
+ STATUS_SUCCESS or error
+
+--*/
+{
+ PBUSHANDLER BusHandler;
+ UCHAR buffer[PCI_COMMON_HDR_LENGTH];
+ UCHAR buffer2[PCI_COMMON_HDR_LENGTH];
+ PPCI_COMMON_CONFIG PciData, PciData2;
+ PCI_SLOT_NUMBER PciSlot;
+ ULONG i, j, length, type;
+ PHYSICAL_ADDRESS Address;
+ PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescriptor;
+ static PCM_RESOURCE_LIST CmResList;
+
+ BusHandler = HalpGetPciBusHandler (BusNumber);
+ if (!BusHandler) {
+ return 0;
+ }
+
+ *pAllocatedResources = NULL;
+
+ PciData = (PPCI_COMMON_CONFIG) buffer;
+ PciData2 = (PPCI_COMMON_CONFIG) buffer2;
+ PciSlot = *((PPCI_SLOT_NUMBER) &Slot);
+ BusNumber = BusHandler->BusNumber;
+
+ //
+ // Read the PCI device's configuration
+ //
+
+ HalpReadPCIConfig (BusHandler, PciSlot, PciData, 0, PCI_COMMON_HDR_LENGTH);
+ if (PciData->VendorID == PCI_INVALID_VENDORID) {
+ return STATUS_NO_SUCH_DEVICE;
+ }
+
+ //
+ // Make a copy of the device's current settings
+ //
+
+ RtlMoveMemory (buffer2, buffer, PCI_COMMON_HDR_LENGTH);
+
+ //
+ // Set resources to all bits on to see what type of resources
+ // are required.
+ //
+
+ for (j=0; j < PCI_TYPE0_ADDRESSES; j++) {
+ PciData->u.type0.BaseAddresses[j] = 0xFFFFFFFF;
+ }
+ PciData->u.type0.ROMBaseAddress = 0xFFFFFFFF;
+
+ PciData->Command &= ~(PCI_ENABLE_IO_SPACE | PCI_ENABLE_MEMORY_SPACE);
+ PciData->u.type0.ROMBaseAddress &= ~PCI_ROMADDRESS_ENABLED;
+ HalpWritePCIConfig (BusHandler, PciSlot, PciData, 0, PCI_COMMON_HDR_LENGTH);
+ HalpReadPCIConfig (BusHandler, PciSlot, PciData, 0, PCI_COMMON_HDR_LENGTH);
+ HalpPCIPin2Line (BusHandler, RootHandler, PciSlot, PciData);
+
+ //
+ // Restore the device's settings in case we don't complete
+ //
+
+ HalpWritePCIConfig (BusHandler, PciSlot, buffer2, 0, PCI_COMMON_HDR_LENGTH);
+
+ //
+ // Build a CmResource descriptor list for the device
+ //
+
+ if (!CmResList) {
+ // NtLdr pool is only allocated and never freed. Allocate the
+ // buffer once, and from then on just use the buffer over
+
+ CmResList = ExAllocatePool (PagedPool,
+ sizeof (CM_RESOURCE_LIST) +
+ sizeof (CM_PARTIAL_RESOURCE_DESCRIPTOR) * (PCI_TYPE0_ADDRESSES + 2)
+ );
+ }
+
+ if (!CmResList) {
+ return STATUS_NO_MEMORY;
+ }
+
+ RtlZeroMemory (CmResList,
+ sizeof (CM_RESOURCE_LIST) +
+ sizeof (CM_PARTIAL_RESOURCE_DESCRIPTOR) * (PCI_TYPE0_ADDRESSES + 2)
+ );
+
+ *pAllocatedResources = CmResList;
+ CmResList->List[0].InterfaceType = PCIBus;
+ CmResList->List[0].BusNumber = BusNumber;
+
+ CmDescriptor = CmResList->List[0].PartialResourceList.PartialDescriptors;
+ if (PciData->u.type0.InterruptPin) {
+
+ CmDescriptor->Type = CmResourceTypeInterrupt;
+ CmDescriptor->ShareDisposition = CmResourceShareShared;
+ CmDescriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
+
+ // in the loader interrupts aren't actually enabled, so just
+ // pass back the untranslated values
+ CmDescriptor->u.Interrupt.Level = PciData->u.type0.InterruptLine;
+ CmDescriptor->u.Interrupt.Vector = PciData->u.type0.InterruptLine;
+ CmDescriptor->u.Interrupt.Affinity = 1;
+
+ CmResList->List[0].PartialResourceList.Count++;
+ CmDescriptor++;
+ }
+
+ // clear last address index + 1
+ PciData->u.type0.BaseAddresses[PCI_TYPE0_ADDRESSES] = 0;
+ if (PciData2->u.type0.ROMBaseAddress & PCI_ROMADDRESS_ENABLED) {
+
+ // put rom address in last index+1
+ PciData->u.type0.BaseAddresses[PCI_TYPE0_ADDRESSES] =
+ PciData->u.type0.ROMBaseAddress & ~PCI_ADDRESS_IO_SPACE;
+
+ PciData2->u.type0.BaseAddresses[PCI_TYPE0_ADDRESSES] =
+ PciData2->u.type0.ROMBaseAddress & ~PCI_ADDRESS_IO_SPACE;
+ }
+
+ for (j=0; j < PCI_TYPE0_ADDRESSES + 1; j++) {
+ if (PciData->u.type0.BaseAddresses[j]) {
+ i = PciData->u.type0.BaseAddresses[j];
+
+ // scan for first set bit, that's the length & alignment
+ length = 1 << (i & PCI_ADDRESS_IO_SPACE ? 2 : 4);
+ Address.HighPart = 0;
+ Address.LowPart = PciData2->u.type0.BaseAddresses[j] & ~(length-1);
+ while (!(i & length) && length) {
+ length <<= 1;
+ }
+
+ // translate bus specific address
+ type = (i & PCI_ADDRESS_IO_SPACE) ? 0 : 1;
+ if (!HalTranslateBusAddress (
+ PCIBus,
+ BusNumber,
+ Address,
+ &type,
+ &Address )) {
+ // translation failed, skip it
+ continue;
+ }
+
+ // fill in CmDescriptor to return
+ if (type == 0) {
+ CmDescriptor->Type = CmResourceTypePort;
+ CmDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
+ CmDescriptor->Flags = CM_RESOURCE_PORT_IO;
+ CmDescriptor->u.Port.Length = length;
+ CmDescriptor->u.Port.Start = Address;
+ } else {
+ CmDescriptor->Type = CmResourceTypeMemory;
+ CmDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
+ CmDescriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
+ CmDescriptor->u.Memory.Length = length;
+ CmDescriptor->u.Memory.Start = Address;
+
+ if (j == PCI_TYPE0_ADDRESSES) {
+ // this is a ROM address
+ CmDescriptor->Flags = CM_RESOURCE_MEMORY_READ_ONLY;
+ }
+ }
+
+ CmResList->List[0].PartialResourceList.Count++;
+ CmDescriptor++;
+
+ if (i & PCI_TYPE_64BIT) {
+ // skip upper half of 64 bit address.
+ j++;
+ }
+ }
+ }
+
+ return STATUS_SUCCESS;
+}
diff --git a/private/ntos/boot/lib/i386/ixphwsup.c b/private/ntos/boot/lib/i386/ixphwsup.c
new file mode 100644
index 000000000..d32344ce6
--- /dev/null
+++ b/private/ntos/boot/lib/i386/ixphwsup.c
@@ -0,0 +1,119 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ ixphwsup.c
+
+Abstract:
+
+ This module contains the IopXxx routines for the NT I/O system that
+ are hardware dependent. Were these routines not hardware dependent,
+ they would normally reside in the internal.c module.
+
+Author:
+
+ Darryl E. Havens (darrylh) 11-Apr-1990
+
+Environment:
+
+ Kernel mode, local to I/O system
+
+Revision History:
+
+
+--*/
+
+#include "bootx86.h"
+#include "arc.h"
+#include "ixfwhal.h"
+#include "eisa.h"
+
+
+PADAPTER_OBJECT
+IopAllocateAdapter(
+ IN ULONG MapRegistersPerChannel,
+ IN PVOID AdapterBaseVa,
+ IN PVOID ChannelNumber
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and initializes an adapter object to represent an
+ adapter or a DMA controller on the system. If no map registers are required
+ then a standalone adapter object is allocated with no master adapter.
+
+ If map registers are required, then a master adapter object is used to
+ allocate the map registers. For Isa systems these registers are really
+ phyically contiguous memory pages.
+
+Arguments:
+
+ MapRegistersPerChannel - Specifies the number of map registers that each
+ channel provides for I/O memory mapping.
+
+ AdapterBaseVa - Address of the the DMA controller.
+
+ ChannelNumber - Unused.
+
+Return Value:
+
+ The function value is a pointer to the allocate adapter object.
+
+--*/
+
+{
+
+ PADAPTER_OBJECT AdapterObject;
+ CSHORT Size;
+
+ //
+ // Determine the size of the adapter.
+ //
+
+ Size = sizeof( ADAPTER_OBJECT );
+
+ //
+ // Now create the adapter object.
+ //
+
+ AdapterObject = FwAllocateHeap(Size);
+
+ //
+ // If the adapter object was successfully created, then attempt to insert
+ // it into the the object table.
+ //
+
+ if (AdapterObject) {
+
+ RtlZeroMemory(AdapterObject, Size);
+
+ //
+ // Initialize the adapter object itself.
+ //
+
+ AdapterObject->Type = IO_TYPE_ADAPTER;
+ AdapterObject->Size = Size;
+ AdapterObject->MapRegistersPerChannel = 0;
+ AdapterObject->AdapterBaseVa = AdapterBaseVa;
+ AdapterObject->PagePort = NULL;
+ AdapterObject->AdapterInUse = FALSE;
+
+ } else {
+
+ //
+ // An error was incurred for some reason. Set the return value
+ // to NULL.
+ //
+
+ return(NULL);
+ }
+
+ return AdapterObject;
+
+}
+
+
diff --git a/private/ntos/boot/lib/i386/lnkconst.asm b/private/ntos/boot/lib/i386/lnkconst.asm
new file mode 100644
index 000000000..aa4b19b12
--- /dev/null
+++ b/private/ntos/boot/lib/i386/lnkconst.asm
@@ -0,0 +1,18 @@
+
+
+
+.386p
+
+_DATA segment dword use32 public 'DATA'
+
+ extrn osloader_EXPORTS:DWORD
+ extrn header:DWORD
+
+ public _osloader_EXPORTS
+ public _header
+
+_osloader_EXPORTS DD osloader_EXPORTS
+_header DD header
+
+_DATA ends
+ end
diff --git a/private/ntos/boot/lib/i386/machine.c b/private/ntos/boot/lib/i386/machine.c
new file mode 100644
index 000000000..45524df56
--- /dev/null
+++ b/private/ntos/boot/lib/i386/machine.c
@@ -0,0 +1,390 @@
+/*++
+
+Module Name:
+
+ machine.c
+
+Author:
+
+ Thomas Parslow [TomP] Feb-13-1990
+ Reworked substantially in Tokyo 7-July-95 (tedm)
+
+Abstract:
+
+ Machine/hardware dependent routines reside within this module/file.
+ (Video is in disp_tm.c and disp_gm.c.)
+
+--*/
+
+
+#include "arccodes.h"
+#include "bootx86.h"
+
+#define FLOPPY_CONTROL_REGISTER (PUCHAR)0x3f2
+
+
+////////////////////////////////////////////////////////////
+// //
+// D I S K I/O S U P P O R T S E C T I O N //
+// //
+////////////////////////////////////////////////////////////
+
+
+//
+// Currently Supported Disk I/O Functions
+//
+
+#define RESET_DISK_SYSTEM 00
+#define RESET_HARD_DISK_SYSTEM 13
+#define READ_SECTOR 02
+#define WRITE_SECTOR 03
+
+#define FLOPPY_RETRY 4
+#define HARDDISK_RETRY 2
+
+
+ARC_STATUS
+MdGetPhysicalSectors(
+ IN USHORT Drive,
+ IN USHORT HeadNumber,
+ IN USHORT TrackNumber,
+ IN USHORT SectorNumber,
+ IN USHORT NumberOfSectors,
+ PUCHAR PointerToBuffer
+ )
+/*++
+
+Routine Description:
+
+ Does a call-back to the SU module through one of the entries
+ in the external services table.
+
+Arguments:
+
+ Drive - Supplies disk drive to read sectors from .
+
+ 0x00 - 1st floppy drive
+ 0x01 - 2nd floppy drive
+
+ 0x80 - 1st hard drive
+ 0x81 - 2nd hard drive
+
+ HeadNumber - Supplies the zero based head number to read sector from.
+
+ TrackNumber - Supplies the zero based track number to read the sector from .
+
+ SectorNumber - Supplies the one based starting sector number.
+
+ NumberOfSectors - Supplies the number of sectors to read
+
+ PointerToBuffer - Supplies Virtual Address of buffer to write sectors into.
+ N.B. This address MUST be below the 1MB boundary, as BIOS
+ cannot reach it if it isn't. This routine will
+ care of splitting the
+
+Returns:
+
+ ESUCCESS - operation successful
+ EIO - I/O error
+
+
+--*/
+{
+ ARC_STATUS Status;
+ int Retry;
+ int MaxRetry;
+
+// DBG1( CHECKPOINT("MdGetPhysSec"); )
+
+ ASSERT((ULONG)PointerToBuffer < 0x100000);
+
+ // Note, even though args are short, they are pushed on the stack with
+ // 32bit alignment so the effect on the stack seen by the 16bit real
+ // mode code is the same as if we were pushing longs here.
+ //
+
+ if (NumberOfSectors == 0) {
+ return(ESUCCESS);
+ }
+
+ // prevent cylinder # from wrapping
+
+ if(TrackNumber > 1023) {
+ return(E2BIG);
+ }
+
+// MaxRetry = Drive < 128 ? FLOPPY_RETRY : HARDDISK_RETRY;
+ MaxRetry = 10;
+
+ Retry=0;
+ do {
+
+#if 0
+ BlPrint("Requesting: d=%x, h=%x t=%x sn=%x num=%x buf=%lx\n",
+ Drive,HeadNumber,TrackNumber,SectorNumber,NumberOfSectors,
+ PointerToBuffer);
+#endif
+
+ Status = GET_SECTOR(
+ READ_SECTOR,
+ Drive,
+ HeadNumber,
+ TrackNumber,
+ SectorNumber,
+ NumberOfSectors,
+ PointerToBuffer
+ );
+
+ if (Status) {
+// BlPrint("Error %lx from BIOS, resetting\n",Status);
+ MdResetDiskSystem(Drive);
+ }
+
+ } while ( (Status) && (Retry++ < MaxRetry) );
+ return Status;
+}
+
+#if defined(ELTORITO)
+ARC_STATUS
+MdEddsGetPhysicalSectors(
+ IN USHORT Drive,
+ IN ULONG LBALow,
+ IN ULONG LBAHigh,
+ IN USHORT NumberOfBlocks,
+ PUCHAR PointerToBuffer
+ )
+/*++
+
+Routine Description:
+
+ Does a call-back to the SU module through one of the entries
+ in the external services table.
+
+Arguments:
+
+ Drive - Supplies disk drive to read sectors from .
+
+ LBA - Supplies the zero Logical Block Address to start reading from.
+
+ NumberOfBlocks - Supplies the number of logical blocks to read
+
+ PointerToBuffer - Supplies Virtual Address of buffer to write sectors into.
+ N.B. This address MUST be below the 1MB boundary, as BIOS
+ cannot reach it if it isn't. This routine will
+ care of splitting the
+
+Returns:
+
+ ESUCCESS - operation successful
+ EIO - I/O error
+
+
+--*/
+{
+ ARC_STATUS Status;
+ int Retry;
+ int MaxRetry;
+
+ ASSERT((ULONG)PointerToBuffer < 0x100000);
+
+ // Note, even though args are short, they are pushed on the stack with
+ // 32bit alignment so the effect on the stack seen by the 16bit real
+ // mode code is the same as if we were pushing longs here.
+ //
+
+ if (NumberOfBlocks == 0) {
+ return(ESUCCESS);
+ }
+
+ MaxRetry = 10;
+
+ Retry=0;
+ do {
+
+ Status = GET_EDDS_SECTOR(
+ Drive,
+ LBALow,
+ LBAHigh,
+ NumberOfBlocks,
+ PointerToBuffer
+ );
+
+// if (Status) {
+// BlPrint("Error %lx from BIOS, resetting\n",Status);
+// MdResetDiskSystem(Drive);
+// }
+
+ } while ( (Status) && (Retry++ < MaxRetry) );
+ return Status;
+}
+#endif
+
+ARC_STATUS
+MdPutPhysicalSectors(
+ IN USHORT Drive,
+ IN USHORT HeadNumber,
+ IN USHORT TrackNumber,
+ IN USHORT SectorNumber,
+ IN USHORT NumberOfSectors,
+ PUCHAR PointerToBuffer
+ )
+/*++
+
+Routine Description:
+
+ Does a call-back to the SU module through one of the entries
+ in the external services table.
+
+Arguments:
+
+ Drive - Supplies disk drive to write sectors to
+
+ 0x00 - 1st floppy drive
+ 0x01 - 2nd floppy drive
+
+ 0x80 - 1st hard drive
+ 0x81 - 2nd hard drive
+
+ HeadNumber - Supplies the zero based head number to write sector to.
+
+ TrackNumber - Supplies the zero based track number to write the sector to.
+
+ SectorNumber - Supplies the one based starting sector number.
+
+ NumberOfSectors - Supplies the number of sectors to write
+
+ PointerToBuffer - Supplies Virtual Address of buffer containing data to
+ write.
+ N.B. This address MUST be below the 1MB boundary, as BIOS
+ cannot reach it if it isn't.
+
+Returns:
+
+ ESUCCESS - operation successful
+ EIO - I/O error
+
+
+--*/
+{
+ ARC_STATUS Status;
+ int Retry;
+ int MaxRetry;
+
+// BlPrint("Requesting: d=%x, h=%x t=%x sn=%x num=%x buf=%lx\n",
+// Drive,HeadNumber,TrackNumber,SectorNumber,NumberOfSectors,
+// PointerToBuffer);
+
+// DBG1( CHECKPOINT("MdPutPhysSec"); )
+
+ // Note, even though args are short, they are pushed on the stack with
+ // 32bit alignment so the effect on the stack seen by the 16bit real
+ // mode code is the same as if we were pushing longs here.
+ //
+
+ if (NumberOfSectors == 0) {
+ return(ESUCCESS);
+ }
+
+ // prevent cylinder # from wrapping
+
+ if(TrackNumber > 1023) {
+ return(E2BIG);
+ }
+
+ MaxRetry = Drive < 128 ? FLOPPY_RETRY : HARDDISK_RETRY;
+
+ Retry=0;
+ do {
+
+ Status = GET_SECTOR(
+ WRITE_SECTOR,
+ Drive,
+ HeadNumber,
+ TrackNumber,
+ SectorNumber,
+ NumberOfSectors,
+ PointerToBuffer
+ );
+
+ if (Status) {
+ MdResetDiskSystem(Drive);
+ }
+
+ } while ( (Status) && (Retry++ < MaxRetry) );
+ return Status;
+}
+
+
+VOID
+MdShutoffFloppy(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Shuts off the floppy drive motor
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UCHAR Value;
+
+ WRITE_PORT_UCHAR( FLOPPY_CONTROL_REGISTER, 0xC );
+
+}
+
+
+NTSTATUS
+MdResetDiskSystem(
+ USHORT Drive
+ )
+/*++
+
+
+Routine Description:
+
+ Reset the specified drive. Generally used after an error is returned
+ by the GetSector routine.
+
+Arguments:
+
+ Drive - The drive number to reset.
+
+ 0x00 - 1st floppy drive
+ 0x01 - 2nd floppy drive
+
+ 0x80 - 1st hard drive
+ 0x81 - 2nd hard drive
+
+Returns:
+
+ NTSTATUS error code. Zero if no error.
+
+
+--*/
+{
+ NTSTATUS Status;
+
+ Status = RESET_DISK((USHORT)((Drive < 128) ? RESET_DISK_SYSTEM : RESET_HARD_DISK_SYSTEM),
+ Drive,
+ 0,
+ 0,
+ 0,
+ 0,
+ NULL);
+
+ return Status;
+}
+
+
+// END OF FILE //
diff --git a/private/ntos/boot/lib/i386/mca.h b/private/ntos/boot/lib/i386/mca.h
new file mode 100644
index 000000000..554f9a2c1
--- /dev/null
+++ b/private/ntos/boot/lib/i386/mca.h
@@ -0,0 +1,240 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+Copyright (c) 1991 NCR Corporation
+
+Module Name:
+
+ mca.h
+
+Abstract:
+
+ This module contains the defines and structure definitions for
+ Micro Channel machines.
+
+Author:
+
+ David Risner (o-ncrdr) 21-Jul-1991
+
+Revision History:
+
+
+--*/
+
+#ifndef _MCA_
+#define _MCA_
+
+
+
+
+
+//
+// Define the DMA page register structure (for 8237 compatibility)
+//
+#ifndef _EISA_
+typedef struct _DMA_PAGE{
+ UCHAR Reserved1;
+ UCHAR Channel2;
+ UCHAR Channel3;
+ UCHAR Channel1;
+ UCHAR Reserved2[3];
+ UCHAR Channel0;
+ UCHAR Reserved3;
+ UCHAR Channel6;
+ UCHAR Channel7;
+ UCHAR Channel5;
+ UCHAR Reserved4[3];
+ UCHAR RefreshPage;
+} DMA_PAGE, *PDMA_PAGE;
+
+//
+// Define DMA 1 address and count structure (for 8237 compatibility)
+//
+
+typedef struct _DMA1_ADDRESS_COUNT {
+ UCHAR DmaBaseAddress;
+ UCHAR DmaBaseCount;
+} DMA1_ADDRESS_COUNT, *PDMA1_ADDRESS_COUNT;
+
+//
+// Define DMA 2 address and count structure (for 8237 compatibility)
+//
+
+typedef struct _DMA2_ADDRESS_COUNT {
+ UCHAR DmaBaseAddress;
+ UCHAR Reserved1;
+ UCHAR DmaBaseCount;
+ UCHAR Reserved2;
+} DMA2_ADDRESS_COUNT, *PDMA2_ADDRESS_COUNT;
+
+//
+// Define DMA 1 control register structure (for 8237 compatibility)
+//
+
+typedef struct _DMA1_CONTROL {
+ DMA1_ADDRESS_COUNT DmaAddressCount[4];
+ UCHAR DmaStatus;
+ UCHAR DmaRequest;
+ UCHAR SingleMask;
+ UCHAR Mode;
+ UCHAR ClearBytePointer;
+ UCHAR MasterClear;
+ UCHAR ClearMask;
+ UCHAR AllMask;
+} DMA1_CONTROL, *PDMA1_CONTROL;
+
+//
+// Define DMA 2 control register structure (for 8237 compatibility)
+//
+
+typedef struct _DMA2_CONTROL {
+ DMA2_ADDRESS_COUNT DmaAddressCount[4];
+ UCHAR DmaStatus;
+ UCHAR Reserved1;
+ UCHAR DmaRequest;
+ UCHAR Reserved2;
+ UCHAR SingleMask;
+ UCHAR Reserved3;
+ UCHAR Mode;
+ UCHAR Reserved4;
+ UCHAR ClearBytePointer;
+ UCHAR Reserved5;
+ UCHAR MasterClear;
+ UCHAR Reserved6;
+ UCHAR ClearMask;
+ UCHAR Reserved7;
+ UCHAR AllMask;
+ UCHAR Reserved8;
+} DMA2_CONTROL, *PDMA2_CONTROL;
+#endif //_EISA_
+
+typedef struct _MCA_DMA_CONTROLLER {
+ UCHAR DmaFunctionLsb; // Offset 0x018
+ UCHAR DmaFunctionMsb; // Offset 0x019
+ UCHAR DmaFunctionData; // Offset 0x01a
+ UCHAR Reserved01;
+ UCHAR ScbAttentionPort; // Offset 0x01c
+ UCHAR ScbCommandPort; // Offset 0x01d
+ UCHAR Reserved02;
+ UCHAR ScbStatusPort; // Offset 0x01f
+} MCA_DMA_CONTROLLER, *PMCA_DMA_CONTROLLER;
+
+//
+// Define Programmable Option Select register set
+//
+
+typedef struct _PROGRAMMABLE_OPTION_SELECT {
+ UCHAR AdapterIdLsb;
+ UCHAR AdapterIdMsb;
+ UCHAR OptionSelectData1;
+ UCHAR OptionSelectData2;
+ UCHAR OptionSelectData3;
+ UCHAR OptionSelectData4;
+ UCHAR SubaddressExtensionLsb;
+ UCHAR SubaddressExtensionMsb;
+} PROGRAMMABLE_OPTION_SELECT, *PPROGRAMMABLE_OPTION_SELECT;
+
+//
+// Define Micro Channel i/o address map
+//
+
+typedef struct _MCA_CONTROL {
+ DMA1_CONTROL Dma1BasePort; // Offset 0x000
+ UCHAR Reserved0[8];
+ UCHAR ExtendedDmaBasePort[8]; // Offset 0x018
+ UCHAR Interrupt1ControlPort0; // Offset 0x020
+ UCHAR Interrupt1ControlPort1; // Offset 0x021
+ UCHAR Reserved1[64 - 1];
+ UCHAR SystemControlPortB; // Offset 0x061
+ UCHAR Reserved2[32 - 2];
+ DMA_PAGE DmaPageLowPort; // Offset 0x080
+ UCHAR Reserved3;
+ UCHAR CardSelectedFeedback; // Offset 0x091
+ UCHAR SystemControlPortA; // Offset 0x092
+ UCHAR Reserved4;
+ UCHAR SystemBoardSetup; // Offset 0x094
+ UCHAR Reserved5;
+ UCHAR AdapterSetup; // Offset 0x096
+ UCHAR AdapterSetup2; // Offset 0x097
+ UCHAR Reserved7[8];
+ UCHAR Interrupt2ControlPort0; // Offset 0x0a0
+ UCHAR Interrupt2ControlPort1; // Offset 0x0a1
+ UCHAR Reserved8[32-2];
+ DMA2_CONTROL Dma2BasePort; // Offset 0x0c0
+ UCHAR Reserved9[32];
+ PROGRAMMABLE_OPTION_SELECT Pos; // Offset 0x100
+} MCA_CONTROL, *PMCA_CONTROL;
+
+//
+// Define POS adapter setup equates for use with AdapterSetup field above
+//
+
+#define MCA_ADAPTER_SETUP_ON 0x008
+#define MCA_ADAPTER_SETUP_OFF 0x000
+
+//
+// Define DMA Extended Function register
+//
+
+typedef struct _DMA_EXTENDED_FUNCTION {
+ UCHAR ChannelNumber : 3;
+ UCHAR Reserved : 1;
+ UCHAR Command : 4;
+} DMA_EXTENDED_FUNCTION, *PDMA_EXTENDED_FUNCTION;
+
+//
+// Define Command values
+//
+
+#define WRITE_IO_ADDRESS 0x00 // write I/O address reg
+#define WRITE_MEMORY_ADDRESS 0x20 // write memory address reg
+#define READ_MEMORY_ADDRESS 0x30 // read memory address reg
+#define WRITE_TRANSFER_COUNT 0x40 // write transfer count reg
+#define READ_TRANSFER_COUNT 0x50 // read transfer count reg
+#define READ_STATUS 0x60 // read status register
+#define WRITE_MODE 0x70 // write mode register
+#define WRITE_ARBUS 0x80 // write arbus register
+#define SET_MASK_BIT 0x90 // set bit in mask reg
+#define CLEAR_MASK_BIT 0xa0 // clear bit in mask reg
+#define MASTER_CLEAR 0xd0 // master clear
+
+//
+// Define DMA Extended Mode register
+//
+
+typedef struct _DMA_EXTENDED_MODE_MCA {
+ UCHAR ProgrammedIo : 1; // 0 = do not use programmed i/o address
+ UCHAR Reserved0 : 1;
+ UCHAR DmaOpcode : 1; // 0 = verify memory, 1 = data transfer
+ UCHAR TransferDirection : 1; // 0 = read memory, 1 = write memory
+ UCHAR Reserved1 : 2;
+ UCHAR DmaWidth : 1; // 0 = 8bit, 1 = 16bit
+ UCHAR Reserved2 : 1;
+} DMA_EXTENDED_MODE_MCA, *PDMA_EXTENDED_MODE_MCA;
+
+//
+// DMA Extended Mode equates for use with the _DMA_EXTENDED_MODE structure.
+//
+
+#define DMA_EXT_USE_PIO 0x01
+#define DMA_EXT_NO_PIO 0x00
+#define DMA_EXT_VERIFY 0x00
+#define DMA_EXT_DATA_XFER 0x01
+#define DMA_EXT_WIDTH_8_BIT 0x00
+#define DMA_EXT_WIDTH_16_BIT 0x01
+
+//
+// DMA mode option definitions
+//
+
+#define DMA_MODE_READ 0x00 // read data into memory
+#define DMA_MODE_WRITE 0x08 // write data from memory
+#define DMA_MODE_VERIFY 0x00 // verify data
+#define DMA_MODE_TRANSFER 0x04 // transfer data
+
+//
+// DMA extended mode constants
+//
+
+#define MAX_MCA_DMA_CHANNEL_NUMBER 0x07 // maximum MCA DMA channel number
+#endif
diff --git a/private/ntos/boot/lib/i386/mdequ.inc b/private/ntos/boot/lib/i386/mdequ.inc
new file mode 100644
index 000000000..14f9d169c
--- /dev/null
+++ b/private/ntos/boot/lib/i386/mdequ.inc
@@ -0,0 +1,224 @@
+;----------------------------------------------------------------------------
+; MDEQU.INC - General equate file
+;
+; Microsoft Confidential
+; Copyright (C) Microsoft Corporation 1992-1993
+; All Rights Reserved.
+;
+; History:
+; 20-Jul-92 chuckst Initial version.
+;
+; VxD History:
+; 21-Apr-93 jeffpar Adapted for MRCI.386
+;----------------------------------------------------------------------------
+
+
+; Define the following variable to generate the standalone
+; version of DBLSPACE.BIN, which loads as a device driver under
+; MS-DOS 5.0 or greater.
+;
+;STANDALONE equ 0ffffh
+
+
+; Note that the final version of DblSpace switched to 6-8-12 encoding
+; which assumes the following scheme:
+;
+; ccccccc10 raw char ( < 128)
+; ccccccc01 raw char ( >=128)
+; oooooo00 6-bit offset
+; oooooooo011 8-bit offset
+; oooooooooooo111 12-bit offset
+;
+
+MAX_6BIT_OFFSET equ 63
+MAX_8BIT_OFFSET equ (MAX_6BIT_OFFSET+256)
+MAX_12BIT_OFFSET equ ((MAX_8BIT_OFFSET+4096)-1)
+SPECIAL_EOS equ 4415 ;End of Sector code
+.errnz MAX_12BIT_OFFSET+1 ne SPECIAL_EOS
+
+MAX_LENGTH_BITS equ 17
+MAX_TRUE_LENGTH equ 512
+MAX_RAW_LENGTH equ (MAX_TRUE_LENGTH-2) ; lengths are stored 2 less than true length
+
+
+fatal_error_0 equ 0 ; re-entered at strat
+fatal_error_1 equ 1 ; irpt without 1 strat
+fatal_error_2 equ 2 ; 2 irpts per strat
+fatal_error_3 equ 3 ; get_sqztor, number too low
+fatal_error_4 equ 4 ; put_sqztor, number too low
+fatal_error_5 equ 5 ; get_sqztor, number too high
+fatal_error_6 equ 6 ; put_sqztor, number too high
+fatal_error_7 equ 7 ; DOS system I/O too high
+fatal_error_8 equ 8 ; DOS system I/O too low
+fatal_error_9 equ 9 ; HEAP I/O too high
+fatal_error_10 equ 10 ; HEAP I/O too low
+fatal_error_11 equ 11 ; BITFAT I/O too high
+fatal_error_12 equ 12 ; BITFAT I/O too low
+fatal_error_13 equ 13 ; MDFAT I/O too high
+fatal_error_14 equ 14 ; MDFAT I/O too low
+fatal_error_15 equ 15 ; Bad signature check on CVF fragment list
+fatal_error_16 equ 16 ; Invalid int2f subfn (for forcing popup)
+fatal_error_17 equ 17 ; free to free sqztor
+fatal_error_18 equ 18 ; unfree to used sqztor
+
+;;
+;; Equates
+;;
+
+multMagicdrv equ 4a11h ; Int2f multiplex number
+
+DRVMAP_CPR_BIT equ 80h ; bit indicating mounted CVF in drv_map array
+
+cr = 13
+lf = 10
+tab = 9
+ctrlz = 1ah
+
+CVF_SEQ_SWAP equ 0 ; Sequence number which implies SWAP
+CVF_SEQ_MAX equ 255 ; Maximum allowable sequence number
+
+MAX_ACTIVATES equ 24 ; 26 drive letters, less two floppies
+
+BIG_CLUSTER equ 8192 ;Size of BIG cluster (8K)
+SMALL_CLUSTER equ 4096 ;Size of SMALL cluster (4K)
+
+BPTR equ BYTE PTR
+
+MAX_FULL equ 32 ;;64;Minimum of free sectors b4 we declare this disk as full
+MAX_WARN equ 256 ;Minimum free sectors to generate an 'almost full' warning
+
+;; temp_buf_list values
+ORIGINAL_DATA equ 1 ;This sector has an original data
+NEW_DATA equ 2 ;This sector contains new data
+
+MAX_DEMO_HIWORD_SIZE equ 48 ;Maximum high word for demo file
+MAX_SECTOR_SIZE equ 2048 ;Maximum host sector size (2K)
+
+IO_PART_SPACE equ 2048 ;Page size for sqztor table
+PART_CLUSTER_SIZE_POW2 equ 9 ;How many clusters per one page (DWORD per cluster)
+
+BIT_FAT_SPACE equ 2048 ;Page size of sec_list table (free space)
+SECTORS_PER_BIT_FAT_POW2 equ 14 ;In power 2 if sectors
+SECTORS_PER_BIT_FAT equ 16384 ;Number of bits (sectors) in one page
+
+;BPB equates
+DBL_SIGN equ 512 ;Where the 'DBL' signature can be located
+RETRACT_SIGNATURE equ 1 ; signature is last full sector, ie:
+; ; end of file (rounded down to sector)
+; ; minus 1
+
+RH equ ds:[bx] ;Addressability to Request Header structure
+
+MAX_DISK_UNITS equ 15 ;Maximumm of extended disk we can handle
+
+cMINFILEFRAGMENTS equ 50 ;Minimum file fragment heap size
+cDEFFILEFRAGMENTS equ 700 ;Default " " " "
+cMAXFILEFRAGMENTS equ 10000 ;Maximum " " " "
+
+; cluster_to_Sqztor equates. See globals definition
+NO_FLAGS_MASK equ 001FH ;Just the entry, without flags
+RESERVED1_MASK equ 0020H ;Reserved bit just after 21-bit sector#
+PHYSICAL_SIZE_MASK equ 03C0H ;Only the physical size bits
+PHYSICAL_SIZE_OFFSET equ 6 ;THe physical size bits offset
+PLAINTEXT_MASK equ 3C00H ;Only the plaintext size bits
+PLAINTEXT_OFFSET equ 10 ;Plaintext size bits offset
+UNCODED_CLUSTER_MASK equ 4000H ;Uncompress cluster bit
+USED_CLUSTER_MASK equ 8000H ;Used cluster bit
+
+PARA_SIZE_POW2 equ 4 ;Number of bytes in one 8088 paragraph
+STACK_SIZE equ 768 ;Size of our stack
+
+; Device driver equates
+READ_DISK_CMD equ 4
+WRITE_DISK_CMD equ 8
+
+STAT_WRITP equ 8000H ;Write protect violation
+STAT_DFULL equ 8027h ;Disk full error
+STAT_NRDY equ 8002H ;Device not ready
+STAT_NOCOM equ 8003H ;Unkown command
+STAT_CRC equ 8004H ;CRC error
+STAT_SNF equ 8008H ;sector not found error
+STAT_SEEK equ 8006H ;Seek error
+STAT_WRITE equ 800AH ;Write FAULT
+STAT_READ equ 800BH ;Read fault
+STAT_GEN equ 800CH ;General failore
+
+DOS EQU 21H ;DOS request INT
+DOS_PCHR EQU 02H ;print character function
+
+;Constants for compression/Decompression alg.
+MAX_BITS equ 12 ;Maximum bits (2048 entries)
+TABLESIZE equ 2048 ;Hash table size
+
+shCHUNK equ 9
+cbCHUNK equ (1 shl shCHUNK) ; size of a 'chunk'
+.errnz cbCHUNK ne 512
+cbLONGCOPY equ 32 ; do extra checking for string copies >= this
+
+
+;Generic IOCTL return codes
+NO_ERROR equ 0 ;No error
+LETTER_BOUNDRY_ERROR equ 1 ;Letter out of bounds
+UNIT_USED_ERROR equ 2 ;Unit already used
+NO_FREE_SLOT_ERROR equ 3 ;No reserved slot available
+STAMP_ERROR equ 4 ;Stamp error on extended disk
+
+
+;Cluster signature
+;Compressed clusters has the signature:
+; 44 53 00 00 - Cluster compressed real time
+; 44 53 00 01 - Cluster SuperCompressed offline
+; 44 53 00 02 - Cluster XCompressed real time
+;
+; NOTE: If you load these signature as words, they look like:
+;
+; low word = 5344h
+; high word = 0000h or 0100h
+
+; XCMP defines a different REAL_TIME_COMPRESSED signature so a XCMP and
+; non XCMP driver can be used on the same CVF and not get confused trying
+; to UpdateCompress a XCMP block (XCMP does not support UpdateCompress).
+
+SIG_SIZE equ 4 ; 4 byte signature
+STANDARD_COMPRESSED equ 0000h ; High word of stamp
+SUPER_COMPRESSED equ 0100h ; High word of stamp
+X_COMPRESSED equ 0200h ; High word of stamp
+REAL_TIME_COMPRESSED equ X_COMPRESSED ; Stamp used for real-time compress
+
+;;
+;; We always keep at least 64k of extra sqztors around so a
+;; file overwrite won't expand to more sqztors that are available.
+;; Of course this is a raw heuristic since these should also
+;; be contingous. For more info, see dospatch.asm and
+;; low_dlb.asm referenece to FUDGESTOR
+FUDGESTOR equ 128
+
+
+; eXperimental compression code uses a lookup table to find past
+; occurances of individual characters. The table is currently
+; 256 rows (1 for each possible byte value) X N (tracks N occurances
+; of each character).
+
+cltROWS EQU 256 ; lookup table 256 rows x
+cltCOLS EQU 8 ; N columns
+
+;
+; The following basic structures were moved from MDSTRUC.INC to
+; eliminate the need to include MDSTRUC.INC except where necessary;
+; MDSTRUC.INC is primarily disk-management structures that are of no
+; interest to MRCI.
+;
+
+;*** offst_segmt -- struc allows easy access to parts of dword pointer
+;
+offst_segmt struc
+offst dw 0
+segmt dw 0
+offst_segmt ends
+
+;*** loword_hiword -- struct allows easy access to words of dword
+;
+loword_hiword struc
+loword dw 0
+hiword dw 0
+loword_hiword ends
diff --git a/private/ntos/boot/lib/i386/memory.c b/private/ntos/boot/lib/i386/memory.c
new file mode 100644
index 000000000..6b6e23eb6
--- /dev/null
+++ b/private/ntos/boot/lib/i386/memory.c
@@ -0,0 +1,1704 @@
+/*++
+
+
+Copyright (c) 1990, 1991 Microsoft Corporation
+
+
+Module Name:
+
+ memory.c
+
+Abstract:
+
+ This module sets up paging so that the first 1Mb of virtual memory is
+ directly mapped to the first 1Mb of physical memory. This allows the
+ BIOS callbacks to work, and the osloader to continue running below
+ 1Mb. It also maps all of physical memory to KSEG0_BASE, so osloader
+ can load kernel code into kernel space, and allocate kernel parameters
+ in kernel space.
+
+Memory Map used by NTLDR:
+
+ 000000 - 000fff RM IDT & Bios Data Area
+
+ 007C00 - 007fff BPB loaded by Bootstrap
+
+ 010000 - 01ffff ABIOS Data Structures (64K)
+ Loadable miniport drivers, free memory
+
+ 020000 - 02ffff SU + real-mode stack
+
+ 030000 - 030000 Permanent heap (GDT, IDT, TSS, Page Dir, Page Tables)
+ (grows up)
+ |
+ v
+
+ ^
+ |
+ (grows down)
+ 030000 - 05ffff Temporary heap
+
+ 060000 - 062000 osloader stack (grows down)
+
+ 062000 - 09ffff osloader heap (grows down)
+
+ 0b8000 - 0bbfff Video Buffer
+
+ 0d0000 - 0fffff Bios and Adaptor ROM area
+
+Author:
+
+ John Vert (jvert) 18-Jun-1991
+
+Environment:
+
+ Kernel Mode
+
+
+Revision History:
+
+
+--*/
+
+#include "arccodes.h"
+#include "bootx86.h"
+
+//
+// 1-megabyte boundary line (in pages)
+//
+
+#define _1MB ((ULONG)0x100000 >> PAGE_SHIFT)
+
+//
+// 16-megabyte boundary line (in pages)
+//
+
+#define _16MB ((ULONG)0x1000000 >> PAGE_SHIFT)
+
+//
+// Bogus memory line. (We don't ever want to use the memory that is in
+// the 0x40 pages just under the 16Mb line.)
+//
+
+#define _16MB_BOGUS (((ULONG)0x1000000-0x40*PAGE_SIZE) >> PAGE_SHIFT)
+
+#define ROM_START_PAGE (0x0A0000 >> PAGE_SHIFT)
+#define ROM_END_PAGE (0x100000 >> PAGE_SHIFT)
+
+//
+// Current heap start pointers (physical addresses)
+// Note that 0x50000 to 0x5ffff is reserved for detection configuration memory
+//
+
+ULONG FwPermanentHeap = PERMANENT_HEAP_START * PAGE_SIZE;
+ULONG FwTemporaryHeap = (TEMPORARY_HEAP_START - 0x10) * PAGE_SIZE;
+
+//
+// Current pool pointers. This is different than the temporary/permanent
+// heaps, because it is not required to be under 1MB. It is used by the
+// SCSI miniports for allocating their extensions and for the dbcs font image.
+//
+#define FW_POOL_SIZE 64
+ULONG FwPoolStart;
+ULONG FwPoolEnd;
+
+//
+// This gets set to FALSE right before we call into the osloader, so we
+// know that the fw memory descriptors can no longer be changed at will.
+//
+BOOLEAN FwDescriptorsValid = TRUE;
+
+//
+// Private function prototypes
+//
+
+ARC_STATUS
+MempCopyGdt(
+ VOID
+ );
+
+ARC_STATUS
+MempSetupPaging(
+ IN ULONG StartPage,
+ IN ULONG NumberOfPages
+ );
+
+VOID
+MempDisablePages(
+ VOID
+ );
+
+ARC_STATUS
+MempTurnOnPaging(
+ VOID
+ );
+
+ARC_STATUS
+MempAllocDescriptor(
+ IN ULONG StartPage,
+ IN ULONG EndPage,
+ IN TYPE_OF_MEMORY MemoryType
+ );
+
+ARC_STATUS
+MempSetDescriptorRegion (
+ IN ULONG StartPage,
+ IN ULONG EndPage,
+ IN TYPE_OF_MEMORY MemoryType
+ );
+
+//
+// Global - memory management variables.
+//
+
+PHARDWARE_PTE PDE;
+PHARDWARE_PTE HalPT;
+
+#define MAX_DESCRIPTORS 60
+
+MEMORY_DESCRIPTOR MDArray[MAX_DESCRIPTORS]; // Memory Descriptor List
+ULONG NumberDescriptors=0;
+
+ARC_STATUS
+InitializeMemorySubsystem(
+ PBOOT_CONTEXT BootContext
+ )
+/*++
+
+Routine Description:
+
+ The initial heap is mapped and allocated. Pointers to the
+ Page directory and page tables are initialized.
+
+Arguments:
+
+ BootContext - Supplies basic information provided by SU module.
+
+Returns:
+
+ ESUCCESS - Memory succesfully initialized.
+
+--*/
+
+{
+ ARC_STATUS Status;
+ PSU_MEMORY_DESCRIPTOR SuMemory;
+ ULONG PageStart;
+ ULONG PageEnd;
+ ULONG RomStart = ROM_START_PAGE;
+ ULONG LoaderStart;
+ ULONG LoaderEnd;
+ ULONG BAddr, EAddr, BRound, ERound;
+
+ //
+ // Start by creating memory descriptors to describe all of the memory
+ // we know about. Then setup the page tables. Finally, allocate
+ // descriptors that describe our memory layout.
+ //
+
+ //
+ // We know that one of the SU descriptors is for < 1Mb,
+ // and we don't care about that, since we know everything we'll run
+ // on will have at least 1Mb of memory. The rest are for extended
+ // memory, and those are the ones we are interested in.
+ //
+
+ SuMemory = BootContext->MemoryDescriptorList;
+ while (SuMemory->BlockSize != 0) {
+
+ BAddr = SuMemory->BlockBase;
+ EAddr = BAddr + SuMemory->BlockSize - 1;
+
+ //
+ // Round the starting address to a page boundry.
+ //
+
+ BRound = BAddr & (ULONG) (PAGE_SIZE - 1);
+ if (BRound) {
+ BAddr = BAddr + PAGE_SIZE - BRound;
+ }
+
+ //
+ // Round the ending address to a page boundry minus 1
+ //
+
+ ERound = (EAddr + 1) & (ULONG) (PAGE_SIZE - 1);
+ if (ERound) {
+ EAddr -= ERound;
+ }
+
+ //
+ // Covert begining & ending address to page
+ //
+
+ PageStart = BAddr >> PAGE_SHIFT;
+ PageEnd = (EAddr + 1) >> PAGE_SHIFT;
+
+ //
+ // If this memory descriptor describes conventional ( <640k )
+ // memory, then assume the ROM starts immediately after it
+ // ends.
+ //
+
+ if (PageStart == 0) {
+ RomStart = PageEnd;
+ }
+
+ //
+ // If PageStart was rounded up to a page boundry, then add
+ // the fractional page as SpecialMemory
+ //
+
+ if (BRound) {
+ Status = MempSetDescriptorRegion (
+ PageStart - 1,
+ PageStart,
+ MemorySpecialMemory
+ );
+ if (Status != ESUCCESS) {
+ break;
+ }
+ }
+
+ //
+ // If PageEnd was rounded down to a page boundry, then add
+ // the fractional page as SpecialMemory
+ //
+
+ if (ERound) {
+ Status = MempSetDescriptorRegion (
+ PageEnd,
+ PageEnd + 1,
+ MemorySpecialMemory
+ );
+ if (Status != ESUCCESS) {
+ break;
+ }
+
+ //
+ // RomStart starts after the reserved page
+ //
+
+ if (RomStart == PageEnd) {
+ RomStart += 1;
+ }
+ }
+
+ //
+ // Add memory range PageStart though PageEnd
+ //
+
+ if (PageEnd <= _16MB_BOGUS) {
+
+ //
+ // This memory descriptor is all below the 16MB_BOGUS mark
+ //
+
+ Status = MempSetDescriptorRegion( PageStart, PageEnd, MemoryFree );
+
+ } else if (PageStart >= _16MB) {
+
+ //
+ // This memory descriptor is all above the 16MB mark.
+ // We never use memory above 16Mb in the loader environment,
+ // mainly so we don't have to worry about DMA transfers from
+ // ISA cards.
+ //
+ // Memory above 16MB is not used by the loader, so it's
+ // flagged as FirmwareTemporary
+ //
+
+ Status = MempSetDescriptorRegion( PageStart, PageEnd,
+ MemoryFirmwareTemporary );
+
+ } else {
+
+ //
+ // This memory descriptor describes memory within the
+ // last 40h pages of the 16MB mark - otherwise known as
+ // 16MB_BOGUS.
+ //
+ //
+
+ if (PageStart < _16MB_BOGUS) {
+
+ //
+ // Clip starting address to 16MB_BOGUS mark, and add
+ // memory below 16MB_BOGUS as useable memory.
+ //
+
+ Status = MempSetDescriptorRegion( PageStart, _16MB_BOGUS,
+ MemoryFree );
+ if (Status != ESUCCESS) {
+ break;
+ }
+
+ PageStart = _16MB_BOGUS;
+ }
+
+ //
+ // Add remaining memory as FirmwareTemporary. Memory above
+ // 16MB is never used within the loader.
+ // The bogus range will be reset later on.
+ //
+
+ Status = MempSetDescriptorRegion( PageStart, PageEnd,
+ MemoryFirmwareTemporary );
+ }
+
+ if (Status != ESUCCESS) {
+ break;
+ }
+
+ //
+ // Move to the next memory descriptor
+ //
+
+ ++SuMemory;
+ }
+
+ if (Status != ESUCCESS) {
+ BlPrint("MempSetDescriptorRegion failed %lx\n",Status);
+ return(Status);
+ }
+
+ //
+ // Set the range 16MB_BOGUS - 16MB as unusable
+ //
+
+ Status = MempSetDescriptorRegion(_16MB_BOGUS, _16MB, MemorySpecialMemory);
+ if (Status != ESUCCESS) {
+ return(Status);
+ }
+
+ //
+ // Hack for EISA machines that insist there is usable memory in the
+ // ROM area, where we know darn well there isn't.
+ //
+
+ // Remove anything in this range..
+ MempSetDescriptorRegion(ROM_START_PAGE, ROM_END_PAGE, LoaderMaximum);
+
+ //
+ // Describe the BIOS area
+ //
+ MempSetDescriptorRegion(RomStart, ROM_END_PAGE, MemoryFirmwarePermanent);
+
+ //
+ // Now we have descriptors that map all of physical memory. Carve
+ // out descriptors from these that describe the parts that we are
+ // currently using.
+ //
+
+ //
+ // Create the descriptors which describe the low 1Mb of memory.
+ //
+
+ //
+ // 00000 - 00fff real-mode interrupt vectors
+ //
+ Status = MempAllocDescriptor(0, 1, MemoryFirmwarePermanent);
+ if (Status != ESUCCESS) {
+ return(Status);
+ }
+
+ //
+ // 01000 - 1ffff loadable miniport drivers, free memory.
+ //
+ Status = MempAllocDescriptor(1, 0x20, MemoryFree);
+ if (Status != ESUCCESS) {
+ return(Status);
+ }
+
+ //
+ // 20000 - 2ffff SU module, SU stack
+ //
+ Status = MempAllocDescriptor(0x20, PERMANENT_HEAP_START, MemoryFirmwareTemporary);
+ if (Status != ESUCCESS) {
+ return(Status);
+ }
+
+ //
+ // 30000 - 30000 Firmware Permanent
+ // This starts out as zero-length. It grows into the firmware temporary
+ // heap descriptor as we allocate permanent pages for the Page Directory
+ // and Page Tables
+ //
+
+ Status = MempAllocDescriptor(PERMANENT_HEAP_START,
+ PERMANENT_HEAP_START,
+ LoaderMemoryData);
+ if (Status != ESUCCESS) {
+ return(Status);
+ }
+
+ //
+ // 30000 - 5ffff Firmware temporary heap
+ //
+
+ Status = MempAllocDescriptor(PERMANENT_HEAP_START,
+ TEMPORARY_HEAP_START,
+ MemoryFirmwareTemporary);
+ if (Status != ESUCCESS) {
+ return(Status);
+ }
+
+ //
+ // Stack we are currently running on.
+ //
+ Status = MempAllocDescriptor(TEMPORARY_HEAP_START,
+ TEMPORARY_HEAP_START+2,
+ MemoryFirmwareTemporary);
+ if (Status != ESUCCESS) {
+ return(Status);
+ }
+
+ //
+ // Describe the osloader memory image
+ //
+ LoaderStart = BootContext->OsLoaderStart >> PAGE_SHIFT;
+ LoaderEnd = (BootContext->OsLoaderEnd + PAGE_SIZE - 1) >> PAGE_SHIFT;
+ Status = MempAllocDescriptor(LoaderStart,
+ LoaderEnd,
+ MemoryLoadedProgram);
+ if (Status != ESUCCESS) {
+ return(Status);
+ }
+
+ //
+ // Describe the memory pool used to allocate memory for the SCSI
+ // miniports.
+ //
+ Status = MempAllocDescriptor(LoaderEnd,
+ LoaderEnd + FW_POOL_SIZE,
+ MemoryFirmwareTemporary);
+ if (Status != ESUCCESS) {
+ return(Status);
+ }
+ FwPoolStart = LoaderEnd << PAGE_SHIFT;
+ FwPoolEnd = FwPoolStart + (FW_POOL_SIZE << PAGE_SHIFT);
+
+ //
+ // HACKHACK - try to mark a page just below the osloader as firmwaretemp,
+ // so it will not get used for heap/stack. This is to force
+ // our heap/stack to be < 1Mb.
+ //
+ MempAllocDescriptor((BootContext->OsLoaderStart >> PAGE_SHIFT)-1,
+ BootContext->OsLoaderStart >> PAGE_SHIFT,
+ MemoryFirmwareTemporary);
+
+
+ Status = MempTurnOnPaging();
+
+ if (Status != ESUCCESS) {
+ return(Status);
+ }
+
+ Status = MempCopyGdt();
+
+ //
+ // Find any reserved ranges described by the firmware and
+ // record these
+ //
+
+ return(Status);
+}
+
+
+VOID
+InitializeMemoryDescriptors (
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Pass 2 of InitializeMemorySubsystem. This function reads the
+ firmware address space map and reserves ranges the firmware declares
+ as "address space reserved".
+
+ Note: free memory range descriptors has already been reported by su.
+
+Arguments:
+
+ none
+
+Returns:
+
+ none
+
+--*/
+{
+ ULONG BAddr, EAddr, round;
+ E820FRAME Frame;
+
+#ifdef LOADER_DEBUG
+ BlPrint("Begin InitializeMemoryDescriptors\n") ;
+#endif
+
+ Frame.Key = 0;
+ do {
+ Frame.Size = sizeof (Frame.Descriptor);
+ GET_MEMORY_DESCRIPTOR (&Frame);
+ if (Frame.ErrorFlag || Frame.Size < sizeof (Frame.Descriptor)) {
+ break;
+ }
+
+#ifdef LOADER_DEBUG
+ BlPrint("*E820: %lx %lx:%lx %lx:%lx %lx %lx\n",
+ Frame.Size,
+ Frame.Descriptor.BaseAddrHigh, Frame.Descriptor.BaseAddrLow,
+ Frame.Descriptor.SizeHigh, Frame.Descriptor.SizeLow,
+ Frame.Descriptor.MemoryType,
+ Frame.Key
+ );
+#endif
+
+ BAddr = Frame.Descriptor.BaseAddrLow;
+ EAddr = Frame.Descriptor.BaseAddrLow + Frame.Descriptor.SizeLow - 1;
+
+ //
+ // All the processors we have right now only support 32 bits
+ // If the upper 32 bits of the Base Address is non-zero, then
+ // this range is entirely above the 4g mark and can be ignored
+ //
+
+ if (Frame.Descriptor.BaseAddrHigh == 0) {
+
+ if (EAddr < BAddr) {
+ //
+ // address wrapped - truncate the Ending address to
+ // 32 bits of address space
+ //
+
+ EAddr = 0xFFFFFFFF;
+ }
+
+ //
+ // Based upon the address range descriptor type, find the
+ // available memory and add it to the descriptor list
+ //
+
+ switch (Frame.Descriptor.MemoryType) {
+ case 1:
+ //
+ // This is a memory descriptor - it's already been handled
+ // by su (eisac.c)
+ //
+ // However, any memory within 16MB_BOGUS - 16MB was
+ // considered unuseable. Reclaim memory within this
+ // region which is described via this interface.
+ //
+
+ round = BAddr & (PAGE_SIZE-1);
+ BAddr = BAddr >> PAGE_SHIFT;
+ if (round) {
+ BAddr += 1;
+ }
+
+ EAddr = (EAddr >> PAGE_SHIFT) + 1;
+
+ //
+ // Clip to bogus range
+ //
+
+ if (BAddr < _16MB_BOGUS && EAddr >= _16MB_BOGUS) {
+ BAddr = _16MB_BOGUS;
+ }
+
+ if (EAddr > (_16MB-1) && BAddr <= (_16MB-1)) {
+ EAddr = (_16MB-1);
+ }
+
+ if (BAddr >= _16MB_BOGUS && EAddr <= (_16MB-1)) {
+ //
+ // Reclaim memory within the bogus range
+ // by setting it to FirmwareTemporary
+ //
+
+ MempSetDescriptorRegion (
+ BAddr,
+ EAddr,
+ MemoryFirmwareTemporary
+ );
+ }
+
+ break;
+
+ default: // unkown types are treated as Reserved
+ case 2:
+
+ //
+ // This memory descriptor is a reserved address range
+ //
+
+ BAddr = BAddr >> PAGE_SHIFT;
+
+ round = (EAddr + 1) & (ULONG) (PAGE_SIZE - 1);
+ EAddr = EAddr >> PAGE_SHIFT;
+ if (round) {
+ EAddr += 1;
+ }
+
+ MempSetDescriptorRegion (
+ BAddr,
+ EAddr + 1,
+ MemorySpecialMemory
+ );
+
+ break;
+ }
+ }
+
+ } while (Frame.Key) ;
+
+
+ //
+ // Disable pages from KSEG0 which are disabled
+ //
+
+ MempDisablePages ( );
+
+
+#ifdef LOADER_DEBUG
+ BlPrint("Complete InitializeMemoryDescriptors\n") ;
+#endif
+}
+
+
+
+ARC_STATUS
+MempCopyGdt(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Copies the GDT & IDT into pages allocated out of our permanent heap.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ ESUCCESS - GDT & IDT copy successful
+
+--*/
+
+{
+ #pragma pack(2)
+ static struct {
+ USHORT Limit;
+ ULONG Base;
+ } GdtDef,IdtDef;
+ #pragma pack(4)
+
+ ULONG NumPages;
+ ULONG BlockSize;
+
+ PKGDTENTRY NewGdt;
+
+ //
+ // Get the current location of the GDT & IDT
+ //
+ _asm {
+ sgdt GdtDef;
+ sidt IdtDef;
+ }
+
+ if (GdtDef.Base + GdtDef.Limit + 1 != IdtDef.Base) {
+
+ //
+ // Just a sanity check to make sure that the IDT immediately
+ // follows the GDT. (As set up in SUDATA.ASM)
+ //
+
+ BlPrint("ERROR - GDT and IDT are not contiguous!\n");
+ BlPrint("GDT - %lx (%x) IDT - %lx (%x)\n",
+ GdtDef.Base, GdtDef.Limit,
+ IdtDef.Base, IdtDef.Limit);
+ while (1);
+ }
+
+ BlockSize = GdtDef.Limit+1 + IdtDef.Limit+1;
+
+ NumPages = (BlockSize + PAGE_SIZE-1) >> PAGE_SHIFT;
+
+ NewGdt = (PKGDTENTRY)FwAllocateHeapPermanent(NumPages);
+
+ if (NewGdt == NULL) {
+ return(ENOMEM);
+ }
+
+ RtlMoveMemory( (PVOID)NewGdt,
+ (PVOID)GdtDef.Base,
+ NumPages << PAGE_SHIFT );
+
+ GdtDef.Base = (ULONG) NewGdt;
+
+ IdtDef.Base = (ULONG)( (PUCHAR)NewGdt+GdtDef.Limit+1);
+
+ _asm {
+ lgdt GdtDef;
+ lidt IdtDef;
+ }
+ return(ESUCCESS);
+}
+
+ARC_STATUS
+MempSetDescriptorRegion (
+ IN ULONG StartPage,
+ IN ULONG EndPage,
+ IN TYPE_OF_MEMORY MemoryType
+ )
+/*++
+
+Routine Description:
+
+ This function sets a range to the corrisponding memory type.
+ Descriptors will be removed, modified, inserted as needed to
+ set the specified range.
+
+Arguments:
+
+ StartPage - Supplies the beginning page of the new memory descriptor
+
+ EndPage - Supplies the ending page of the new memory descriptor
+
+ MemoryType - Supplies the type of memory of the new memory descriptor
+
+Return Value:
+
+ ESUCCESS - Memory descriptor succesfully added to MDL array
+
+ ENOMEM - MDArray is full.
+
+--*/
+{
+ ULONG i;
+ ULONG sp, ep;
+ TYPE_OF_MEMORY mt;
+ BOOLEAN RegionAdded;
+
+ if (EndPage <= StartPage) {
+ //
+ // This is a completely bogus memory descriptor. Ignore it.
+ //
+
+#ifdef LOADER_DEBUG
+ BlPrint("Attempt to create invalid memory descriptor %lx - %lx\n",
+ StartPage,EndPage);
+#endif
+ return(ESUCCESS);
+ }
+
+ RegionAdded = FALSE;
+
+ //
+ // Clip, remove, any descriptors in target area
+ //
+
+ for (i=0; i < NumberDescriptors; i++) {
+ sp = MDArray[i].BasePage;
+ ep = MDArray[i].BasePage + MDArray[i].PageCount;
+ mt = MDArray[i].MemoryType;
+
+ if (sp < StartPage) {
+ if (ep > StartPage && ep <= EndPage) {
+ // truncate this descriptor
+ ep = StartPage;
+ }
+
+ if (ep > EndPage) {
+ //
+ // Target area is contained totally within this
+ // descriptor. Split the descriptor into two ranges
+ //
+
+ if (NumberDescriptors == MAX_DESCRIPTORS) {
+ return(ENOMEM);
+ }
+
+ //
+ // Add descriptor for EndPage - ep
+ //
+
+ MDArray[NumberDescriptors].MemoryType = mt;
+ MDArray[NumberDescriptors].BasePage = EndPage;
+ MDArray[NumberDescriptors].PageCount = ep - EndPage;
+ NumberDescriptors += 1;
+
+ //
+ // Adjust current descriptor for sp - StartPage
+ //
+
+ ep = StartPage;
+ }
+
+ } else {
+ // sp >= StartPage
+
+ if (sp < EndPage) {
+ if (ep < EndPage) {
+ //
+ // This descriptor is totally within the target area -
+ // remove it
+ //
+
+ ep = sp;
+
+ } else {
+ // bump begining page of this descriptor
+ sp = EndPage;
+ }
+ }
+ }
+
+ //
+ // Check if the new range can be appended or prepended to
+ // this descriptor
+ //
+ if (mt == MemoryType && !RegionAdded) {
+ if (sp == EndPage) {
+ // prepend region being set
+ sp = StartPage;
+ RegionAdded = TRUE;
+
+ } else if (ep == StartPage) {
+ // append region being set
+ ep = EndPage;
+ RegionAdded = TRUE;
+
+ }
+ }
+
+ if (MDArray[i].BasePage == sp && MDArray[i].PageCount == ep-sp) {
+
+ //
+ // Descriptor was not editted
+ //
+
+ continue;
+ }
+
+ //
+ // Reset this descriptor
+ //
+
+ MDArray[i].BasePage = sp;
+ MDArray[i].PageCount = ep - sp;
+
+ if (ep == sp) {
+
+ //
+ // Descriptor vanished - remove it
+ //
+
+ NumberDescriptors -= 1;
+ if (i < NumberDescriptors) {
+ MDArray[i] = MDArray[NumberDescriptors];
+ }
+
+ i--; // backup & recheck current position
+ }
+ }
+
+ //
+ // If region wasn't already added to a neighboring region, then
+ // create a new descriptor now
+ //
+
+ if (!RegionAdded && MemoryType < LoaderMaximum) {
+ if (NumberDescriptors == MAX_DESCRIPTORS) {
+ return(ENOMEM);
+ }
+
+#ifdef LOADER_DEBUG
+ BlPrint("Adding '%lx - %lx, type %x' to descriptor list\n",
+ StartPage << PAGE_SHIFT,
+ EndPage << PAGE_SHIFT,
+ (USHORT) MemoryType
+ );
+#endif
+
+ MDArray[NumberDescriptors].MemoryType = MemoryType;
+ MDArray[NumberDescriptors].BasePage = StartPage;
+ MDArray[NumberDescriptors].PageCount = EndPage - StartPage;
+ NumberDescriptors += 1;
+ }
+ return (ESUCCESS);
+}
+
+ARC_STATUS
+MempAllocDescriptor(
+ IN ULONG StartPage,
+ IN ULONG EndPage,
+ IN TYPE_OF_MEMORY MemoryType
+ )
+
+/*++
+
+Routine Description:
+
+ This routine carves out a specific memory descriptor from the
+ memory descriptors that have already been created. The MD array
+ is updated to reflect the new state of memory.
+
+ The new memory descriptor must be completely contained within an
+ already existing memory descriptor. (i.e. memory that does not
+ exist should never be marked as a certain type)
+
+Arguments:
+
+ StartPage - Supplies the beginning page of the new memory descriptor
+
+ EndPage - Supplies the ending page of the new memory descriptor
+
+ MemoryType - Supplies the type of memory of the new memory descriptor
+
+Return Value:
+
+ ESUCCESS - Memory descriptor succesfully added to MDL array
+
+ ENOMEM - MDArray is full.
+
+--*/
+{
+ ULONG i;
+
+ //
+ // Walk through the memory descriptors until we find one that
+ // contains the start of the descriptor.
+ //
+ for (i=0; i<NumberDescriptors; i++) {
+ if ((MDArray[i].MemoryType == MemoryFree) &&
+ (MDArray[i].BasePage <= StartPage ) &&
+ (MDArray[i].BasePage+MDArray[i].PageCount > StartPage) &&
+ (MDArray[i].BasePage+MDArray[i].PageCount >= EndPage)) {
+
+ break;
+ }
+ }
+
+ if (i==NumberDescriptors) {
+ return(ENOMEM);
+ }
+
+ if (MDArray[i].BasePage == StartPage) {
+
+ if (MDArray[i].BasePage+MDArray[i].PageCount == EndPage) {
+
+ //
+ // The new descriptor is identical to the existing descriptor.
+ // Simply change the memory type of the existing descriptor in
+ // place.
+ //
+
+ MDArray[i].MemoryType = MemoryType;
+ } else {
+
+ //
+ // The new descriptor starts on the same page, but is smaller
+ // than the existing descriptor. Shrink the existing descriptor
+ // by moving its start page up, and create a new descriptor.
+ //
+ if (NumberDescriptors == MAX_DESCRIPTORS) {
+ return(ENOMEM);
+ }
+ MDArray[i].BasePage = EndPage;
+ MDArray[i].PageCount -= (EndPage-StartPage);
+
+ MDArray[NumberDescriptors].BasePage = StartPage;
+ MDArray[NumberDescriptors].PageCount = EndPage-StartPage;
+ MDArray[NumberDescriptors].MemoryType = MemoryType;
+ ++NumberDescriptors;
+
+ }
+ } else if (MDArray[i].BasePage+MDArray[i].PageCount == EndPage) {
+
+ //
+ // The new descriptor ends on the same page. Shrink the existing
+ // by decreasing its page count, and create a new descriptor.
+ //
+ if (NumberDescriptors == MAX_DESCRIPTORS) {
+ return(ENOMEM);
+ }
+ MDArray[i].PageCount = StartPage - MDArray[i].BasePage;
+
+ MDArray[NumberDescriptors].BasePage = StartPage;
+ MDArray[NumberDescriptors].PageCount = EndPage-StartPage;
+ MDArray[NumberDescriptors].MemoryType = MemoryType;
+ ++NumberDescriptors;
+ } else {
+
+ //
+ // The new descriptor is in the middle of the existing descriptor.
+ // Shrink the existing descriptor by decreasing its page count, and
+ // create two new descriptors.
+ //
+
+ if (NumberDescriptors+1 >= MAX_DESCRIPTORS) {
+ return(ENOMEM);
+ }
+
+ MDArray[NumberDescriptors].BasePage = EndPage;
+ MDArray[NumberDescriptors].PageCount = MDArray[i].PageCount -
+ (EndPage-MDArray[i].BasePage);
+ MDArray[NumberDescriptors].MemoryType = MemoryFree;
+ ++NumberDescriptors;
+
+ MDArray[i].PageCount = StartPage - MDArray[i].BasePage;
+
+ MDArray[NumberDescriptors].BasePage = StartPage;
+ MDArray[NumberDescriptors].PageCount = EndPage-StartPage;
+ MDArray[NumberDescriptors].MemoryType = MemoryType;
+ ++NumberDescriptors;
+ }
+
+ return(ESUCCESS);
+}
+
+ARC_STATUS
+MempTurnOnPaging(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Sets up the page tables and enables paging
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ ESUCCESS - Paging successfully turned on
+
+--*/
+
+{
+ ULONG i;
+ ARC_STATUS Status;
+
+ //
+ // Walk down the memory descriptor list and call MempSetupPaging
+ // for each descriptor in it.
+ //
+
+ for (i=0; i<NumberDescriptors; i++) {
+ if (MDArray[i].BasePage < _16MB) {
+ Status = MempSetupPaging(MDArray[i].BasePage,
+ MDArray[i].PageCount);
+ if (Status != ESUCCESS) {
+ BlPrint("ERROR - MempSetupPaging(%lx, %lx) failed\n",
+ MDArray[i].BasePage,
+ MDArray[i].PageCount);
+ return(Status);
+ }
+
+ }
+ }
+
+ //
+ // Turn on paging
+ //
+ _asm {
+ //
+ // Load physical address of page directory
+ //
+ mov eax,PDE
+ mov cr3,eax
+
+ //
+ // Enable paging mode
+ //
+ mov eax,cr0
+ or eax,CR0_PG
+ mov cr0,eax
+
+ }
+ return(ESUCCESS);
+}
+
+
+ARC_STATUS
+MempSetupPaging(
+ IN ULONG StartPage,
+ IN ULONG NumberPages
+ )
+
+/*++
+
+Routine Description:
+
+ Allocates the Page Directory and as many Page Tables as are required to
+ identity map the lowest 1Mb of memory and map all of physical memory
+ into KSEG0.
+
+Arguments:
+
+ StartPage - Supplies the first page to start mapping.
+
+ NumberPage - Supplies the number of pages to map.
+
+Return Value:
+
+ ESUCCESS - Paging successfully set up
+
+--*/
+
+{
+ PHARDWARE_PTE PhysPageTable;
+ PHARDWARE_PTE KsegPageTable;
+ ULONG Entry;
+ ULONG Page;
+
+ if (PDE==NULL) {
+ //
+ // This is our first call, so we need to allocate a Page Directory.
+ //
+ PDE = FwAllocateHeapPermanent(1);
+ if (PDE == NULL) {
+ return(ENOMEM);
+ }
+
+ RtlZeroMemory(PDE,PAGE_SIZE);
+
+ //
+ // Now we map the page directory onto itself at 0xC0000000
+ //
+
+ PDE[HYPER_SPACE_ENTRY].PageFrameNumber = (ULONG)PDE >> PAGE_SHIFT;
+ PDE[HYPER_SPACE_ENTRY].Valid = 1;
+ PDE[HYPER_SPACE_ENTRY].Write = 1;
+
+ //
+ // Allocate one page for the HAL to use to map memory. This goes in
+ // the very last PDE slot. (V.A. 0xFFC00000 - 0xFFFFFFFF )
+ //
+
+ HalPT = FwAllocateHeapPermanent(1);
+ if (HalPT == NULL) {
+ return(ENOMEM);
+ }
+ RtlZeroMemory(HalPT,PAGE_SIZE);
+ PDE[1023].PageFrameNumber = (ULONG)HalPT >> PAGE_SHIFT;
+ PDE[1023].Valid = 1;
+ PDE[1023].Write = 1;
+ }
+
+ //
+ // All the page tables we use to set up the physical==virtual mapping
+ // are marked as FirmwareTemporary. They get blasted as soon as
+ // memory management gets initialized, so we don't need them lying
+ // around any longer.
+ //
+
+ for (Page=StartPage; Page < StartPage+NumberPages; Page++) {
+ Entry = Page >> 10;
+ if (((PULONG)PDE)[Entry] == 0) {
+ PhysPageTable = (PHARDWARE_PTE)FwAllocateHeapAligned(PAGE_SIZE);
+ if (PhysPageTable == NULL) {
+ return(ENOMEM);
+ }
+ RtlZeroMemory(PhysPageTable,PAGE_SIZE);
+
+ KsegPageTable = (PHARDWARE_PTE)FwAllocateHeapPermanent(1);
+ if (KsegPageTable == NULL) {
+ return(ENOMEM);
+ }
+ RtlZeroMemory(KsegPageTable,PAGE_SIZE);
+
+ PDE[Entry].PageFrameNumber = (ULONG)PhysPageTable >> PAGE_SHIFT;
+ PDE[Entry].Valid = 1;
+ PDE[Entry].Write = 1;
+
+ PDE[Entry+(KSEG0_BASE >> 22)].PageFrameNumber = ((ULONG)KsegPageTable >> PAGE_SHIFT);
+ PDE[Entry+(KSEG0_BASE >> 22)].Valid = 1;
+ PDE[Entry+(KSEG0_BASE >> 22)].Write = 1;
+ } else {
+ PhysPageTable = (PHARDWARE_PTE)(PDE[Entry].PageFrameNumber << PAGE_SHIFT);
+ KsegPageTable = (PHARDWARE_PTE)(PDE[Entry+(KSEG0_BASE >> 22)].PageFrameNumber << PAGE_SHIFT);
+ }
+
+ if (Page == 0) {
+ PhysPageTable[Page & 0x3ff].PageFrameNumber = Page;
+ PhysPageTable[Page & 0x3ff].Valid = 0;
+ PhysPageTable[Page & 0x3ff].Write = 0;
+
+ KsegPageTable[Page & 0x3ff].PageFrameNumber = Page;
+ KsegPageTable[Page & 0x3ff].Valid = 0;
+ KsegPageTable[Page & 0x3ff].Write = 0;
+
+ } else {
+ PhysPageTable[Page & 0x3ff].PageFrameNumber = Page;
+ PhysPageTable[Page & 0x3ff].Valid = 1;
+ PhysPageTable[Page & 0x3ff].Write = 1;
+
+ KsegPageTable[Page & 0x3ff].PageFrameNumber = Page;
+ KsegPageTable[Page & 0x3ff].Valid = 1;
+ KsegPageTable[Page & 0x3ff].Write = 1;
+ }
+ }
+ return(ESUCCESS);
+}
+
+VOID
+MempDisablePages(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Frees as many Page Tables as are required from KSEG0
+
+Arguments:
+
+ StartPage - Supplies the first page to start mapping.
+
+ NumberPage - Supplies the number of pages to map.
+
+Return Value:
+ none
+
+--*/
+{
+ PHARDWARE_PTE KsegPageTable;
+ ULONG Entry;
+ ULONG Page;
+ ULONG EndPage;
+ ULONG i;
+
+ //
+ // Cleanup KSEG0. The MM PFN database is an array of entries which track each
+ // page of main memory. Large enough memory holes will cause this array
+ // to be sparse. MM requires enabled PTEs to have entries in the PFN database.
+ // So locate any memory hole and remove their PTEs.
+ //
+
+ for (i=0; i<NumberDescriptors; i++) {
+ if (MDArray[i].MemoryType == MemorySpecialMemory ||
+ MDArray[i].MemoryType == MemoryFirmwarePermanent) {
+
+
+ Page = MDArray[i].BasePage;
+ EndPage = Page + MDArray[i].PageCount;
+
+ //
+ // KSEG0 only maps to 16MB, so clip the high end there
+ //
+
+ if (EndPage > _16MB) {
+ EndPage = _16MB;
+ }
+
+ //
+ // Some PTEs below 1M may need to stay mapped since they may have
+ // been put into ABIOS selectors. Instead of determining which PTEs
+ // they may be, we will leave PTEs below 1M alone. This doesn't
+ // cause the PFN any problems since we know there is some memory
+ // below then 680K mark and some more memory at the 1M mark. Thus
+ // there is not a large enough "memory hole" to cause the PFN database
+ // to be sparse below 1M.
+ //
+ // Clip starting address to 1MB
+ //
+
+ if (Page < _1MB) {
+ Page = _1MB;
+ }
+
+ //
+ // For each page in this range make sure it disabled in KSEG0.
+ //
+
+ while (Page < EndPage) {
+
+ Entry = (Page >> 10) + (KSEG0_BASE >> 22);
+ if (PDE[Entry].Valid == 1) {
+ KsegPageTable = (PHARDWARE_PTE)(PDE[Entry].PageFrameNumber << PAGE_SHIFT);
+
+ KsegPageTable[Page & 0x3ff].PageFrameNumber = 0;
+ KsegPageTable[Page & 0x3ff].Valid = 0;
+ KsegPageTable[Page & 0x3ff].Write = 0;
+ }
+
+ Page += 1;
+ }
+ }
+ }
+}
+
+PVOID
+FwAllocateHeapPermanent(
+ IN ULONG NumberPages
+ )
+
+/*++
+
+Routine Description:
+
+ This allocates pages from the private heap. The memory descriptor for
+ the LoaderMemoryData area is grown to include the returned pages, while
+ the memory descriptor for the temporary heap is shrunk by the same amount.
+
+ N.B. DO NOT call this routine after we have passed control to
+ BlOsLoader! Once BlOsLoader calls BlMemoryInitialize, the
+ firmware memory descriptors are sucked into the OS Loader heap
+ and those are the descriptors passed to the kernel. So any
+ changes in the firmware private heap will be irrelevant.
+
+ If you need to allocate permanent memory after the OS Loader
+ has initialized, use BlAllocateDescriptor.
+
+Arguments:
+
+ NumberPages - size of memory to allocate (in pages)
+
+Return Value:
+
+ Pointer to block of memory, if successful.
+ NULL, if unsuccessful.
+
+--*/
+
+{
+ PVOID MemoryPointer;
+ PMEMORY_DESCRIPTOR Descriptor;
+
+ if (FwPermanentHeap + (NumberPages << PAGE_SHIFT) > FwTemporaryHeap) {
+
+ //
+ // Our heaps collide, so we are out of memory
+ //
+
+ BlPrint("Out of permanent heap!\n");
+ while (1) {
+ }
+
+ return(NULL);
+ }
+
+ //
+ // Find the memory descriptor which describes the LoaderMemoryData area,
+ // so we can grow it to include the just-allocated pages.
+ //
+ Descriptor = MDArray;
+ while (Descriptor->MemoryType != LoaderMemoryData) {
+ ++Descriptor;
+ if (Descriptor > MDArray+MAX_DESCRIPTORS) {
+ BlPrint("ERROR - FwAllocateHeapPermanent couldn't find the\n");
+ BlPrint(" LoaderMemoryData descriptor!\n");
+ while (1) {
+ }
+ return(NULL);
+ }
+ }
+ Descriptor->PageCount += NumberPages;
+
+ //
+ // We know that the memory descriptor after this one is the firmware
+ // temporary heap descriptor. Since it is physically contiguous with our
+ // LoaderMemoryData block, we remove the pages from its descriptor.
+ //
+
+ ++Descriptor;
+ Descriptor->PageCount -= NumberPages;
+ Descriptor->BasePage += NumberPages;
+
+ MemoryPointer = (PVOID)FwPermanentHeap;
+ FwPermanentHeap += NumberPages << PAGE_SHIFT;
+
+ return(MemoryPointer);
+}
+
+
+PVOID
+FwAllocateHeap(
+ IN ULONG Size
+ )
+
+/*++
+
+Routine Description:
+
+ Allocates memory from the "firmware" temporary heap.
+
+Arguments:
+
+ Size - Supplies size of block to allocate
+
+Return Value:
+
+ PVOID - Pointer to the beginning of the block
+ NULL - Out of memory
+
+--*/
+
+{
+ ULONG i;
+ ULONG SizeInPages;
+ ULONG StartPage;
+ ARC_STATUS Status;
+
+ if (((FwTemporaryHeap - FwPermanentHeap) < Size) && (FwDescriptorsValid)) {
+ //
+ // Large allocations get their own descriptor so miniports that
+ // have huge device extensions don't suck up all of the heap.
+ //
+ // Note that we can only do this while running in "firmware" mode.
+ // Once we call into the osloader, it sucks all the memory descriptors
+ // out of the "firmware" and changes to this list will not show
+ // up there.
+ //
+ // We are looking for a descriptor that is MemoryFree and <16Mb.
+ //
+ SizeInPages = (Size+PAGE_SIZE-1) >> PAGE_SHIFT;
+
+ for (i=0; i<NumberDescriptors; i++) {
+ if ((MDArray[i].MemoryType == MemoryFree) &&
+ (MDArray[i].BasePage <= _16MB_BOGUS) &&
+ (MDArray[i].PageCount >= SizeInPages)) {
+ break;
+ }
+ }
+
+ if (i < NumberDescriptors) {
+ StartPage = MDArray[i].BasePage+MDArray[i].PageCount-SizeInPages;
+ Status = MempAllocDescriptor(StartPage,
+ StartPage+SizeInPages,
+ MemoryFirmwareTemporary);
+ if (Status==ESUCCESS) {
+ return((PVOID)(StartPage << PAGE_SHIFT));
+ }
+ }
+ }
+
+ FwTemporaryHeap -= Size;
+
+ //
+ // Round down to 16-byte boundary
+ //
+
+ FwTemporaryHeap &= ~((ULONG)0xf);
+
+ if (FwTemporaryHeap < FwPermanentHeap) {
+#if DBG
+ BlPrint("Out of temporary heap!\n");
+#endif
+ return(NULL);
+ }
+
+ return((PVOID)FwTemporaryHeap);
+
+}
+
+
+PVOID
+FwAllocatePool(
+ IN ULONG Size
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates memory from the firmware pool. Note that
+ this memory is NOT under the 1MB line, so it cannot be used for
+ anything that must be accessed from real mode. It is currently used
+ only by the SCSI miniport drivers and dbcs font loader.
+
+Arguments:
+
+ Size - Supplies size of block to allocate.
+
+Return Value:
+
+ PVOID - pointer to the beginning of the block
+ NULL - out of memory
+
+--*/
+
+{
+ PVOID Buffer;
+ ULONG NewSize;
+
+ //
+ // round size up to 16 byte boundary
+ //
+ NewSize = (Size + 15) & ~0xf;
+ if ((FwPoolStart + NewSize) <= FwPoolEnd) {
+
+ Buffer = (PVOID)FwPoolStart;
+ FwPoolStart += NewSize;
+ return(Buffer);
+
+ } else {
+ //
+ // we've used up all our pool, try to allocate from the heap.
+ //
+ return(FwAllocateHeap(Size));
+ }
+
+
+}
+
+
+PVOID
+FwAllocateHeapAligned(
+ IN ULONG Size
+ )
+
+/*++
+
+Routine Description:
+
+ Allocates memory from the "firmware" temporary heap. This memory is
+ always allocated on a page boundary, so it can readily be used for
+ temporary page tables
+
+Arguments:
+
+ Size - Supplies size of block to allocate
+
+Return Value:
+
+ PVOID - Pointer to the beginning of the block
+ NULL - Out of memory
+
+--*/
+
+{
+
+ FwTemporaryHeap -= Size;
+
+ //
+ // Round down to a page boundary
+ //
+
+ FwTemporaryHeap &= ~(PAGE_SIZE-1);
+
+ if (FwTemporaryHeap < FwPermanentHeap) {
+ BlPrint("Out of temporary heap!\n");
+ return(NULL);
+ }
+ RtlZeroMemory((PVOID)FwTemporaryHeap,Size);
+
+ return((PVOID)FwTemporaryHeap);
+
+}
+
+
+PVOID
+MmMapIoSpace (
+ IN PHYSICAL_ADDRESS PhysicalAddress,
+ IN ULONG NumberOfBytes,
+ IN MEMORY_CACHING_TYPE CacheType
+ )
+
+/*++
+
+Routine Description:
+
+ This function returns the corresponding virtual address for a
+ known physical address.
+
+Arguments:
+
+ PhysicalAddress - Supplies the phiscal address.
+
+ NumberOfBytes - Unused.
+
+ CacheType - Unused.
+
+Return Value:
+
+ Returns the corresponding virtual address.
+
+Environment:
+
+ Kernel mode. Any IRQL level.
+
+--*/
+
+{
+ ULONG i;
+ ULONG j;
+ ULONG NumberPages;
+
+ NumberPages = (NumberOfBytes+PAGE_SIZE-1) >> PAGE_SHIFT;
+
+ //
+ // We use the HAL's PDE for mapping memory buffers.
+ // Find enough free PTEs.
+ //
+
+ for (i=0; i<=1024-NumberPages; i++) {
+ for (j=0; j < NumberPages; j++) {
+ if ((((PULONG)HalPT))[i+j]) {
+ break;
+ }
+ }
+
+ if (j == NumberPages) {
+ for (j=0; j<NumberPages; j++) {
+ HalPT[i+j].PageFrameNumber =
+ (PhysicalAddress.LowPart >> PAGE_SHIFT)+j;
+ HalPT[i+j].Valid = 1;
+ HalPT[i+j].Write = 1;
+ HalPT[i+j].WriteThrough = 1;
+ if (CacheType == MmNonCached) {
+ HalPT[i+j].CacheDisable = 1;
+ }
+ }
+
+ return((PVOID)(0xffc00000 | (i<<12) | (PhysicalAddress.LowPart & 0xfff)));
+ }
+
+ }
+ return(NULL);
+}
+
+
+VOID
+MmUnmapIoSpace (
+ IN PVOID BaseAddress,
+ IN ULONG NumberOfBytes
+ )
+
+/*++
+
+Routine Description:
+
+ This function unmaps a range of physical address which were previously
+ mapped via an MmMapIoSpace function call.
+
+Arguments:
+
+ BaseAddress - Supplies the base virtual address where the physical
+ address was previously mapped.
+
+ NumberOfBytes - Supplies the number of bytes which were mapped.
+
+Return Value:
+
+ None.
+
+Environment:
+
+ Kernel mode, IRQL of DISPATCH_LEVEL or below.
+
+--*/
+
+{
+ return;
+}
+// END OF FILE //
diff --git a/private/ntos/boot/lib/i386/ntsetup.c b/private/ntos/boot/lib/i386/ntsetup.c
new file mode 100644
index 000000000..a9816474d
--- /dev/null
+++ b/private/ntos/boot/lib/i386/ntsetup.c
@@ -0,0 +1,379 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ ntsetup.c
+
+Abstract:
+
+ This module is the tail-end of the osloader program. It performs all
+ x86-specific allocations and setups for ntoskrnl. osloader.c calls
+ this module immediately before branching into the loaded kernel image.
+
+Author:
+
+ John Vert (jvert) 20-Jun-1991
+
+Environment:
+
+
+Revision History:
+
+--*/
+
+#include "bootx86.h"
+
+extern PVOID CommonDataArea;
+extern PHARDWARE_PTE HalPT;
+
+//
+// Private function prototypes
+//
+VOID
+NSFixProcessorContext(
+ IN ULONG PCR,
+ IN ULONG TSS
+ );
+
+VOID
+NSDumpMemoryDescriptors(
+ IN PLIST_ENTRY ListHead
+ );
+
+VOID
+NSUnmapFreeDescriptors(
+ IN PLIST_ENTRY ListHead
+ );
+
+VOID
+NSDumpMemory(
+ PVOID Start,
+ ULONG Length
+ );
+
+
+
+
+ARC_STATUS
+BlSetupForNt(
+ IN PLOADER_PARAMETER_BLOCK BlLoaderBlock
+ )
+
+/*++
+
+Routine Description:
+
+ Called by osloader to handle any processor-dependent allocations or
+ setups.
+
+Arguments:
+
+ BlLoaderBlock - Pointer to the parameters which will be passed to
+ ntoskrnl
+
+ EntryPoint - Supplies the entry point for ntoskrnl.exe
+
+Return Value:
+
+ ESUCCESS - All setup succesfully completed.
+
+--*/
+
+{
+ ARC_STATUS Status;
+ ULONG TssSize;
+ ULONG TssPages;
+ static ULONG PCR;
+ static ULONG TSS;
+
+ //
+ // First clean up the display, meaning that any messages displayed after
+ // this point cannot be DBCS. Unfortunately there are a couple of messages
+ // that can be displayed in certain error paths from this point out but
+ // fortunately they are extremely rare.
+ //
+ // Note that TextGrTerminate goes into real mode to do some of its work
+ // so we really really have to call it here (see comment at bottom of
+ // this routine about real mode).
+ //
+ TextGrTerminate();
+ SETUP_DISPLAY_FOR_NT();
+
+ //
+ // Above this point, all the memory for ABIOS is identity mapped, i.e.
+ // Physical address = Virtual Address. The identity mapped virtual
+ // address will not work in kernel. So, we have to remap these
+ // addresses to > 2GB virtual addresses.
+ //
+
+ if (CommonDataArea != NULL) {
+ RemapAbiosSelectors();
+ }
+
+ BlLoaderBlock->u.I386.CommonDataArea = CommonDataArea;
+ BlLoaderBlock->u.I386.MachineType = MachineType;
+
+ Status = BlAllocateDescriptor(LoaderStartupPcrPage,
+ 0,
+ 2,
+ &PCR);
+
+ if (Status != ESUCCESS) {
+ BlPrint("Couldn't allocate PCR descriptor\n");
+ return(Status);
+ }
+
+ //
+ // Mapped hardcoded virtual pointer to the boot processors PCR
+ // The virtual pointer comes from the HAL reserved area
+ //
+
+ //
+ // First zero out any PTEs that may have already been mapped for
+ // a SCSI card.
+ //
+
+ RtlZeroMemory(HalPT, PAGE_SIZE);
+ _asm {
+ mov eax, cr3
+ mov cr3, eax
+ }
+
+ HalPT[(KI_USER_SHARED_DATA - 0xFFC00000) >> PAGE_SHIFT].PageFrameNumber = PCR+1;
+ HalPT[(KI_USER_SHARED_DATA - 0xFFC00000) >> PAGE_SHIFT].Valid = 1;
+ HalPT[(KI_USER_SHARED_DATA - 0xFFC00000) >> PAGE_SHIFT].Write = 1;
+ RtlZeroMemory((PVOID)KI_USER_SHARED_DATA, PAGE_SIZE);
+
+ HalPT[(KIP0PCRADDRESS - 0xFFC00000) >> PAGE_SHIFT].PageFrameNumber = PCR;
+ HalPT[(KIP0PCRADDRESS - 0xFFC00000) >> PAGE_SHIFT].Valid = 1;
+ HalPT[(KIP0PCRADDRESS - 0xFFC00000) >> PAGE_SHIFT].Write = 1;
+ PCR = KIP0PCRADDRESS;
+
+ //
+ // Allocate space for Tss
+ //
+
+ TssSize = (sizeof(KTSS) + PAGE_SIZE) & ~(PAGE_SIZE - 1);
+ TssPages = TssSize / PAGE_SIZE;
+
+ Status = (ULONG)BlAllocateDescriptor( LoaderMemoryData,
+ 0,
+ TssPages,
+ (PULONG)(&TSS) );
+ if (Status != ESUCCESS) {
+ goto SetupFailed;
+ }
+
+ TSS = KSEG0_BASE | (TSS << PAGE_SHIFT);
+
+#ifdef LOADER_DEBUG
+ NSDumpMemoryDescriptors(&(BlLoaderBlock->MemoryDescriptorListHead));
+#endif
+ NSUnmapFreeDescriptors(&(BlLoaderBlock->MemoryDescriptorListHead));
+
+ //
+ // N. B. DO NOT GO BACK INTO REAL MODE AFTER REMAPPING THE GDT AND
+ // IDT TO HIGH MEMORY!! If you do, they will get re-mapped
+ // back into low-memory, then UN-mapped by MmInit, and you
+ // will be completely tubed!
+ //
+
+ NSFixProcessorContext(PCR,TSS);
+ return(ESUCCESS);
+
+SetupFailed:
+ return(Status);
+}
+
+
+VOID
+NSFixProcessorContext(
+ IN ULONG PCR,
+ IN ULONG TSS
+ )
+
+/*++
+
+Routine Description:
+
+ This relocates the GDT, IDT, PCR, and TSS to high virtual memory space.
+
+Arguments:
+
+ PCR - Pointer to the PCR's location (in high virtual memory)
+ TSS - Pointer to kernel's TSS (in high virtual memory)
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ #pragma pack(2)
+ static struct {
+ USHORT Limit;
+ ULONG Base;
+ } GdtDef,IdtDef;
+ #pragma pack(4)
+
+ PKGDTENTRY pGdt;
+
+ //
+ // Kernel expects the PCR to be zero-filled on startup
+ //
+ RtlZeroMemory((PVOID)PCR,PAGE_SIZE);
+
+ _asm {
+ sgdt GdtDef;
+ sidt IdtDef;
+ }
+
+ GdtDef.Base = KSEG0_BASE | GdtDef.Base;
+
+ IdtDef.Base = KSEG0_BASE | IdtDef.Base;
+ pGdt = (PKGDTENTRY)GdtDef.Base;
+
+ //
+ // Initialize selector that points to PCR
+ //
+ pGdt[6].BaseLow = (USHORT)(PCR & 0xffff);
+ pGdt[6].HighWord.Bytes.BaseMid = (UCHAR)((PCR >> 16) & 0xff);
+ pGdt[6].HighWord.Bytes.BaseHi = (UCHAR)((PCR >> 24) & 0xff);
+
+ //
+ // Initialize selector that points to TSS
+ //
+ pGdt[5].BaseLow = (USHORT)(TSS & 0xffff);
+ pGdt[5].HighWord.Bytes.BaseMid = (UCHAR)((TSS >> 16) & 0xff);
+ pGdt[5].HighWord.Bytes.BaseHi = (UCHAR)((TSS >> 24) & 0xff);
+
+ _asm {
+ lgdt GdtDef;
+ lidt IdtDef;
+ }
+}
+
+VOID
+NSUnmapFreeDescriptors(
+ IN PLIST_ENTRY ListHead
+ )
+
+/*++
+
+Routine Description:
+
+ Unmaps memory which is marked as free, so it memory management will know
+ to reclaim it.
+
+Arguments:
+
+ ListHead - pointer to the start of the MemoryDescriptorList
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PLIST_ENTRY CurrentLink;
+ PMEMORY_ALLOCATION_DESCRIPTOR CurrentDescriptor;
+ ULONG StartPage, EndPage;
+ PHARDWARE_PTE PageTable;
+ extern PHARDWARE_PTE PDE;
+
+ CurrentLink = ListHead->Flink;
+ while (CurrentLink != ListHead) {
+ CurrentDescriptor = (PMEMORY_ALLOCATION_DESCRIPTOR)CurrentLink;
+
+ if ( (CurrentDescriptor->MemoryType == LoaderFree) ||
+ ((CurrentDescriptor->MemoryType == LoaderFirmwareTemporary) &&
+ (CurrentDescriptor->BasePage < (0x1000000 >> PAGE_SHIFT))) ||
+ (CurrentDescriptor->MemoryType == LoaderLoadedProgram) ||
+ (CurrentDescriptor->MemoryType == LoaderOsloaderStack) ) {
+
+ StartPage = CurrentDescriptor->BasePage | (KSEG0_BASE >> PAGE_SHIFT);
+ EndPage = StartPage + CurrentDescriptor->PageCount;
+ while(StartPage < EndPage) {
+ PageTable= (PHARDWARE_PTE)
+ (PDE[StartPage>>10].PageFrameNumber << PAGE_SHIFT);
+ if (PageTable != NULL) {
+ *(PULONG)(PageTable+(StartPage & 0x3ff))= 0;
+ }
+
+ StartPage++;
+ }
+ }
+ CurrentLink = CurrentLink->Flink;
+ }
+
+
+}
+
+
+//
+// Temp. for debugging
+//
+VOID
+NSDumpMemory(
+ PVOID Start,
+ ULONG Length
+ )
+{
+ ULONG cnt;
+
+ BlPrint(" %lx:\n",(ULONG)Start);
+ for (cnt=0; cnt<Length; cnt++) {
+ BlPrint("%x ",*((PUSHORT)(Start)+cnt));
+ if (((cnt+1)%16)==0) {
+ BlPrint("\n");
+ }
+ }
+}
+
+VOID
+NSDumpMemoryDescriptors(
+ IN PLIST_ENTRY ListHead
+ )
+
+/*++
+
+Routine Description:
+
+ Dumps a memory descriptor list to the screen. Used for debugging only.
+
+Arguments:
+
+ ListHead - Pointer to the head of the memory descriptor list
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PLIST_ENTRY CurrentLink;
+ PMEMORY_ALLOCATION_DESCRIPTOR CurrentDescriptor;
+
+ CurrentLink = ListHead->Flink;
+ while (CurrentLink != ListHead) {
+ CurrentDescriptor = (PMEMORY_ALLOCATION_DESCRIPTOR)CurrentLink;
+ BlPrint("Fl = %lx Bl = %lx ",
+ (ULONG)CurrentDescriptor->ListEntry.Flink,
+ (ULONG)CurrentDescriptor->ListEntry.Blink
+ );
+ BlPrint("Type %x Base %lx Pages %lx\n",
+ (USHORT)(CurrentDescriptor->MemoryType),
+ CurrentDescriptor->BasePage,
+ CurrentDescriptor->PageCount
+ );
+ CurrentLink = CurrentLink->Flink;
+ }
+ while (!GET_KEY()) {
+ }
+}
+
diff --git a/private/ntos/boot/lib/i386/osloader.def b/private/ntos/boot/lib/i386/osloader.def
new file mode 100644
index 000000000..6801acdb3
--- /dev/null
+++ b/private/ntos/boot/lib/i386/osloader.def
@@ -0,0 +1,58 @@
+NAME osloader
+
+EXPORTS
+ BlLoadImage
+ BlpBindImportName
+ BlAllocateAlignedDescriptor
+ BlOpen
+ BlClose
+ BlRead
+ BlWrite
+ BlGetFileInformation
+ BlSetFileInformation
+
+ RtlAssert
+ ScsiDebugPrint
+ ScsiPortInitialize
+ ScsiPortFreeDeviceBase
+ ScsiPortGetDeviceBase
+ ScsiPortGetLogicalUnit
+ ScsiPortGetPhysicalAddress
+ ScsiPortGetSrb
+ ScsiPortGetUncachedExtension
+ ScsiPortGetVirtualAddress
+ ScsiPortFlushDma
+ ScsiPortIoMapTransfer
+ ScsiPortNotification
+ ScsiPortLogError
+ ScsiPortCompleteRequest
+ ScsiPortMoveMemory
+ ScsiPortReadPortUchar
+ ScsiPortReadPortUshort
+ ScsiPortReadPortUlong
+ ScsiPortReadRegisterUchar
+ ScsiPortReadRegisterUshort
+ ScsiPortReadRegisterUlong
+ ScsiPortReadRegisterBufferUchar
+ ScsiPortReadRegisterBufferUshort
+ ScsiPortReadRegisterBufferUlong
+ ScsiPortReadPortBufferUchar
+ ScsiPortReadPortBufferUshort
+ ScsiPortReadPortBufferUlong
+ ScsiPortStallExecution
+ ScsiPortWritePortUchar
+ ScsiPortWritePortUshort
+ ScsiPortWritePortUlong
+ ScsiPortWriteRegisterUchar
+ ScsiPortWriteRegisterUshort
+ ScsiPortWriteRegisterUlong
+ ScsiPortWriteRegisterBufferUchar
+ ScsiPortWriteRegisterBufferUshort
+ ScsiPortWriteRegisterBufferUlong
+ ScsiPortWritePortBufferUchar
+ ScsiPortWritePortBufferUshort
+ ScsiPortWritePortBufferUlong
+ ScsiPortConvertUlongToPhysicalAddress
+ ScsiPortConvertPhysicalAddressToUlong
+ ScsiPortGetBusData
+ ScsiPortSetBusDataByOffset
diff --git a/private/ntos/boot/lib/i386/rdcomp.asm b/private/ntos/boot/lib/i386/rdcomp.asm
new file mode 100644
index 000000000..df257ac13
--- /dev/null
+++ b/private/ntos/boot/lib/i386/rdcomp.asm
@@ -0,0 +1,317 @@
+ IFDEF DBLSPACE_LEGAL
+ page ,130
+ title DeCompressor
+;-----------------------------------------------------------------------
+; Name: RDCOMP.ASM
+;
+; Routines defined:
+; Decompress32
+;
+; Description:
+; This file holds the code that is responsible for decompressing
+; the compressed data.
+;
+; VxD History:
+; 22-Apr-93 jeffpar Major adaptation and cleanup for MRCI32.386
+;-----------------------------------------------------------------------
+
+ .386p
+
+ .xlist
+;; include vmm.inc
+;; include debug.inc
+ include mdequ.inc
+ .list
+
+ MD_STAMP equ "SD"
+
+;;;-----------------------------------------------------------------------
+;;; Data segment
+;;;-----------------------------------------------------------------------
+;;
+;;VxD_LOCKED_DATA_SEG
+;;
+;; public pLowerBound
+;;pLowerBound dd 0 ; if non-zero, then this is the lowest linear
+;; ; address we treat as *our* error
+;; public pUpperBound
+;;pUpperBound dd 0 ; if non-zero, then this is the highest linear
+;; ; address we treat as *our* error (plus one)
+;; public pPrevPgFltHdlr
+;;pPrevPgFltHdlr dd 0 ; if non-zero, addr of previous page fault hdlr
+;;
+;;VxD_LOCKED_DATA_ENDS
+;;
+;;
+;;VxD_PAGEABLE_DATA_SEG
+_DATA SEGMENT DWORD PUBLIC 'DATA'
+
+ include decode.inc ; include macros and tables used for decoding
+
+ public decode_data_end
+decode_data_end label byte
+
+;;VxD_PAGEABLE_DATA_ENDS
+_DATA ENDS
+
+
+;-----------------------------------------------------------------------
+; Code segment
+;-----------------------------------------------------------------------
+
+;;VxD_PAGEABLE_CODE_SEG
+_TEXT SEGMENT DWORD USE32 PUBLIC 'CODE'
+ ASSUME CS:FLAT, DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+
+ public aCmdAt
+aCmdAt dd CmdAt0,CmdAt1,CmdAt2,CmdAt3,CmdAt4,CmdAt5,CmdAt6,CmdAt7
+
+
+;-----------------------------------------------------------------------
+; Decompression Algorithm
+; -----------------------
+; Decode the next chunk of text in 'coding_buffer', into the buffer as
+; stated in the 'init'.
+;
+; Entry:
+; CLD
+; EBX == start of cluster (see BUGBUG in MRCI32IncDecompress!)
+; ECX == chunk count
+; ESI -> compressed data
+; EDI -> destination buffer
+; EDX == remaining data(low)/bits(high) from last call, 0 if none
+;
+; Exit:
+; If successful, CY clear and:
+; ESI == offset to next byte uncompressed data (if any)
+; EDI == offset to next free byte in dest buffer
+; EDX == remaining data(low)/bits(high) for next call, 0 if none
+;
+; Uses:
+; Everything except EBP
+;-----------------------------------------------------------------------
+
+;;BeginProc Decompress32
+ public Decompress32
+Decompress32 proc near
+
+ push ebp
+ push ebp ; [esp] is our "chunk_count"
+
+;; push ebx
+ sub ebx,MAX_12BIT_OFFSET ;
+;; mov [pLowerBound],ebx ;
+;; pop [pUpperBound] ; fault handler enabled *now*
+
+ mov eax,edx ; remaining data to AX
+ shr edx,16 ; move state to low word of EDX
+ jnz short @F ; jump if continuing previous state
+ lodsw ; new decompression, load initial data
+@@: mov [esp],ecx ; save chunk count
+
+DecodeLoop:
+;
+; AX has the remaining bits, DL has the next state
+;
+ mov ebp,cbCHUNK ; (ebp) is # bytes left this chunk
+ DecodeRestart
+
+ LastErrSJump equ <FirstErrSJump>
+FirstErrSJump: jmp DecodeError ; put first nice fat jump out of the way
+
+irpc c,<01234567>
+ CmdAt c
+endm
+ jmp CmdAt0
+
+irpc c,<01234567>
+ LengthAt c
+endm
+
+ DoGeneralLength ; generate code here to handle large lengths
+
+DecodeDone:
+;
+; AX has the remaining bits, DL has the next state -- check chunk status
+;
+ test ebp,ebp ; perfect chunk-size decompression?
+ jnz DecodeCheckLast ; no, check for last chunk
+
+ dec dword ptr [esp] ; chunks remaining?
+ jz DecodeSuccess ; no, so we're all done
+ jmp DecodeLoop ; yes, process them
+
+ public DecodeError
+DecodeError label near
+ stc ; random decomp failure jump target
+ jmp short DecodeExit
+
+DecodeCheckLast:
+ dec dword ptr [esp] ; chunks remaining?
+ jnz DecodeError ; yes, then we have an error
+
+DecodeSuccess:
+ mov dh,1 ; return non-0 EDX indicating state exists
+ shl edx,16 ; move state to high word of EDX
+ movzx eax,ax ; make sure high word of EAX is clear
+ or edx,eax ; EDX == state (and carry is CLEAR)
+
+DecodeExit:
+;; mov [pUpperBound],0 ; fault handler disabled *now*
+;; mov [pLowerBound],0 ;
+ pop ebp ; throw away our "chunk_count" at [esp]
+ pop ebp
+ ret
+
+;;EndProc Decompress32
+ Decompress32 endp
+
+
+
+
+
+;;VxD_PAGEABLE_CODE_ENDS
+_TEXT ENDS
+
+;;
+;;VxD_LOCKED_CODE_SEG
+;;
+;;;-----------------------------------------------------------------------
+;;; Decompress32_Page_Fault
+;;; -----------------------
+;;; Looks for VMM page faults caused by the decompressor. The fault
+;;; must have taken place in the range from [pLowerBound] to [pUpperBound]-1.
+;;; If the fault IS in that range, then we set EIP to DecodeError.
+;;;
+;;; WARNING: this takes advantage of the fact that the decompressor does not
+;;; use the stack; otherwise, we would obviously need to record and re-set ESP
+;;; to a known point as well.
+;;;
+;;; This is in locked code to insure that a subsequent fault doesn't destroy
+;;; the information necessary to process the first (eg, CR2)!
+;;;
+;;; Entry:
+;;; EBX == VM handle
+;;; EBP -> VMM re-entrant stack frame
+;;;
+;;; Uses:
+;;; May use everything except SEG REGS
+;;;-----------------------------------------------------------------------
+;;
+;;BeginProc Decompress32_Page_Fault
+;;;
+;;; Note: the fall-through case is the common one (ie, not our page fault)
+;;;
+;; push eax
+;; mov eax,cr2 ; get faulting address
+;; cmp eax,[pUpperBound]
+;; jb short dpf_maybe ; it might be ours
+;; ; otherwise, definitely not
+;;dpf_prev:
+;; pop eax ; we've been told to preserve everything
+;; jmp [pPrevPgFltHdlr] ; dispatch to real page fault handler
+;; ; (if we installed, then there *is* one)
+;;dpf_maybe:
+;; cmp eax,[pLowerBound]
+;; jb short dpf_prev ; not going to "fix" it
+;;
+;; Trace_Out "Decompress32_Page_Fault: correcting fault on bad cluster"
+;;
+;; mov [ebp].Client_EIP,OFFSET32 DecodeError
+;; pop eax
+;; ret ; we "fixed" it
+;;
+;;EndProc Decompress32_Page_Fault
+;;
+;;VxD_LOCKED_CODE_ENDS
+
+
+;++
+;
+; ULONG
+; DblsMrcfDecompress (
+; PUCHAR UncompressedBuffer,
+; ULONG UncompressedLength,
+; PUCHAR CompressedBuffer,
+; ULONG CompressedLength,
+; PMRCF_DECOMPRESS WorkSpace
+; )
+;
+; Routine Description:
+;
+; This routine decompresses a buffer of StandardCompressed or MaxCompressed
+; data.
+;
+; Arguments:
+;
+; UncompressedBuffer - buffer to receive uncompressed data
+;
+; UncompressedLength - length of UncompressedBuffer
+;
+; NOTE: UncompressedLength must be the EXACT length of the uncompressed
+; data, as Decompress uses this information to detect
+; when decompression is complete. If this value is
+; incorrect, Decompress may crash!
+;
+; CompressedBuffer - buffer containing compressed data
+;
+; CompressedLength - length of CompressedBuffer
+;
+; WorkSpace - pointer to a private work area for use by this operation
+;
+; Return Value:
+;
+; ULONG - Returns the size of the decompressed data in bytes. Returns 0 if
+; there was an error in the decompress.
+;--
+
+_TEXT SEGMENT DWORD USE32 PUBLIC 'CODE'
+ ASSUME CS:FLAT, DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+ public _DblsMrcfDecompress@20
+_DblsMrcfDecompress@20 proc near
+
+ push esi
+ push edi
+ push ebx
+
+ mov ecx,dword ptr [esp+20]
+ mov edx,ecx
+ shr ecx,9
+ and edx,512-1
+ jz @f
+ inc ecx
+ sub edx,edx
+@@: mov esi,dword ptr [esp+24]
+ mov edi,dword ptr [esp+16]
+ mov ebx,edi
+
+ cld
+ lodsd
+ cmp ax,MD_STAMP
+ je @f
+ sub eax,eax
+ jz done
+
+@@: call Decompress32
+ jnc @f
+ sub eax,eax
+ jz done
+
+@@: sub edi,dword ptr [esp+16]
+ mov eax,edi
+
+done:
+ pop ebx
+ pop edi
+ pop esi
+
+ ret 20
+
+_DblsMrcfDecompress@20 endp
+
+_TEXT ENDS
+ ENDIF ; DEF DBLSPACE_LEGAL
+ end
+
diff --git a/private/ntos/boot/lib/i386/sources b/private/ntos/boot/lib/i386/sources
new file mode 100644
index 000000000..6e7602869
--- /dev/null
+++ b/private/ntos/boot/lib/i386/sources
@@ -0,0 +1,24 @@
+i386_SOURCES=scsiboot.c \
+ scsidisk.c \
+ i386\abiosc.c \
+ i386\biosdrv.c \
+ i386\stubs.c \
+ i386\display.c \
+ i386\disp_gr.c \
+ i386\disp_tm.c \
+ i386\flopcach.c \
+ i386\entry.c \
+ i386\arcemul.c \
+ i386\ixbusdat.c \
+ i386\ixhwsup.c \
+ i386\ixphwsup.c \
+ i386\ixpcibus.c \
+ i386\memory.c \
+ i386\ntsetup.c \
+ i386\machine.c \
+ i386\ixcmos.asm \
+ i386\xxioacc.asm \
+ i386\lnkconst.asm\
+ i386\rdcomp.asm
+
+C_DEFINES=$(C_DEFINES) -DELTORITO
diff --git a/private/ntos/boot/lib/i386/stubs.c b/private/ntos/boot/lib/i386/stubs.c
new file mode 100644
index 000000000..f05b44e32
--- /dev/null
+++ b/private/ntos/boot/lib/i386/stubs.c
@@ -0,0 +1,190 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ stubs.c
+
+Abstract:
+
+ This module implements stub routines for the boot code.
+
+Author:
+
+ David N. Cutler (davec) 7-Nov-1990
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+--*/
+
+#include "ntos.h"
+#include "bootx86.h"
+#include "stdio.h"
+#include "stdarg.h"
+
+VOID
+KeBugCheck (
+ IN ULONG BugCheckCode
+ )
+
+/*++
+
+Routine Description:
+
+ This function crashes the system in a controlled manner.
+
+Arguments:
+
+ BugCheckCode - Supplies the reason for the bug check.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Print out the bug check code and break.
+ //
+
+ BlPrint("\n*** BugCheck (%lx) ***\n\n", BugCheckCode);
+ while(TRUE) {
+ };
+ return;
+}
+
+PVOID
+MmDbgReadCheck (
+ IN PVOID VirtualAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the phyiscal address for a virtual address
+ which is valid (mapped) for read access.
+
+Arguments:
+
+ VirtualAddress - Supplies the virtual address to check.
+
+Return Value:
+
+ Returns NULL if the address is not valid or readable, otherwise
+ returns the physical address of the corresponding virtual address.
+
+--*/
+
+{
+
+ return VirtualAddress;
+}
+
+PVOID
+MmDbgTranslatePhysicalAddress (
+ IN PHYSICAL_ADDRESS PhysicalAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the phyiscal address for a physical address
+ which is valid (mapped).
+
+Arguments:
+
+ PhysicalAddress - Supplies the physical address to check.
+
+Return Value:
+
+ Returns NULL if the address is not valid or readable, otherwise
+ returns the physical address of the corresponding virtual address.
+
+--*/
+
+{
+
+ return (PVOID)PhysicalAddress.LowPart;
+}
+
+PVOID
+MmDbgWriteCheck (
+ IN PVOID VirtualAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the phyiscal address for a virtual address
+ which is valid (mapped) for write access.
+
+Arguments:
+
+ VirtualAddress - Supplies the virtual address to check.
+
+Return Value:
+
+ Returns NULL if the address is not valid or readable, otherwise
+ returns the physical address of the corresponding virtual address.
+
+--*/
+
+{
+ return VirtualAddress;
+}
+
+VOID
+RtlAssert(
+ IN PVOID FailedAssertion,
+ IN PVOID FileName,
+ IN ULONG LineNumber,
+ IN PCHAR Message OPTIONAL
+ )
+{
+
+ BlPrint( "\n*** Assertion failed %s in %s line %d\n",
+ FailedAssertion,
+ FileName,
+ LineNumber );
+ if (Message) {
+ BlPrint(Message);
+ }
+
+ while (TRUE) {
+ }
+}
+
+VOID
+DbgBreakPoint(
+ VOID
+ )
+{
+ BlPrint("DbgBreakPoint hit\n");
+ while (TRUE) {
+ }
+}
+
+ULONG
+DbgPrint(
+ IN PCH Format,
+ ...
+ )
+{
+ va_list arglist;
+ UCHAR Buffer[100];
+
+ va_start(arglist, Format);
+ vsprintf(Buffer, Format, arglist);
+ BlPrint(Buffer);
+ return 0;
+}
diff --git a/private/ntos/boot/lib/i386/xxioacc.asm b/private/ntos/boot/lib/i386/xxioacc.asm
new file mode 100644
index 000000000..e362f7746
--- /dev/null
+++ b/private/ntos/boot/lib/i386/xxioacc.asm
@@ -0,0 +1,362 @@
+ title "ix ioaccess"
+;++
+;
+; Copyright (c) 1989 Microsoft Corporation
+;
+; Module Name:
+;
+; ixioacc.asm
+;
+; Abstract:
+;
+; Procedures to correctly touch I/O registers.
+;
+; Author:
+;
+; Bryan Willman (bryanwi) 16 May 1990
+;
+; Environment:
+;
+; User or Kernel, although privledge (IOPL) may be required.
+;
+; Revision History:
+;
+;--
+
+.386p
+ include callconv.inc
+ .list
+
+_TEXT SEGMENT DWORD PUBLIC 'CODE'
+ ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+;++
+;
+; I/O port space read and write functions.
+;
+; These have to be actual functions on the 386, because we need
+; to use assembler, but cannot return a value if we inline it.
+;
+; This set of functions manipulates I/O registers in PORT space.
+; (Uses x86 in and out instructions)
+;
+; WARNING: Port addresses must always be in the range 0 to 64K, because
+; that's the range the hardware understands.
+;
+;--
+
+
+
+;++
+;
+; UCHAR
+; READ_PORT_UCHAR(
+; PUCHAR Port
+; )
+;
+; Arguments:
+; (esp+4) = Port
+;
+; Returns:
+; Value in Port.
+;
+;--
+cPublicProc _READ_PORT_UCHAR,1
+
+ mov dx,[esp+4] ; (dx) = Port
+ in al,dx
+ stdRET _READ_PORT_UCHAR
+
+stdENDP _READ_PORT_UCHAR
+
+;++
+;
+; USHORT
+; READ_PORT_USHORT(
+; PUSHORT Port
+; )
+;
+; Arguments:
+; (esp+4) = Port
+;
+; Returns:
+; Value in Port.
+;
+;--
+cPublicProc _READ_PORT_USHORT,1
+
+ mov dx,[esp+4] ; (dx) = Port
+ in ax,dx
+ stdRET _READ_PORT_USHORT
+
+stdENDP _READ_PORT_USHORT
+
+
+
+;++
+;
+; ULONG
+; READ_PORT_ULONG(
+; PULONG Port
+; )
+;
+; Arguments:
+; (esp+4) = Port
+;
+; Returns:
+; Value in Port.
+;
+;--
+cPublicProc _READ_PORT_ULONG,1
+
+ mov dx,[esp+4] ; (dx) = Port
+ in eax,dx
+ stdRET _READ_PORT_ULONG
+
+stdENDP _READ_PORT_ULONG
+
+
+
+;++
+;
+; VOID
+; READ_PORT_BUFFER_UCHAR(
+; PUCHAR Port,
+; PUCHAR Buffer,
+; ULONG Count
+; )
+;
+; Arguments:
+; (esp+4) = Port
+; (esp+8) = Buffer address
+; (esp+12) = Count
+;
+;--
+cPublicProc _READ_PORT_BUFFER_UCHAR,3
+
+ mov dx,[esp+4] ; (dx) = Port
+ mov ecx,[esp+12] ; (ecx) = transfer count
+ push edi
+ mov edi,[esp+12] ; (edi) = (esp+8+push) = buffer
+ rep insb
+ pop edi
+ stdRET _READ_PORT_BUFFER_UCHAR
+
+stdENDP _READ_PORT_BUFFER_UCHAR
+
+
+;++
+;
+; VOID
+; READ_PORT_BUFFER_USHORT(
+; PUSHORT Port,
+; PUSHORT Buffer,
+; ULONG Count
+; )
+;
+; Arguments:
+; (esp+4) = Port
+; (esp+8) = Buffer address
+; (esp+12) = Count
+;
+;--
+cPublicProc _READ_PORT_BUFFER_USHORT,3
+
+ mov dx,[esp+4] ; (dx) = Port
+ mov ecx,[esp+12] ; (ecx) = transfer count
+ push edi
+ mov edi,[esp+12] ; (edi) = (esp+8+push) = buffer
+ rep insw
+ pop edi
+ stdRET _READ_PORT_BUFFER_USHORT
+
+stdENDP _READ_PORT_BUFFER_USHORT
+
+
+;++
+;
+; VOID
+; READ_PORT_BUFFER_ULONG(
+; PULONG Port,
+; PULONG Buffer,
+; ULONG Count
+; )
+;
+; Arguments:
+; (esp+4) = Port
+; (esp+8) = Buffer address
+; (esp+12) = Count
+;
+;--
+cPublicProc _READ_PORT_BUFFER_ULONG,3
+
+ mov dx,[esp+4] ; (dx) = Port
+ mov ecx,[esp+12] ; (ecx) = transfer count
+ push edi
+ mov edi,[esp+12] ; (edi) = (esp+8+push) = buffer
+ rep insd
+ pop edi
+ stdRET _READ_PORT_BUFFER_ULONG
+
+stdENDP _READ_PORT_BUFFER_ULONG
+
+
+
+;++
+;
+; VOID
+; WRITE_PORT_UCHAR(
+; PUCHAR Port,
+; UCHAR Value
+; )
+;
+; Arguments:
+; (esp+4) = Port
+; (esp+8) = Value
+;
+;--
+cPublicProc _WRITE_PORT_UCHAR,2
+
+ mov dx,[esp+4] ; (dx) = Port
+ mov al,[esp+8] ; (al) = Value
+ out dx,al
+ stdRET _WRITE_PORT_UCHAR
+
+stdENDP _WRITE_PORT_UCHAR
+
+
+
+;++
+;
+; VOID
+; WRITE_PORT_USHORT(
+; PUSHORT Port,
+; USHORT Value
+; )
+;
+; Arguments:
+; (esp+4) = Port
+; (esp+8) = Value
+;
+;--
+cPublicProc _WRITE_PORT_USHORT,2
+
+ mov dx,[esp+4] ; (dx) = Port
+ mov ax,[esp+8] ; (ax) = Value
+ out dx,ax
+ stdRET _WRITE_PORT_USHORT
+
+stdENDP _WRITE_PORT_USHORT
+
+
+
+;++
+;
+; VOID
+; WRITE_PORT_ULONG(
+; PULONG Port,
+; ULONG Value
+; )
+;
+; Arguments:
+; (esp+4) = Port
+; (esp+8) = Value
+;
+;--
+cPublicProc _WRITE_PORT_ULONG,2
+
+ mov dx,[esp+4] ; (dx) = Port
+ mov eax,[esp+8] ; (eax) = Value
+ out dx,eax
+ stdRET _WRITE_PORT_ULONG
+
+stdENDP _WRITE_PORT_ULONG
+
+
+
+;++
+;
+; VOID
+; WRITE_PORT_BUFFER_UCHAR(
+; PUCHAR Port,
+; PUCHAR Buffer,
+; ULONG Count
+; )
+;
+; Arguments:
+; (esp+4) = Port
+; (esp+8) = Buffer address
+; (esp+12) = Count
+;
+;--
+cPublicProc _WRITE_PORT_BUFFER_UCHAR,3
+
+ mov dx,[esp+4] ; (dx) = Port
+ mov ecx,[esp+12] ; (ecx) = transfer count
+ push esi
+ mov esi,[esp+12] ; (esi) = (esp+8+push) = buffer
+ rep outsb
+ pop esi
+ stdRET _WRITE_PORT_BUFFER_UCHAR
+
+stdENDP _WRITE_PORT_BUFFER_UCHAR
+
+
+;++
+;
+; VOID
+; WRITE_PORT_BUFFER_USHORT(
+; PUSHORT Port,
+; PUSHORT Buffer,
+; ULONG Count
+; )
+;
+; Arguments:
+; (esp+4) = Port
+; (esp+8) = Buffer address
+; (esp+12) = Count
+;
+;--
+cPublicProc _WRITE_PORT_BUFFER_USHORT,3
+
+ mov dx,[esp+4] ; (dx) = Port
+ mov ecx,[esp+12] ; (ecx) = transfer count
+ push esi
+ mov esi,[esp+12] ; (esi) = (esp+8+push) = buffer
+ rep outsw
+ pop esi
+ stdRET _WRITE_PORT_BUFFER_USHORT
+
+stdENDP _WRITE_PORT_BUFFER_USHORT
+
+
+;++
+;
+; VOID
+; WRITE_PORT_BUFFER_ULONG(
+; PULONG Port,
+; PULONG Buffer,
+; ULONG Count
+; )
+;
+; Arguments:
+; (esp+4) = Port
+; (esp+8) = Buffer address
+; (esp+12) = Count
+;
+;--
+cPublicProc _WRITE_PORT_BUFFER_ULONG,3
+
+ mov dx,[esp+4] ; (dx) = Port
+ mov ecx,[esp+12] ; (ecx) = transfer count
+ push esi
+ mov esi,[esp+12] ; (esi) = (esp+8+push) = buffer
+ rep outsd
+ pop esi
+ stdRET _WRITE_PORT_BUFFER_ULONG
+
+stdENDP _WRITE_PORT_BUFFER_ULONG
+
+
+_TEXT ends
+ end
diff --git a/private/ntos/boot/lib/makefile b/private/ntos/boot/lib/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/boot/lib/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/boot/lib/mips/coffldr.c b/private/ntos/boot/lib/mips/coffldr.c
new file mode 100644
index 000000000..8acafd6b4
--- /dev/null
+++ b/private/ntos/boot/lib/mips/coffldr.c
@@ -0,0 +1,247 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ coffldr.c
+
+Abstract:
+
+ This module implements the code to load COFF format image into memory
+ and relocate it if necessary.
+
+Author:
+
+ David N. Cutler (davec) 10-May-1991
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+--*/
+
+#include "bldr.h"
+#include "firmware.h"
+#include "string.h"
+#include "ntimage.h"
+
+ARC_STATUS
+FwLoadImage(
+ IN PCHAR LoadFile,
+ OUT PVOID *TransferRoutine
+ )
+
+/*++
+
+Routine Description:
+
+ This routine attempts to load the specified file from the specified
+ device.
+
+Arguments:
+
+ LoadFile - Supplies a pointer to string descriptor for the name of
+ the file to load.
+
+ TransferRoutine - Supplies the address of where to store the start
+ address for the image.
+
+Return Value:
+
+ ESUCCESS is returned if the specified image file is loaded
+ successfully. Otherwise, an unsuccessful status is returned
+ that describes the reason for failure.
+
+--*/
+
+{
+
+ ULONG BasePage;
+ ULONG Count;
+ PIMAGE_FILE_HEADER CoffHeader;
+ PIMAGE_OPTIONAL_HEADER OptionalHeader;
+ PIMAGE_SECTION_HEADER SectionHeader;
+ ULONG FileId;
+ ULONG Index;
+ UCHAR LocalBuffer[SECTOR_SIZE+32];
+ PUCHAR LocalPointer;
+ PFW_MEMORY_DESCRIPTOR MemoryDescriptor;
+ ULONG PageCount;
+ ARC_STATUS Status;
+ LARGE_INTEGER SeekValue;
+
+ //
+ // Align the buffer on a Dcache fill size.
+ //
+
+ LocalPointer = (PVOID)((ULONG)((PCHAR)LocalBuffer +
+ PCR->FirstLevelDcacheFillSize - 1) & ~(PCR->FirstLevelDcacheFillSize - 1));
+
+ //
+ // Set the image start address to null.
+ //
+
+ *TransferRoutine = NULL;
+
+ //
+ // Attempt to open the load file.
+ //
+ // ****** temp ******
+ //
+ // This will eventually use FwOpen rather than BlOpen. For now both
+ // BlOpen and FwOpen share a single copy of the file table in the
+ // firmware loader. Eventually there will be a separate file table
+ // for the firmware loader and the boot loader.
+ //
+ // ****** temp ******
+ //
+
+ Status = BlOpen(2, LoadFile, ArcOpenReadOnly, &FileId);
+ if (Status != ESUCCESS) {
+ return Status;
+ }
+
+ //
+ // Read the image header from the file.
+ //
+
+ Status = FwRead(FileId, LocalPointer, SECTOR_SIZE, &Count);
+ if (Status != ESUCCESS) {
+ FwClose(FileId);
+ return Status;
+ }
+
+ //
+ // Get a pointer to the file header and begin processing it.
+ //
+
+ CoffHeader = (PIMAGE_FILE_HEADER)LocalPointer;
+ OptionalHeader =
+ (PIMAGE_OPTIONAL_HEADER)((ULONG)CoffHeader + sizeof(IMAGE_FILE_HEADER));
+
+ SectionHeader =
+ (PIMAGE_SECTION_HEADER)((ULONG)CoffHeader + sizeof(IMAGE_FILE_HEADER) +
+ CoffHeader->SizeOfOptionalHeader);
+
+ //
+ // If the image file is not the specified type, then return bad image
+ // type status.
+ //
+
+ if (((CoffHeader->Machine != IMAGE_TYPE_R3000) &&
+ (CoffHeader->Machine != IMAGE_TYPE_R4000)) ||
+ ((CoffHeader->Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE) == 0)) {
+ FwClose(FileId);
+ return EBADF;
+ }
+
+ //
+ // ******* add code ******
+ //
+ // Code needs to be added here to find the appropriate piece of memory
+ // to put the loaded image in.
+ //
+ // ******* add code ******
+ //
+
+
+ //
+ // Return the transfer routine to the caller.
+ //
+
+ *TransferRoutine = (PVOID)OptionalHeader->AddressOfEntryPoint;
+
+ //
+ // Scan through the sections and either read them into memory or clear
+ // the memory as appropriate.
+ //
+
+ for (Index = 0; Index < CoffHeader->NumberOfSections; Index += 1) {
+
+ //
+ // If the section is a code or initialized data section, then read
+ // the code or data into memory.
+ //
+
+ if (((SectionHeader->Characteristics & IMAGE_SCN_CNT_CODE) != 0) ||
+ ((SectionHeader->Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) != 0)) {
+ SeekValue.LowPart = SectionHeader->PointerToRawData;
+ SeekValue.HighPart = 0;
+ Status = FwSeek(FileId,
+ &SeekValue,
+ SeekAbsolute);
+
+ if (Status != ESUCCESS) {
+ break;
+ }
+
+ Status = FwRead(FileId,
+ (PVOID)SectionHeader->VirtualAddress,
+ SectionHeader->SizeOfRawData,
+ &Count);
+
+ if (Status != ESUCCESS) {
+ break;
+ }
+
+ //
+ // If the section is uninitialized data, then zero the specifed memory.
+ //
+
+ } else if ((SectionHeader->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) != 0) {
+ RtlZeroMemory((PVOID)SectionHeader->VirtualAddress,
+ SectionHeader->SizeOfRawData);
+
+ //
+ // Unknown section type.
+ //
+
+ } else {
+ Status = EBADF;
+ break;
+ }
+
+ SectionHeader += 1;
+ }
+
+ //
+ // Close file, allocate a memory descriptor if necessary, and return
+ // completion status.
+ //
+
+ FwClose(FileId);
+ if (Status == ESUCCESS) {
+
+ //
+ // ****** temp ******
+ //
+ // default the address of the memory descriptor for now.
+ //
+ // ****** temp ******
+ //
+
+ MemoryDescriptor = &FwMemoryTable[2];
+
+ //
+ // Compute the starting page and the number of pages that are consumed
+ // by the loaded image, and then allocate a memory descriptor for the
+ // allocated region.
+ //
+
+ BasePage = (OptionalHeader->BaseOfCode & 0xfffffff) >> PAGE_SHIFT;
+ PageCount = (((OptionalHeader->BaseOfData & 0xfffffff) +
+ OptionalHeader->SizeOfInitializedData +
+ OptionalHeader->SizeOfUninitializedData + PAGE_SIZE - 1) >>
+ PAGE_SHIFT) - BasePage;
+
+ FwGenerateDescriptor(MemoryDescriptor,
+ MemoryLoadedProgram,
+ BasePage,
+ PageCount);
+ }
+
+ return Status;
+}
diff --git a/private/ntos/boot/lib/mips/fwio.c b/private/ntos/boot/lib/mips/fwio.c
new file mode 100644
index 000000000..f89b04624
--- /dev/null
+++ b/private/ntos/boot/lib/mips/fwio.c
@@ -0,0 +1,345 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ fwio.c
+
+Abstract:
+
+ This module implements the ARC firmware I/O operations for a MIPS
+ R3000 or R4000 Jazz system.
+
+Author:
+
+ David N. Cutler (davec) 14-May-1991
+
+
+Revision History:
+
+--*/
+
+//#include "bldr.h"
+#include "bootlib.h"
+#include "firmware.h"
+
+//
+// Define file table.
+//
+
+BL_FILE_TABLE BlFileTable[BL_FILE_TABLE_SIZE];
+
+VOID
+FwIoInitialize (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the file table used by the firmware to
+ export I/O functions to client programs loaded from the system
+ partition and initializes the I/O entry points in the firmware
+ transfer vector.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ULONG Index;
+
+ //
+ // Initialize the I/O entry points in the firmware transfer vector.
+ //
+
+ (PARC_CLOSE_ROUTINE)SYSTEM_BLOCK->FirmwareVector[CloseRoutine] = FwClose;
+ (PARC_MOUNT_ROUTINE)SYSTEM_BLOCK->FirmwareVector[MountRoutine] = FwMount;
+ (PARC_OPEN_ROUTINE)SYSTEM_BLOCK->FirmwareVector[OpenRoutine] = FwOpen;
+ (PARC_READ_ROUTINE)SYSTEM_BLOCK->FirmwareVector[ReadRoutine] = FwRead;
+ (PARC_READ_STATUS_ROUTINE)SYSTEM_BLOCK->FirmwareVector[ReadStatusRoutine] =
+ FwGetReadStatus;
+ (PARC_SEEK_ROUTINE)SYSTEM_BLOCK->FirmwareVector[SeekRoutine] = FwSeek;
+ (PARC_WRITE_ROUTINE)SYSTEM_BLOCK->FirmwareVector[WriteRoutine] = FwWrite;
+
+ //
+ // Initialize the file table.
+ //
+
+ for (Index = 0; Index < BL_FILE_TABLE_SIZE; Index += 1) {
+ BlFileTable[Index].Flags.Open = 0;
+ }
+
+ return;
+}
+
+ARC_STATUS
+FwClose (
+ IN ULONG FileId
+ )
+
+/*++
+
+Routine Description:
+
+ This function closes a file or a device that is open.
+
+Arguments:
+
+ FileId - Supplies the file table index.
+
+Return Value:
+
+ If the specified file is open, then a close is attempted and
+ the status of the operation is returned. Otherwise, return an
+ unsuccessful status.
+
+--*/
+
+{
+
+ //
+ // If the file is open, then attempt to close it. Otherwise return an
+ // access error.
+ //
+
+ if (BlFileTable[FileId].Flags.Open == 1) {
+ return (BlFileTable[FileId].DeviceEntryTable->Close)(FileId);
+
+ } else {
+ return EACCES;
+ }
+}
+
+ARC_STATUS
+FwMount (
+ IN PCHAR MountPath,
+ IN MOUNT_OPERATION Operation
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+
+ return ESUCCESS;
+}
+
+ARC_STATUS
+FwOpen (
+ IN PCHAR OpenPath,
+ IN OPEN_MODE OpenMode,
+ OUT PULONG FileId
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+
+ if (*OpenPath != 'x') {
+ *FileId = BOOT_FILEID;
+
+ } else {
+ *FileId = ARC_CONSOLE_OUTPUT;
+ }
+
+ return ESUCCESS;
+}
+
+ARC_STATUS
+FwRead (
+ IN ULONG FileId,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ This function reads from a file or a device that is open.
+
+Arguments:
+
+ FileId - Supplies the file table index.
+
+ Buffer - Supplies a pointer to the buffer that receives the data
+ read.
+
+ Length - Supplies the number of bytes that are to be read.
+
+ Count - Supplies a pointer to a variable that receives the number of
+ bytes actually transfered.
+
+Return Value:
+
+ If the specified file is open for read, then a read is attempted
+ and the status of the operation is returned. Otherwise, return an
+ unsuccessful status.
+
+--*/
+
+{
+
+ //
+ // If the file is open for read, then attempt to read from it. Otherwise
+ // return an access error.
+ //
+
+ if ((BlFileTable[FileId].Flags.Open == 1) &&
+ (BlFileTable[FileId].Flags.Read == 1)) {
+ return (BlFileTable[FileId].DeviceEntryTable->Read)(FileId,
+ Buffer,
+ Length,
+ Count);
+
+ } else {
+ return EACCES;
+ }
+}
+
+ARC_STATUS
+FwGetReadStatus (
+ IN ULONG FileId
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ return ESUCCESS;
+}
+
+ARC_STATUS
+FwSeek (
+ IN ULONG FileId,
+ IN PLARGE_INTEGER Offset,
+ IN SEEK_MODE SeekMode
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+ If the specified file is open, then a seek is attempted and
+ the status of the operation is returned. Otherwise, return an
+ unsuccessful status.
+
+--*/
+
+{
+
+ //
+ // If the file is open, then attempt to seek on it. Otherwise return an
+ // access error.
+ //
+
+ if (BlFileTable[FileId].Flags.Open == 1) {
+ return (BlFileTable[FileId].DeviceEntryTable->Seek)(FileId,
+ Offset,
+ SeekMode);
+
+ } else {
+ return EACCES;
+ }
+}
+
+ARC_STATUS
+FwWrite (
+ IN ULONG FileId,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ This function writes to a file or a device that is open.
+
+Arguments:
+
+ FileId - Supplies the file table index.
+
+ Buffer - Supplies a pointer to the buffer that contains the data
+ to write.
+
+ Length - Supplies the number of bytes that are to be written.
+
+ Count - Supplies a pointer to a variable that receives the number of
+ bytes actually transfered.
+
+Return Value:
+
+ If the specified file is open for write, then a write is attempted
+ and the status of the operation is returned. Otherwise, return an
+ unsuccessful status.
+
+--*/
+
+{
+
+ //
+ // If the file is open for write, then attempt to read from it. Otherwise
+ // return an access error.
+ //
+
+ if ((BlFileTable[FileId].Flags.Open == 1) &&
+ (BlFileTable[FileId].Flags.Write == 1)) {
+ return (BlFileTable[FileId].DeviceEntryTable->Write)(FileId,
+ Buffer,
+ Length,
+ Count);
+
+ } else {
+ return EACCES;
+ }
+}
diff --git a/private/ntos/boot/lib/mips/ntsetup.c b/private/ntos/boot/lib/mips/ntsetup.c
new file mode 100644
index 000000000..8495e71dc
--- /dev/null
+++ b/private/ntos/boot/lib/mips/ntsetup.c
@@ -0,0 +1,652 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ ntsetup.c
+
+Abstract:
+
+ This module is the tail-end of the OS loader program. It performs all
+ MIPS specific allocations and initialize. The OS loader invokes this
+ this routine immediately before calling the loaded kernel image.
+
+Author:
+
+ John Vert (jvert) 20-Jun-1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "bldr.h"
+#include "stdio.h"
+
+//
+// Define macro to round structure size to next 16-byte boundary
+//
+
+#define ROUND_UP(x) ((sizeof(x) + 15) & (~15))
+
+//
+// Configuration Data Header
+// The following structure is copied from fw\mips\oli2msft.h
+// NOTE shielint - Somehow, this structure got incorporated into
+// firmware EISA configuration data. We need to know the size of the
+// header and remove it before writing eisa configuration data to
+// registry.
+//
+
+typedef struct _CONFIGURATION_DATA_HEADER {
+ USHORT Version;
+ USHORT Revision;
+ PCHAR Type;
+ PCHAR Vendor;
+ PCHAR ProductName;
+ PCHAR SerialNumber;
+} CONFIGURATION_DATA_HEADER;
+
+#define CONFIGURATION_DATA_HEADER_SIZE sizeof(CONFIGURATION_DATA_HEADER)
+
+//
+// Internal function references
+//
+
+ARC_STATUS
+ReorganizeEisaConfigurationTree(
+ IN PCONFIGURATION_COMPONENT_DATA RootEntry
+ );
+
+ARC_STATUS
+CreateEisaConfigurationData (
+ IN PCONFIGURATION_COMPONENT_DATA RootEntry
+ );
+
+VOID
+BlQueryImplementationAndRevision (
+ OUT PULONG ProcessorId,
+ OUT PULONG FloatingId
+ );
+
+ARC_STATUS
+BlSetupForNt(
+ IN PLOADER_PARAMETER_BLOCK BlLoaderBlock
+ )
+
+/*++
+
+Routine Description:
+
+ This function initializes the MIPS specific kernel data structures
+ required by the NT system.
+
+Arguments:
+
+ BlLoaderBlock - Supplies the address of the loader parameter block.
+
+Return Value:
+
+ ESUCCESS is returned if the setup is successfully complete. Otherwise,
+ an unsuccessful status is returned.
+
+--*/
+
+{
+
+ PCONFIGURATION_COMPONENT_DATA ConfigEntry;
+ ULONG FloatingId;
+ CHAR Identifier[256];
+ ULONG KernelPage;
+ ULONG LinesPerBlock;
+ ULONG LineSize;
+ PCHAR NewIdentifier;
+ ULONG PrcbPage;
+ ULONG ProcessorId;
+ ARC_STATUS Status;
+
+ //
+ // If the host configuration is not a multiprocessor machine, then add
+ // the processor and floating point coprocessor identification to the
+ // processor identification string.
+ //
+
+ if (SYSTEM_BLOCK->RestartBlock == NULL) {
+ ConfigEntry = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
+ ProcessorClass,
+ CentralProcessor,
+ NULL);
+
+ if (ConfigEntry != NULL) {
+ BlQueryImplementationAndRevision(&ProcessorId, &FloatingId);
+ sprintf(&Identifier[0],
+ "%s - Pr %d/%d, Fp %d/%d",
+ ConfigEntry->ComponentEntry.Identifier,
+ (ProcessorId >> 8) & 0xff,
+ ProcessorId & 0xff,
+ (FloatingId >> 8) & 0xff,
+ FloatingId & 0xff);
+
+ NewIdentifier = (PCHAR)BlAllocateHeap(strlen(&Identifier[0]) + 1);
+ if (NewIdentifier != NULL) {
+ strcpy(NewIdentifier, &Identifier[0]);
+ ConfigEntry->ComponentEntry.IdentifierLength = strlen(NewIdentifier);
+ ConfigEntry->ComponentEntry.Identifier = NewIdentifier;
+ }
+ }
+ }
+
+ //
+ // Find System entry and check each of its direct child to
+ // look for EisaAdapter.
+ //
+
+ ConfigEntry = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
+ SystemClass,
+ ArcSystem,
+ NULL);
+ if (ConfigEntry) {
+ ConfigEntry = ConfigEntry->Child;
+ }
+
+ while (ConfigEntry) {
+
+ if ((ConfigEntry->ComponentEntry.Class == AdapterClass) &&
+ (ConfigEntry->ComponentEntry.Type == EisaAdapter)) {
+
+ //
+ // Convert EISA format configuration data to our CM_ format.
+ //
+
+ Status = ReorganizeEisaConfigurationTree(ConfigEntry);
+ if (Status != ESUCCESS) {
+ return(Status);
+ }
+ }
+ ConfigEntry = ConfigEntry->Sibling;
+ }
+
+ //
+ // Find the primary data and instruction cache configuration entries, and
+ // compute the fill size and cache size for each cache. These entries MUST
+ // be present on all ARC compliant systems.
+ //
+
+ ConfigEntry = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
+ CacheClass,
+ PrimaryDcache,
+ NULL);
+
+ if (ConfigEntry != NULL) {
+ LinesPerBlock = ConfigEntry->ComponentEntry.Key >> 24;
+ LineSize = 1 << ((ConfigEntry->ComponentEntry.Key >> 16) & 0xff);
+ BlLoaderBlock->u.Mips.FirstLevelDcacheFillSize = LinesPerBlock * LineSize;
+ BlLoaderBlock->u.Mips.FirstLevelDcacheSize =
+ 1 << ((ConfigEntry->ComponentEntry.Key & 0xffff) + PAGE_SHIFT);
+
+ } else {
+ return EINVAL;
+ }
+
+ ConfigEntry = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
+ CacheClass,
+ PrimaryIcache,
+ NULL);
+
+ if (ConfigEntry != NULL) {
+ LinesPerBlock = ConfigEntry->ComponentEntry.Key >> 24;
+ LineSize = 1 << ((ConfigEntry->ComponentEntry.Key >> 16) & 0xff);
+ BlLoaderBlock->u.Mips.FirstLevelIcacheFillSize = LinesPerBlock * LineSize;
+ BlLoaderBlock->u.Mips.FirstLevelIcacheSize =
+ 1 << ((ConfigEntry->ComponentEntry.Key & 0xffff) + PAGE_SHIFT);
+
+ } else {
+ return EINVAL;
+ }
+
+ //
+ // Find the secondary data and instruction cache configuration entries,
+ // and if present, compute the fill size and cache size for each cache.
+ // These entries are optional, and may or may not, be present.
+ //
+
+ ConfigEntry = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
+ CacheClass,
+ SecondaryCache,
+ NULL);
+
+ if (ConfigEntry != NULL) {
+ LinesPerBlock = ConfigEntry->ComponentEntry.Key >> 24;
+ LineSize = 1 << ((ConfigEntry->ComponentEntry.Key >> 16) & 0xff);
+ BlLoaderBlock->u.Mips.SecondLevelDcacheFillSize = LinesPerBlock * LineSize;
+ BlLoaderBlock->u.Mips.SecondLevelDcacheSize =
+ 1 << ((ConfigEntry->ComponentEntry.Key & 0xffff) + PAGE_SHIFT);
+
+ BlLoaderBlock->u.Mips.SecondLevelIcacheSize = 0;
+ BlLoaderBlock->u.Mips.SecondLevelIcacheFillSize = 0;
+
+ } else {
+ ConfigEntry = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
+ CacheClass,
+ SecondaryDcache,
+ NULL);
+
+ if (ConfigEntry != NULL) {
+ LinesPerBlock = ConfigEntry->ComponentEntry.Key >> 24;
+ LineSize = 1 << ((ConfigEntry->ComponentEntry.Key >> 16) & 0xff);
+ BlLoaderBlock->u.Mips.SecondLevelDcacheFillSize = LinesPerBlock * LineSize;
+ BlLoaderBlock->u.Mips.SecondLevelDcacheSize =
+ 1 << ((ConfigEntry->ComponentEntry.Key & 0xffff) + PAGE_SHIFT);
+
+ ConfigEntry = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
+ CacheClass,
+ SecondaryIcache,
+ NULL);
+
+ if (ConfigEntry != NULL) {
+ LinesPerBlock = ConfigEntry->ComponentEntry.Key >> 24;
+ LineSize = 1 << ((ConfigEntry->ComponentEntry.Key >> 16) & 0xff);
+ BlLoaderBlock->u.Mips.SecondLevelIcacheFillSize = LinesPerBlock * LineSize;
+ BlLoaderBlock->u.Mips.SecondLevelIcacheSize =
+ 1 << ((ConfigEntry->ComponentEntry.Key & 0xffff) + PAGE_SHIFT);
+
+ } else {
+ BlLoaderBlock->u.Mips.SecondLevelIcacheSize = 0;
+ BlLoaderBlock->u.Mips.SecondLevelIcacheFillSize = 0;
+ }
+
+ } else {
+ BlLoaderBlock->u.Mips.SecondLevelDcacheSize = 0;
+ BlLoaderBlock->u.Mips.SecondLevelDcacheFillSize = 0;
+ BlLoaderBlock->u.Mips.SecondLevelIcacheSize = 0;
+ BlLoaderBlock->u.Mips.SecondLevelIcacheFillSize = 0;
+ }
+ }
+
+ //
+ // Allocate DPC stack pages for the boot processor.
+ //
+
+ Status = BlAllocateDescriptor(LoaderStartupDpcStack,
+ 0,
+ KERNEL_STACK_SIZE >> PAGE_SHIFT,
+ &KernelPage);
+
+ if (Status != ESUCCESS) {
+ return(Status);
+ }
+
+ BlLoaderBlock->u.Mips.InterruptStack =
+ (KSEG0_BASE | (KernelPage << PAGE_SHIFT)) + KERNEL_STACK_SIZE;
+
+ //
+ // Allocate kernel stack pages for the boot processor idle thread.
+ //
+
+ Status = BlAllocateDescriptor(LoaderStartupKernelStack,
+ 0,
+ KERNEL_STACK_SIZE >> PAGE_SHIFT,
+ &KernelPage);
+
+ if (Status != ESUCCESS) {
+ return(Status);
+ }
+
+ BlLoaderBlock->KernelStack =
+ (KSEG0_BASE | (KernelPage << PAGE_SHIFT)) + KERNEL_STACK_SIZE;
+
+ //
+ // Allocate panic stack pages for the boot processor.
+ //
+
+ Status = BlAllocateDescriptor(LoaderStartupPanicStack,
+ 0,
+ KERNEL_STACK_SIZE >> PAGE_SHIFT,
+ &KernelPage);
+
+ if (Status != ESUCCESS) {
+ return(Status);
+ }
+
+ BlLoaderBlock->u.Mips.PanicStack =
+ (KSEG0_BASE | (KernelPage << PAGE_SHIFT)) + KERNEL_STACK_SIZE;
+
+ //
+ // Allocate and zero two pages for the PCR.
+ //
+
+ Status = BlAllocateDescriptor(LoaderStartupPcrPage,
+ 0,
+ 2,
+ &BlLoaderBlock->u.Mips.PcrPage);
+
+ if (Status != ESUCCESS) {
+ return(Status);
+ }
+
+ BlLoaderBlock->u.Mips.PcrPage2 = BlLoaderBlock->u.Mips.PcrPage + 1;
+ RtlZeroMemory((PVOID)(KSEG0_BASE | (BlLoaderBlock->u.Mips.PcrPage << PAGE_SHIFT)),
+ PAGE_SIZE * 2);
+
+ //
+ // Allocate and zero two pages for the PDR and one page of memory for
+ // the initial processor block, idle process, and idle thread structures.
+ //
+
+ Status = BlAllocateDescriptor(LoaderStartupPdrPage,
+ 0,
+ 3,
+ &BlLoaderBlock->u.Mips.PdrPage);
+
+ if (Status != ESUCCESS) {
+ return(Status);
+ }
+
+ RtlZeroMemory((PVOID)(KSEG0_BASE | (BlLoaderBlock->u.Mips.PdrPage << PAGE_SHIFT)),
+ PAGE_SIZE * 3);
+
+ //
+ // The storage for processor control block, the idle thread object, and
+ // the idle thread process object are allocated from the third page of the
+ // PDR allocation. The addresses of these data structures are computed
+ // and stored in the loader parameter block and the memory is zeroed.
+ //
+
+ PrcbPage = BlLoaderBlock->u.Mips.PdrPage + 2;
+ if (PAGE_SIZE >= (ROUND_UP(KPRCB) + ROUND_UP(EPROCESS) + ROUND_UP(ETHREAD))) {
+ BlLoaderBlock->Prcb = KSEG0_BASE | (PrcbPage << PAGE_SHIFT);
+ BlLoaderBlock->Process = BlLoaderBlock->Prcb + ROUND_UP(KPRCB);
+ BlLoaderBlock->Thread = BlLoaderBlock->Process + ROUND_UP(EPROCESS);
+
+ } else {
+ return(ENOMEM);
+ }
+
+ //
+ // Flush all caches.
+ //
+
+ if (SYSTEM_BLOCK->FirmwareVectorLength > (sizeof(PVOID) * FlushAllCachesRoutine)) {
+ ArcFlushAllCaches();
+ }
+
+ return(ESUCCESS);
+}
+
+ARC_STATUS
+ReorganizeEisaConfigurationTree(
+ IN PCONFIGURATION_COMPONENT_DATA RootEntry
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sorts the eisa adapter configuration tree based on
+ the slot the component resided in. It also creates a new configuration
+ data for EisaAdapter component to contain ALL the eisa slot and function
+ information. Finally the Eisa tree will be wiped out.
+
+Arguments:
+
+ RootEntry - Supplies a pointer to a EisaAdapter component. This is
+ the root of Eisa adapter tree.
+
+
+Returns:
+
+ ESUCCESS is returned if the reorganization is successfully complete.
+ Otherwise, an unsuccessful status is returned.
+
+--*/
+{
+
+ PCONFIGURATION_COMPONENT_DATA CurrentEntry, PreviousEntry;
+ PCONFIGURATION_COMPONENT_DATA EntryFound, EntryFoundPrevious;
+ PCONFIGURATION_COMPONENT_DATA AttachedEntry, DetachedList;
+ ARC_STATUS Status;
+
+ //
+ // We sort the direct children of EISA adapter tree based on the slot
+ // they reside in. Only the direct children of EISA root need to be
+ // sorted.
+ // Note the "Key" field of CONFIGURATION_COMPONENT contains
+ // EISA slot number.
+ //
+
+ //
+ // First, detach all the children from EISA root.
+ //
+
+ AttachedEntry = NULL; // Child list of Eisa root
+ DetachedList = RootEntry->Child; // Detached child list
+ PreviousEntry = NULL;
+
+ while (DetachedList) {
+
+ //
+ // Find the component with the smallest slot number from detached
+ // list.
+ //
+
+ EntryFound = DetachedList;
+ EntryFoundPrevious = NULL;
+ CurrentEntry = DetachedList->Sibling;
+ PreviousEntry = DetachedList;
+ while (CurrentEntry) {
+ if (CurrentEntry->ComponentEntry.Key <
+ EntryFound->ComponentEntry.Key) {
+ EntryFound = CurrentEntry;
+ EntryFoundPrevious = PreviousEntry;
+ }
+ PreviousEntry = CurrentEntry;
+ CurrentEntry = CurrentEntry->Sibling;
+ }
+
+ //
+ // Remove the component from the detached child list.
+ // If the component is not the head of the detached list, we remove it
+ // by setting its previous entry's sibling to the component's sibling.
+ // Otherwise, we simply update Detach list head to point to the
+ // component's sibling.
+ //
+
+ if (EntryFoundPrevious) {
+ EntryFoundPrevious->Sibling = EntryFound->Sibling;
+ } else {
+ DetachedList = EntryFound->Sibling;
+ }
+
+ //
+ // Attach the component to the child list of Eisa root.
+ //
+
+ if (AttachedEntry) {
+ AttachedEntry->Sibling = EntryFound;
+ } else {
+ RootEntry->Child = EntryFound;
+ }
+ AttachedEntry = EntryFound;
+ AttachedEntry->Sibling = NULL;
+ }
+
+ //
+ // Finally, we traverse the Eisa tree to collect all the Eisa slot
+ // and function information and put it to the configuration data of
+ // Eisa root entry.
+ //
+
+ Status = CreateEisaConfigurationData(RootEntry);
+
+ //
+ // Wipe out all the children of EISA tree.
+ // NOTE shielint - For each child component, we should convert its
+ // configuration data from EISA format to our CM_ format.
+ //
+
+ RootEntry->Child = NULL;
+ return(Status);
+
+}
+
+ARC_STATUS
+CreateEisaConfigurationData (
+ IN PCONFIGURATION_COMPONENT_DATA RootEntry
+ )
+
+/*++
+
+Routine Description:
+
+ This routine traverses Eisa configuration tree to collect all the
+ slot and function information and attaches it to the configuration data
+ of Eisa RootEntry.
+
+ Note that this routine assumes that the EISA tree has been sorted based
+ on the slot number.
+
+Arguments:
+
+ RootEntry - Supplies a pointer to the Eisa configuration
+ component entry.
+
+Returns:
+
+ ESUCCESS is returned if the new EisaAdapter configuration data is
+ successfully created. Otherwise, an unsuccessful status is returned.
+
+--*/
+{
+ ULONG DataSize, NextSlot = 0, i;
+ PCM_PARTIAL_RESOURCE_LIST Descriptor;
+ PCONFIGURATION_COMPONENT Component;
+ PCONFIGURATION_COMPONENT_DATA CurrentEntry;
+ PUCHAR DataPointer;
+ CM_EISA_SLOT_INFORMATION EmptySlot =
+ {EISA_EMPTY_SLOT, 0, 0, 0, 0, 0, 0, 0};
+
+ //
+ // Remove the configuration data of Eisa Adapter
+ //
+
+ RootEntry->ConfigurationData = NULL;
+ RootEntry->ComponentEntry.ConfigurationDataLength = 0;
+
+ //
+ // If the EISA stree contains valid slot information, i.e.
+ // root has children attaching to it.
+ //
+
+ if (RootEntry->Child) {
+
+ //
+ // First find out how much memory is needed to store EISA config
+ // data.
+ //
+
+ DataSize = sizeof(CM_PARTIAL_RESOURCE_LIST);
+ CurrentEntry = RootEntry->Child;
+
+ while (CurrentEntry) {
+ Component = &CurrentEntry->ComponentEntry;
+ if (CurrentEntry->ConfigurationData) {
+ if (Component->Key > NextSlot) {
+
+ //
+ // If there is any empty slot between current slot
+ // and previous checked slot, we need to count the
+ // space for the empty slots.
+ //
+
+ DataSize += (Component->Key - NextSlot) *
+ sizeof(CM_EISA_SLOT_INFORMATION);
+ }
+ DataSize += Component->ConfigurationDataLength + 1 -
+ CONFIGURATION_DATA_HEADER_SIZE;
+ NextSlot = Component->Key + 1;
+ }
+ CurrentEntry = CurrentEntry->Sibling;
+ }
+
+ //
+ // Allocate memory from heap to hold the EISA configuration data.
+ //
+
+ DataPointer = BlAllocateHeap(DataSize);
+
+ if (DataPointer == NULL) {
+ return ENOMEM;
+ } else {
+ RootEntry->ConfigurationData = DataPointer;
+ RootEntry->ComponentEntry.ConfigurationDataLength = DataSize;
+ }
+
+ //
+ // Create a CM_PARTIAL_RESOURCE_LIST for the new configuration data.
+ //
+
+ Descriptor = (PCM_PARTIAL_RESOURCE_LIST)DataPointer;
+ Descriptor->Version = 0;
+ Descriptor->Revision = 0;
+ Descriptor->Count = 1;
+ Descriptor->PartialDescriptors[0].Type = CmResourceTypeDeviceSpecific;
+ Descriptor->PartialDescriptors[0].ShareDisposition = 0;
+ Descriptor->PartialDescriptors[0].Flags = 0;
+ Descriptor->PartialDescriptors[0].u.DeviceSpecificData.Reserved1 = 0;
+ Descriptor->PartialDescriptors[0].u.DeviceSpecificData.Reserved2 = 0;
+ Descriptor->PartialDescriptors[0].u.DeviceSpecificData.DataSize =
+ DataSize - sizeof(CM_PARTIAL_RESOURCE_LIST);
+
+ //
+ // Visit each child of the RootEntry and copy its ConfigurationData
+ // to the new configuration data area.
+ // N.B. The configuration data includes a slot information and zero
+ // or more function information. The slot information provided
+ // by ARC eisa data does not have "ReturnedCode" as defined in
+ // our CM_EISA_SLOT_INFORMATION. This code will convert the
+ // standard EISA slot information to our CM format.
+ //
+
+ CurrentEntry = RootEntry->Child;
+ DataPointer += sizeof(CM_PARTIAL_RESOURCE_LIST);
+ NextSlot = 0;
+
+ while (CurrentEntry) {
+ Component = &CurrentEntry->ComponentEntry;
+ if (CurrentEntry->ConfigurationData) {
+
+ //
+ // Check if there is any empty slot. If yes, create empty
+ // slot information. Also make sure the config data area is
+ // big enough.
+ //
+
+ if (Component->Key > NextSlot) {
+ for (i = NextSlot; i < CurrentEntry->ComponentEntry.Key; i++ ) {
+ *(PCM_EISA_SLOT_INFORMATION)DataPointer = EmptySlot;
+ DataPointer += sizeof(CM_EISA_SLOT_INFORMATION);
+ }
+ }
+
+ *DataPointer++ = 0; // See comment above
+ RtlMoveMemory( // Skip config data header
+ DataPointer,
+ (PUCHAR)CurrentEntry->ConfigurationData +
+ CONFIGURATION_DATA_HEADER_SIZE,
+ Component->ConfigurationDataLength -
+ CONFIGURATION_DATA_HEADER_SIZE
+ );
+ DataPointer += Component->ConfigurationDataLength -
+ CONFIGURATION_DATA_HEADER_SIZE;
+ NextSlot = Component->Key + 1;
+ }
+ CurrentEntry = CurrentEntry->Sibling;
+ }
+ }
+ return(ESUCCESS);
+}
+
diff --git a/private/ntos/boot/lib/mips/query.s b/private/ntos/boot/lib/mips/query.s
new file mode 100644
index 000000000..29fabc321
--- /dev/null
+++ b/private/ntos/boot/lib/mips/query.s
@@ -0,0 +1,70 @@
+// TITLE("Query Implemention and Revision Information")
+//++
+//
+// Copyright (c) 1993 Microsoft Corporation
+//
+// Module Name:
+//
+// query.s
+//
+// Abstract:
+//
+// This module implements code to query the processor and floating
+// coprocessor implementation and revsion information.
+//
+// Author:
+//
+// David N. Cutler (davec) 22-Jun-1993
+//
+// Environment:
+//
+// User mode.
+//
+// Revision History:
+//
+//--
+
+#include "ksmips.h"
+
+ SBTTL("Query Implementation and Revision")
+//++
+//
+// VOID
+// BlQueryImplementationAndRevision (
+// OUT PULONG ProcessorId,
+// OUT PULONG FloatingId
+// )
+//
+// Routine Description:
+//
+// This function returns the implementation and revision of the host
+// processor and floating coprocessor.
+//
+// Arguments:
+//
+// ProcessorId (a0) - Supplies a pointer to a variable that receives the
+// processor information.
+//
+// Floatingid (a1) - Supplies a pointer to a variable that receives the
+// floating coprocessor information.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(BlQueryImplementationAndRevision)
+
+ .set noreorder
+ .set noat
+ mfc0 t0,prid // get implementation and revision
+ cfc1 t1,fsrid // get implementation and revision
+ sw t0,0(a0) //
+ sw t1,0(a1) //
+ .set at
+ .set reorder
+
+ j ra // return
+
+ .end BlQueryImplementationAndRevision
diff --git a/private/ntos/boot/lib/mips/sources b/private/ntos/boot/lib/mips/sources
new file mode 100644
index 000000000..1f03137d2
--- /dev/null
+++ b/private/ntos/boot/lib/mips/sources
@@ -0,0 +1,5 @@
+MIPS_SOURCES=mips\ntsetup.c \
+ mips\query.s \
+ mips\stubs.c \
+ mips\xxchkstk.s
+
diff --git a/private/ntos/boot/lib/mips/stubs.c b/private/ntos/boot/lib/mips/stubs.c
new file mode 100644
index 000000000..38e29c624
--- /dev/null
+++ b/private/ntos/boot/lib/mips/stubs.c
@@ -0,0 +1,245 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ stubs.c
+
+Abstract:
+
+ This module implements stub routines for the boot code.
+
+Author:
+
+ David N. Cutler (davec) 7-Nov-1990
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+--*/
+
+#define _BLDR_
+#include "ntos.h"
+
+//
+// Define global data.
+//
+
+ULONG BlDcacheFillSize = 32;
+
+VOID
+KeBugCheck (
+ IN ULONG BugCheckCode
+ )
+
+/*++
+
+Routine Description:
+
+ This function crashes the system in a controlled manner.
+
+Arguments:
+
+ BugCheckCode - Supplies the reason for the bug check.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Print out the bug check code and break.
+ //
+
+ DbgPrint("\n*** BugCheck (%lx) ***\n\n", BugCheckCode);
+ while(TRUE) {
+ DbgBreakPoint();
+ };
+ return;
+}
+
+LARGE_INTEGER
+KeQueryPerformanceCounter (
+ OUT PLARGE_INTEGER Frequency OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a stub for the kernel debugger and always returns a
+ value of zero.
+
+Arguments:
+
+ Frequency - Supplies an optional pointer to a variable which receives
+ the performance counter frequency in Hertz.
+
+Return Value:
+
+ A value of zero is returned.
+
+--*/
+
+{
+
+ LARGE_INTEGER Counter;
+
+ //
+ // Return the current system time as the function value.
+ //
+
+ Counter.LowPart = 0;
+ Counter.HighPart = 0;
+ return Counter;
+}
+
+VOID
+KeStallExecutionProcessor (
+ IN ULONG MicroSeconds
+ )
+
+/*++
+
+Routine Description:
+
+ This function stalls execution for the specified number of microseconds.
+
+Arguments:
+
+ MicroSeconds - Supplies the number of microseconds that execution is to be
+ stalled.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ULONG Index;
+ ULONG Limit;
+ PULONG Store;
+ ULONG Value;
+
+ //
+ // ****** begin temporary code ******
+ //
+ // This code must be replaced with a smarter version. For now it assumes
+ // an execution rate of 40,000,000 instructions per second and 4 instructions
+ // per iteration.
+ //
+
+ Store = &Value;
+ Limit = (MicroSeconds * 40 / 4);
+ for (Index = 0; Index < Limit; Index += 1) {
+ *Store = Index;
+ }
+ return;
+}
+
+PVOID
+MmDbgReadCheck (
+ IN PVOID VirtualAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the phyiscal address for a virtual address
+ which is valid (mapped) for read access.
+
+Arguments:
+
+ VirtualAddress - Supplies the virtual address to check.
+
+Return Value:
+
+ Returns NULL if the address is not valid or readable, otherwise
+ returns the physical address of the corresponding virtual address.
+
+--*/
+
+{
+
+ return VirtualAddress;
+}
+
+PVOID
+MmDbgTranslatePhysicalAddress (
+ IN PHYSICAL_ADDRESS PhysicalAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the phyiscal address for a physical address
+ which is valid (mapped).
+
+Arguments:
+
+ PhysicalAddress - Supplies the physical address to check.
+
+Return Value:
+
+ Returns NULL if the address is not valid or readable, otherwise
+ returns the physical address of the corresponding virtual address.
+
+--*/
+
+{
+
+ return (PVOID)PhysicalAddress.LowPart;
+}
+
+PVOID
+MmDbgWriteCheck (
+ IN PVOID VirtualAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the phyiscal address for a virtual address
+ which is valid (mapped) for write access.
+
+Arguments:
+
+ VirtualAddress - Supplies the virtual address to check.
+
+Return Value:
+
+ Returns NULL if the address is not valid or readable, otherwise
+ returns the physical address of the corresponding virtual address.
+
+--*/
+
+{
+ return VirtualAddress;
+}
+
+VOID
+RtlAssert(
+ IN PVOID FailedAssertion,
+ IN PVOID FileName,
+ IN ULONG LineNumber,
+ IN PCHAR Message OPTIONAL
+ )
+{
+
+ DbgPrint( "\n*** Assertion failed\n");
+ while (TRUE) {
+ DbgBreakPoint();
+ }
+}
diff --git a/private/ntos/boot/lib/mips/xxchkstk.s b/private/ntos/boot/lib/mips/xxchkstk.s
new file mode 100644
index 000000000..25d262dcf
--- /dev/null
+++ b/private/ntos/boot/lib/mips/xxchkstk.s
@@ -0,0 +1,54 @@
+// TITLE("Runtime Stack Checking")
+//++
+//
+// Copyright (c) 1992 Microsoft Corporation
+//
+// Module Name:
+//
+// xxchkstk.s
+//
+// Abstract:
+//
+// This module implements a stub routine for runtime stack checking.
+//
+// Author:
+//
+// David N. Cutler (davec) 21-Sep-1992
+//
+// Environment:
+//
+// User mode.
+//
+// Revision History:
+//
+//--
+
+#include "ksmips.h"
+
+ SBTTL("Check Stack")
+//++
+//
+// VOID
+// _RtlCheckStack (
+// IN ULONG Allocation
+// )
+//
+// Routine Description:
+//
+// This function provides a stub routine for runtime stack checking.
+//
+// Arguments:
+//
+// Allocation (t8) - Supplies the size of the allocation in bytes.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(_RtlCheckStack)
+
+ j ra // return
+
+ .end _RtlCheckStack
diff --git a/private/ntos/boot/lib/mips/xxconout.c b/private/ntos/boot/lib/mips/xxconout.c
new file mode 100644
index 000000000..22a015931
--- /dev/null
+++ b/private/ntos/boot/lib/mips/xxconout.c
@@ -0,0 +1,400 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ xxconout.c
+
+Abstract:
+
+ This module implements a stubbed MIPS console out driver that simply
+ uses debug print to do its output.
+
+Author:
+
+ David N. Cutler (davec) 28-Aug-1991
+
+Environment:
+
+ Kernel mode.
+
+Revision History:
+
+--*/
+
+//#include "bldr.h"
+#include "bootlib.h"
+#include "firmware.h"
+#include "string.h"
+
+//
+// Define prototypes for all routines used by this module.
+//
+
+ARC_STATUS
+ConsoleOutClose (
+ IN ULONG FileId
+ );
+
+ARC_STATUS
+ConsoleOutMount (
+ IN PCHAR MountPath,
+ IN MOUNT_OPERATION Operation
+ );
+
+ARC_STATUS
+ConsoleOutOpen (
+ IN PCHAR OpenPath,
+ IN OPEN_MODE OpenMode,
+ OUT PULONG FileId
+ );
+
+ARC_STATUS
+ConsoleOutRead (
+ IN ULONG FileId,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ );
+
+ARC_STATUS
+ConsoleOutGetReadStatus (
+ IN ULONG FileId
+ );
+
+ARC_STATUS
+ConsoleOutSeek (
+ IN ULONG FileId,
+ IN PLARGE_INTEGER Offset,
+ IN SEEK_MODE SeekMode
+ );
+
+ARC_STATUS
+ConsoleOutWrite (
+ IN ULONG FileId,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ );
+//
+// Define static data.
+//
+
+BL_DEVICE_ENTRY_TABLE ConsoleOutEntryTable;
+
+ARC_STATUS
+ConsoleOutClose (
+ IN ULONG FileId
+ )
+
+/*++
+
+Routine Description:
+
+ This function closes the file table entry specified by the file id.
+
+Arguments:
+
+ FileId - Supplies the file table index.
+
+Return Value:
+
+ ESUCCESS is returned
+
+--*/
+
+{
+
+ BlFileTable[FileId].Flags.Open = 0;
+ return ESUCCESS;
+}
+
+ARC_STATUS
+ConsoleOutMount (
+ IN PCHAR MountPath,
+ IN MOUNT_OPERATION Operation
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ return ESUCCESS;
+}
+
+ARC_STATUS
+ConsoleOutOpen (
+ IN PCHAR OpenPath,
+ IN OPEN_MODE OpenMode,
+ OUT PULONG FileId
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ return ESUCCESS;
+}
+
+ARC_STATUS
+ConsoleOutRead (
+ IN ULONG FileId,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ This function is invalid for the console and returns an error.
+
+Arguments:
+
+ FileId - Supplies the file table index.
+
+ Buffer - Supplies a pointer to the buffer that receives the data
+ read.
+
+ Length - Supplies the number of bytes to be read.
+
+ Count - Supplies a pointer to a variable that receives the number of
+ bytes actually read.
+
+Return Value:
+
+ ENODEV is returned.
+
+--*/
+
+{
+
+ return ENODEV;
+}
+
+ARC_STATUS
+ConsoleOutGetReadStatus (
+ IN ULONG FileId
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ return ESUCCESS;
+}
+
+ARC_STATUS
+ConsoleOutSeek (
+ IN ULONG FileId,
+ IN PLARGE_INTEGER Offset,
+ IN SEEK_MODE SeekMode
+ )
+
+/*++
+
+Routine Description:
+
+ This function sets the device position to the specified offset for
+ the specified file id.
+
+Arguments:
+
+ FileId - Supplies the file table index.
+
+ Offset - Supplies to new device position.
+
+ SeekMode - Supplies the mode for the position.
+
+Return Value:
+
+ ESUCCESS is returned.
+
+--*/
+
+{
+
+ return ESUCCESS;
+}
+
+ARC_STATUS
+ConsoleOutWrite (
+ IN ULONG FileId,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ This function write information to the console ConsoleOut device.
+
+Arguments:
+
+ FileId - Supplies the file table index.
+
+ Buffer - Supplies a pointer to the buffer that receives the data
+ read.
+
+ Length - Supplies the number of bytes to be read.
+
+ Count - Supplies a pointer to a variable that receives the number of
+ bytes actually read.
+
+Return Value:
+
+ ESUCCESS is returne as the function value.
+
+--*/
+
+{
+
+ CHAR LocalBuffer[512];
+
+ //
+ // Copy the string to the local buffer so it can be zero terminated.
+ //
+
+ strncpy(&LocalBuffer[0], (PCHAR)Buffer, Length);
+ LocalBuffer[Length] = 0;
+
+ //
+ // Output the string using debug print.
+ //
+
+ DbgPrint("%s", &LocalBuffer[0]);
+ return ESUCCESS;
+}
+
+NTSTATUS
+ConsoleOutBootInitialize(
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is invoked to initialize the console output dirver.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+ConsoleOutBootClose(
+ )
+
+/*++
+
+Routine Description:
+
+ This routine closes the console output driver.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Normal, successful completion status.
+
+--*/
+
+{
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+ConsoleOutBootOpen (
+ IN ULONG FileId
+ )
+
+/*++
+
+Routine Description:
+
+ This routine opens the console driver and initializes the device entry
+ table in the specified file table entry.
+
+Arguments:
+
+ FileId - Supplies the file id for the file table entry.
+
+Return Value:
+
+ STATUS_SUCCESS.
+
+--*/
+
+{
+
+ //
+ // Initialize the ConsoleOut disk device entry table.
+ //
+
+ ConsoleOutEntryTable.Close = ConsoleOutClose;
+ ConsoleOutEntryTable.Mount = ConsoleOutMount;
+ ConsoleOutEntryTable.Open = ConsoleOutOpen;
+ ConsoleOutEntryTable.Read = ConsoleOutRead;
+ ConsoleOutEntryTable.GetReadStatus = ConsoleOutGetReadStatus;
+ ConsoleOutEntryTable.Seek = ConsoleOutSeek;
+ ConsoleOutEntryTable.Write = ConsoleOutWrite;
+
+ //
+ // Initialize the file table entry for the specified file id.
+ //
+
+ BlFileTable[FileId].Flags.Open = 1;
+ BlFileTable[FileId].Flags.Write = 1;
+ BlFileTable[FileId].DeviceId = 0;
+ BlFileTable[FileId].Position.LowPart = 0;
+ BlFileTable[FileId].Position.HighPart = 0;
+ BlFileTable[FileId].DeviceEntryTable = &ConsoleOutEntryTable;
+ return STATUS_SUCCESS;
+}
diff --git a/private/ntos/boot/lib/nlsboot.c b/private/ntos/boot/lib/nlsboot.c
new file mode 100644
index 000000000..fb3b5339c
--- /dev/null
+++ b/private/ntos/boot/lib/nlsboot.c
@@ -0,0 +1,709 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ nlsboot.c
+
+Abstract:
+
+ This module contains NLS routines for use by the OS Loader. Before
+ the NLS tables are loaded, they convert between ANSI and Unicode by
+ zero-extending.
+
+Author:
+
+ John Vert (jvert) 11-Nov-1992
+
+Revision History:
+
+ John Vert (jvert) 11-Nov-1992
+ created - mostly copied from old RTL routines
+
+--*/
+#include "bldr.h"
+
+//
+// Hack-o-rama string routines to use before tables are loaded
+//
+
+#define upcase(C) (WCHAR )(((C) >= 'a' && (C) <= 'z' ? (C) - ('a' - 'A') : (C)))
+
+
+NTSTATUS
+RtlAnsiStringToUnicodeString(
+ OUT PUNICODE_STRING DestinationString,
+ IN PANSI_STRING SourceString,
+ IN BOOLEAN AllocateDestinationString
+ )
+
+{
+ ULONG UnicodeLength;
+ ULONG Index;
+ NTSTATUS st;
+
+ UnicodeLength = (SourceString->Length << 1) + sizeof(UNICODE_NULL);
+
+ if ( UnicodeLength > MAXUSHORT ) {
+ return STATUS_INVALID_PARAMETER_2;
+ }
+
+ DestinationString->Length = (USHORT)(UnicodeLength - sizeof(UNICODE_NULL));
+ if ( AllocateDestinationString ) {
+ return STATUS_NO_MEMORY;
+ }
+ else {
+ if ( DestinationString->Length >= DestinationString->MaximumLength ) {
+ return STATUS_BUFFER_OVERFLOW;
+ }
+ }
+
+ Index = 0;
+ while(Index < DestinationString->Length ) {
+ DestinationString->Buffer[Index] = (WCHAR)SourceString->Buffer[Index];
+ Index++;
+ }
+ DestinationString->Buffer[Index] = UNICODE_NULL;
+
+ return STATUS_SUCCESS;
+}
+
+LONG
+RtlCompareUnicodeString(
+ IN PUNICODE_STRING String1,
+ IN PUNICODE_STRING String2,
+ IN BOOLEAN CaseInSensitive
+ )
+
+/*++
+
+Routine Description:
+
+ The RtlCompareUnicodeString function compares two counted strings. The
+ return value indicates if the strings are equal or String1 is less than
+ String2 or String1 is greater than String2.
+
+ The CaseInSensitive parameter specifies if case is to be ignored when
+ doing the comparison.
+
+Arguments:
+
+ String1 - Pointer to the first string.
+
+ String2 - Pointer to the second string.
+
+ CaseInsensitive - TRUE if case should be ignored when doing the
+ comparison.
+
+Return Value:
+
+ Signed value that gives the results of the comparison:
+
+ Zero - String1 equals String2
+
+ < Zero - String1 less than String2
+
+ > Zero - String1 greater than String2
+
+
+--*/
+
+{
+
+ UNALIGNED WCHAR *s1, *s2;
+ USHORT n1, n2;
+ WCHAR c1, c2;
+ LONG cDiff;
+
+ s1 = String1->Buffer;
+ s2 = String2->Buffer;
+ n1 = (USHORT )(String1->Length / sizeof(WCHAR));
+ n2 = (USHORT )(String2->Length / sizeof(WCHAR));
+ while (n1 && n2) {
+ c1 = *s1++;
+ c2 = *s2++;
+
+ if (CaseInSensitive) {
+ //
+ // Note that this needs to reference the translation table !
+ //
+ c1 = upcase(c1);
+ c2 = upcase(c2);
+ }
+
+ if ((cDiff = ((LONG)c1 - (LONG)c2)) != 0) {
+ return( cDiff );
+ }
+
+ n1--;
+ n2--;
+ }
+
+ return( n1 - n2 );
+}
+
+BOOLEAN
+RtlEqualUnicodeString(
+ IN PUNICODE_STRING String1,
+ IN PUNICODE_STRING String2,
+ IN BOOLEAN CaseInSensitive
+ )
+
+/*++
+
+Routine Description:
+
+ The RtlEqualUnicodeString function compares two counted unicode strings for
+ equality.
+
+ The CaseInSensitive parameter specifies if case is to be ignored when
+ doing the comparison.
+
+Arguments:
+
+ String1 - Pointer to the first string.
+
+ String2 - Pointer to the second string.
+
+ CaseInsensitive - TRUE if case should be ignored when doing the
+ comparison.
+
+Return Value:
+
+ Boolean value that is TRUE if String1 equals String2 and FALSE otherwise.
+
+--*/
+
+{
+ UNALIGNED WCHAR *s1, *s2;
+ USHORT n1, n2;
+ WCHAR c1, c2;
+
+ s1 = String1->Buffer;
+ s2 = String2->Buffer;
+ n1 = (USHORT )(String1->Length / sizeof(WCHAR));
+ n2 = (USHORT )(String2->Length / sizeof(WCHAR));
+
+ if ( n1 != n2 ) {
+ return FALSE;
+ }
+
+ if (CaseInSensitive) {
+
+ while ( n1 ) {
+
+ if ( *s1++ != *s2++ ) {
+ c1 = upcase(*(s1-1));
+ c2 = upcase(*(s2-1));
+ if (c1 != c2) {
+ return( FALSE );
+ }
+ }
+ n1--;
+ }
+ }
+ else {
+
+ while ( n1 ) {
+
+ if (*s1++ != *s2++) {
+ return( FALSE );
+ }
+
+ n1--;
+ }
+ }
+
+ return TRUE;
+}
+
+
+VOID
+RtlInitString(
+ OUT PSTRING DestinationString,
+ IN PCSZ SourceString OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ The RtlInitString function initializes an NT counted string.
+ The DestinationString is initialized to point to the SourceString
+ and the Length and MaximumLength fields of DestinationString are
+ initialized to the length of the SourceString, which is zero if
+ SourceString is not specified.
+
+Arguments:
+
+ DestinationString - Pointer to the counted string to initialize
+
+ SourceString - Optional pointer to a null terminated string that
+ the counted string is to point to.
+
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ DestinationString->Length = 0;
+ DestinationString->Buffer = (PCHAR)SourceString;
+ if (ARGUMENT_PRESENT( SourceString )) {
+ while (*SourceString++) {
+ DestinationString->Length++;
+ }
+
+ DestinationString->MaximumLength = (SHORT)(DestinationString->Length+1);
+ }
+ else {
+ DestinationString->MaximumLength = 0;
+ }
+}
+
+
+VOID
+RtlInitUnicodeString(
+ OUT PUNICODE_STRING DestinationString,
+ IN PCWSTR SourceString OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ The RtlInitUnicodeString function initializes an NT counted
+ unicode string. The DestinationString is initialized to point to
+ the SourceString and the Length and MaximumLength fields of
+ DestinationString are initialized to the length of the SourceString,
+ which is zero if SourceString is not specified.
+
+Arguments:
+
+ DestinationString - Pointer to the counted string to initialize
+
+ SourceString - Optional pointer to a null terminated unicode string that
+ the counted string is to point to.
+
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ USHORT Length = 0;
+ DestinationString->Length = 0;
+ DestinationString->Buffer = (PWSTR)SourceString;
+ if (ARGUMENT_PRESENT( SourceString )) {
+ while (*SourceString++) {
+ Length += sizeof(*SourceString);
+ }
+
+ DestinationString->Length = Length;
+
+ DestinationString->MaximumLength = Length+(USHORT)sizeof(UNICODE_NULL);
+ }
+ else {
+ DestinationString->MaximumLength = 0;
+ }
+}
+
+
+NTSTATUS
+RtlAppendUnicodeStringToString (
+ IN PUNICODE_STRING Destination,
+ IN PUNICODE_STRING Source
+ )
+
+/*++
+
+Routine Description:
+
+ This routine will concatinate two PSTRINGs together. It will copy
+ bytes from the source up to the MaximumLength of the destination.
+
+Arguments:
+
+ IN PSTRING Destination, - Supplies the destination string
+ IN PSTRING Source - Supplies the source for the string copy
+
+Return Value:
+
+ STATUS_SUCCESS - The source string was successfully appended to the
+ destination counted string.
+
+ STATUS_BUFFER_TOO_SMALL - The destination string length was not big
+ enough to allow the source string to be appended. The Destination
+ string length is not updated.
+
+--*/
+
+{
+ USHORT n = Source->Length;
+ UNALIGNED WCHAR *dst;
+
+ if (n) {
+ if ((n + Destination->Length) > Destination->MaximumLength) {
+ return( STATUS_BUFFER_TOO_SMALL );
+ }
+
+ dst = &Destination->Buffer[ (Destination->Length / sizeof( WCHAR )) ];
+ RtlMoveMemory( dst, Source->Buffer, n );
+
+ Destination->Length += n;
+
+ if (Destination->Length < Destination->MaximumLength) {
+ dst[ n / sizeof( WCHAR ) ] = UNICODE_NULL;
+ }
+ }
+
+ return( STATUS_SUCCESS );
+}
+
+
+NTSTATUS
+RtlAppendUnicodeToString (
+ IN PUNICODE_STRING Destination,
+ IN PWSTR Source OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This routine appends the supplied UNICODE string to an existing
+ PUNICODE_STRING.
+
+ It will copy bytes from the Source PSZ to the destination PSTRING up to
+ the destinations PUNICODE_STRING->MaximumLength field.
+
+Arguments:
+
+ IN PUNICODE_STRING Destination, - Supplies a pointer to the destination
+ string
+ IN PWSTR Source - Supplies the string to append to the destination
+
+Return Value:
+
+ STATUS_SUCCESS - The source string was successfully appended to the
+ destination counted string.
+
+ STATUS_BUFFER_TOO_SMALL - The destination string length was not big
+ enough to allow the source string to be appended. The Destination
+ string length is not updated.
+
+--*/
+
+{
+ USHORT n;
+ UNALIGNED WCHAR *dst;
+
+ if (ARGUMENT_PRESENT( Source )) {
+ UNICODE_STRING UniSource;
+
+ RtlInitUnicodeString(&UniSource, Source);
+
+ n = UniSource.Length;
+
+ if ((n + Destination->Length) > Destination->MaximumLength) {
+ return( STATUS_BUFFER_TOO_SMALL );
+ }
+
+ dst = &Destination->Buffer[ (Destination->Length / sizeof( WCHAR )) ];
+ RtlMoveMemory( dst, Source, n );
+
+ Destination->Length += n;
+
+ if (Destination->Length < Destination->MaximumLength) {
+ dst[ n / sizeof( WCHAR ) ] = UNICODE_NULL;
+ }
+ }
+
+ return( STATUS_SUCCESS );
+}
+
+WCHAR
+RtlUpcaseUnicodeChar(
+ IN WCHAR SourceCharacter
+ )
+
+/*++
+
+Routine Description:
+
+ This function translates the specified unicode character to its
+ equivalent upcased unicode chararacter. The purpose for this routine
+ is to allow for character by character upcase translation. The
+ translation is done with respect to the current system locale
+ information.
+
+
+Arguments:
+
+ SourceCharacter - Supplies the unicode character to be upcased.
+
+Return Value:
+
+ Returns the upcased unicode equivalent of the specified input character.
+
+--*/
+
+{
+
+ return (upcase(SourceCharacter));
+}
+
+WCHAR
+RtlAnsiCharToUnicodeChar(
+ IN OUT PUCHAR *SourceCharacter
+ )
+
+/*++
+
+Routine Description:
+
+ This function translates the specified ansi character to unicode and
+ returns the unicode value. The purpose for this routine is to allow
+ for character by character ansi to unicode translation. The
+ translation is done with respect to the current system locale
+ information.
+
+
+Arguments:
+
+ SourceCharacter - Supplies a pointer to an ansi character pointer.
+ Through two levels of indirection, this supplies an ansi
+ character that is to be translated to unicode. After
+ translation, the ansi character pointer is modified to point to
+ the next character to be converted. This is done to allow for
+ dbcs ansi characters.
+
+Return Value:
+
+ Returns the unicode equivalent of the specified ansi character.
+
+--*/
+
+{
+ WCHAR UnicodeCharacter;
+ ULONG cbCharSize;
+ NTSTATUS st;
+
+
+ UnicodeCharacter = (WCHAR)**SourceCharacter;
+ (*SourceCharacter)++;
+ return(UnicodeCharacter);
+}
+
+NTSTATUS
+RtlUpcaseUnicodeToMultiByteN(
+ OUT PCH MultiByteString,
+ IN ULONG MaxBytesInMultiByteString,
+ OUT PULONG BytesInMultiByteString OPTIONAL,
+ IN PWCH UnicodeString,
+ IN ULONG BytesInUnicodeString)
+
+/*++
+
+Routine Description:
+
+ This functions upper cases the specified unicode source string and
+ converts it into an ansi string. The translation is done with respect
+ to the ANSI Code Page (ACP) loaded at boot time.
+
+Arguments:
+
+ MultiByteString - Returns an ansi string that is equivalent to the
+ upper case of the unicode source string. If the translation can
+ not be done, an error is returned.
+
+ MaxBytesInMultiByteString - Supplies the maximum number of bytes to be
+ written to MultiByteString. If this causes MultiByteString to be a
+ truncated equivalent of UnicodeString, no error condition results.
+
+ BytesInMultiByteString - Returns the number of bytes in the returned
+ ansi string pointed to by MultiByteString.
+
+ UnicodeString - Supplies the unicode source string that is to be
+ converted to ansi.
+
+ BytesInUnicodeString - The number of bytes in the the string pointed to by
+ UnicodeString.
+
+Return Value:
+
+ SUCCESS - The conversion was successful
+
+--*/
+
+{
+ ULONG TmpCount;
+ ULONG LoopCount;
+ ULONG CharsInUnicodeString;
+ UCHAR SbChar;
+ WCHAR UnicodeChar;
+ ULONG i;
+
+ //
+ // Convert Unicode byte count to character count. Byte count of
+ // multibyte string is equivalent to character count.
+ //
+ CharsInUnicodeString = BytesInUnicodeString / sizeof(WCHAR);
+
+ LoopCount = (CharsInUnicodeString < MaxBytesInMultiByteString) ?
+ CharsInUnicodeString : MaxBytesInMultiByteString;
+
+ if (ARGUMENT_PRESENT(BytesInMultiByteString))
+ *BytesInMultiByteString = LoopCount;
+
+
+ for (i=0;i<LoopCount;i++) {
+
+ MultiByteString[i] = (UCHAR)RtlUpcaseUnicodeChar((UCHAR)(UnicodeString[i]));
+ }
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+RtlMultiByteToUnicodeN(
+ OUT PWCH UnicodeString,
+ IN ULONG MaxBytesInUnicodeString,
+ OUT PULONG BytesInUnicodeString OPTIONAL,
+ IN PCH MultiByteString,
+ IN ULONG BytesInMultiByteString)
+
+/*++
+
+Routine Description:
+
+ This functions converts the specified ansi source string into a
+ Unicode string. The translation is done with respect to the
+ ANSI Code Page (ACP) installed at boot time. Single byte characters
+ in the range 0x00 - 0x7f are simply zero extended as a performance
+ enhancement. In some far eastern code pages 0x5c is defined as the
+ Yen sign. For system translation we always want to consider 0x5c
+ to be the backslash character. We get this for free by zero extending.
+
+ NOTE: This routine only supports precomposed Unicode characters.
+
+Arguments:
+
+ UnicodeString - Returns a unicode string that is equivalent to
+ the ansi source string.
+
+ MaxBytesInUnicodeString - Supplies the maximum number of bytes to be
+ written to UnicodeString. If this causes UnicodeString to be a
+ truncated equivalent of MultiByteString, no error condition results.
+
+ BytesInUnicodeString - Returns the number of bytes in the returned
+ unicode string pointed to by UnicodeString.
+
+ MultiByteString - Supplies the ansi source string that is to be
+ converted to unicode.
+
+ BytesInMultiByteString - The number of bytes in the string pointed to
+ by MultiByteString.
+
+Return Value:
+
+ SUCCESS - The conversion was successful.
+
+
+--*/
+
+{
+ ULONG LoopCount;
+ PUSHORT TranslateTable;
+ ULONG MaxCharsInUnicodeString;
+ ULONG i;
+
+ MaxCharsInUnicodeString = MaxBytesInUnicodeString / sizeof(WCHAR);
+
+ LoopCount = (MaxCharsInUnicodeString < BytesInMultiByteString) ?
+ MaxCharsInUnicodeString : BytesInMultiByteString;
+
+ if (ARGUMENT_PRESENT(BytesInUnicodeString))
+ *BytesInUnicodeString = LoopCount * sizeof(WCHAR);
+
+ for (i=0;i<LoopCount;i++) {
+ UnicodeString[i] = (WCHAR)((UCHAR)(MultiByteString[i]));
+ }
+
+ return(STATUS_SUCCESS);
+}
+
+NTSTATUS
+RtlUnicodeToMultiByteN(
+ OUT PCH MultiByteString,
+ IN ULONG MaxBytesInMultiByteString,
+ OUT PULONG BytesInMultiByteString OPTIONAL,
+ IN PWCH UnicodeString,
+ IN ULONG BytesInUnicodeString)
+
+/*++
+
+Routine Description:
+
+ This functions converts the specified unicode source string into an
+ ansi string. The translation is done with respect to the
+ ANSI Code Page (ACP) loaded at boot time.
+
+Arguments:
+
+ MultiByteString - Returns an ansi string that is equivalent to the
+ unicode source string. If the translation can not be done,
+ an error is returned.
+
+ MaxBytesInMultiByteString - Supplies the maximum number of bytes to be
+ written to MultiByteString. If this causes MultiByteString to be a
+ truncated equivalent of UnicodeString, no error condition results.
+
+ BytesInMultiByteString - Returns the number of bytes in the returned
+ ansi string pointed to by MultiByteString.
+
+ UnicodeString - Supplies the unicode source string that is to be
+ converted to ansi.
+
+ BytesInUnicodeString - The number of bytes in the the string pointed to by
+ UnicodeString.
+
+Return Value:
+
+ SUCCESS - The conversion was successful
+
+--*/
+
+{
+ ULONG TmpCount;
+ ULONG LoopCount;
+ ULONG CharsInUnicodeString;
+ UCHAR SbChar;
+ WCHAR UnicodeChar;
+ ULONG i;
+
+ //
+ // Convert Unicode byte count to character count. Byte count of
+ // multibyte string is equivalent to character count.
+ //
+ CharsInUnicodeString = BytesInUnicodeString / sizeof(WCHAR);
+
+ LoopCount = (CharsInUnicodeString < MaxBytesInMultiByteString) ?
+ CharsInUnicodeString : MaxBytesInMultiByteString;
+
+ if (ARGUMENT_PRESENT(BytesInMultiByteString))
+ *BytesInMultiByteString = LoopCount;
+
+
+ for (i=0;i<LoopCount;i++) {
+ MultiByteString[i] = (CHAR)(UnicodeString[i]);
+ }
+
+ return STATUS_SUCCESS;
+
+}
diff --git a/private/ntos/boot/lib/ntfsboot.c b/private/ntos/boot/lib/ntfsboot.c
new file mode 100644
index 000000000..2e903aa31
--- /dev/null
+++ b/private/ntos/boot/lib/ntfsboot.c
@@ -0,0 +1,3416 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ NtfsBoot.c
+
+Abstract:
+
+ This module implements the Ntfs boot file system used by the operating system
+ loader.
+
+Author:
+
+ Gary Kimura [GaryKi] 10-April-1992
+
+Revision History:
+
+--*/
+
+//
+// Stuff to get around the fact that we include both Fat, Hpfs, and Ntfs include
+// environments
+//
+
+#define _FAT_
+#define _HPFS_
+#define _CVF_
+
+#define VBO ULONG
+#define LBO ULONG
+#define BIOS_PARAMETER_BLOCK ULONG
+#define CVF_LAYOUT ULONG
+#define CVF_HEADER ULONG
+#define COMPONENT_LOCATION ULONG
+#define PCVF_FAT_EXTENSIONS PCHAR
+
+typedef struct DIRENT {
+ char Garbage[32];
+} DIRENT; // sizeof = 32
+
+
+#include "bootlib.h"
+#include "stdio.h"
+
+BOOTFS_INFO NtfsBootFsInfo={L"ntfs"};
+
+#undef VBO
+#undef LBO
+#undef BIOS_PARAMETER_BLOCK
+#undef DIRENT
+
+#include "ntfs.h"
+
+VOID NtfsPrint( IN PCHAR FormatString, ... )
+{ va_list arglist; CHAR text[78+1]; ULONG Count,Length;
+
+ va_start(arglist,FormatString);
+ Length = _vsnprintf(text,sizeof(text),FormatString,arglist);
+ text[78] = 0;
+ ArcWrite(ARC_CONSOLE_OUTPUT,text,Length,&Count);
+ va_end(arglist);
+}
+
+VOID NtfsGetChar(VOID) { UCHAR c; ULONG count; ArcRead(ARC_CONSOLE_INPUT,&c,1,&count); }
+
+#define ReadConsole(c) { \
+ UCHAR Key=0; ULONG Count; \
+ while (Key != c) { \
+ if (ArcGetReadStatus(BlConsoleInDeviceId) == ESUCCESS) { \
+ ArcRead(BlConsoleInDeviceId, &Key, sizeof(Key), &Count); \
+ } \
+ } \
+}
+
+
+//
+// Low level disk read routines
+//
+//
+// VOID
+// ReadDisk (
+// IN ULONG DeviceId,
+// IN LONGLONG Lbo,
+// IN ULONG ByteCount,
+// IN OUT PVOID Buffer
+// );
+//
+
+ARC_STATUS
+NtfsReadDisk (
+ IN ULONG DeviceId,
+ IN LONGLONG Lbo,
+ IN ULONG ByteCount,
+ IN OUT PVOID Buffer
+ );
+
+#define ReadDisk(A,B,C,D) { ARC_STATUS _s; \
+ if ((_s = NtfsReadDisk(A,B,C,D)) != ESUCCESS) {return _s;} \
+}
+
+//
+// Attribute lookup and read routines
+//
+//
+// VOID
+// LookupAttribute (
+// IN PNTFS_STRUCTURE_CONTEXT StructureContext,
+// IN LONGLONG FileRecord,
+// IN ATTRIBUTE_TYPE_CODE TypeCode,
+// OUT PBOOLEAN FoundAttribute,
+// OUT PNTFS_ATTRIBUTE_CONTEXT AttributeContext
+// );
+//
+// VOID
+// ReadAttribute (
+// IN PNTFS_STRUCTURE_CONTEXT StructureContext,
+// IN PNTFS_ATTRIBUTE_CONTEXT AttributeContext,
+// IN VBO Vbo,
+// IN ULONG Length,
+// IN PVOID Buffer
+// );
+//
+// VOID
+// ReadAndDecodeFileRecord (
+// IN PNTFS_STRUCTURE_CONTEXT StructureContext,
+// IN LONGLONG FileRecord,
+// OUT PULONG Index
+// );
+//
+// VOID
+// DecodeUsa (
+// IN PVOID UsaBuffer,
+// IN ULONG Length
+// );
+//
+
+ARC_STATUS
+NtfsLookupAttribute(
+ IN PNTFS_STRUCTURE_CONTEXT StructureContext,
+ IN LONGLONG FileRecord,
+ IN ATTRIBUTE_TYPE_CODE TypeCode,
+ OUT PBOOLEAN FoundAttribute,
+ OUT PNTFS_ATTRIBUTE_CONTEXT AttributeContext
+ );
+
+ARC_STATUS
+NtfsReadResidentAttribute (
+ IN PNTFS_STRUCTURE_CONTEXT StructureContext,
+ IN PNTFS_ATTRIBUTE_CONTEXT AttributeContext,
+ IN VBO Vbo,
+ IN ULONG Length,
+ IN PVOID Buffer
+ );
+
+ARC_STATUS
+NtfsReadNonresidentAttribute (
+ IN PNTFS_STRUCTURE_CONTEXT StructureContext,
+ IN PNTFS_ATTRIBUTE_CONTEXT AttributeContext,
+ IN VBO Vbo,
+ IN ULONG Length,
+ IN PVOID Buffer
+ );
+
+ARC_STATUS
+NtfsReadAndDecodeFileRecord (
+ IN PNTFS_STRUCTURE_CONTEXT StructureContext,
+ IN LONGLONG FileRecord,
+ OUT PULONG Index
+ );
+
+ARC_STATUS
+NtfsDecodeUsa (
+ IN PVOID UsaBuffer,
+ IN ULONG Length
+ );
+
+#define LookupAttribute(A,B,C,D,E) { ARC_STATUS _s; \
+ if ((_s = NtfsLookupAttribute(A,B,C,D,E)) != ESUCCESS) {return _s;} \
+}
+
+#define ReadAttribute(A,B,C,D,E) { ARC_STATUS _s; \
+ if ((B)->IsAttributeResident) { \
+ if ((_s = NtfsReadResidentAttribute(A,B,C,D,E)) != ESUCCESS) {return _s;} \
+ } else { \
+ if ((_s = NtfsReadNonresidentAttribute(A,B,C,D,E)) != ESUCCESS) {return _s;} \
+ } \
+}
+
+#define ReadAndDecodeFileRecord(A,B,C) { ARC_STATUS _s; \
+ if ((_s = NtfsReadAndDecodeFileRecord(A,B,C)) != ESUCCESS) { return _s; } \
+}
+
+#define DecodeUsa(A,B) { ARC_STATUS _s; \
+ if ((_s = NtfsDecodeUsa(A,B)) != ESUCCESS) {return _s;} \
+}
+
+
+//
+// Directory and index lookup routines
+//
+//
+// VOID
+// SearchForFileName (
+// IN PNTFS_STRUCTURE_CONTEXT StructureContext,
+// IN PNTFS_ATTRIBUTE_CONTEXT IndexRoot,
+// IN PNTFS_ATTRIBUTE_CONTEXT IndexAllocation OPTIONAL,
+// IN PNTFS_ATTRIBUTE_CONTEXT AllocationBitmap OPTIONAL,
+// IN STRING FileName,
+// OUT PBOOLEAN FoundFileName,
+// OUT PLONGLONG FileRecord,
+// OUT PBOOLEAN IsDirectory
+// );
+//
+// VOID
+// IsRecordAllocated (
+// IN PNTFS_STRUCTURE_CONTEXT StructureContext,
+// IN PNTFS_ATTRIBUTE_CONTEXT AllocationBitmap,
+// IN ULONG BitOffset,
+// OUT PBOOLEAN IsAllocated
+// );
+//
+
+ARC_STATUS
+NtfsSearchForFileName (
+ IN PNTFS_STRUCTURE_CONTEXT StructureContext,
+ IN PNTFS_ATTRIBUTE_CONTEXT IndexRoot,
+ IN PNTFS_ATTRIBUTE_CONTEXT IndexAllocation OPTIONAL,
+ IN PNTFS_ATTRIBUTE_CONTEXT AllocationBitmap OPTIONAL,
+ IN STRING FileName,
+ OUT PBOOLEAN FoundFileName,
+ OUT PLONGLONG FileRecord,
+ OUT PBOOLEAN IsDirectory
+ );
+
+ARC_STATUS
+NtfsIsRecordAllocated (
+ IN PNTFS_STRUCTURE_CONTEXT StructureContext,
+ IN PNTFS_ATTRIBUTE_CONTEXT AllocationBitmap,
+ IN ULONG BitOffset,
+ OUT PBOOLEAN IsAllocated
+ );
+
+#define SearchForFileName(A,B,C,D,E,F,G,H) { ARC_STATUS _s; \
+ if ((_s = NtfsSearchForFileName(A,B,C,D,E,F,G,H)) != ESUCCESS) {return _s;} \
+}
+
+#define IsRecordAllocated(A,B,C,D) { ARC_STATUS _s; \
+ if ((_s = NtfsIsRecordAllocated(A,B,C,D)) != ESUCCESS) {return _s;} \
+}
+
+
+//
+// Mcb support routines
+//
+//
+// VOID
+// LoadMcb (
+// IN PNTFS_STRUCTURE_CONTEXT StructureContext,
+// IN PNTFS_ATTRIBUTE_CONTEXT AttributeContext,
+// IN VBO Vbo,
+// IN PNTFS_MCB Mcb
+// );
+//
+// VOID
+// VboToLbo (
+// IN PNTFS_STRUCTURE_CONTEXT StructureContext,
+// IN PNTFS_ATTRIBUTE_CONTEXT AttributeContext,
+// IN VBO Vbo,
+// OUT PLBO Lbo,
+// OUT PULONG ByteCount
+// );
+//
+// VOID
+// DecodeRetrievalInformation (
+// IN PNTFS_STRUCTURE_CONTEXT StructureContext,
+// IN PNTFS_MCB Mcb,
+// IN VCN Vcn,
+// IN PATTRIBUTE_RECORD_HEADER AttributeHeader
+// );
+//
+
+ARC_STATUS
+NtfsLoadMcb (
+ IN PNTFS_STRUCTURE_CONTEXT StructureContext,
+ IN PNTFS_ATTRIBUTE_CONTEXT AttributeContext,
+ IN VBO Vbo,
+ IN PNTFS_MCB Mcb
+ );
+
+ARC_STATUS
+NtfsVboToLbo (
+ IN PNTFS_STRUCTURE_CONTEXT StructureContext,
+ IN PNTFS_ATTRIBUTE_CONTEXT AttributeContext,
+ IN VBO Vbo,
+ OUT PLBO Lbo,
+ OUT PULONG ByteCount
+ );
+
+ARC_STATUS
+NtfsDecodeRetrievalInformation (
+ IN PNTFS_STRUCTURE_CONTEXT StructureContext,
+ IN PNTFS_MCB Mcb,
+ IN VCN Vcn,
+ IN PATTRIBUTE_RECORD_HEADER AttributeHeader
+ );
+
+#define LoadMcb(A,B,C,D) { ARC_STATUS _s; \
+ if ((_s = NtfsLoadMcb(A,B,C,D)) != ESUCCESS) {return _s;} \
+}
+
+#define VboToLbo(A,B,C,D,E) { ARC_STATUS _s; \
+ if ((_s = NtfsVboToLbo(A,B,C,D,E)) != ESUCCESS) {return _s;} \
+}
+
+#define DecodeRetrievalInformation(A,B,C,D) { ARC_STATUS _s; \
+ if ((_s = NtfsDecodeRetrievalInformation(A,B,C,D)) != ESUCCESS) {return _s;} \
+}
+
+
+//
+// Miscellaneous routines
+//
+
+
+VOID
+NtfsFirstComponent (
+ IN OUT PSTRING String,
+ OUT PSTRING FirstComponent
+ );
+
+BOOLEAN
+NtfsAreNamesEqual (
+ IN STRING AnsiString,
+ IN UNICODE_STRING UnicodeString
+ );
+
+//
+// VOID
+// FileReferenceToLargeInteger (
+// IN PFILE_REFERENCE FileReference,
+// OUT PLONGLONG LargeInteger
+// );
+//
+// VOID
+// InitializeAttributeContext (
+// IN PNTFS_STRUCTURE_CONTEXT StructureContext,
+// IN PVOID FileRecordBuffer,
+// IN PVOID AttributeHeader,
+// IN LONGLONG FileRecord,
+// OUT PNTFS_ATTRIBUTE_CONTEXT AttributeContext
+// );
+//
+
+#define FileReferenceToLargeInteger(FR,LI) { \
+ *(LI) = *(PLONGLONG)&(FR); \
+ ((PFILE_REFERENCE)(LI))->SequenceNumber = 0; \
+}
+
+//
+//**** note that the code to get the compression engine will need to change
+//**** once the NTFS format changes
+//
+
+#define InitializeAttributeContext(SC,FRB,AH,FR,AC) { \
+ (AC)->TypeCode = (AH)->TypeCode; \
+ (AC)->FileRecord = (FR); \
+ (AC)->FileRecordOffset = (USHORT)PtrOffset((FRB),(AH)); \
+ if ((AC)->IsAttributeResident = ((AH)->FormCode == RESIDENT_FORM)) { \
+ (AC)->DataSize = /*xxFromUlong*/((AH)->Form.Resident.ValueLength); \
+ } else { \
+ (AC)->DataSize = (AH)->Form.Nonresident.FileSize; \
+ } \
+ (AC)->CompressionFormat = COMPRESSION_FORMAT_NONE; \
+ if ((AH)->Flags & ATTRIBUTE_FLAG_COMPRESSION_MASK) { \
+ ULONG _i; \
+ (AC)->CompressionFormat = COMPRESSION_FORMAT_LZNT1; \
+ (AC)->CompressionUnit = (SC)->BytesPerCluster; \
+ for (_i = 0; _i < (AH)->Form.Nonresident.CompressionUnit; _i += 1) { \
+ (AC)->CompressionUnit *= 2; \
+ } \
+ } \
+}
+
+#define FlagOn(Flags,SingleFlag) ((BOOLEAN)(((Flags) & (SingleFlag)) != 0))
+#define SetFlag(Flags,SingleFlag) { (Flags) |= (SingleFlag); }
+#define ClearFlag(Flags,SingleFlag) { (Flags) &= ~(SingleFlag); }
+
+#define Add2Ptr(POINTER,INCREMENT) ((PVOID)((PUCHAR)(POINTER) + (INCREMENT)))
+#define PtrOffset(BASE,OFFSET) ((ULONG)((ULONG)(OFFSET) - (ULONG)(BASE)))
+
+#define Minimum(X,Y) ((X) < (Y) ? (X) : (Y))
+
+#define IsCharZero(C) (((C) & 0x000000ff) == 0x00000000)
+#define IsCharLtrZero(C) (((C) & 0x00000080) == 0x00000080)
+
+//
+// The following types and macros are used to help unpack the packed and misaligned
+// fields found in the Bios parameter block
+//
+
+typedef union _UCHAR1 { UCHAR Uchar[1]; UCHAR ForceAlignment; } UCHAR1, *PUCHAR1;
+typedef union _UCHAR2 { UCHAR Uchar[2]; USHORT ForceAlignment; } UCHAR2, *PUCHAR2;
+typedef union _UCHAR4 { UCHAR Uchar[4]; ULONG ForceAlignment; } UCHAR4, *PUCHAR4;
+
+//
+// This macro copies an unaligned src byte to an aligned dst byte
+//
+
+#define CopyUchar1(Dst,Src) { \
+ *((UCHAR1 *)(Dst)) = *((UNALIGNED UCHAR1 *)(Src)); \
+ }
+
+//
+// This macro copies an unaligned src word to an aligned dst word
+//
+
+#define CopyUchar2(Dst,Src) { \
+ *((UCHAR2 *)(Dst)) = *((UNALIGNED UCHAR2 *)(Src)); \
+ }
+
+//
+// This macro copies an unaligned src longword to an aligned dsr longword
+//
+
+#define CopyUchar4(Dst,Src) { \
+ *((UCHAR4 *)(Dst)) = *((UNALIGNED UCHAR4 *)(Src)); \
+ }
+
+
+//
+// Define global data.
+//
+
+ULONG LastMcb = 0;
+BOOLEAN FirstTime = TRUE;
+
+//
+// File entry table - This is a structure that provides entry to the NTFS
+// file system procedures. It is exported when a NTFS file structure
+// is recognized.
+//
+
+BL_DEVICE_ENTRY_TABLE NtfsDeviceEntryTable;
+
+//
+// These are the static buffers that we use when read file records and index
+// allocation buffers. To save ourselves some extra reads we will identify the
+// current file record by its Vbo within the mft.
+//
+
+#define BUFFER_COUNT (64)
+
+USHORT NtfsFileRecordBufferPinned[BUFFER_COUNT];
+VBO NtfsFileRecordBufferVbo[BUFFER_COUNT];
+PFILE_RECORD_SEGMENT_HEADER NtfsFileRecordBuffer[BUFFER_COUNT];
+
+PINDEX_ALLOCATION_BUFFER NtfsIndexAllocationBuffer;
+
+//
+// The following field are used to identify and store the cached
+// compressed buffer and its uncompressed equivalent. The first
+// two fields identifies the attribute stream, and the third field
+// identifies the Vbo within the attribute stream that we have
+// cached. The compressed and uncompressed buffer contains
+// the data.
+//
+
+LONGLONG NtfsCompressedFileRecord;
+USHORT NtfsCompressedOffset;
+ULONG NtfsCompressedVbo;
+
+PUCHAR NtfsCompressedBuffer;
+PUCHAR NtfsUncompressedBuffer;
+
+UCHAR NtfsBuffer0[MAXIMUM_FILE_RECORD_SIZE+256];
+UCHAR NtfsBuffer1[MAXIMUM_FILE_RECORD_SIZE+256];
+UCHAR NtfsBuffer2[MAXIMUM_INDEX_ALLOCATION_SIZE+256];
+UCHAR NtfsBuffer3[MAXIMUM_COMPRESSION_UNIT_SIZE+256];
+UCHAR NtfsBuffer4[MAXIMUM_COMPRESSION_UNIT_SIZE+256];
+
+
+PBL_DEVICE_ENTRY_TABLE
+IsNtfsFileStructure (
+ IN ULONG DeviceId,
+ IN PVOID OpaqueStructureContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines if the partition on the specified channel contains an
+ Ntfs file system volume.
+
+Arguments:
+
+ DeviceId - Supplies the file table index for the device on which read operations
+ are to be performed.
+
+ StructureContext - Supplies a pointer to a Ntfs file structure context.
+
+Return Value:
+
+ A pointer to the Ntfs entry table is returned if the partition is recognized as
+ containing a Ntfs volume. Otherwise, NULL is returned.
+
+--*/
+
+{
+ PNTFS_STRUCTURE_CONTEXT StructureContext = (PNTFS_STRUCTURE_CONTEXT)OpaqueStructureContext;
+
+ PPACKED_BOOT_SECTOR BootSector;
+ BIOS_PARAMETER_BLOCK Bpb;
+
+ ULONG ClusterSize;
+ ULONG FileRecordSize;
+
+ PATTRIBUTE_RECORD_HEADER AttributeHeader;
+
+ ULONG i;
+
+ //
+ // Clear the file system context block for the specified channel and initialize
+ // the global buffer pointers that we use for buffering I/O
+ //
+
+ RtlZeroMemory(StructureContext, sizeof(NTFS_STRUCTURE_CONTEXT));
+
+ //
+ // Zero out the pinned buffer array because we start with nothing pinned
+ // Also negate the vbo array to not let us get spooked with stale data
+ //
+
+ RtlZeroMemory( NtfsFileRecordBufferPinned, sizeof(NtfsFileRecordBufferPinned));
+ for (i = 0; i < BUFFER_COUNT; i += 1) { NtfsFileRecordBufferVbo[i] = -1; }
+
+ NtfsCompressedFileRecord = 0;
+ NtfsCompressedOffset = 0;
+ NtfsCompressedVbo = 0;
+
+ //
+ // Set up a local pointer that we will use to read in the boot sector and check
+ // for an Ntfs partition. We will temporarily use the global file record buffer
+ //
+
+ BootSector = (PPACKED_BOOT_SECTOR)NtfsFileRecordBuffer[0];
+
+ //
+ // Now read in the boot sector and return null if we can't do the read
+ //
+
+ if (NtfsReadDisk(DeviceId, 0, sizeof(PACKED_BOOT_SECTOR), BootSector) != ESUCCESS) {
+
+ return NULL;
+ }
+
+ //
+ // Unpack the Bios parameter block
+ //
+
+ NtfsUnpackBios( &Bpb, &BootSector->PackedBpb );
+
+ //
+ // Check if it is NTFS, by first checking the signature, then must be zero
+ // fields, then the media type, and then sanity check the non zero fields.
+ //
+
+ if (RtlCompareMemory( &BootSector->Oem[0], "NTFS ", 8) != 8) {
+
+ return NULL;
+ }
+
+ if ((Bpb.ReservedSectors != 0) ||
+ (Bpb.Fats != 0) ||
+ (Bpb.RootEntries != 0) ||
+ (Bpb.Sectors != 0) ||
+ (Bpb.SectorsPerFat != 0) ||
+ (Bpb.LargeSectors != 0)) {
+
+ return NULL;
+ }
+
+ if ((Bpb.Media != 0xf0) &&
+ (Bpb.Media != 0xf8) &&
+ (Bpb.Media != 0xf9) &&
+ (Bpb.Media != 0xfc) &&
+ (Bpb.Media != 0xfd) &&
+ (Bpb.Media != 0xfe) &&
+ (Bpb.Media != 0xff)) {
+
+ return NULL;
+ }
+
+ if ((Bpb.BytesPerSector != 128) &&
+ (Bpb.BytesPerSector != 256) &&
+ (Bpb.BytesPerSector != 512) &&
+ (Bpb.BytesPerSector != 1024) &&
+ (Bpb.BytesPerSector != 2048)) {
+
+ return NULL;
+ }
+
+ if ((Bpb.SectorsPerCluster != 1) &&
+ (Bpb.SectorsPerCluster != 2) &&
+ (Bpb.SectorsPerCluster != 4) &&
+ (Bpb.SectorsPerCluster != 8) &&
+ (Bpb.SectorsPerCluster != 16) &&
+ (Bpb.SectorsPerCluster != 32) &&
+ (Bpb.SectorsPerCluster != 64) &&
+ (Bpb.SectorsPerCluster != 128)) {
+
+ return NULL;
+ }
+
+ if ((BootSector->NumberSectors == 0) ||
+ (BootSector->MftStartLcn == 0) ||
+ (BootSector->Mft2StartLcn == 0) ||
+ (BootSector->ClustersPerFileRecordSegment == 0) ||
+ (BootSector->DefaultClustersPerIndexAllocationBuffer == 0)) {
+
+ return NULL;
+ }
+
+ if ((BootSector->ClustersPerFileRecordSegment < 0) &&
+ ((BootSector->ClustersPerFileRecordSegment > -9) ||
+ (BootSector->ClustersPerFileRecordSegment < -31))) {
+
+ return NULL;
+ }
+
+ //
+ // So far the boot sector has checked out to be an NTFS partition so now compute
+ // some of the volume constants.
+ //
+
+ StructureContext->DeviceId = DeviceId;
+
+ StructureContext->BytesPerCluster =
+ ClusterSize = Bpb.SectorsPerCluster * Bpb.BytesPerSector;
+
+ //
+ // If the number of clusters per file record is less than zero then the file record
+ // size computed by using the negative of this number as a shift value.
+ //
+
+ if (BootSector->ClustersPerFileRecordSegment > 0) {
+
+ StructureContext->BytesPerFileRecord =
+ FileRecordSize = BootSector->ClustersPerFileRecordSegment * ClusterSize;
+
+ } else {
+
+ StructureContext->BytesPerFileRecord =
+ FileRecordSize = 1 << (-1 * BootSector->ClustersPerFileRecordSegment);
+ }
+
+ //
+ // Read in the base file record for the mft
+ //
+
+ if (NtfsReadDisk( DeviceId,
+ /*xxXMul*/(BootSector->MftStartLcn * ClusterSize),
+ FileRecordSize,
+ NtfsFileRecordBuffer[0]) != ESUCCESS) {
+
+ return NULL;
+ }
+
+ //
+ // Decode Usa for the file record
+ //
+
+ if (NtfsDecodeUsa(NtfsFileRecordBuffer[0], FileRecordSize) != ESUCCESS) {
+
+ return NULL;
+ }
+
+ //
+ // Make sure the file record is in use
+ //
+
+ if (!FlagOn(NtfsFileRecordBuffer[0]->Flags, FILE_RECORD_SEGMENT_IN_USE)) {
+
+ return NULL;
+ }
+
+ //
+ // Search for the unnamed $data attribute header, if we reach $end then it is
+ // an error
+ //
+
+ for (AttributeHeader = NtfsFirstAttribute( NtfsFileRecordBuffer[0] );
+ (AttributeHeader->TypeCode != $DATA) || (AttributeHeader->NameLength != 0);
+ AttributeHeader = NtfsGetNextRecord( AttributeHeader )) {
+
+ if (AttributeHeader->TypeCode == $END) {
+
+ return NULL;
+ }
+ }
+
+ //
+ // Make sure the $data attribute for the mft is non resident
+ //
+
+ if (AttributeHeader->FormCode != NONRESIDENT_FORM) {
+
+ return NULL;
+ }
+
+ //
+ // Now set the mft structure context up for later use
+ //
+
+ InitializeAttributeContext( StructureContext,
+ NtfsFileRecordBuffer[0],
+ AttributeHeader,
+ 0,
+ &StructureContext->MftAttributeContext );
+
+ //
+ // Now decipher the part of the Mcb that is stored in the file record
+ //
+
+ if (NtfsDecodeRetrievalInformation( StructureContext,
+ &StructureContext->MftBaseMcb,
+ 0,
+ AttributeHeader ) != ESUCCESS) {
+
+ return NULL;
+ }
+
+ //
+ // We have finished initializing the structure context so now Initialize the
+ // file entry table and return the address of the table.
+ //
+
+ NtfsDeviceEntryTable.Open = NtfsOpen;
+ NtfsDeviceEntryTable.Close = NtfsClose;
+ NtfsDeviceEntryTable.Read = NtfsRead;
+ NtfsDeviceEntryTable.Seek = NtfsSeek;
+ NtfsDeviceEntryTable.Write = NtfsWrite;
+ NtfsDeviceEntryTable.GetFileInformation = NtfsGetFileInformation;
+ NtfsDeviceEntryTable.SetFileInformation = NtfsSetFileInformation;
+ NtfsDeviceEntryTable.BootFsInfo = &NtfsBootFsInfo;
+
+ return &NtfsDeviceEntryTable;
+}
+
+
+ARC_STATUS
+NtfsClose (
+ IN ULONG FileId
+ )
+
+/*++
+
+Routine Description:
+
+ This routine closes the file specified by the file id.
+
+Arguments:
+
+ FileId - Supplies the file table index.
+
+Return Value:
+
+ ESUCCESS if returned as the function value.
+
+--*/
+
+{
+ //
+ // Indicate that the file isn't open any longer
+ //
+
+ BlFileTable[FileId].Flags.Open = 0;
+
+ //
+ // And return to our caller
+ //
+
+ return ESUCCESS;
+}
+
+
+ARC_STATUS
+NtfsGetFileInformation (
+ IN ULONG FileId,
+ OUT PFILE_INFORMATION Buffer
+ )
+
+/*++
+
+Routine Description:
+
+ This procedure returns to the user a buffer filled with file information
+
+Arguments:
+
+ FileId - Supplies the File id for the operation
+
+ Buffer - Supplies the buffer to receive the file information. Note that
+ it must be large enough to hold the full file name
+
+Return Value:
+
+ ESUCCESS is returned if the open operation is successful. Otherwise,
+ an unsuccessful status is returned that describes the reason for failure.
+
+--*/
+
+{
+ PBL_FILE_TABLE FileTableEntry;
+ PNTFS_STRUCTURE_CONTEXT StructureContext;
+ PNTFS_FILE_CONTEXT FileContext;
+
+ NTFS_ATTRIBUTE_CONTEXT AttributeContext;
+ BOOLEAN Found;
+
+ STANDARD_INFORMATION StandardInformation;
+
+ ULONG i;
+
+ //
+ // Setup some local references
+ //
+
+ FileTableEntry = &BlFileTable[FileId];
+ StructureContext = (PNTFS_STRUCTURE_CONTEXT)FileTableEntry->StructureContext;
+ FileContext = &FileTableEntry->u.NtfsFileContext;
+
+ //
+ // Zero out the output buffer and fill in its non-zero values
+ //
+
+ RtlZeroMemory(Buffer, sizeof(FILE_INFORMATION));
+
+ Buffer->EndingAddress.QuadPart = FileContext->DataSize;
+ Buffer->CurrentPosition = FileTableEntry->Position;
+
+ //
+ // Locate and read in the standard information for the file. This will get us
+ // the attributes for the file.
+ //
+
+ LookupAttribute( StructureContext,
+ FileContext->FileRecord,
+ $STANDARD_INFORMATION,
+ &Found,
+ &AttributeContext );
+
+ if (!Found) { return EBADF; }
+
+ ReadAttribute( StructureContext,
+ &AttributeContext,
+ 0,
+ sizeof(STANDARD_INFORMATION),
+ &StandardInformation );
+
+ //
+ // Now check for set bits in the standard information structure and set the
+ // appropriate bits in the output buffer
+ //
+
+ if (FlagOn(StandardInformation.FileAttributes, FAT_DIRENT_ATTR_READ_ONLY)) {
+
+ SetFlag(Buffer->Attributes, ArcReadOnlyFile);
+ }
+
+ if (FlagOn(StandardInformation.FileAttributes, FAT_DIRENT_ATTR_HIDDEN)) {
+
+ SetFlag(Buffer->Attributes, ArcHiddenFile);
+ }
+
+ if (FlagOn(StandardInformation.FileAttributes, FAT_DIRENT_ATTR_SYSTEM)) {
+
+ SetFlag(Buffer->Attributes, ArcSystemFile);
+ }
+
+ if (FlagOn(StandardInformation.FileAttributes, FAT_DIRENT_ATTR_ARCHIVE)) {
+
+ SetFlag(Buffer->Attributes, ArcArchiveFile);
+ }
+
+ if (FlagOn(StandardInformation.FileAttributes, DUP_FILE_NAME_INDEX_PRESENT)) {
+
+ SetFlag(Buffer->Attributes, ArcDirectoryFile);
+ }
+
+ //
+ // Get the file name from the file table entry
+ //
+
+ Buffer->FileNameLength = FileTableEntry->FileNameLength;
+
+ for (i = 0; i < FileTableEntry->FileNameLength; i += 1) {
+
+ Buffer->FileName[i] = FileTableEntry->FileName[i];
+ }
+
+ //
+ // And return to our caller
+ //
+
+ return ESUCCESS;
+}
+
+
+ARC_STATUS
+NtfsOpen (
+ IN PCHAR FileName,
+ IN OPEN_MODE OpenMode,
+ IN PULONG FileId
+ )
+
+/*++
+
+Routine Description:
+
+ This routine searches the root directory for a file matching FileName.
+ If a match is found the dirent for the file is saved and the file is
+ opened.
+
+Arguments:
+
+ FileName - Supplies a pointer to a zero terminated file name.
+
+ OpenMode - Supplies the mode of the open.
+
+ FileId - Supplies a pointer to a variable that specifies the file
+ table entry that is to be filled in if the open is successful.
+
+Return Value:
+
+ ESUCCESS is returned if the open operation is successful. Otherwise,
+ an unsuccessful status is returned that describes the reason for failure.
+
+--*/
+
+{
+ PBL_FILE_TABLE FileTableEntry;
+ PNTFS_STRUCTURE_CONTEXT StructureContext;
+ PNTFS_FILE_CONTEXT FileContext;
+
+ STRING PathName;
+ STRING Name;
+
+ LONGLONG FileRecord;
+ BOOLEAN IsDirectory;
+ BOOLEAN Found;
+
+ NTFS_ATTRIBUTE_CONTEXT AttributeContext1;
+ NTFS_ATTRIBUTE_CONTEXT AttributeContext2;
+ NTFS_ATTRIBUTE_CONTEXT AttributeContext3;
+
+ PNTFS_ATTRIBUTE_CONTEXT IndexRoot;
+ PNTFS_ATTRIBUTE_CONTEXT IndexAllocation;
+ PNTFS_ATTRIBUTE_CONTEXT AllocationBitmap;
+
+ //NtfsPrint("%d NtfsOpen(\"%s\")\n\r", __LINE__, FileName);
+
+ //
+ // Load our local variables
+ //
+
+ FileTableEntry = &BlFileTable[*FileId];
+ StructureContext = (PNTFS_STRUCTURE_CONTEXT)FileTableEntry->StructureContext;
+ FileContext = &FileTableEntry->u.NtfsFileContext;
+
+ //
+ // Zero out the file context and position information in the file table entry
+ //
+
+ FileTableEntry->Position.QuadPart = 0;
+
+ RtlZeroMemory(FileContext, sizeof(NTFS_FILE_CONTEXT));
+
+ //
+ // Construct a file name descriptor from the input file name
+ //
+
+ RtlInitString( &PathName, FileName );
+
+ //
+ // Open the root directory as our starting point, The root directory file
+ // reference number is 5.
+ //
+
+ FileRecord = 5;
+ IsDirectory = TRUE;
+
+ //
+ // While the path name has some characters left in it and current attribute
+ // context is a directory we will continue our search
+ //
+
+ while ((PathName.Length > 0) && IsDirectory) {
+
+ //
+ // Extract the first component and search the directory for a match, but
+ // first copy the first part to the file name buffer in the file table entry
+ //
+
+ if (PathName.Buffer[0] == '\\') {
+
+ PathName.Buffer +=1;
+ PathName.Length -=1;
+ }
+
+ for (FileTableEntry->FileNameLength = 0;
+ (((USHORT)FileTableEntry->FileNameLength < PathName.Length) &&
+ (PathName.Buffer[FileTableEntry->FileNameLength] != '\\'));
+ FileTableEntry->FileNameLength += 1) {
+
+ FileTableEntry->FileName[FileTableEntry->FileNameLength] =
+ PathName.Buffer[FileTableEntry->FileNameLength];
+ }
+
+ NtfsFirstComponent( &PathName, &Name );
+
+ //
+ // The current file record must be a directory so now lookup the index root,
+ // allocation and bitmap for the directory and then we can do our search.
+ //
+
+ IndexRoot = &AttributeContext1;
+
+ LookupAttribute( StructureContext,
+ FileRecord,
+ $INDEX_ROOT,
+ &Found,
+ IndexRoot);
+
+ if (!Found) { return EBADF; }
+
+ IndexAllocation = &AttributeContext2;
+
+ LookupAttribute( StructureContext,
+ FileRecord,
+ $INDEX_ALLOCATION,
+ &Found,
+ IndexAllocation);
+
+ if (!Found) { IndexAllocation = NULL; }
+
+ AllocationBitmap = &AttributeContext3;
+
+ LookupAttribute( StructureContext,
+ FileRecord,
+ $BITMAP,
+ &Found,
+ AllocationBitmap);
+
+ if (!Found) { AllocationBitmap = NULL; }
+
+ //
+ // Search for the name in the current directory
+ //
+
+ SearchForFileName( StructureContext,
+ IndexRoot,
+ IndexAllocation,
+ AllocationBitmap,
+ Name,
+ &Found,
+ &FileRecord,
+ &IsDirectory );
+
+ //
+ // If we didn't find it then we should get out right now
+ //
+
+ if (!Found) { return ENOENT; }
+ }
+
+ //
+ // At this point we have exhausted our pathname or we did not get a directory
+ // Check if we didn't get a directory and we still have a name to crack
+ //
+
+ if (PathName.Length > 0) {
+
+ return ENOTDIR;
+ }
+
+ //
+ // Now FileRecord is the one we wanted to open. Check the various open modes
+ // against what we have located
+ //
+
+ if (IsDirectory) {
+
+ switch (OpenMode) {
+
+ case ArcOpenDirectory:
+
+ //
+ // To open the directory we will lookup the index root as our file
+ // context and then increment the appropriate counters.
+ //
+
+ LookupAttribute( StructureContext,
+ FileRecord,
+ $INDEX_ROOT,
+ &Found,
+ FileContext );
+
+ if (!Found) { return EBADF; }
+
+ FileTableEntry->Flags.Open = 1;
+ FileTableEntry->Flags.Read = 1;
+
+ return ESUCCESS;
+
+ case ArcCreateDirectory:
+
+ return EROFS;
+
+ default:
+
+ return EISDIR;
+ }
+
+ }
+
+ switch (OpenMode) {
+
+ case ArcOpenReadOnly:
+
+ //
+ // To open the file we will lookup the $data as our file context and then
+ // increment the appropriate counters.
+ //
+
+ LookupAttribute( StructureContext,
+ FileRecord,
+ $DATA,
+ &Found,
+ FileContext );
+
+ if (!Found) { return EBADF; }
+
+ FileTableEntry->Flags.Open = 1;
+ FileTableEntry->Flags.Read = 1;
+
+ return ESUCCESS;
+
+ case ArcOpenDirectory:
+
+ return ENOTDIR;
+
+ default:
+
+ return EROFS;
+ }
+}
+
+
+ARC_STATUS
+NtfsRead (
+ IN ULONG FileId,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Transfer
+ )
+
+/*++
+
+Routine Description:
+
+ This routine reads data from the specified file.
+
+Arguments:
+
+ FileId - Supplies the file table index.
+
+ Buffer - Supplies a pointer to the buffer that receives the data
+ read.
+
+ Length - Supplies the number of bytes that are to be read.
+
+ Transfer - Supplies a pointer to a variable that receives the number
+ of bytes actually transfered.
+
+Return Value:
+
+ ESUCCESS is returned if the read operation is successful. Otherwise,
+ an unsuccessful status is returned that describes the reason for failure.
+
+--*/
+
+{
+ PBL_FILE_TABLE FileTableEntry;
+ PNTFS_STRUCTURE_CONTEXT StructureContext;
+ PNTFS_FILE_CONTEXT FileContext;
+
+ LONGLONG AmountLeft;
+
+ //
+ // Setup some local references
+ //
+
+ FileTableEntry = &BlFileTable[FileId];
+ StructureContext = (PNTFS_STRUCTURE_CONTEXT)FileTableEntry->StructureContext;
+ FileContext = &FileTableEntry->u.NtfsFileContext;
+
+ //
+ // Compute the amount left in the file and then from that we compute the amount
+ // for the transfer
+ //
+
+ AmountLeft = /*xxSub*/( FileContext->DataSize - FileTableEntry->Position.QuadPart);
+
+ if (/*xxLeq*/(/*xxFromUlong*/(Length) <= AmountLeft)) {
+
+ *Transfer = Length;
+
+ } else {
+
+ *Transfer = ((ULONG)AmountLeft);
+ }
+
+ //
+ // Now issue the read attribute
+ //
+
+ ReadAttribute( StructureContext,
+ FileContext,
+ FileTableEntry->Position.QuadPart,
+ *Transfer,
+ Buffer );
+
+ //
+ // Update the current position, and return to our caller
+ //
+
+ FileTableEntry->Position.QuadPart = /*xxAdd*/(FileTableEntry->Position.QuadPart + /*xxFromUlong*/(*Transfer));
+
+ return ESUCCESS;
+}
+
+
+ARC_STATUS
+NtfsSeek (
+ IN ULONG FileId,
+ IN PLARGE_INTEGER Offset,
+ IN SEEK_MODE SeekMode
+ )
+
+/*++
+
+Routine Description:
+
+ This routine seeks to the specified position for the file specified
+ by the file id.
+
+Arguments:
+
+ FileId - Supplies the file table index.
+
+ Offset - Supplies the offset in the file to position to.
+
+ SeekMode - Supplies the mode of the seek operation.
+
+Return Value:
+
+ ESUCCESS if returned as the function value.
+
+--*/
+
+{
+ PBL_FILE_TABLE FileTableEntry;
+ LONGLONG NewPosition;
+
+ //
+ // Load our local variables
+ //
+
+ FileTableEntry = &BlFileTable[FileId];
+
+ //
+ // Compute the new position
+ //
+
+ if (SeekMode == SeekAbsolute) {
+
+ NewPosition = Offset->QuadPart;
+
+ } else {
+
+ NewPosition = /*xxAdd*/(FileTableEntry->Position.QuadPart + Offset->QuadPart);
+ }
+
+ //
+ // If the new position is greater than the file size then return an error
+ //
+
+ if (/*xxGtr*/(NewPosition > FileTableEntry->u.NtfsFileContext.DataSize)) {
+
+ return EINVAL;
+ }
+
+ //
+ // Otherwise set the new position and return to our caller
+ //
+
+ FileTableEntry->Position.QuadPart = NewPosition;
+
+ return ESUCCESS;
+}
+
+
+ARC_STATUS
+NtfsSetFileInformation (
+ IN ULONG FileId,
+ IN ULONG AttributeFlags,
+ IN ULONG AttributeMask
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets the file attributes of the indicated file
+
+Arguments:
+
+ FileId - Supplies the File Id for the operation
+
+ AttributeFlags - Supplies the value (on or off) for each attribute being modified
+
+ AttributeMask - Supplies a mask of the attributes being altered. All other
+ file attributes are left alone.
+
+Return Value:
+
+ ESUCCESS is returned if the read operation is successful. Otherwise,
+ an unsuccessful status is returned that describes the reason for failure.
+
+--*/
+
+{
+ return EROFS;
+}
+
+
+ARC_STATUS
+NtfsWrite (
+ IN ULONG FileId,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Transfer
+ )
+
+/*++
+
+Routine Description:
+
+ This routine writes data to the specified file.
+
+Arguments:
+
+ FileId - Supplies the file table index.
+
+ Buffer - Supplies a pointer to the buffer that contains the data
+ written.
+
+ Length - Supplies the number of bytes that are to be written.
+
+ Transfer - Supplies a pointer to a variable that receives the number
+ of bytes actually transfered.
+
+Return Value:
+
+ ESUCCESS is returned if the write operation is successful. Otherwise,
+ an unsuccessful status is returned that describes the reason for failure.
+
+--*/
+
+{
+ return EROFS;
+}
+
+
+ARC_STATUS
+NtfsInitialize (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the ntfs boot filesystem.
+ Currently this is a no-op.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ ESUCCESS.
+
+--*/
+
+{
+ //
+ // The first time we will zero out the file record buffer and allocate
+ // a few buffers for read in data.
+ //
+
+ RtlZeroMemory( NtfsFileRecordBuffer, sizeof(NtfsFileRecordBuffer));
+
+ NtfsFileRecordBuffer[0] = ALIGN_BUFFER(NtfsBuffer0);
+ NtfsFileRecordBuffer[1] = ALIGN_BUFFER(NtfsBuffer1);
+ NtfsIndexAllocationBuffer = ALIGN_BUFFER(NtfsBuffer2);
+ NtfsCompressedBuffer = ALIGN_BUFFER(NtfsBuffer3);
+ NtfsUncompressedBuffer = ALIGN_BUFFER(NtfsBuffer4);
+
+ return ESUCCESS;
+}
+
+
+//
+// Local support routine
+//
+
+ARC_STATUS
+NtfsReadDisk (
+ IN ULONG DeviceId,
+ IN LONGLONG Lbo,
+ IN ULONG ByteCount,
+ IN OUT PVOID Buffer
+ )
+
+/*++
+
+Routine Description:
+
+ This routine reads in zero or more bytes from the specified device.
+
+Arguments:
+
+ DeviceId - Supplies the device id to use in the arc calls.
+
+ Lbo - Supplies the LBO to start reading from.
+
+ ByteCount - Supplies the number of bytes to read.
+
+ Buffer - Supplies a pointer to the buffer to read the bytes into.
+
+Return Value:
+
+ ESUCCESS is returned if the read operation is successful. Otherwise,
+ an unsuccessful status is returned that describes the reason for failure.
+
+--*/
+
+{
+ ARC_STATUS Status;
+ ULONG i;
+
+ //
+ // Special case the zero byte read request
+ //
+
+ if (ByteCount == 0) {
+
+ return ESUCCESS;
+ }
+
+ //
+ // Seek to the appropriate offset on the volume
+ //
+
+ if ((Status = ArcSeek( DeviceId, (PLARGE_INTEGER)&Lbo, SeekAbsolute )) != ESUCCESS) {
+
+ return Status;
+ }
+
+ //
+ // Issue the arc read request
+ //
+
+ if ((Status = ArcRead( DeviceId, Buffer, ByteCount, &i)) != ESUCCESS) {
+
+ return Status;
+ }
+
+ //
+ // Make sure we got back the amount requested
+ //
+
+ if (ByteCount != i) {
+
+ return EIO;
+ }
+
+ //
+ // Everything is fine so return success to our caller
+ //
+
+ return ESUCCESS;
+}
+
+
+//
+// Local support routine
+//
+
+ARC_STATUS
+NtfsLookupAttribute (
+ IN PNTFS_STRUCTURE_CONTEXT StructureContext,
+ IN LONGLONG FileRecord,
+ IN ATTRIBUTE_TYPE_CODE TypeCode,
+ OUT PBOOLEAN FoundAttribute,
+ OUT PNTFS_ATTRIBUTE_CONTEXT AttributeContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine search the input file record for the indicated
+ attribute record. It will search through multiple related
+ file records to find the attribute. If the type code is for $data
+ then the attribute we look for must be unnamed otherwise we will
+ ignore the names of the attributes and return the first attriubute
+ of the indicated type.
+
+Arguments:
+
+ StructureContext - Supplies the volume structure for this operation
+
+ FileRecord - Supplies the file record to start searching from. This need
+ not be the base file record.
+
+ TypeCode - Supplies the attribute type that we are looking for
+
+ FoundAttribute - Receives an indicating if the attribute was located
+
+ AttributeContext - Receives the attribute context for the found attribute
+
+Return Value:
+
+ ESUCCESS is returned if the operation is successful. Otherwise,
+ an unsuccessful status is returned that describes the reason for failure.
+
+--*/
+
+{
+ PATTRIBUTE_RECORD_HEADER AttributeHeader;
+
+ NTFS_ATTRIBUTE_CONTEXT AttributeContext1;
+ PNTFS_ATTRIBUTE_CONTEXT AttributeList;
+
+ LONGLONG li;
+ ATTRIBUTE_LIST_ENTRY AttributeListEntry;
+
+ ULONG BufferIndex;
+
+ //
+ // Unless other noted we will assume we haven't found the attribute
+ //
+
+ *FoundAttribute = FALSE;
+
+ //
+ // Read in the file record and if necessary move ourselves up to the base file
+ // record
+ //
+
+ ReadAndDecodeFileRecord( StructureContext,
+ FileRecord,
+ &BufferIndex );
+
+ if (/*!xxEqlZero*/(*((PLONGLONG)&(NtfsFileRecordBuffer[BufferIndex]->BaseFileRecordSegment)) != 0)) {
+
+ //
+ // This isn't the base file record so now extract the base file record
+ // number and read it in
+ //
+
+ FileReferenceToLargeInteger( NtfsFileRecordBuffer[BufferIndex]->BaseFileRecordSegment,
+ &FileRecord );
+
+ NtfsFileRecordBufferPinned[BufferIndex] -= 1;
+
+ ReadAndDecodeFileRecord( StructureContext,
+ FileRecord,
+ &BufferIndex );
+ }
+
+ //
+ // Now we have read in the base file record so search for the target attribute
+ // type code and also remember if we find the attribute list attribute
+ //
+
+ AttributeList = NULL;
+
+ for (AttributeHeader = NtfsFirstAttribute( NtfsFileRecordBuffer[BufferIndex] );
+ AttributeHeader->TypeCode != $END;
+ AttributeHeader = NtfsGetNextRecord( AttributeHeader )) {
+
+ //
+ // We have located the attribute in question if the type code match and if
+ // it is either not the data attribute or if it is the data attribute then
+ // it is also unnamed
+ //
+
+ if ((AttributeHeader->TypeCode == TypeCode)
+
+ &&
+
+ ((TypeCode != $DATA) ||
+ ((TypeCode == $DATA) && (AttributeHeader->NameLength == 0)))) {
+
+ //
+ // Indicate that we have found the attribute and setup the output
+ // attribute context and then return to our caller
+ //
+
+ *FoundAttribute = TRUE;
+
+ InitializeAttributeContext( StructureContext,
+ NtfsFileRecordBuffer[BufferIndex],
+ AttributeHeader,
+ FileRecord,
+ AttributeContext );
+
+ NtfsFileRecordBufferPinned[BufferIndex] -= 1;
+
+ return ESUCCESS;
+ }
+
+ //
+ // Check if this is the attribute list attribute and if so then setup a
+ // local attribute context to use just in case we don't find the attribute
+ // we're after in the base file record
+ //
+
+ if (AttributeHeader->TypeCode == $ATTRIBUTE_LIST) {
+
+ InitializeAttributeContext( StructureContext,
+ NtfsFileRecordBuffer[BufferIndex],
+ AttributeHeader,
+ FileRecord,
+ AttributeList = &AttributeContext1 );
+ }
+ }
+
+ //
+ // If we reach this point then the attribute has not been found in the base file
+ // record so check if we have located an attribute list. If not then the search
+ // has not been successful
+ //
+
+ if (AttributeList == NULL) {
+
+ NtfsFileRecordBufferPinned[BufferIndex] -= 1;
+
+ return ESUCCESS;
+ }
+
+ //
+ // Now that we've located the attribute list we need to continue our search. So
+ // what this outer loop does is search down the attribute list looking for a
+ // match.
+ //
+
+ for (li = 0;
+ /*xxLtr*/(li < AttributeList->DataSize);
+ li = /*xxAdd*/(li + /*xxFromUlong*/(AttributeListEntry.RecordLength))) {
+
+ //
+ // Read in the attribute list entry. We don't need to read in the name,
+ // just the first part of the list entry.
+ //
+
+ ReadAttribute( StructureContext,
+ AttributeList,
+ li,
+ sizeof(ATTRIBUTE_LIST_ENTRY),
+ &AttributeListEntry );
+
+ //
+ // Now check if the attribute matches, and it is the first of multiple
+ // segments, and either it is not $data or if it is $data then it is unnamed
+ //
+
+ if ((AttributeListEntry.AttributeTypeCode == TypeCode)
+
+ &&
+
+ /*xxEqlZero*/(AttributeListEntry.LowestVcn == 0)
+
+ &&
+
+ ((TypeCode != $DATA) ||
+ ((TypeCode == $DATA) && (AttributeListEntry.AttributeNameLength == 0)))) {
+
+ //
+ // We found a match so now compute the file record containing the
+ // attribute we're after and read in the file record
+ //
+
+ FileReferenceToLargeInteger( AttributeListEntry.SegmentReference,
+ &FileRecord );
+
+ NtfsFileRecordBufferPinned[BufferIndex] -= 1;
+
+ ReadAndDecodeFileRecord( StructureContext,
+ FileRecord,
+ &BufferIndex );
+
+ //
+ // Now search down the file record for our matching attribute, and it
+ // better be there otherwise the attribute list is wrong.
+ //
+
+ for (AttributeHeader = NtfsFirstAttribute( NtfsFileRecordBuffer[BufferIndex] );
+ AttributeHeader->TypeCode != $END;
+ AttributeHeader = NtfsGetNextRecord( AttributeHeader )) {
+
+ //
+ // We have located the attribute in question if the type code match
+ // and if it is either not the data attribute or if it is the data
+ // attribute then it is also unnamed
+ //
+
+ if ((AttributeHeader->TypeCode == TypeCode)
+
+ &&
+
+ ((TypeCode != $DATA) ||
+ ((TypeCode == $DATA) && (AttributeHeader->NameLength == 0)))) {
+
+ //
+ // Indicate that we have found the attribute and setup the
+ // output attribute context and return to our caller
+ //
+
+ *FoundAttribute = TRUE;
+
+ InitializeAttributeContext( StructureContext,
+ NtfsFileRecordBuffer[BufferIndex],
+ AttributeHeader,
+ FileRecord,
+ AttributeContext );
+
+ NtfsFileRecordBufferPinned[BufferIndex] -= 1;
+
+ return ESUCCESS;
+ }
+ }
+
+ NtfsFileRecordBufferPinned[BufferIndex] -= 1;
+
+ return EBADF;
+ }
+ }
+
+ //
+ // If we reach this point we've exhausted the attribute list without finding the
+ // attribute
+ //
+
+ NtfsFileRecordBufferPinned[BufferIndex] -= 1;
+
+ return ESUCCESS;
+}
+
+
+//
+// Local support routine
+//
+
+ARC_STATUS
+NtfsReadResidentAttribute (
+ IN PNTFS_STRUCTURE_CONTEXT StructureContext,
+ IN PNTFS_ATTRIBUTE_CONTEXT AttributeContext,
+ IN VBO Vbo,
+ IN ULONG Length,
+ IN PVOID Buffer
+ )
+
+/*++
+
+Routine Description:
+
+ This routine reads in the value of a resident attribute. The attribute
+ must be resident.
+
+Arguments:
+
+ StructureContext - Supplies the volume structure for this operation
+
+ AttributeContext - Supplies the attribute being read.
+
+ Vbo - Supplies the offset within the value to return
+
+ Length - Supplies the number of bytes to return
+
+ Buffer - Supplies a pointer to the output buffer for storing the data
+
+Return Value:
+
+ ESUCCESS is returned if the read operation is successful. Otherwise,
+ an unsuccessful status is returned that describes the reason for failure.
+
+--*/
+
+{
+ PATTRIBUTE_RECORD_HEADER AttributeHeader;
+
+ ULONG BufferIndex;
+
+ //
+ // Read in the file record containing the resident attribute
+ //
+
+ ReadAndDecodeFileRecord( StructureContext,
+ AttributeContext->FileRecord,
+ &BufferIndex );
+
+ //
+ // Get a pointer to the attribute header
+ //
+
+ AttributeHeader = Add2Ptr( NtfsFileRecordBuffer[BufferIndex],
+ AttributeContext->FileRecordOffset );
+
+ //
+ // Copy the amount of data the user asked for starting with the proper offset
+ //
+
+ RtlMoveMemory( Buffer,
+ Add2Ptr(NtfsGetValue(AttributeHeader), ((ULONG)Vbo)),
+ Length );
+
+ //
+ // And return to our caller
+ //
+
+ NtfsFileRecordBufferPinned[BufferIndex] -= 1;
+
+ return ESUCCESS;
+}
+
+
+//
+// Local support routine
+//
+
+ARC_STATUS
+NtfsReadNonresidentAttribute (
+ IN PNTFS_STRUCTURE_CONTEXT StructureContext,
+ IN PNTFS_ATTRIBUTE_CONTEXT AttributeContext,
+ IN VBO Vbo,
+ IN ULONG Length,
+ IN PVOID Buffer
+ )
+
+/*++
+
+Routine Description:
+
+ This routine reads in the value of a Nonresident attribute. The attribute
+ must be Nonresident.
+
+Arguments:
+
+ StructureContext - Supplies the volume structure for this operation
+
+ AttributeContext - Supplies the attribute being read.
+
+ Vbo - Supplies the offset within the value to return
+
+ Length - Supplies the number of bytes to return
+
+ Buffer - Supplies a pointer to the output buffer for storing the data
+
+Return Value:
+
+ ESUCCESS is returned if the read operation is successful. Otherwise,
+ an unsuccessful status is returned that describes the reason for failure.
+
+--*/
+
+{
+ //
+ // Check if we are reading a compressed attribute
+ //
+
+ if (AttributeContext->CompressionFormat != 0) {
+
+ //
+ // While there is still some more to copy into the
+ // caller's buffer, we will load the cached compressed buffers
+ // and then copy out the data
+ //
+
+ while (Length > 0) {
+
+ ULONG ByteCount;
+
+ //
+ // Load up the cached compressed buffers with the
+ // the proper data. First check if the buffer is
+ // already (i.e., the file record and offset match and
+ // the vbo we're after is within the buffers range)
+ //
+
+ if (/*xxNeq*/(NtfsCompressedFileRecord != AttributeContext->FileRecord) ||
+ (NtfsCompressedOffset != AttributeContext->FileRecordOffset) ||
+ (((ULONG)Vbo) < NtfsCompressedVbo) ||
+ (((ULONG)Vbo) >= (NtfsCompressedVbo + AttributeContext->CompressionUnit))) {
+
+ ULONG i;
+ LBO Lbo;
+
+ //
+ // Load up the cached identification information
+ //
+
+ NtfsCompressedFileRecord = AttributeContext->FileRecord;
+ NtfsCompressedOffset = AttributeContext->FileRecordOffset;
+
+ NtfsCompressedVbo = ((ULONG)Vbo) & ~(AttributeContext->CompressionUnit - 1);
+
+ //
+ // Now load up the compressed buffer with data. We keep on
+ // loading until we're done loading or the Lbo we get back is
+ // zero.
+ //
+
+ for (i = 0; i < AttributeContext->CompressionUnit; i += ByteCount) {
+
+ VboToLbo( StructureContext,
+ AttributeContext,
+ /*xxFromUlong*/(NtfsCompressedVbo + i),
+ &Lbo,
+ &ByteCount );
+
+ if (/*xxEqlZero*/(Lbo == 0)) { break; }
+
+ //
+ // Trim the byte count down to a compression unit and we'll catch the
+ // excess the next time through the loop
+ //
+
+ if ((i + ByteCount) > AttributeContext->CompressionUnit) {
+
+ ByteCount = AttributeContext->CompressionUnit - i;
+ }
+
+ ReadDisk( StructureContext->DeviceId, Lbo, ByteCount, &NtfsCompressedBuffer[i] );
+ }
+
+ //
+ // If the index for the preceding loop is zero then we know
+ // that there isn't any data on disk for the compression unit
+ // and in-fact the compression unit is all zeros
+ //
+
+ if (i == 0) {
+
+ RtlZeroMemory( NtfsUncompressedBuffer, AttributeContext->CompressionUnit );
+
+ //
+ // Otherwise the unit we just read in cannot be compressed
+ // because it completely fills up the compression unit
+ //
+
+ } else if (i >= AttributeContext->CompressionUnit) {
+
+ RtlMoveMemory( NtfsUncompressedBuffer,
+ NtfsCompressedBuffer,
+ AttributeContext->CompressionUnit );
+
+ //
+ // If the index for the preceding loop is less then the
+ // compression unit size then we know that the data we
+ // read in is less than the compression unit and we hit
+ // a zero lbo. So the unit must be compressed.
+ //
+
+ } else {
+
+ NTSTATUS Status;
+
+ Status = RtlDecompressBuffer( AttributeContext->CompressionFormat,
+ NtfsUncompressedBuffer,
+ AttributeContext->CompressionUnit,
+ NtfsCompressedBuffer,
+ i,
+ &ByteCount );
+
+ if (!NT_SUCCESS(Status)) {
+
+ return EINVAL;
+ }
+
+ //
+ // Check if the decompressed buffer doesn't fill up the
+ // compression unit and if so then zero out the remainder
+ // of the uncompressed buffer
+ //
+
+ if (ByteCount < AttributeContext->CompressionUnit) {
+
+ RtlZeroMemory( &NtfsUncompressedBuffer[ByteCount],
+ AttributeContext->CompressionUnit - ByteCount );
+ }
+ }
+ }
+
+ //
+ // Now copy off the data from the compressed buffer to the
+ // user buffer and continue the loop until the length is zero.
+ // The amount of data we need to copy is the smaller of the
+ // length the user wants back or the number of bytes left in
+ // the uncompressed buffer from the requested vbo to the end
+ // of the buffer.
+ //
+
+ ByteCount = Minimum( Length,
+ NtfsCompressedVbo + AttributeContext->CompressionUnit - ((ULONG)Vbo) );
+
+ RtlMoveMemory( Buffer,
+ &NtfsUncompressedBuffer[ ((ULONG)Vbo) - NtfsCompressedVbo ],
+ ByteCount );
+
+ //
+ // Update the length to be what the user now needs read in,
+ // also update the Vbo and Buffer to be the next locations
+ // to be read in.
+ //
+
+ Length -= ByteCount;
+ Vbo = /*xxAdd*/( Vbo + /*xxFromUlong*/(ByteCount));
+ Buffer = (PCHAR)Buffer + ByteCount;
+ }
+
+ return ESUCCESS;
+ }
+
+ //
+ // Read in runs of data until the byte count goes to zero
+ //
+
+ while (Length > 0) {
+
+ LBO Lbo;
+ ULONG CurrentRunByteCount;
+
+ //
+ // Lookup the corresponding Lbo and run length for the current position
+ // (i.e., vbo)
+ //
+
+ VboToLbo( StructureContext,
+ AttributeContext,
+ Vbo,
+ &Lbo,
+ &CurrentRunByteCount );
+
+ //
+ // While there are bytes to be read in from the current run length and we
+ // haven't exhausted the request we loop reading in bytes. The biggest
+ // request we'll handle is only 32KB contiguous bytes per physical read.
+ // So we might need to loop through the run
+ //
+
+ while ((Length > 0) && (CurrentRunByteCount > 0)) {
+
+ LONG SingleReadSize;
+
+ //
+ // Compute the size of the next physical read
+ //
+
+ SingleReadSize = Minimum(Length, 32*1024);
+ SingleReadSize = Minimum((ULONG)SingleReadSize, CurrentRunByteCount);
+
+ //
+ // Don't read beyond the data size
+ //
+
+ if (/*xxGtr*/(/*xxAdd*/(Vbo + /*xxFromUlong*/(SingleReadSize)) > AttributeContext->DataSize )) {
+
+ SingleReadSize = ((ULONG)(/*xxSub*/(AttributeContext->DataSize - Vbo)));
+
+ //
+ // If the readjusted read length is now zero then we're done
+ //
+
+ if (SingleReadSize <= 0) {
+
+ return ESUCCESS;
+ }
+
+ //
+ // By also setting length we'll make sure that this is our last read
+ //
+
+ Length = SingleReadSize;
+ }
+
+ //
+ // Issue the read
+ //
+
+ ReadDisk( StructureContext->DeviceId, Lbo, SingleReadSize, Buffer );
+
+ //
+ // Update the remaining length, current run byte count, and new lbo
+ // offset
+ //
+
+ Length -= SingleReadSize;
+ CurrentRunByteCount -= SingleReadSize;
+ Lbo = /*xxAdd*/(Lbo + /*xxFromUlong*/(SingleReadSize));
+ Vbo = /*xxAdd*/(Vbo + /*xxFromUlong*/(SingleReadSize));
+
+ //
+ // Update the buffer to point to the next byte location to fill in
+ //
+
+ Buffer = (PCHAR)Buffer + SingleReadSize;
+ }
+ }
+
+ //
+ // If we get here then the remaining byte count is zero so we can return success
+ // to our caller
+ //
+
+ return ESUCCESS;
+}
+
+
+//
+// Local support routine
+//
+
+
+ARC_STATUS
+NtfsReadAndDecodeFileRecord (
+ IN PNTFS_STRUCTURE_CONTEXT StructureContext,
+ IN LONGLONG FileRecord,
+ OUT PULONG Index
+ )
+
+/*++
+
+Routine Description:
+
+ This routine reads in the specified file record into the indicated
+ ntfs file record buffer index provided that the buffer is not pinned.
+ It will also look at the current buffers and see if any will already
+ satisfy the request or assign an unused buffer if necessary and
+ fix Index to point to the right buffer
+
+Arguments:
+
+ StructureContext - Supplies the volume structure for this operation
+
+ FileRecord - Supplies the file record number being read
+
+ Index - Receives the index of where we put the buffer. After this
+ call the buffer is pinned and will need to be unpinned if it is
+ to be reused.
+
+Return Value:
+
+ ESUCCESS is returned if the operation is successful. Otherwise,
+ an unsuccessful status is returned that describes the reason for failure.
+
+--*/
+
+{
+ ARC_STATUS Status;
+
+ //
+ // For each buffer that is not null check if we have a hit on the
+ // file record and if so then increment the pin count and return
+ // that index
+ //
+
+ for (*Index = 0; (*Index < BUFFER_COUNT) && (NtfsFileRecordBuffer[*Index] != NULL); *Index += 1) {
+
+ if (NtfsFileRecordBufferVbo[*Index] == FileRecord) {
+
+ NtfsFileRecordBufferPinned[*Index] += 1;
+ return ESUCCESS;
+ }
+ }
+
+ //
+ // Check for the first unpinned buffer and make sure we haven't exhausted the
+ // array
+ //
+
+ for (*Index = 0; (*Index < BUFFER_COUNT) && (NtfsFileRecordBufferPinned[*Index] != 0); *Index += 1) {
+
+ NOTHING;
+ }
+
+ if (*Index == BUFFER_COUNT) { return E2BIG; }
+
+ //
+ // We have an unpinned buffer that we want to use, check if we need to
+ // allocate a buffer to actually hold the data
+ //
+
+ if (NtfsFileRecordBuffer[*Index] == NULL) {
+
+ NtfsFileRecordBuffer[*Index] = BlAllocateHeapAligned(MAXIMUM_FILE_RECORD_SIZE);
+ }
+
+ //
+ // Pin the buffer and then read in the data
+ //
+
+ NtfsFileRecordBufferPinned[*Index] += 1;
+
+ if ((Status = NtfsReadNonresidentAttribute( StructureContext,
+ &StructureContext->MftAttributeContext,
+ FileRecord * StructureContext->BytesPerFileRecord,
+ StructureContext->BytesPerFileRecord,
+ NtfsFileRecordBuffer[*Index] )) != ESUCCESS) {
+
+ return Status;
+ }
+
+ //
+ // Decode the usa
+ //
+
+ if ((Status = NtfsDecodeUsa( NtfsFileRecordBuffer[*Index],
+ StructureContext->BytesPerFileRecord )) != ESUCCESS) {
+
+ return Status;
+ }
+
+ //
+ // And set the file record so that we know where it came from
+ //
+
+ NtfsFileRecordBufferVbo[*Index] = FileRecord;
+
+ return ESUCCESS;
+}
+
+
+//
+// Local support routine
+//
+
+ARC_STATUS
+NtfsDecodeUsa (
+ IN PVOID UsaBuffer,
+ IN ULONG Length
+ )
+
+/*++
+
+Routine Description:
+
+ This routine takes as input file record or index buffer and applies the
+ usa transformation to get it back into a state that we can use it.
+
+Arguments:
+
+ UsaBuffer - Supplies the buffer used in this operation
+
+ Length - Supplies the length of the buffer in bytes
+
+Return Value:
+
+ ESUCCESS is returned if the operation is successful. Otherwise,
+ an unsuccessful status is returned that describes the reason for failure.
+
+--*/
+
+{
+ PMULTI_SECTOR_HEADER MultiSectorHeader;
+
+ PUSHORT UsaOffset;
+ ULONG UsaSize;
+
+ ULONG i;
+ PUSHORT ProtectedUshort;
+
+ //
+ // Setup our local variables
+ //
+
+ MultiSectorHeader = (PMULTI_SECTOR_HEADER)UsaBuffer;
+
+ UsaOffset = Add2Ptr(UsaBuffer, MultiSectorHeader->UpdateSequenceArrayOffset);
+ UsaSize = MultiSectorHeader->UpdateSequenceArraySize;
+
+ //
+ // For every entry in the usa we need to compute the address of the protected
+ // ushort and then check that the protected ushort is equal to the current
+ // sequence number (i.e., the number at UsaOffset[0]) and then replace the
+ // protected ushort number with the saved ushort in the usa.
+ //
+
+ for (i = 1; i < UsaSize; i += 1) {
+
+ ProtectedUshort = Add2Ptr( UsaBuffer,
+ (SEQUENCE_NUMBER_STRIDE * i) - sizeof(USHORT));
+
+ if (*ProtectedUshort != UsaOffset[0]) {
+
+ return EBADF;
+ }
+
+ *ProtectedUshort = UsaOffset[i];
+ }
+
+ //
+ // And return to our caller
+ //
+
+ return ESUCCESS;
+}
+
+
+//
+// Local support routine
+//
+
+ARC_STATUS
+NtfsSearchForFileName (
+ IN PNTFS_STRUCTURE_CONTEXT StructureContext,
+ IN PNTFS_ATTRIBUTE_CONTEXT IndexRoot,
+ IN PNTFS_ATTRIBUTE_CONTEXT IndexAllocation OPTIONAL,
+ IN PNTFS_ATTRIBUTE_CONTEXT AllocationBitmap OPTIONAL,
+ IN STRING FileName,
+ OUT PBOOLEAN FoundFileName,
+ OUT PLONGLONG FileRecord,
+ OUT PBOOLEAN IsDirectory
+ )
+
+/*++
+
+Routine Description:
+
+ This routine searches a given index root and allocation for the specified
+ file name.
+
+Arguments:
+
+ StructureContext - Supplies the volume structure for this operation
+
+ IndexRoot - Supplies the attribute context for the root index of the
+ directory being searched
+
+ IndexAllocation - Optionally supplies the attribute context for the
+ index allocation of a directory that spilled out of its index root.
+
+ AllocationBitmap - Optionally supplies the attribute context for the
+ index allocation bitmap of a directory that spilled out of its index
+ root.
+
+ FileName - Supplies the file name being searched for (in ansi).
+
+ FoundFileName - Receives a value to indicate if we found the specified
+ file name in the directory
+
+ FileRecord - Receives the file record for the entry if one was located.
+
+ IsDirectory - Receives a value to indicate if the found index is itself
+ a directory
+
+Return Value:
+
+ ESUCCESS is returned if the operation is successful. Otherwise,
+ an unsuccessful status is returned that describes the reason for failure.
+
+--*/
+
+{
+ PATTRIBUTE_RECORD_HEADER IndexAttributeHeader;
+ PINDEX_ROOT IndexRootValue;
+ PINDEX_HEADER IndexHeader;
+
+ ULONG NextIndexBuffer;
+ ULONG BytesPerIndexBuffer;
+
+ ULONG BufferIndex;
+
+ //
+ // unless otherwise set we will assume that our search has failed
+ //
+
+ *FoundFileName = FALSE;
+
+ //
+ // First read in and search the index root for the file name. We know the index
+ // root is resident so we'll save some buffering and just read in file record
+ // with the index root directly
+ //
+
+ ReadAndDecodeFileRecord( StructureContext,
+ IndexRoot->FileRecord,
+ &BufferIndex );
+
+ IndexAttributeHeader = Add2Ptr( NtfsFileRecordBuffer[BufferIndex],
+ IndexRoot->FileRecordOffset );
+
+ IndexRootValue = NtfsGetValue( IndexAttributeHeader );
+
+ IndexHeader = &IndexRootValue->IndexHeader;
+
+ //
+ // We also setup ourselves so that if the current index does not contain a match
+ // we will read in the next index and continue our search
+ //
+
+ NextIndexBuffer = 0;
+
+ BytesPerIndexBuffer = IndexRootValue->BytesPerIndexBuffer;
+
+ //
+ // Now we'll just continue looping intil we either find a match or exhaust all
+ // of the index buffer
+ //
+
+ while (TRUE) {
+
+ PINDEX_ENTRY IndexEntry;
+ BOOLEAN IsAllocated;
+ VBO Vbo;
+
+ //
+ // Search the current index buffer (from index header looking for a match
+ //
+
+ for (IndexEntry = Add2Ptr(IndexHeader, IndexHeader->FirstIndexEntry);
+ !FlagOn(IndexEntry->Flags, INDEX_ENTRY_END);
+ IndexEntry = Add2Ptr(IndexEntry, IndexEntry->Length)) {
+
+ PFILE_NAME FileNameEntry;
+ UNICODE_STRING UnicodeFileName;
+
+ //
+ // Get the FileName for this index entry
+ //
+
+ FileNameEntry = Add2Ptr(IndexEntry, sizeof(INDEX_ENTRY));
+
+ UnicodeFileName.Length = FileNameEntry->FileNameLength * 2;
+ UnicodeFileName.Buffer = &FileNameEntry->FileName[0];
+
+ //
+ // Check if this the name we're after if it is then say we found it and
+ // setup the output variables
+ //
+
+ if (NtfsAreNamesEqual( FileName, UnicodeFileName )) {
+
+ *FoundFileName = TRUE;
+
+ FileReferenceToLargeInteger( IndexEntry->FileReference,
+ FileRecord );
+
+ *IsDirectory = FlagOn( FileNameEntry->Info.FileAttributes,
+ DUP_FILE_NAME_INDEX_PRESENT);
+
+ NtfsFileRecordBufferPinned[BufferIndex] -= 1;
+
+ return ESUCCESS;
+ }
+ }
+
+ //
+ // At this point we've searched one index header and need to read in another
+ // one to check. But first make sure there are additional index buffers
+ //
+
+ if (!ARGUMENT_PRESENT(IndexAllocation) ||
+ !ARGUMENT_PRESENT(AllocationBitmap)) {
+
+ NtfsFileRecordBufferPinned[BufferIndex] -= 1;
+
+ return ESUCCESS;
+ }
+
+ //
+ // Now the following loop reads in the valid index buffer. The variable
+ // next index buffer denotes the buffer we want to read in. The idea is to
+ // first check that the buffer is part of the index allocation otherwise
+ // we've exhausted the list without finding a match. Once we know the
+ // allocation exists then we check if the record is really allocated if it
+ // is not allocated we try the next buffer and so on.
+ //
+
+ IsAllocated = FALSE;
+
+ while (!IsAllocated) {
+
+ //
+ // Compute the starting vbo of the next index buffer and check if it is
+ // still within the data size.
+ //
+
+ Vbo = /*xxFromUlong*/(BytesPerIndexBuffer * NextIndexBuffer);
+
+ if (/*xxGeq*/(Vbo >= IndexAllocation->DataSize)) { return ESUCCESS; }
+
+ //
+ // Now check if the index buffer is in use
+ //
+
+ IsRecordAllocated( StructureContext,
+ AllocationBitmap,
+ NextIndexBuffer,
+ &IsAllocated );
+
+ NextIndexBuffer += 1;
+ }
+
+ //
+ // At this point we've computed the next index allocation buffer to read in
+ // so read it in, decode it, and go back to the top of our loop
+ //
+
+ ReadAttribute( StructureContext,
+ IndexAllocation,
+ Vbo,
+ BytesPerIndexBuffer,
+ NtfsIndexAllocationBuffer );
+
+ DecodeUsa( NtfsIndexAllocationBuffer, BytesPerIndexBuffer );
+
+ IndexHeader = &NtfsIndexAllocationBuffer->IndexHeader;
+ }
+}
+
+
+//
+// Local support routine
+//
+
+ARC_STATUS
+NtfsIsRecordAllocated (
+ IN PNTFS_STRUCTURE_CONTEXT StructureContext,
+ IN PNTFS_ATTRIBUTE_CONTEXT AllocationBitmap,
+ IN ULONG BitOffset,
+ OUT PBOOLEAN IsAllocated
+ )
+
+/*++
+
+Routine Description:
+
+ This routine indicates to the caller if the specified index allocation record
+ is in use (i.e., its bit is 1).
+
+Arguments:
+
+ StructureContext - Supplies the volume structure for this operation
+
+ AllocationBitmap - Supplies the attribute context for the index allocation bitmap
+
+ BitOffset - Supplies the offset (zero based) being checked
+
+ IsAllocated - Recieves an value indicating if the record is allocated or not
+
+Return Value:
+
+ ESUCCESS is returned if the operation is successful. Otherwise,
+ an unsuccessful status is returned that describes the reason for failure.
+
+--*/
+
+{
+ ULONG ByteIndex;
+ ULONG BitIndex;
+ UCHAR LocalByte;
+
+ //
+ // This routine is rather dumb in that it only reads in the byte that contains
+ // the bit we're interested in and doesn't keep any state information between
+ // calls. We first break down the bit offset into the byte and bit within
+ // the byte that we need to check
+ //
+
+ ByteIndex = BitOffset / 8;
+ BitIndex = BitOffset % 8;
+
+ //
+ // Read in a single byte containing the bit we need to check
+ //
+
+ ReadAttribute( StructureContext,
+ AllocationBitmap,
+ /*xxFromUlong*/(ByteIndex),
+ 1,
+ &LocalByte );
+
+ //
+ // Shift over the local byte so that the bit we want is in the low order bit and
+ // then mask it out to see if the bit is set
+ //
+
+ if (FlagOn(LocalByte >> BitIndex, 0x01)) {
+
+ *IsAllocated = TRUE;
+
+ } else {
+
+ *IsAllocated = FALSE;
+ }
+
+ //
+ // And return to our caller
+ //
+
+ return ESUCCESS;
+}
+
+
+//
+// Local support routine
+//
+
+ARC_STATUS
+NtfsLoadMcb (
+ IN PNTFS_STRUCTURE_CONTEXT StructureContext,
+ IN PNTFS_ATTRIBUTE_CONTEXT AttributeContext,
+ IN VBO Vbo,
+ IN PNTFS_MCB Mcb
+ )
+
+/*++
+
+Routine Description:
+
+ This routine loads into one of the cached mcbs the retrival information for the
+ starting vbo.
+
+Arguments:
+
+ StructureContext - Supplies the volume structure for this operation
+
+ AttributeContext - Supplies the Nonresident attribute being queried
+
+ Vbo - Supplies the starting Vbo to use when loading the mcb
+
+ Mcb - Supplies the mcb that we should be loading
+
+Return Value:
+
+ ESUCCESS is returned if the operation is successful. Otherwise,
+ an unsuccessful status is returned that describes the reason for failure.
+
+--*/
+
+{
+ PATTRIBUTE_RECORD_HEADER AttributeHeader;
+
+ ULONG BytesPerCluster;
+
+ VBO LowestVbo;
+ VBO HighestVbo;
+
+ LONGLONG FileRecord;
+
+ NTFS_ATTRIBUTE_CONTEXT AttributeContext1;
+ PNTFS_ATTRIBUTE_CONTEXT AttributeList;
+
+ LONGLONG li;
+ LONGLONG Previousli;
+ ATTRIBUTE_LIST_ENTRY AttributeListEntry;
+
+ ATTRIBUTE_TYPE_CODE TypeCode;
+
+ ULONG BufferIndex;
+ ULONG SavedBufferIndex;
+
+ //
+ // Load our local variables
+ //
+
+ BytesPerCluster = StructureContext->BytesPerCluster;
+
+ //
+ // Setup a pointer to the cached mcb, indicate the attribute context that is will
+ // now own the cached mcb, and zero out the mcb
+ //
+
+ Mcb->InUse = 0;
+
+ //
+ // Read in the file record that contains the non-resident attribute and get a
+ // pointer to the attribute header
+ //
+
+ ReadAndDecodeFileRecord( StructureContext,
+ AttributeContext->FileRecord,
+ &BufferIndex );
+
+ AttributeHeader = Add2Ptr( NtfsFileRecordBuffer[BufferIndex],
+ AttributeContext->FileRecordOffset );
+
+ //
+ // Compute the lowest and highest vbo that is described by this attribute header
+ //
+
+ LowestVbo = /*xxXMul*/( AttributeHeader->Form.Nonresident.LowestVcn *
+ BytesPerCluster );
+
+ HighestVbo = /*xxXMul*/( AttributeHeader->Form.Nonresident.HighestVcn *
+ BytesPerCluster );
+
+ //
+ // Now check if the vbo we are after is within the range of this attribute header
+ // and if so then decode the retrieval information and return to our caller
+ //
+
+ if (/*xxLeq*/(LowestVbo <= Vbo) && /*xxLeq*/(Vbo <= HighestVbo)) {
+
+ DecodeRetrievalInformation( StructureContext, Mcb, Vbo, AttributeHeader );
+
+ NtfsFileRecordBufferPinned[BufferIndex] -= 1;
+
+ return ESUCCESS;
+ }
+
+ //
+ // At this point the attribute header does not contain the range we need so read
+ // in the base file record and we'll search the attribute list for a attribute
+ // header that we need.
+ //
+
+ //****if (!xxEqlZero(NtfsFileRecordBuffer[BufferIndex]->BaseFileRecordSegment)) {
+
+ FileReferenceToLargeInteger( NtfsFileRecordBuffer[BufferIndex]->BaseFileRecordSegment,
+ &FileRecord );
+
+ NtfsFileRecordBufferPinned[BufferIndex] -= 1;
+
+ ReadAndDecodeFileRecord( StructureContext,
+ FileRecord,
+ &BufferIndex );
+ //****}
+
+ //
+ // Now we have read in the base file record so search for the attribute list
+ // attribute
+ //
+
+ AttributeList = NULL;
+
+ for (AttributeHeader = NtfsFirstAttribute( NtfsFileRecordBuffer[BufferIndex] );
+ AttributeHeader->TypeCode != $END;
+ AttributeHeader = NtfsGetNextRecord( AttributeHeader )) {
+
+ //
+ // Check if this is the attribute list attribute and if so then setup a local
+ // attribute context
+ //
+
+ if (AttributeHeader->TypeCode == $ATTRIBUTE_LIST) {
+
+ InitializeAttributeContext( StructureContext,
+ NtfsFileRecordBuffer[BufferIndex],
+ AttributeHeader,
+ FileRecord,
+ AttributeList = &AttributeContext1 );
+ }
+ }
+
+ //
+ // We have better located an attribute list otherwise we're in trouble
+ //
+
+ if (AttributeList == NULL) {
+
+ NtfsFileRecordBufferPinned[BufferIndex] -= 1;
+
+ return EINVAL;
+ }
+
+ //
+ // Setup a local for the type code
+ //
+
+ TypeCode = AttributeContext->TypeCode;
+
+ //
+ // Now that we've located the attribute list we need to continue our search. So
+ // what this outer loop does is search down the attribute list looking for a
+ // match.
+ //
+
+ NtfsFileRecordBufferPinned[SavedBufferIndex = BufferIndex] += 1;
+
+ for (Previousli = li = 0;
+ /*xxLtr*/(li < AttributeList->DataSize);
+ li = /*xxAdd*/(li + /*xxFromUlong*/(AttributeListEntry.RecordLength))) {
+
+ //
+ // Read in the attribute list entry. We don't need to read in the name,
+ // just the first part of the list entry.
+ //
+
+ ReadAttribute( StructureContext,
+ AttributeList,
+ li,
+ sizeof(ATTRIBUTE_LIST_ENTRY),
+ &AttributeListEntry );
+
+ //
+ // Now check if the attribute matches, and either it is not $data or if it
+ // is $data then it is unnamed
+ //
+
+ if ((AttributeListEntry.AttributeTypeCode == TypeCode)
+
+ &&
+
+ ((TypeCode != $DATA) ||
+ ((TypeCode == $DATA) && (AttributeListEntry.AttributeNameLength == 0)))) {
+
+ //
+ // If the lowest vcn is is greater than the vbo we've after then
+ // we are done and can use previous li otherwise set previous li accordingly.
+
+ if (Vbo < AttributeListEntry.LowestVcn * BytesPerCluster) {
+
+ break;
+ }
+
+ Previousli = li;
+ }
+ }
+
+ //
+ // Now we should have found the offset for the attribute list entry
+ // so read it in and verify that it is correct
+ //
+
+ ReadAttribute( StructureContext,
+ AttributeList,
+ Previousli,
+ sizeof(ATTRIBUTE_LIST_ENTRY),
+ &AttributeListEntry );
+
+ if ((AttributeListEntry.AttributeTypeCode == TypeCode)
+
+ &&
+
+ ((TypeCode != $DATA) ||
+ ((TypeCode == $DATA) && (AttributeListEntry.AttributeNameLength == 0)))) {
+
+ //
+ // We found a match so now compute the file record containing this
+ // attribute and read in the file record
+ //
+
+ FileReferenceToLargeInteger( AttributeListEntry.SegmentReference, &FileRecord );
+
+ NtfsFileRecordBufferPinned[BufferIndex] -= 1;
+
+ ReadAndDecodeFileRecord( StructureContext,
+ FileRecord,
+ &BufferIndex );
+
+ //
+ // Now search down the file record for our matching attribute, and it
+ // better be there otherwise the attribute list is wrong.
+ //
+
+ for (AttributeHeader = NtfsFirstAttribute( NtfsFileRecordBuffer[BufferIndex] );
+ AttributeHeader->TypeCode != $END;
+ AttributeHeader = NtfsGetNextRecord( AttributeHeader )) {
+
+ //
+ // As a quick check make sure that this attribute is non resident
+ //
+
+ if (AttributeHeader->FormCode == NONRESIDENT_FORM) {
+
+ //
+ // Compute the range of this attribute header
+ //
+
+ LowestVbo = /*xxXMul*/( AttributeHeader->Form.Nonresident.LowestVcn *
+ BytesPerCluster );
+
+ HighestVbo = /*xxXMul*/( AttributeHeader->Form.Nonresident.HighestVcn *
+ BytesPerCluster);
+
+ //
+ // We have located the attribute in question if the type code
+ // match, it is within the proper range, and if it is either not
+ // the data attribute or if it is the data attribute then it is
+ // also unnamed
+ //
+
+ if ((AttributeHeader->TypeCode == TypeCode)
+
+ &&
+
+ /*xxLeq*/(LowestVbo <= Vbo) && /*xxLeq*/(Vbo <= HighestVbo)
+
+ &&
+
+ ((TypeCode != $DATA) ||
+ ((TypeCode == $DATA) && (AttributeHeader->NameLength == 0)))) {
+
+ //
+ // We've located the attribute so now it is time to decode
+ // the retrieval information and return to our caller
+ //
+
+ DecodeRetrievalInformation( StructureContext,
+ Mcb,
+ Vbo,
+ AttributeHeader );
+
+ NtfsFileRecordBufferPinned[BufferIndex] -= 1;
+ NtfsFileRecordBufferPinned[SavedBufferIndex] -= 1;
+
+ return ESUCCESS;
+ }
+ }
+ }
+ }
+
+ NtfsFileRecordBufferPinned[BufferIndex] -= 1;
+ NtfsFileRecordBufferPinned[SavedBufferIndex] -= 1;
+
+ return EINVAL;
+}
+
+
+//
+// Local support routine
+//
+
+
+ARC_STATUS
+NtfsVboToLbo (
+ IN PNTFS_STRUCTURE_CONTEXT StructureContext,
+ IN PNTFS_ATTRIBUTE_CONTEXT AttributeContext,
+ IN VBO Vbo,
+ OUT PLBO Lbo,
+ OUT PULONG ByteCount
+ )
+
+/*++
+
+Routine Description:
+
+ This routine computes the run denoted by the input vbo to into its
+ corresponding lbo and also returns the number of bytes remaining in
+ the run.
+
+Arguments:
+
+ StructureContext - Supplies the volume structure for this operation
+
+ AttributeContext - Supplies the Nonresident attribute being queried
+
+ Vbo - Supplies the Vbo to match
+
+ Lbo - Recieves the corresponding Lbo
+
+ ByteCount - Receives the number of bytes remaining in the run
+
+Return Value:
+
+ ESUCCESS is returned if the operation is successful. Otherwise,
+ an unsuccessful status is returned that describes the reason for failure.
+
+--*/
+
+{
+ PNTFS_MCB Mcb;
+ ULONG i;
+
+ //
+ // Check if we are doing the mft or some other attribute
+ //
+
+ Mcb = NULL;
+
+ if (AttributeContext == &StructureContext->MftAttributeContext) {
+
+ //
+ // For the mft we start with the base mcb but if the vbo is not in the mcb
+ // then we immediately switch over to the cached mcb
+ //
+
+ Mcb = &StructureContext->MftBaseMcb;
+
+ if (/*xxLtr*/(Vbo < Mcb->Vbo[0]) || /*xxGeq*/(Vbo >= Mcb->Vbo[Mcb->InUse])) {
+
+ Mcb = NULL;
+ }
+ }
+
+ //
+ // If the Mcb is still null then we are to use the cached mcb, first find
+ // if one of the cached ones contains the range we're after
+ //
+
+ if (Mcb == NULL) {
+
+ for (i = 0; i < 16; i += 1) {
+
+ //
+ // check if we have a hit, on the same attribute and range
+ //
+
+ Mcb = &StructureContext->CachedMcb[i];
+
+ if ((/*xxEql*/(AttributeContext->FileRecord == StructureContext->CachedMcbFileRecord[i]) &&
+ (AttributeContext->FileRecordOffset == StructureContext->CachedMcbFileRecordOffset[i]) &&
+ /*xxLeq*/(Mcb->Vbo[0] <= Vbo) && /*xxLtr*/(Vbo < Mcb->Vbo[Mcb->InUse]))) {
+
+ break;
+ }
+
+ Mcb = NULL;
+ }
+
+ //
+ // If we didn't get a hit then we need to load a new mcb we'll
+ // alternate through our two cached mcbs
+ //
+
+ if (Mcb == NULL) {
+
+
+ Mcb = &StructureContext->CachedMcb[LastMcb % 16];
+ StructureContext->CachedMcbFileRecord[LastMcb % 16] = AttributeContext->FileRecord;
+ StructureContext->CachedMcbFileRecordOffset[LastMcb % 16] = AttributeContext->FileRecordOffset;
+
+ LastMcb += 1;
+
+ LoadMcb( StructureContext, AttributeContext, Vbo, Mcb );
+ }
+ }
+
+ //
+ // At this point the mcb contains the vbo asked for. So now search for the vbo.
+ // Note that we could also do binary search here but because the run count is
+ // probably small the extra overhead of a binary search doesn't buy us anything
+ //
+
+ for (i = 0; i < Mcb->InUse; i += 1) {
+
+
+ //
+ // We found our slot if the vbo we're after is less than the next mcb's vbo
+ //
+
+ if (/*xxLtr*/(Vbo < Mcb->Vbo[i+1])) {
+
+ //
+ // Compute the corresponding lbo which is the stored lbo plus the
+ // difference between the stored vbo and the vbo we're looking up.
+ // Also compute the byte count which is the difference between the
+ // current vbo we're looking up and the vbo for the next run
+ //
+
+ if (/*xxNeqZero*/(Mcb->Lbo[i] != 0)) {
+
+ *Lbo = /*xxAdd*/(Mcb->Lbo[i] + /*xxSub*/(Vbo - Mcb->Vbo[i]));
+
+ } else {
+
+ *Lbo = 0;
+ }
+
+ *ByteCount = ((ULONG)/*xxSub*/(Mcb->Vbo[i+1] - Vbo));
+
+ //
+ // And return to our caller
+ //
+
+ return ESUCCESS;
+ }
+ }
+
+ //
+ // If we really reach here we have an error. Most likely the file is not large
+ // enough for the requested vbo
+ //
+
+ return EINVAL;
+}
+
+
+//
+// Local support routine
+//
+
+ARC_STATUS
+NtfsDecodeRetrievalInformation (
+ IN PNTFS_STRUCTURE_CONTEXT StructureContext,
+ IN PNTFS_MCB Mcb,
+ IN VBO Vbo,
+ IN PATTRIBUTE_RECORD_HEADER AttributeHeader
+ )
+
+/*++
+
+Routine Description:
+
+ This routine does the decode of the retrival information stored in a Nonresident
+ attribute header into the specified output mcb starting with the specified
+ Lbo.
+
+Arguments:
+
+ StructureContext - Supplies the volume structure for this operation
+
+ Mcb - Supplies the Mcb used in this operation
+
+ Vbo - Supplies the starting vbo that must be stored in the mcb
+
+ AttributeHeader - Supplies the non resident attribute header that
+ we are to use in this operation
+
+Return Value:
+
+ ESUCCESS is returned if the operation is successful. Otherwise,
+ an unsuccessful status is returned that describes the reason for failure.
+
+--*/
+
+{
+ ULONG BytesPerCluster;
+
+ VBO NextVbo;
+ LBO CurrentLbo;
+ VBO CurrentVbo;
+
+ LONGLONG Change;
+ PCHAR ch;
+ ULONG VboBytes;
+ ULONG LboBytes;
+
+ //
+ // Initialize our locals
+ //
+
+ BytesPerCluster = StructureContext->BytesPerCluster;
+
+ //
+ // Setup the next vbo and current lbo and ch for the following loop that decodes
+ // the retrieval information
+ //
+
+ NextVbo = /*xxXMul*/(AttributeHeader->Form.Nonresident.LowestVcn * BytesPerCluster);
+
+ CurrentLbo = 0;
+
+ ch = Add2Ptr( AttributeHeader,
+ AttributeHeader->Form.Nonresident.MappingPairsOffset );
+
+ Mcb->InUse = 0;
+
+ //
+ // Loop to process mapping pairs
+ //
+
+ while (!IsCharZero(*ch)) {
+
+ //
+ // Set current Vbo from initial value or last pass through loop
+ //
+
+ CurrentVbo = NextVbo;
+
+ //
+ // Extract the counts from the two nibbles of this byte
+ //
+
+ VboBytes = *ch & 0x0f;
+ LboBytes = *ch++ >> 4;
+
+ //
+ // Extract the Vbo change and update next vbo
+ //
+
+ Change = 0;
+
+ if (IsCharLtrZero(*(ch + VboBytes - 1))) {
+
+ return EINVAL;
+ }
+
+ RtlMoveMemory( &Change, ch, VboBytes );
+
+ ch += VboBytes;
+
+ NextVbo = /*xxAdd*/(NextVbo + /*xXMul*/(Change * BytesPerCluster));
+
+ //
+ // If we have reached the maximum for this mcb then it is time
+ // to return and not decipher any more retrieval information
+ //
+
+ if (Mcb->InUse >= MAXIMUM_NUMBER_OF_MCB_ENTRIES - 1) {
+
+ break;
+ }
+
+ //
+ // Now check if there is an lbo change. If there isn't
+ // then we only need to update the vbo, because this
+ // is sparse/compressed file.
+ //
+
+ if (LboBytes != 0) {
+
+ //
+ // Extract the Lbo change and update current lbo
+ //
+
+ Change = 0;
+
+ if (IsCharLtrZero(*(ch + LboBytes - 1))) {
+
+ Change = /*xxSub*/( Change - 1 );
+ }
+
+ RtlMoveMemory( &Change, ch, LboBytes );
+
+ ch += LboBytes;
+
+ CurrentLbo = /*xxAdd*/( CurrentLbo + /*xxXMul*/(Change * BytesPerCluster));
+ }
+
+ //
+ // Now check if the Next Vbo is greater than the Vbo we after
+ //
+
+ if (/*xxGeq*/(NextVbo >= Vbo)) {
+
+ //
+ // Load this entry into the mcb and advance our in use counter
+ //
+
+ Mcb->Vbo[Mcb->InUse] = CurrentVbo;
+ Mcb->Lbo[Mcb->InUse] = (LboBytes != 0 ? CurrentLbo : 0);
+ Mcb->Vbo[Mcb->InUse + 1] = NextVbo;
+
+ Mcb->InUse += 1;
+ }
+ }
+
+ return ESUCCESS;
+}
+
+
+//
+// Local support routine
+//
+
+VOID
+NtfsFirstComponent (
+ IN OUT PSTRING String,
+ OUT PSTRING FirstComponent
+ )
+
+/*++
+
+Routine Description:
+
+ This routine takes an input path name and separates it into its first
+ file name component and the remaining part.
+
+Arguments:
+
+ String - Supplies the original string being dissected (in ansi). On return
+ this string will now point to the remaining part.
+
+ FirstComponent - Recieves the string representing the first file name in
+ the input string.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG Index;
+
+ //
+ // Copy over the string variable into the first component variable
+ //
+
+ *FirstComponent = *String;
+
+ //
+ // Now if the first character in the name is a backslash then
+ // simply skip over the backslash.
+ //
+
+ if (FirstComponent->Buffer[0] == '\\') {
+
+ FirstComponent->Buffer += 1;
+ FirstComponent->Length -= 1;
+ }
+
+ //
+ // Now search the name for a backslash
+ //
+
+ for (Index = 0; Index < FirstComponent->Length; Index += 1) {
+
+ if (FirstComponent->Buffer[Index] == '\\') {
+
+ break;
+ }
+ }
+
+ //
+ // At this point Index denotes a backslash or is equal to the length of the
+ // string. So update string to be the remaining part. Decrement the length of
+ // the first component by the approprate amount
+ //
+
+ String->Buffer = &FirstComponent->Buffer[Index];
+ String->Length = (SHORT)(FirstComponent->Length - Index);
+
+ FirstComponent->Length = (SHORT)Index;
+
+ //
+ // And return to our caller.
+ //
+
+ return;
+}
+
+
+//
+// Local support routine
+//
+
+#define ToUpper(C) ((((C) >= 'a') && ((C) <= 'z')) ? (C) - 'a' + 'A' : (C))
+
+BOOLEAN
+NtfsAreNamesEqual (
+ IN STRING AnsiString,
+ IN UNICODE_STRING UnicodeString
+ )
+
+/*++
+
+Routine Description:
+
+ This routine compares two names (one ansi and one unicode) for equality.
+
+Arguments:
+
+ AnsiString - Supplies the ansi string to compare
+
+ UnicodeString - Supplies the unicode string to compare
+
+Return Value:
+
+ TRUE is returned if the strings are equal and FALSE otherwise.
+
+--*/
+
+{
+ ULONG i;
+
+ //
+ // First check if the two strings are of equivalent lengths
+ //
+
+ if (AnsiString.Length*2 != UnicodeString.Length) {
+
+ return FALSE;
+ }
+
+ //
+ // The lengths match up so now for each ansi character check the unicode
+ // character
+ //
+
+ for (i = 0; i < AnsiString.Length; i += 1) {
+
+ //**** upcase for now if ((USHORT)AnsiString.Buffer[i] != UnicodeString.Buffer[i]) {
+
+ if (ToUpper((USHORT)AnsiString.Buffer[i]) != ToUpper(UnicodeString.Buffer[i])) {
+
+ return FALSE;
+ }
+ }
+
+ //
+ // Everything matched up so return true to our caller
+ //
+
+ return TRUE;
+}
diff --git a/private/ntos/boot/lib/peldr.c b/private/ntos/boot/lib/peldr.c
new file mode 100644
index 000000000..c95a4d94a
--- /dev/null
+++ b/private/ntos/boot/lib/peldr.c
@@ -0,0 +1,499 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ peldr.c
+
+Abstract:
+
+ This module implements the code to load a PE format image into memory
+ and relocate it if necessary.
+
+Author:
+
+ David N. Cutler (davec) 10-May-1991
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+--*/
+
+#include "bldr.h"
+#include "string.h"
+#include "ntimage.h"
+
+extern ULONG BlConsoleOutDeviceId;
+
+//
+// Define forward referenced prototypes.
+//
+
+USHORT
+ChkSum(
+ ULONG PartialSum,
+ PUSHORT Source,
+ ULONG Length
+ );
+
+
+ARC_STATUS
+BlLoadImage(
+ IN ULONG DeviceId,
+ IN TYPE_OF_MEMORY MemoryType,
+ IN PCHAR LoadFile,
+ IN USHORT ImageType,
+ OUT PVOID *ImageBase
+ )
+
+/*++
+
+Routine Description:
+
+ This routine attempts to load the specified file from the specified
+ device.
+
+Arguments:
+
+ DeviceId - Supplies the file table index of the device to load the
+ specified image file from.
+
+ MemoryType - Supplies the type of memory to to be assigned to the
+ allocated memory descriptor.
+
+ BootFile - Supplies a pointer to string descriptor for the name of
+ the file to load.
+
+ ImageType - Supplies the type of image that is expected.
+
+ ImageBase - Supplies a pointer to a variable that receives the
+ address of the image base.
+
+Return Value:
+
+ ESUCCESS is returned if the specified image file is loaded
+ successfully. Otherwise, an unsuccessful status is returned
+ that describes the reason for failure.
+
+--*/
+
+{
+
+ ULONG ActualBase;
+ ULONG BasePage;
+ ULONG Count;
+ ULONG FileId;
+ PVOID NewImageBase;
+ ULONG Index;
+ UCHAR LocalBuffer[(SECTOR_SIZE * 2) + 256];
+ PUCHAR LocalPointer;
+ ULONG NumberOfSections;
+ ULONG PageCount;
+ USHORT MachineType;
+ ARC_STATUS Status;
+ PIMAGE_NT_HEADERS NtHeaders;
+ PIMAGE_SECTION_HEADER SectionHeader;
+ LARGE_INTEGER SeekPosition;
+ ULONG RelocSize;
+ PIMAGE_BASE_RELOCATION RelocDirectory;
+ ULONG RelocPage;
+ ULONG RelocPageCount;
+ PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor;
+ FILE_INFORMATION FileInfo;
+ PUSHORT AdjustSum;
+ USHORT PartialSum;
+ ULONG CheckSum;
+ ULONG VirtualSize;
+ ULONG SizeOfRawData;
+
+ //
+ // Align the buffer on a Dcache fill boundary.
+ //
+
+ LocalPointer = ALIGN_BUFFER(LocalBuffer);
+
+ //
+ // Attempt to open the image file.
+ //
+
+ Status = BlOpen(DeviceId, LoadFile, ArcOpenReadOnly, &FileId);
+ if (Status != ESUCCESS) {
+ return Status;
+ }
+
+ //
+ // Read the first two sectors of the image header from the file.
+ //
+
+ Status = BlRead(FileId, LocalPointer, SECTOR_SIZE * 2, &Count);
+ if (Status != ESUCCESS) {
+ BlClose(FileId);
+ return Status;
+ }
+
+ //
+ // If the image file is not the specified type, is not executable, or is
+ // not a NT image, then return bad image type status.
+ //
+
+ NtHeaders = RtlImageNtHeader(LocalPointer);
+
+ if (!NtHeaders) {
+ BlClose(FileId);
+ return EBADF;
+ }
+
+ MachineType = NtHeaders->FileHeader.Machine;
+ if (MachineType == IMAGE_FILE_MACHINE_R4000 &&
+ ImageType == IMAGE_FILE_MACHINE_R3000) {
+ ImageType = IMAGE_FILE_MACHINE_R4000;
+ }
+
+ if ((MachineType != ImageType) ||
+ ((NtHeaders->FileHeader.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE) == 0)) {
+
+ BlClose(FileId);
+ return EBADF;
+ }
+
+ //
+ // Compute the starting page and the number of pages that are consumed
+ // by the entire image, and then allocate a memory descriptor for the
+ // allocated region.
+ //
+
+ NumberOfSections = NtHeaders->FileHeader.NumberOfSections;
+ SectionHeader = IMAGE_FIRST_SECTION( NtHeaders );
+
+ BasePage = (NtHeaders->OptionalHeader.ImageBase & 0x1fffffff) >> PAGE_SHIFT;
+ if (strcmp((PCHAR)&SectionHeader[NumberOfSections - 1].Name, ".debug") == 0) {
+ NumberOfSections -= 1;
+ PageCount = (NtHeaders->OptionalHeader.SizeOfImage -
+ SectionHeader[NumberOfSections].SizeOfRawData + PAGE_SIZE - 1) >> PAGE_SHIFT;
+
+ } else {
+ PageCount =
+ (NtHeaders->OptionalHeader.SizeOfImage + PAGE_SIZE - 1) >> PAGE_SHIFT;
+ }
+
+ Status = BlAllocateDescriptor(MemoryType,
+ BasePage,
+ PageCount,
+ &ActualBase);
+
+ if (Status != ESUCCESS) {
+ BlClose(FileId);
+ return EBADF;
+ }
+
+ //
+ // Compute the address of the file header.
+ //
+
+ NewImageBase = (PVOID)(KSEG0_BASE | (ActualBase << PAGE_SHIFT));
+
+ //
+ // Read the entire image header from the file.
+ //
+
+ SeekPosition.QuadPart = 0;
+ Status = BlSeek(FileId, &SeekPosition, SeekAbsolute);
+ if (Status != ESUCCESS) {
+ BlClose(FileId);
+ return Status;
+ }
+
+ Status = BlRead(FileId,
+ NewImageBase,
+ NtHeaders->OptionalHeader.SizeOfHeaders,
+ &Count);
+
+ if (Status != ESUCCESS) {
+ BlClose(FileId);
+ return Status;
+ }
+
+ NtHeaders = RtlImageNtHeader(NewImageBase);
+
+ //
+ // Compute the address of the section headers, set the
+ // image base address.
+ //
+
+ SectionHeader = IMAGE_FIRST_SECTION( NtHeaders );
+
+ *ImageBase = NewImageBase;
+
+ //
+ // Compute the check sum on the image.
+ //
+
+ PartialSum = ChkSum(0, NewImageBase, NtHeaders->OptionalHeader.SizeOfHeaders / sizeof(USHORT));
+
+ //
+ // Scan through the sections and either read them into memory or clear
+ // the memory as appropriate.
+ //
+
+ for (Index = 0; Index < NumberOfSections; Index += 1) {
+
+ VirtualSize = SectionHeader->Misc.VirtualSize;
+ SizeOfRawData = SectionHeader->SizeOfRawData;
+
+ if ((VirtualSize & 1) == 1) {
+ //
+ // Round to even so that checksum works
+ //
+
+ VirtualSize++;
+ }
+
+ if ((SizeOfRawData & 1) == 1) {
+ //
+ // Round to even so that checksum works
+ //
+
+ SizeOfRawData++;
+ }
+
+ if (VirtualSize == 0) {
+ VirtualSize = SizeOfRawData;
+ }
+
+ if (SectionHeader->PointerToRawData == 0) {
+ //
+ // SizeOfRawData can be non-zero even if PointerToRawData is zero
+ //
+
+ SizeOfRawData = 0;
+ } else if (SizeOfRawData > VirtualSize) {
+ //
+ // Don't load more from image than is expected in memory
+ //
+
+ SizeOfRawData = VirtualSize;
+ }
+
+ if (SizeOfRawData != 0) {
+ SeekPosition.LowPart = SectionHeader->PointerToRawData;
+ Status = BlSeek(FileId,
+ &SeekPosition,
+ SeekAbsolute);
+
+ if (Status != ESUCCESS) {
+ break;
+ }
+
+ Status = BlRead(FileId,
+ (PVOID)(SectionHeader->VirtualAddress + (ULONG)NewImageBase),
+ SizeOfRawData,
+ &Count);
+
+ if (Status != ESUCCESS) {
+ break;
+ }
+
+ //
+ // Remember how far we have read.
+ //
+
+ RelocSize = SectionHeader->PointerToRawData + SizeOfRawData;
+
+ //
+ // Compute the check sum on the section.
+ //
+
+ PartialSum = ChkSum(PartialSum,
+ (PVOID)(SectionHeader->VirtualAddress + (ULONG)NewImageBase),
+ SizeOfRawData / sizeof(USHORT));
+ }
+
+ if (SizeOfRawData < VirtualSize) {
+ //
+ // Zero the portion not loaded from the image
+ //
+
+ RtlZeroMemory((PVOID)(KSEG0_BASE | SectionHeader->VirtualAddress + (ULONG)NewImageBase + SizeOfRawData),
+ VirtualSize - SizeOfRawData);
+
+ }
+
+ SectionHeader += 1;
+ }
+
+ //
+ // Only do the check sum if the image loaded properly and is stripped.
+ //
+
+ if (Status == ESUCCESS &&
+ NtHeaders->FileHeader.Characteristics & IMAGE_FILE_DEBUG_STRIPPED) {
+
+ //
+ // Get the length of the file for check sum validation.
+ //
+
+ Status = BlGetFileInformation(FileId, &FileInfo);
+
+ if (Status != ESUCCESS) {
+
+ //
+ // Set the length to current end of file.
+ //
+
+ Count = RelocSize;
+ FileInfo.EndingAddress.LowPart = RelocSize;
+
+ } else {
+
+ Count = FileInfo.EndingAddress.LowPart;
+ }
+
+ Count -= RelocSize;
+
+ while (Count != 0) {
+ ULONG Length;
+
+ //
+ // Read in the rest of the image an check sum it.
+ //
+
+ Length = Count < SECTOR_SIZE * 2 ? Count : SECTOR_SIZE * 2;
+ if (BlRead(FileId, LocalBuffer, Length, &Length) != ESUCCESS) {
+ break;
+ }
+
+ if (Length == 0) {
+ break;
+
+ }
+
+ PartialSum = ChkSum(PartialSum, (PUSHORT) LocalBuffer, Length / 2);
+ Count -= Length;
+ }
+
+
+ AdjustSum = (PUSHORT)(&NtHeaders->OptionalHeader.CheckSum);
+ PartialSum -= (PartialSum < AdjustSum[0]);
+ PartialSum -= AdjustSum[0];
+ PartialSum -= (PartialSum < AdjustSum[1]);
+ PartialSum -= AdjustSum[1];
+ CheckSum = (ULONG)PartialSum + FileInfo.EndingAddress.LowPart;
+
+ if (CheckSum != NtHeaders->OptionalHeader.CheckSum) {
+ Status = EBADF;
+ }
+
+ }
+
+ //
+ // Close the image file.
+ //
+
+ BlClose(FileId);
+
+ //
+ // If the specified image was successfully loaded, then perform image
+ // relocation if necessary.
+ //
+
+ if (Status == ESUCCESS) {
+
+ //
+ // Compute relocation value.
+ //
+
+ if ((ULONG)NewImageBase != NtHeaders->OptionalHeader.ImageBase) {
+ Status = (ARC_STATUS)LdrRelocateImage(NewImageBase,
+ "OS Loader",
+ ESUCCESS,
+ EBADF,
+ EBADF
+ );
+ }
+ }
+
+ //
+ // Mark the pages from the relocation information to the end of the
+ // image as MemoryFree and adjust the size of the image so table
+ // based structured exception handling will work properly.
+ //
+
+ RelocDirectory = (PIMAGE_BASE_RELOCATION)
+ RtlImageDirectoryEntryToData(NewImageBase,
+ TRUE,
+ IMAGE_DIRECTORY_ENTRY_BASERELOC,
+ &RelocSize );
+
+ if (RelocDirectory != NULL) {
+ RelocPage = ((ULONG)RelocDirectory + PAGE_SIZE - 1) >> PAGE_SHIFT;
+ RelocPage &= ~(KSEG0_BASE >> PAGE_SHIFT);
+ MemoryDescriptor = BlFindMemoryDescriptor(RelocPage);
+ if ((MemoryDescriptor != NULL) && (RelocPage < (ActualBase + PageCount))) {
+ RelocPageCount = MemoryDescriptor->PageCount +
+ MemoryDescriptor->BasePage -
+ RelocPage;
+
+ NtHeaders->OptionalHeader.SizeOfImage =
+ (RelocPage - ActualBase) << PAGE_SHIFT;
+
+ BlGenerateDescriptor(MemoryDescriptor,
+ MemoryFree,
+ RelocPage,
+ RelocPageCount );
+
+ }
+ }
+
+ return Status;
+}
+USHORT
+ChkSum(
+ ULONG PartialSum,
+ PUSHORT Source,
+ ULONG Length
+ )
+
+/*++
+
+Routine Description:
+
+ Compute a partial checksum on a portion of an imagefile.
+
+Arguments:
+
+ PartialSum - Supplies the initial checksum value.
+
+ Sources - Supplies a pointer to the array of words for which the
+ checksum is computed.
+
+ Length - Supplies the length of the array in words.
+
+Return Value:
+
+ The computed checksum value is returned as the function value.
+
+--*/
+
+{
+
+ //
+ // Compute the word wise checksum allowing carries to occur into the
+ // high order half of the checksum longword.
+ //
+
+ while (Length--) {
+ PartialSum += *Source++;
+ PartialSum = (PartialSum >> 16) + (PartialSum & 0xffff);
+ }
+
+ //
+ // Fold final carry into a single word result and return the resultant
+ // value.
+ //
+
+ return (USHORT)(((PartialSum >> 16) + PartialSum) & 0xffff);
+}
diff --git a/private/ntos/boot/lib/ppc/ntsetup.c b/private/ntos/boot/lib/ppc/ntsetup.c
new file mode 100644
index 000000000..82dbf0902
--- /dev/null
+++ b/private/ntos/boot/lib/ppc/ntsetup.c
@@ -0,0 +1,1615 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ ntsetup.c
+
+Abstract:
+
+ This module is the tail-end of the OS loader program. It performs all
+ PPC specific allocations and initialize. The OS loader invokes this
+ this routine immediately before calling the loaded kernel image.
+
+Author:
+
+ John Vert (jvert) 20-Jun-1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "bldr.h"
+#include <stdio.h>
+
+#define KB 1024
+#define MB (KB * KB)
+#define MBpages (MB / PAGE_SIZE)
+
+#define MIN(_a,_b) (((_a) <= (_b)) ? (_a) : (_b))
+#define MAX(_a,_b) (((_a) >= (_b)) ? (_a) : (_b))
+
+#define PAGES(_bytes) ((_bytes) >> PAGE_SHIFT)
+#define BYTES(_pages) ((_pages) << PAGE_SHIFT)
+
+#define PageFromAddress(_addr) PAGES((_addr) & ~KSEG0_BASE)
+#define AddressFromPage(_page) (KSEG0_BASE | BYTES(_page))
+#define RealAddressFromPage(_page) BYTES(_page)
+
+//
+// If a system has less than PAGED_KERNEL_MEMORY_LIMIT pages of memory,
+// we will page the kernel, thus making more memory available for apps.
+// If a system has more than PAGED_KERNEL_MEMORY_LIMIT pages of memory,
+// we will map the kernel using the KSEG0 BAT, thus avoiding translation
+// overhead.
+//
+
+#define PAGED_KERNEL_MEMORY_LIMIT (48*MBpages)
+
+//
+// Boolean indicating whether the kernel is to be paged or mapped by a BAT register.
+//
+
+BOOLEAN PageKernel;
+
+
+//
+// Define macro to round structure size to next 16-byte boundary
+//
+
+#define ROUND_UP(x) ((sizeof(x) + 15) & (~15))
+
+//
+// Configuration Data Header
+// The following structure is copied from fw\ppc\oli2msft.h
+// NOTE shielint - Somehow, this structure got incorporated into
+// firmware EISA configuration data. We need to know the size of the
+// header and remove it before writing eisa configuration data to
+// registry.
+//
+
+typedef struct _CONFIGURATION_DATA_HEADER {
+ USHORT Version;
+ USHORT Revision;
+ PCHAR Type;
+ PCHAR Vendor;
+ PCHAR ProductName;
+ PCHAR SerialNumber;
+} CONFIGURATION_DATA_HEADER;
+
+#define CONFIGURATION_DATA_HEADER_SIZE sizeof(CONFIGURATION_DATA_HEADER)
+
+//
+// Internal function references
+//
+
+ARC_STATUS
+ReorganizeEisaConfigurationTree(
+ IN PCONFIGURATION_COMPONENT_DATA RootEntry
+ );
+
+ARC_STATUS
+CreateEisaConfigurationData (
+ IN PCONFIGURATION_COMPONENT_DATA RootEntry
+ );
+
+VOID
+BlQueryImplementationAndRevision (
+ OUT PULONG ProcessorId,
+ OUT PULONG ProcessorRev
+ );
+
+ARC_STATUS
+NextFreePage (
+ IN OUT PULONG FreePage,
+ IN OUT PULONG NumberFree,
+ IN OUT PMEMORY_ALLOCATION_DESCRIPTOR *FreeDescriptor
+ )
+{
+ PLIST_ENTRY NextEntry;
+ PMEMORY_ALLOCATION_DESCRIPTOR NextDescriptor;
+
+ (*FreePage)++;
+ (*NumberFree)--;
+
+ if (*NumberFree != 0) {
+ return ESUCCESS;
+ }
+
+ BlLog((LOG_ALL,"Generating FirmwarePermanent descriptor for %x pages at %x taken for PTE pages",(*FreeDescriptor)->PageCount,(*FreeDescriptor)->BasePage));
+ (*FreeDescriptor)->MemoryType = LoaderFirmwarePermanent;
+
+ NextEntry = (*FreeDescriptor)->ListEntry.Flink;
+ while (NextEntry != &BlLoaderBlock->MemoryDescriptorListHead) {
+ NextDescriptor = CONTAINING_RECORD(NextEntry,
+ MEMORY_ALLOCATION_DESCRIPTOR,
+ ListEntry);
+
+ if (NextDescriptor->MemoryType == LoaderFree) {
+ *FreeDescriptor = NextDescriptor;
+ *FreePage = NextDescriptor->BasePage;
+ *NumberFree = NextDescriptor->PageCount;
+ BlLog((LOG_ALL,"%x PTE pages available at %x",*NumberFree,*FreePage));
+ return ESUCCESS;
+ }
+
+ NextEntry = NextEntry->Flink;
+ }
+
+ return ENOMEM;
+}
+
+ARC_STATUS
+AllocateKseg0Blocks (
+ OUT PULONG HighestKseg0PageParameter
+ )
+{
+ ARC_STATUS Status;
+ ULONG HighestKseg0Page;
+ ULONG HptPages;
+ ULONG BasePage;
+ ULONG NumberOfPcrs;
+
+ //
+ // We need to allocate a number of items in what will become KSEG0,
+ // mapped by a BAT register. We want these items to be allocated as
+ // low in memory as possible.
+ //
+ // N.B. We do a number of individual allocations, rather than one
+ // large allocation, in order to ensure that the allocations
+ // succeed, even if low memory is fragmented.
+ //
+
+ BlSetAllocationPolicy(BlAllocateLowestFit, BlAllocateHighestFit);
+
+ HighestKseg0Page = 5; // exception vector pages
+
+ BlLogMemoryDescriptors(LOG_ALL_W);
+
+ //
+ // Allocate the hashed page table first, because the HPT must be
+ // aligned based on its size.
+ //
+ // N.B. Not all machines require an HPT (e.g., 603).
+ //
+
+ HptPages = BlLoaderBlock->u.Ppc.HashedPageTableSize;
+ BlLoaderBlock->u.Ppc.HashedPageTable = 0;
+ if (HptPages != 0) {
+ Status = BlAllocateAlignedDescriptor(LoaderFirmwarePermanent,
+ 0,
+ HptPages,
+ HptPages,
+ &BasePage);
+ if (Status != ESUCCESS) {
+ return Status;
+ }
+
+ BlLoaderBlock->u.Ppc.HashedPageTable = RealAddressFromPage(BasePage);
+ RtlZeroMemory((PVOID)AddressFromPage(BasePage), BYTES(HptPages));
+
+ if ((BasePage + HptPages) > HighestKseg0Page) {
+ HighestKseg0Page = BasePage + HptPages;
+ }
+ BlLog((LOG_ALL,"Allocated %x pages for HPT at %x",HptPages,BasePage));
+ }
+
+ //
+ // Allocate PCRs for additional processors. (We don't know how many
+ // processors there might be, so we assume the most.)
+ //
+ // N.B. If we can't get the maximum number of PCR pages, we try for
+ // less. This just means the system won't be able to start 32
+ // processors. If not even one page can be allocated,
+ // however, we give up on the boot, because our next
+ // allocation is sure to fail.
+ //
+
+ BlLoaderBlock->u.Ppc.PcrPagesDescriptor = NULL;
+ NumberOfPcrs = MAXIMUM_PROCESSORS - 1;
+ do {
+ Status = BlAllocateAlignedDescriptor(LoaderStartupPcrPage,
+ 0,
+ NumberOfPcrs,
+ 0,
+ &BasePage);
+ if (Status == ESUCCESS) {
+ break;
+ }
+ NumberOfPcrs--;
+ } while (NumberOfPcrs != 0);
+
+ if (Status != ESUCCESS) {
+ return Status;
+ }
+
+ BlLoaderBlock->u.Ppc.PcrPagesDescriptor = BlFindMemoryDescriptor(BasePage);
+ RtlZeroMemory((PVOID)AddressFromPage(BasePage), NumberOfPcrs * PAGE_SIZE);
+
+ if ((BasePage + NumberOfPcrs) > HighestKseg0Page) {
+ HighestKseg0Page = BasePage + NumberOfPcrs;
+ }
+ BlLog((LOG_ALL,"Allocated %x pages for PCRs at %x",NumberOfPcrs,BasePage));
+
+ //
+ // Allocate a few extra pages in KSEG0 for the kernel to use.
+ //
+
+ Status = BlAllocateDescriptor(LoaderFirmwarePermanent,
+ 0,
+ 5,
+ &BasePage);
+ if (Status != ESUCCESS) {
+ return(Status);
+ }
+
+ BlLoaderBlock->u.Ppc.KernelKseg0PagesDescriptor = BlFindMemoryDescriptor(BasePage);
+ RtlZeroMemory((PVOID)AddressFromPage(BasePage), 5 * PAGE_SIZE);
+
+ if ((BasePage + 5) > HighestKseg0Page) {
+ HighestKseg0Page = BasePage + 5;
+ }
+ BlLog((LOG_ALL,"Allocated %x pages for kernel at %x",5,BasePage));
+
+ //
+ // Allocate and zero three pages, one for the page directory page,
+ // one for the hyperspace PTE page, and one for the HAL's PTE page.
+ //
+
+ Status = BlAllocateDescriptor(LoaderStartupPdrPage,
+ 0,
+ 3,
+ &BasePage);
+
+ if (Status != ESUCCESS) {
+ return(Status);
+ }
+
+ BlLoaderBlock->u.Ppc.PdrPage = BasePage;
+ RtlZeroMemory((PVOID)AddressFromPage(BasePage), 3 * PAGE_SIZE);
+
+ if ((BasePage + 3) > HighestKseg0Page) {
+ HighestKseg0Page = BasePage + 3;
+ }
+ BlLog((LOG_ALL,"Allocated %x pages for PDR at %x",3,BasePage));
+
+ //
+ // Allocate and zero two pages, one for the PCR for processor 0 and
+ // one for the common PCR2 page.
+ //
+
+ Status = BlAllocateDescriptor(LoaderStartupPcrPage,
+ 0,
+ 2,
+ &BasePage);
+
+ if (Status != ESUCCESS) {
+ return(Status);
+ }
+
+ BlLoaderBlock->u.Ppc.PcrPage = BasePage;
+ BlLoaderBlock->u.Ppc.PcrPage2 = BlLoaderBlock->u.Ppc.PcrPage + 1;
+ RtlZeroMemory((PVOID)AddressFromPage(BasePage), 2 * PAGE_SIZE);
+
+ if ((BasePage + 2) > HighestKseg0Page) {
+ HighestKseg0Page = BasePage + 2;
+ }
+ BlLog((LOG_ALL,"Allocated %x pages for PCR at %x",2,BasePage));
+
+ //
+ // Now that we've allocated everything that needs to be in KSEG0, we
+ // can tell the memory allocator to start allocating using a
+ // best-fit algorithm.
+ //
+
+ BlSetAllocationPolicy(BlAllocateBestFit, BlAllocateBestFit);
+
+ *HighestKseg0PageParameter = HighestKseg0Page;
+ BlLogWaitForKeystroke();
+ return ESUCCESS;
+}
+
+ARC_STATUS
+BlSetupForNt(
+ IN PLOADER_PARAMETER_BLOCK BlLoaderBlock
+ )
+
+/*++
+
+Routine Description:
+
+ This function initializes the PPC specific kernel data structures
+ required by the NT system.
+
+Arguments:
+
+ BlLoaderBlock - Supplies the address of the loader parameter block.
+
+Return Value:
+
+ ESUCCESS is returned if the setup is successfully complete. Otherwise,
+ an unsuccessful status is returned.
+
+--*/
+
+{
+
+ PCONFIGURATION_COMPONENT_DATA ConfigEntry;
+ CHAR Identifier[256];
+ ULONG KernelPage;
+ ULONG LinesPerBlock;
+ ULONG LineSize;
+ PCHAR NewIdentifier;
+ ARC_STATUS Status;
+ PCHAR IcacheModeString;
+ PCHAR DcacheModeString;
+ ULONG HighestKseg0Page;
+ ULONG Kseg0Pages;
+ ULONG Page;
+ ULONG HighPage;
+ ULONG Entry;
+ PHARDWARE_PTE PdePage;
+ PHARDWARE_PTE PtePage;
+ PLIST_ENTRY NextEntry;
+ PMEMORY_ALLOCATION_DESCRIPTOR NextDescriptor;
+ PMEMORY_ALLOCATION_DESCRIPTOR FreeDescriptor;
+ ULONG FreePage;
+ ULONG NumberFree;
+
+ ULONG ProcessorId;
+ ULONG ProcessorRev;
+ UCHAR Processor[32];
+ UCHAR Revision[32];
+
+ //
+ // If the host configuration is not a multiprocessor machine, then add
+ // the processor identification to the processor identification string.
+ //
+
+ if (SYSTEM_BLOCK->RestartBlock == NULL) {
+ ConfigEntry = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
+ ProcessorClass,
+ CentralProcessor,
+ NULL);
+
+ if (ConfigEntry != NULL) {
+
+ BlQueryImplementationAndRevision(&ProcessorId, &ProcessorRev);
+
+ //
+ // Unfortunately, PowerPC numbering doesn't directly give us
+ // the name of the part.
+ //
+
+ switch (ProcessorId) {
+ case 6:
+ sprintf(Processor, "603+");
+ break;
+ case 7:
+ sprintf(Processor, "603++");
+ break;
+ case 9:
+ sprintf(Processor, "604+");
+ break;
+ default:
+ sprintf(Processor, "%d", ProcessorId + 600);
+ }
+
+ //
+ // 601 revision is just a number, others are a xx.yy eg
+ // 3.1
+ //
+
+ if ( ProcessorId == 1 ) {
+ sprintf(Revision, "%d", ProcessorRev);
+ } else {
+ sprintf(Revision, "%d.%d", ProcessorRev >> 8,
+ ProcessorRev & 0xff);
+ }
+
+ sprintf(&Identifier[0],
+ "%s - Pr %s, Rev %s",
+ ConfigEntry->ComponentEntry.Identifier,
+ Processor,
+ Revision);
+
+ NewIdentifier = (PCHAR)BlAllocateHeap(strlen(&Identifier[0]) + 1);
+ if (NewIdentifier != NULL) {
+ strcpy(NewIdentifier, &Identifier[0]);
+ ConfigEntry->ComponentEntry.IdentifierLength = strlen(NewIdentifier);
+ ConfigEntry->ComponentEntry.Identifier = NewIdentifier;
+ }
+ }
+ }
+
+ //
+ // Find System entry and check each of its direct child to
+ // look for EisaAdapter.
+ //
+
+ ConfigEntry = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
+ SystemClass,
+ ArcSystem,
+ NULL);
+ if (ConfigEntry) {
+ ConfigEntry = ConfigEntry->Child;
+ }
+
+ while (ConfigEntry) {
+
+ if ((ConfigEntry->ComponentEntry.Class == AdapterClass) &&
+ (ConfigEntry->ComponentEntry.Type == EisaAdapter)) {
+
+ //
+ // Convert EISA format configuration data to our CM_ format.
+ //
+
+ Status = ReorganizeEisaConfigurationTree(ConfigEntry);
+ if (Status != ESUCCESS) {
+ return(Status);
+ }
+ }
+ ConfigEntry = ConfigEntry->Sibling;
+ }
+
+ //
+ // Find the primary data and instruction cache configuration entries, and
+ // compute the fill size and cache size for each cache. These entries MUST
+ // be present on all ARC compliant systems.
+ //
+ // BUT of course they aren't. So we'll handle their not being there by
+ // ignoring their absence and not writing cache sizes to the loader block.
+ //
+
+ ConfigEntry = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
+ CacheClass,
+ PrimaryDcache,
+ NULL);
+
+ if (ConfigEntry != NULL) {
+ LinesPerBlock = ConfigEntry->ComponentEntry.Key >> 24;
+ LineSize = 1 << ((ConfigEntry->ComponentEntry.Key >> 16) & 0xff);
+ BlLoaderBlock->u.Ppc.FirstLevelDcacheFillSize = LinesPerBlock * LineSize;
+ BlLoaderBlock->u.Ppc.FirstLevelDcacheSize =
+ 1 << ((ConfigEntry->ComponentEntry.Key & 0xffff) + PAGE_SHIFT);
+ }
+
+ ConfigEntry = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
+ CacheClass,
+ PrimaryIcache,
+ NULL);
+
+ if (ConfigEntry != NULL) {
+ LinesPerBlock = ConfigEntry->ComponentEntry.Key >> 24;
+ LineSize = 1 << ((ConfigEntry->ComponentEntry.Key >> 16) & 0xff);
+ BlLoaderBlock->u.Ppc.FirstLevelIcacheFillSize = LinesPerBlock * LineSize;
+ BlLoaderBlock->u.Ppc.FirstLevelIcacheSize =
+ 1 << ((ConfigEntry->ComponentEntry.Key & 0xffff) + PAGE_SHIFT);
+
+ }
+
+ //
+ // Find the secondary data and instruction cache configuration entries,
+ // and if present, compute the fill size and cache size for each cache.
+ // These entries are optional, and may or may not, be present.
+ //
+
+ ConfigEntry = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
+ CacheClass,
+ SecondaryCache,
+ NULL);
+
+ if (ConfigEntry != NULL) {
+ LinesPerBlock = ConfigEntry->ComponentEntry.Key >> 24;
+ LineSize = 1 << ((ConfigEntry->ComponentEntry.Key >> 16) & 0xff);
+ BlLoaderBlock->u.Ppc.SecondLevelDcacheFillSize = LinesPerBlock * LineSize;
+ BlLoaderBlock->u.Ppc.SecondLevelDcacheSize =
+ 1 << ((ConfigEntry->ComponentEntry.Key & 0xffff) + PAGE_SHIFT);
+
+ BlLoaderBlock->u.Ppc.SecondLevelIcacheSize = 0;
+ BlLoaderBlock->u.Ppc.SecondLevelIcacheFillSize = 0;
+
+ } else {
+ ConfigEntry = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
+ CacheClass,
+ SecondaryDcache,
+ NULL);
+
+ if (ConfigEntry != NULL) {
+ LinesPerBlock = ConfigEntry->ComponentEntry.Key >> 24;
+ LineSize = 1 << ((ConfigEntry->ComponentEntry.Key >> 16) & 0xff);
+ BlLoaderBlock->u.Ppc.SecondLevelDcacheFillSize = LinesPerBlock * LineSize;
+ BlLoaderBlock->u.Ppc.SecondLevelDcacheSize =
+ 1 << ((ConfigEntry->ComponentEntry.Key & 0xffff) + PAGE_SHIFT);
+
+ ConfigEntry = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
+ CacheClass,
+ SecondaryIcache,
+ NULL);
+
+ if (ConfigEntry != NULL) {
+ LinesPerBlock = ConfigEntry->ComponentEntry.Key >> 24;
+ LineSize = 1 << ((ConfigEntry->ComponentEntry.Key >> 16) & 0xff);
+ BlLoaderBlock->u.Ppc.SecondLevelIcacheFillSize = LinesPerBlock * LineSize;
+ BlLoaderBlock->u.Ppc.SecondLevelIcacheSize =
+ 1 << ((ConfigEntry->ComponentEntry.Key & 0xffff) + PAGE_SHIFT);
+
+ } else {
+ BlLoaderBlock->u.Ppc.SecondLevelIcacheSize = 0;
+ BlLoaderBlock->u.Ppc.SecondLevelIcacheFillSize = 0;
+ }
+
+ } else {
+ BlLoaderBlock->u.Ppc.SecondLevelDcacheSize = 0;
+ BlLoaderBlock->u.Ppc.SecondLevelDcacheFillSize = 0;
+ BlLoaderBlock->u.Ppc.SecondLevelIcacheSize = 0;
+ BlLoaderBlock->u.Ppc.SecondLevelIcacheFillSize = 0;
+ }
+ }
+
+ //
+ // Allocate DPC stack pages for the boot processor.
+ //
+
+ Status = BlAllocateDescriptor(LoaderStartupDpcStack,
+ 0,
+ PAGES(KERNEL_STACK_SIZE),
+ &KernelPage);
+
+ if (Status != ESUCCESS) {
+ return(Status);
+ }
+
+ BlLoaderBlock->u.Ppc.InterruptStack = AddressFromPage(KernelPage) + KERNEL_STACK_SIZE;
+
+ //
+ // Allocate kernel stack pages for the boot processor idle thread.
+ //
+
+ Status = BlAllocateDescriptor(LoaderStartupKernelStack,
+ 0,
+ PAGES(KERNEL_STACK_SIZE),
+ &KernelPage);
+
+ if (Status != ESUCCESS) {
+ return(Status);
+ }
+
+ BlLoaderBlock->KernelStack = AddressFromPage(KernelPage) + KERNEL_STACK_SIZE;
+
+ //
+ // Allocate panic stack pages for the boot processor.
+ //
+
+ Status = BlAllocateDescriptor(LoaderStartupPanicStack,
+ 0,
+ PAGES(KERNEL_STACK_SIZE),
+ &KernelPage);
+
+ if (Status != ESUCCESS) {
+ return(Status);
+ }
+
+ BlLoaderBlock->u.Ppc.PanicStack = AddressFromPage(KernelPage) + KERNEL_STACK_SIZE;
+
+ //
+ // Disable the caches, if requested.
+ //
+
+ BlLoaderBlock->u.Ppc.IcacheMode = 0;
+ if (IcacheModeString = ArcGetEnvironmentVariable("ICACHEMODE")) {
+ if (_stricmp(IcacheModeString, "OFF") == 0) {
+ BlLoaderBlock->u.Ppc.IcacheMode = 1;
+ }
+ }
+
+ BlLoaderBlock->u.Ppc.DcacheMode = 0;
+ if (DcacheModeString = ArcGetEnvironmentVariable("DCACHEMODE")) {
+ if (_stricmp(DcacheModeString, "OFF") == 0) {
+ BlLoaderBlock->u.Ppc.DcacheMode = 1;
+ }
+ }
+
+ //
+ // Allocate the PRCB, process, and thread.
+ //
+
+#define OS_DATA_SIZE PAGES(ROUND_UP(KPRCB)+ROUND_UP(EPROCESS)+ROUND_UP(ETHREAD)+(PAGE_SIZE-1))
+
+ Status = BlAllocateDescriptor(LoaderStartupPdrPage,
+ 0,
+ OS_DATA_SIZE,
+ &KernelPage);
+
+ if (Status != ESUCCESS) {
+ return(Status);
+ }
+
+ BlLoaderBlock->Prcb = AddressFromPage(KernelPage);
+ RtlZeroMemory((PVOID)BlLoaderBlock->Prcb, BYTES(OS_DATA_SIZE));
+ BlLoaderBlock->Process = BlLoaderBlock->Prcb + ROUND_UP(KPRCB);
+ BlLoaderBlock->Thread = BlLoaderBlock->Process + ROUND_UP(EPROCESS);
+
+ //
+ // Initialize the page directory page. Set up the mappings for the
+ // PDR page and the hyperspace page.
+ //
+
+ PdePage = (PHARDWARE_PTE)AddressFromPage(BlLoaderBlock->u.Ppc.PdrPage);
+ BlLog((LOG_ALL,"PDE page at %x",PdePage));
+
+ PdePage[PDE_BASE>>PDI_SHIFT].PageFrameNumber = BlLoaderBlock->u.Ppc.PdrPage;
+ PdePage[PDE_BASE>>PDI_SHIFT].Valid = 1;
+ PdePage[PDE_BASE>>PDI_SHIFT].Write = 1;
+ BlLog((LOG_ALL,"PDE mapped at PdePage[%x] = %x",PDE_BASE>>PDI_SHIFT,*(PULONG)&PdePage[PDE_BASE>>PDI_SHIFT]));
+
+ PdePage[(PDE_BASE>>PDI_SHIFT)+1].PageFrameNumber = BlLoaderBlock->u.Ppc.PdrPage + 1;
+ PdePage[(PDE_BASE>>PDI_SHIFT)+1].Valid = 1;
+ PdePage[(PDE_BASE>>PDI_SHIFT)+1].Write = 1;
+ BlLog((LOG_ALL,"Hyperspace mapped at PdePage[%x] = %x",(PDE_BASE>>PDI_SHIFT)+1,*(PULONG)&PdePage[(PDE_BASE>>PDI_SHIFT)+1]));
+
+ //
+ // Allocate one page for the HAL to use to map memory. This goes in
+ // the very last PDE slot (VA 0xFFC00000 - 0xFFFFFFFF). Our HAL
+ // is currently not using this but it is required since this is
+ // where the magic PTE for the kernel debugger to map physical pages
+ // is located.
+ //
+
+ PdePage[1023].PageFrameNumber = BlLoaderBlock->u.Ppc.PdrPage + 2;
+ PdePage[1023].Valid = 1;
+ PdePage[1023].Write = 1;
+ BlLog((LOG_ALL,"HAL PTE page mapped at PdePage[%x] = %x",1023,*(PULONG)&PdePage[1023]));
+
+ //
+ // Within the above Page Table Page, allocate a PTE for
+ // USER_SHARED_DATA (PcrPage2) at virtual address 0xffffe000. This
+ // is the second to last page in the address space.
+ //
+
+ PtePage = (PHARDWARE_PTE)AddressFromPage(BlLoaderBlock->u.Ppc.PdrPage + 2);
+ BlLog((LOG_ALL,"PCR2 PTE page at %x",PtePage));
+ PtePage[1022].PageFrameNumber = BlLoaderBlock->u.Ppc.PcrPage2;
+ PtePage[1022].Valid = 1;
+ PtePage[1022].Dirty = 1; // allow user read, kernel read/write
+ PtePage[1022].Change = 1;
+ PtePage[1022].Reference = 1;
+ BlLog((LOG_ALL,"PCR2 PTE mapped at PtePage[%x] = %x",1022,*(PULONG)&PtePage[1022]));
+
+ //
+ // If we're paging the kernel, find free memory to use for page
+ // table pages.
+ //
+
+ if (PageKernel) {
+
+ FreePage = 0;
+ NextEntry = BlLoaderBlock->MemoryDescriptorListHead.Flink;
+ while (NextEntry != &BlLoaderBlock->MemoryDescriptorListHead) {
+ NextDescriptor = CONTAINING_RECORD(NextEntry,
+ MEMORY_ALLOCATION_DESCRIPTOR,
+ ListEntry);
+
+ if (NextDescriptor->MemoryType == LoaderFree) {
+ FreeDescriptor = NextDescriptor;
+ FreePage = FreeDescriptor->BasePage;
+ NumberFree = FreeDescriptor->PageCount;
+ break;
+ }
+
+ NextEntry = NextEntry->Flink;
+ }
+
+ if (FreePage == 0) {
+ BlLog((LOG_ALL,"Unable to find free memory for PTE pages"));
+ return ENOMEM;
+ }
+ BlLog((LOG_ALL,"%x PTE pages available at %x",NumberFree,FreePage));
+ }
+
+ //
+ // If we're paging the kernel, then for each page used to load boot
+ // code/data, set up a PTE. Do not do this for pages that reside in
+ // KSEG0. If we're not paging the kernel, find the highest page
+ // used to load boot code/data, so that we know how to set up the
+ // KSEG0 BAT.
+ //
+
+ Kseg0Pages = PageFromAddress(BlLoaderBlock->u.Ppc.Kseg0Top);
+ HighestKseg0Page = 0;
+
+ NextEntry = BlLoaderBlock->MemoryDescriptorListHead.Flink;
+ while (NextEntry != &BlLoaderBlock->MemoryDescriptorListHead) {
+ NextDescriptor = CONTAINING_RECORD(NextEntry,
+ MEMORY_ALLOCATION_DESCRIPTOR,
+ ListEntry);
+
+ if ((NextDescriptor->MemoryType != LoaderExceptionBlock) &&
+ (NextDescriptor->MemoryType != LoaderSystemBlock) &&
+ (NextDescriptor->MemoryType != LoaderFree) &&
+ (NextDescriptor->MemoryType != LoaderBad) &&
+ (NextDescriptor->MemoryType != LoaderLoadedProgram) &&
+ (NextDescriptor->MemoryType != LoaderFirmwareTemporary) &&
+ (NextDescriptor->MemoryType != LoaderFirmwarePermanent) &&
+ (NextDescriptor->MemoryType != LoaderOsloaderStack) &&
+ (NextDescriptor->MemoryType != LoaderSpecialMemory)) {
+
+ HighPage = NextDescriptor->BasePage + NextDescriptor->PageCount;
+
+ if (PageKernel) {
+
+ if (NextDescriptor->BasePage >= Kseg0Pages) {
+
+ BlLog((LOG_ALL,
+ "Setting up mapping for pages[%x:%x]",
+ NextDescriptor->BasePage,
+ HighPage-1));
+ for (Page = NextDescriptor->BasePage; Page < HighPage; Page++) {
+ Entry = AddressFromPage(Page) >> PDI_SHIFT;
+ if (PdePage[Entry].Valid == 0) {
+ PtePage = (PHARDWARE_PTE)AddressFromPage(FreePage);
+ RtlZeroMemory(PtePage, PAGE_SIZE);
+ PdePage[Entry].PageFrameNumber = FreePage;
+ PdePage[Entry].Valid = 1;
+ PdePage[Entry].Write = 1;
+ BlLog((LOG_ALL,
+ "PTE page mapped at PdePage[%x] = %x",
+ Entry,
+ *(PULONG)&PdePage[Entry]));
+ if (NextFreePage(&FreePage, &NumberFree, &FreeDescriptor) != ESUCCESS) {
+ BlLog((LOG_ALL,"Unable to find free memory for PTE pages"));
+ return ENOMEM;
+ }
+ } else {
+ PtePage = (PHARDWARE_PTE)AddressFromPage(PdePage[Entry].PageFrameNumber);
+ }
+ Entry = Page & ((1 << (PDI_SHIFT-PTI_SHIFT)) - 1);
+ PtePage[Entry].PageFrameNumber = Page;
+ PtePage[Entry].Valid = 1;
+ PtePage[Entry].Write = 1;
+ //BlLog((LOG_ALL,
+ // "Page %x mapped at PtePage[%x] (%x) = %x",
+ // Page,
+ // Entry,
+ // &PtePage[Entry],
+ // *(PULONG)&PtePage[Entry]));
+ }
+ //BlLogWaitForKeystroke();
+ }
+
+ } else { // not paging the kernel
+
+ HighestKseg0Page = HighPage;
+ }
+ }
+
+ NextEntry = NextEntry->Flink;
+ }
+
+ if (PageKernel) {
+
+ //
+ // Account for pages taken from FreeDescriptor for page table pages.
+ //
+
+ if (NumberFree != FreeDescriptor->PageCount) {
+ BlLog((LOG_ALL,"Generating FirmwarePermanent descriptor for %x pages at %x taken for PTE pages",FreeDescriptor->PageCount-NumberFree,FreeDescriptor->BasePage));
+ BlGenerateDescriptor(FreeDescriptor,
+ LoaderFirmwarePermanent,
+ FreeDescriptor->BasePage,
+ FreeDescriptor->PageCount - NumberFree);
+ }
+
+ } else {
+
+ //
+ // We're not paging the kernel. Tell the kernel how big the
+ // KSEG0 BAT needs to be -- it must cover all boot code/data.
+ // (If we're paging the kernel, BlPpcMemoryInitialize already
+ // set the KSEG0 BAT size.)
+ //
+
+ Kseg0Pages = PAGES(BlLoaderBlock->u.Ppc.MinimumBlockLength);
+ while (Kseg0Pages < HighestKseg0Page) {
+ Kseg0Pages <<= 1;
+ }
+ BlLoaderBlock->u.Ppc.Kseg0Top = AddressFromPage(Kseg0Pages);
+ BlLog((LOG_ALL,"Highest KSEG0 page: %x, KSEG0 pages: %x",HighestKseg0Page,Kseg0Pages));
+ }
+
+ BlLogWaitForKeystroke();
+
+ return(ESUCCESS);
+}
+
+ARC_STATUS
+ReorganizeEisaConfigurationTree(
+ IN PCONFIGURATION_COMPONENT_DATA RootEntry
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sorts the eisa adapter configuration tree based on
+ the slot the component resided in. It also creates a new configuration
+ data for EisaAdapter component to contain ALL the eisa slot and function
+ information. Finally the Eisa tree will be wiped out.
+
+Arguments:
+
+ RootEntry - Supplies a pointer to a EisaAdapter component. This is
+ the root of Eisa adapter tree.
+
+
+Returns:
+
+ ESUCCESS is returned if the reorganization is successfully complete.
+ Otherwise, an unsuccessful status is returned.
+
+--*/
+{
+
+ PCONFIGURATION_COMPONENT_DATA CurrentEntry, PreviousEntry;
+ PCONFIGURATION_COMPONENT_DATA EntryFound, EntryFoundPrevious;
+ PCONFIGURATION_COMPONENT_DATA AttachedEntry, DetachedList;
+ ARC_STATUS Status;
+
+ //
+ // We sort the direct children of EISA adapter tree based on the slot
+ // they reside in. Only the direct children of EISA root need to be
+ // sorted.
+ // Note the "Key" field of CONFIGURATION_COMPONENT contains
+ // EISA slot number.
+ //
+
+ //
+ // First, detach all the children from EISA root.
+ //
+
+ AttachedEntry = NULL; // Child list of Eisa root
+ DetachedList = RootEntry->Child; // Detached child list
+ PreviousEntry = NULL;
+
+ while (DetachedList) {
+
+ //
+ // Find the component with the smallest slot number from detached
+ // list.
+ //
+
+ EntryFound = DetachedList;
+ EntryFoundPrevious = NULL;
+ CurrentEntry = DetachedList->Sibling;
+ PreviousEntry = DetachedList;
+ while (CurrentEntry) {
+ if (CurrentEntry->ComponentEntry.Key <
+ EntryFound->ComponentEntry.Key) {
+ EntryFound = CurrentEntry;
+ EntryFoundPrevious = PreviousEntry;
+ }
+ PreviousEntry = CurrentEntry;
+ CurrentEntry = CurrentEntry->Sibling;
+ }
+
+ //
+ // Remove the component from the detached child list.
+ // If the component is not the head of the detached list, we remove it
+ // by setting its previous entry's sibling to the component's sibling.
+ // Otherwise, we simply update Detach list head to point to the
+ // component's sibling.
+ //
+
+ if (EntryFoundPrevious) {
+ EntryFoundPrevious->Sibling = EntryFound->Sibling;
+ } else {
+ DetachedList = EntryFound->Sibling;
+ }
+
+ //
+ // Attach the component to the child list of Eisa root.
+ //
+
+ if (AttachedEntry) {
+ AttachedEntry->Sibling = EntryFound;
+ } else {
+ RootEntry->Child = EntryFound;
+ }
+ AttachedEntry = EntryFound;
+ AttachedEntry->Sibling = NULL;
+ }
+
+ //
+ // Finally, we traverse the Eisa tree to collect all the Eisa slot
+ // and function information and put it to the configuration data of
+ // Eisa root entry.
+ //
+
+ Status = CreateEisaConfigurationData(RootEntry);
+
+ //
+ // Wipe out all the children of EISA tree.
+ // NOTE shielint - For each child component, we should convert its
+ // configuration data from EISA format to our CM_ format.
+ //
+
+ RootEntry->Child = NULL;
+ return(Status);
+
+}
+
+ARC_STATUS
+CreateEisaConfigurationData (
+ IN PCONFIGURATION_COMPONENT_DATA RootEntry
+ )
+
+/*++
+
+Routine Description:
+
+ This routine traverses Eisa configuration tree to collect all the
+ slot and function information and attaches it to the configuration data
+ of Eisa RootEntry.
+
+ Note that this routine assumes that the EISA tree has been sorted based
+ on the slot number.
+
+Arguments:
+
+ RootEntry - Supplies a pointer to the Eisa configuration
+ component entry.
+
+Returns:
+
+ ESUCCESS is returned if the new EisaAdapter configuration data is
+ successfully created. Otherwise, an unsuccessful status is returned.
+
+--*/
+{
+ ULONG DataSize, NextSlot = 0, i;
+ PCM_PARTIAL_RESOURCE_LIST Descriptor;
+ PCONFIGURATION_COMPONENT Component;
+ PCONFIGURATION_COMPONENT_DATA CurrentEntry;
+ PUCHAR DataPointer;
+ CM_EISA_SLOT_INFORMATION EmptySlot =
+ {EISA_EMPTY_SLOT, 0, 0, 0, 0, 0, 0, 0};
+
+ //
+ // Remove the configuration data of Eisa Adapter
+ //
+
+ RootEntry->ConfigurationData = NULL;
+ RootEntry->ComponentEntry.ConfigurationDataLength = 0;
+
+ //
+ // If the EISA stree contains valid slot information, i.e.
+ // root has children attaching to it.
+ //
+
+ if (RootEntry->Child) {
+
+ //
+ // First find out how much memory is needed to store EISA config
+ // data.
+ //
+
+ DataSize = sizeof(CM_PARTIAL_RESOURCE_LIST);
+ CurrentEntry = RootEntry->Child;
+
+ while (CurrentEntry) {
+ Component = &CurrentEntry->ComponentEntry;
+ if (CurrentEntry->ConfigurationData) {
+ if (Component->Key > NextSlot) {
+
+ //
+ // If there is any empty slot between current slot
+ // and previous checked slot, we need to count the
+ // space for the empty slots.
+ //
+
+ DataSize += (Component->Key - NextSlot) *
+ sizeof(CM_EISA_SLOT_INFORMATION);
+ }
+ DataSize += Component->ConfigurationDataLength + 1 -
+ CONFIGURATION_DATA_HEADER_SIZE;
+ NextSlot = Component->Key + 1;
+ }
+ CurrentEntry = CurrentEntry->Sibling;
+ }
+
+ //
+ // Allocate memory from heap to hold the EISA configuration data.
+ //
+
+ DataPointer = BlAllocateHeap(DataSize);
+
+ if (DataPointer == NULL) {
+ return ENOMEM;
+ } else {
+ RootEntry->ConfigurationData = DataPointer;
+ RootEntry->ComponentEntry.ConfigurationDataLength = DataSize;
+ }
+
+ //
+ // Create a CM_PARTIAL_RESOURCE_LIST for the new configuration data.
+ //
+
+ Descriptor = (PCM_PARTIAL_RESOURCE_LIST)DataPointer;
+ Descriptor->Version = 0;
+ Descriptor->Revision = 0;
+ Descriptor->Count = 1;
+ Descriptor->PartialDescriptors[0].Type = CmResourceTypeDeviceSpecific;
+ Descriptor->PartialDescriptors[0].ShareDisposition = 0;
+ Descriptor->PartialDescriptors[0].Flags = 0;
+ Descriptor->PartialDescriptors[0].u.DeviceSpecificData.Reserved1 = 0;
+ Descriptor->PartialDescriptors[0].u.DeviceSpecificData.Reserved2 = 0;
+ Descriptor->PartialDescriptors[0].u.DeviceSpecificData.DataSize =
+ DataSize - sizeof(CM_PARTIAL_RESOURCE_LIST);
+
+ //
+ // Visit each child of the RootEntry and copy its ConfigurationData
+ // to the new configuration data area.
+ // N.B. The configuration data includes a slot information and zero
+ // or more function information. The slot information provided
+ // by ARC eisa data does not have "ReturnedCode" as defined in
+ // our CM_EISA_SLOT_INFORMATION. This code will convert the
+ // standard EISA slot information to our CM format.
+ //
+
+ CurrentEntry = RootEntry->Child;
+ DataPointer += sizeof(CM_PARTIAL_RESOURCE_LIST);
+ NextSlot = 0;
+
+ while (CurrentEntry) {
+ Component = &CurrentEntry->ComponentEntry;
+ if (CurrentEntry->ConfigurationData) {
+
+ //
+ // Check if there is any empty slot. If yes, create empty
+ // slot information. Also make sure the config data area is
+ // big enough.
+ //
+
+ if (Component->Key > NextSlot) {
+ for (i = NextSlot; i < CurrentEntry->ComponentEntry.Key; i++ ) {
+ *(PCM_EISA_SLOT_INFORMATION)DataPointer = EmptySlot;
+ DataPointer += sizeof(CM_EISA_SLOT_INFORMATION);
+ }
+ }
+
+ *DataPointer++ = 0; // See comment above
+ RtlMoveMemory( // Skip config data header
+ DataPointer,
+ (PUCHAR)CurrentEntry->ConfigurationData +
+ CONFIGURATION_DATA_HEADER_SIZE,
+ Component->ConfigurationDataLength -
+ CONFIGURATION_DATA_HEADER_SIZE
+ );
+ DataPointer += Component->ConfigurationDataLength -
+ CONFIGURATION_DATA_HEADER_SIZE;
+ NextSlot = Component->Key + 1;
+ }
+ CurrentEntry = CurrentEntry->Sibling;
+ }
+ }
+ return(ESUCCESS);
+}
+
+ARC_STATUS
+BlPpcMemoryInitialize(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Called by BlPpcInitialize to do platform-specific memory initialization.
+ This routine allocates all blocks that need to be in KSEG0 (mapped by a
+ BAT register from virtual 0x80000000 to physical 0). It also changes
+ MemoryLoadedProgram blocks above 8 MB to MemoryFree. This routine also
+ makes the decision about whether the kernel and other boot code is going
+ to be paged.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ARC_STATUS Status;
+ ULONG HighestKseg0Page;
+ ULONG TotalPages;
+ ULONG ContiguousLowMemoryPages;
+ ULONG HighPage;
+ PLIST_ENTRY NextEntry;
+ PMEMORY_ALLOCATION_DESCRIPTOR NextDescriptor;
+ PMEMORY_ALLOCATION_DESCRIPTOR PreviousDescriptor;
+ PMEMORY_ALLOCATION_DESCRIPTOR NewDescriptor;
+ ULONG Kseg0Length;
+ ULONG Kseg0Pages;
+ ULONG Kseg0PagesAdded;
+ PCHAR EnvironmentVariable;
+
+ //
+ // Determine the amount of memory in the system, as well as the
+ // amount of contiguous low memory at physical address 0.
+ //
+ // N.B. The ContiguousLowMemoryPages calculation depends on
+ // the memory descriptor list being sorted.
+ //
+
+ TotalPages = 0;
+ ContiguousLowMemoryPages = 0;
+
+ for (NextEntry = BlLoaderBlock->MemoryDescriptorListHead.Flink;
+ NextEntry != &BlLoaderBlock->MemoryDescriptorListHead;
+ NextEntry = NextEntry->Flink) {
+
+ NextDescriptor = CONTAINING_RECORD(NextEntry,
+ MEMORY_ALLOCATION_DESCRIPTOR,
+ ListEntry);
+
+ TotalPages += NextDescriptor->PageCount;
+ if (NextDescriptor->BasePage == ContiguousLowMemoryPages) {
+ ContiguousLowMemoryPages += NextDescriptor->PageCount;
+ }
+ }
+
+ //
+ // If there is enough memory in the system, don't page the kernel
+ // and the boot drivers -- use the KSEG0 BAT to cover all of it.
+ //
+ // The PAGEKERNEL environment variable can be used to override
+ // this calculation. If the variable doesn't exist, the
+ // calculation is used. If the variable exists and is equal to
+ // "FALSE", the kernel is not paged. If the variable exists and
+ // is not equal to "FALSE", the kernel is paged.
+ //
+
+ EnvironmentVariable = ArcGetEnvironmentVariable("PAGEKERNEL");
+ if (EnvironmentVariable != NULL) {
+ PageKernel = (BOOLEAN)(_stricmp(EnvironmentVariable, "FALSE") != 0);
+ } else {
+ PageKernel = (BOOLEAN)(TotalPages < PAGED_KERNEL_MEMORY_LIMIT);
+ }
+ //PageKernel = FALSE;
+
+ //
+ // Look for memory blocks marked LoadedProgram that are above 8 MB
+ // and below 256 MB. If there are any, that means that we are
+ // running with new firmware that maps free memory above 8 MB and
+ // marks it as LoadedProgram, and we can treat all such memory as
+ // free. Old firmware marks all memory above 8 MB, free or not, as
+ // FirmwareTemporary.
+ //
+ // N.B. Because of the way the original firmware/system interface
+ // was designed, new firmware cannot mark free memory above 8
+ // MB as free, because the old loader might use such memory,
+ // and when the old kernel mapped BAT0 to cover just the low 8
+ // MB, that memory would become inaccessible.
+ //
+ // N.B. We ignore memory above 256 MB because we only want to use
+ // one segment register to map boot code.
+ //
+ // N.B. If we're going to use the KSEG0 BAT to map the kernel, then
+ // we must limit our search for LoadedProgram blocks to the
+ // lower of the processor's BAT size limit and the amount of
+ // contiguous low memory.
+ //
+
+ if (PageKernel) {
+ Kseg0Pages = 256*MBpages;
+ } else {
+ Kseg0Pages = MIN(ContiguousLowMemoryPages,
+ PAGES(BlLoaderBlock->u.Ppc.MaximumBlockLength));
+ }
+
+ NextEntry = BlLoaderBlock->MemoryDescriptorListHead.Flink;
+ while (NextEntry != &BlLoaderBlock->MemoryDescriptorListHead) {
+ NextDescriptor = CONTAINING_RECORD(NextEntry,
+ MEMORY_ALLOCATION_DESCRIPTOR,
+ ListEntry);
+
+ if (NextDescriptor->BasePage >= Kseg0Pages) {
+ break;
+ }
+
+ if ((NextDescriptor->MemoryType == LoaderLoadedProgram) &&
+ (NextDescriptor->BasePage >= 8*MBpages)) {
+
+ //
+ // We have found a LoadedProgram block above 8 MB. If
+ // the block ends below 256 MB, simply mark the block as
+ // free, and remove the descriptor from the memory list and
+ // reinsert it, to allow the block to be merged with the
+ // preceeding block, if possible. If the block crosses 256
+ // MB, split the lower part of the block into a separate
+ // free block, leaving the upper part marked as
+ // LoadedProgram.
+ //
+
+ if ((NextDescriptor->BasePage + NextDescriptor->PageCount) <= Kseg0Pages) {
+
+ NextDescriptor->MemoryType = LoaderFree;
+ BlRemoveDescriptor(NextDescriptor);
+ BlInsertDescriptor(NextDescriptor);
+
+ } else {
+
+ //
+ // The descriptor crosses 256 MB. If the previous
+ // descriptor describes free memory (a likely scenario),
+ // then we can move the low part of the block into that
+ // descriptor.
+ //
+
+ Kseg0PagesAdded = Kseg0Pages - NextDescriptor->BasePage;
+
+ PreviousDescriptor = CONTAINING_RECORD(NextDescriptor->ListEntry.Blink,
+ MEMORY_ALLOCATION_DESCRIPTOR,
+ ListEntry);
+ if ((&PreviousDescriptor->ListEntry != &BlLoaderBlock->MemoryDescriptorListHead) &&
+ (PreviousDescriptor->MemoryType == LoaderFree) &&
+ ((PreviousDescriptor->BasePage + PreviousDescriptor->PageCount) ==
+ NextDescriptor->BasePage)) {
+
+ PreviousDescriptor->PageCount += Kseg0PagesAdded;
+ NextDescriptor->BasePage += Kseg0PagesAdded;
+ NextDescriptor->PageCount -= Kseg0PagesAdded;
+
+ } else {
+
+ //
+ // The previous descriptor does not describe free
+ // memory, so we need a new descriptor. If
+ // allocating a descriptor fails, we just don't
+ // change this block.
+ //
+
+ NewDescriptor = BlAllocateHeap(sizeof(MEMORY_ALLOCATION_DESCRIPTOR));
+ if (NewDescriptor != NULL) {
+ NewDescriptor->MemoryType = LoaderFree;
+ NewDescriptor->BasePage = NextDescriptor->BasePage;
+ NewDescriptor->PageCount = Kseg0PagesAdded;
+ NextDescriptor->BasePage += Kseg0PagesAdded;
+ NextDescriptor->PageCount -= Kseg0PagesAdded;
+ BlInsertDescriptor(NewDescriptor);
+ }
+ }
+ }
+ }
+
+ NextEntry = NextEntry->Flink;
+ }
+
+#define IBAT_BASE 528
+#define DBAT_BASE 536
+
+ BlLog((LOG_ALL,"IBAT0U: %08lx IBAT0L: %08lx IBAT1U: %08lx IBAT1L: %08lx",
+ __sregister_get(IBAT_BASE+0),
+ __sregister_get(IBAT_BASE+1),
+ __sregister_get(IBAT_BASE+2),
+ __sregister_get(IBAT_BASE+3)));
+ BlLog((LOG_ALL,"IBAT2U: %08lx IBAT2L: %08lx IBAT3U: %08lx IBAT3L: %08lx",
+ __sregister_get(IBAT_BASE+4),
+ __sregister_get(IBAT_BASE+5),
+ __sregister_get(IBAT_BASE+6),
+ __sregister_get(IBAT_BASE+7)));
+ BlLog((LOG_ALL,"DBAT0U: %08lx DBAT0L: %08lx DBAT1U: %08lx DBAT1L: %08lx",
+ __sregister_get(DBAT_BASE+0),
+ __sregister_get(DBAT_BASE+1),
+ __sregister_get(DBAT_BASE+2),
+ __sregister_get(DBAT_BASE+3)));
+ BlLog((LOG_ALL,"DBAT2U: %08lx DBAT2L: %08lx DBAT3U: %08lx DBAT3L: %08lx",
+ __sregister_get(DBAT_BASE+4),
+ __sregister_get(DBAT_BASE+5),
+ __sregister_get(DBAT_BASE+6),
+ __sregister_get(DBAT_BASE+7)));
+#if DBG
+ {
+ ULONG sr[16];
+ VOID GetSegmentRegisters(ULONG sr[16]);
+ GetSegmentRegisters(sr);
+ BlLog((LOG_ALL,"SR0 : %08lx SR1 : %08lx SR2 : %08lx SR3 : %08lx",
+ sr[0], sr[1], sr[2], sr[3]));
+ BlLog((LOG_ALL,"SR4 : %08lx SR5 : %08lx SR6 : %08lx SR7 : %08lx",
+ sr[4], sr[5], sr[6], sr[7]));
+ BlLog((LOG_ALL,"SR8 : %08lx SR9 : %08lx SR10: %08lx SR11: %08lx",
+ sr[8], sr[9], sr[10], sr[11]));
+ BlLog((LOG_ALL,"SR12: %08lx SR13: %08lx SR14: %08lx SR15: %08lx",
+ sr[12], sr[13], sr[14], sr[15]));
+ }
+#endif
+ BlLog((LOG_ALL,"SPRG0: %08lx SPRG1: %08lx SPRG2: %08lx SPRG3: %08lx",
+ __sregister_get(272),
+ __sregister_get(273),
+ __sregister_get(274),
+ __sregister_get(275)));
+ BlLog((LOG_ALL_W,"SDR1: %08lx",
+ __sregister_get(25)));
+
+ //
+ // Allow the HPTSIZE environment variable to override the default HPT size.
+ //
+ // The format of the translation is decimal-number[k|K|m|M]. If the format
+ // is incorrect, or if the number is not a valid HPT size, the override is
+ // silently ignored.
+ //
+
+ if (BlLoaderBlock->u.Ppc.HashedPageTableSize != 0) {
+ EnvironmentVariable = ArcGetEnvironmentVariable("HPTSIZE");
+ if (EnvironmentVariable != NULL) {
+ ULONG NewHptSize = 0;
+ PUCHAR p = EnvironmentVariable;
+
+ //
+ // Parse the decimal number portion of the string.
+ //
+
+ while ((*p >= '0') && (*p <= '9')) {
+ NewHptSize = (NewHptSize * 10) + (*p - '0');
+ p++;
+ }
+
+ //
+ // Check for a k or m suffix.
+ //
+
+ if ((*p == 'k') || (*p == 'K')) {
+ NewHptSize = NewHptSize * KB;
+ p++;
+ }
+ if ((*p == 'm') || (*p == 'M')) {
+ NewHptSize = NewHptSize * MB;
+ p++;
+ }
+
+ //
+ // We must be at the end of the string. The number must be a
+ // power of 2, and it must be a valid HPT size.
+ //
+
+ if ((*p == 0) &&
+ ((NewHptSize & (NewHptSize - 1)) == 0) &&
+ ((NewHptSize >= 64*KB) && (NewHptSize <= 32*MB))) {
+
+ //
+ // Override the default HPT size.
+ //
+
+ BlLoaderBlock->u.Ppc.HashedPageTableSize = PAGES(NewHptSize);
+ }
+ }
+ }
+
+ //
+ // Allocate blocks that must be in KSEG0.
+ //
+
+ Status = AllocateKseg0Blocks( &HighestKseg0Page );
+ if (Status != ESUCCESS) {
+ return Status;
+ }
+
+#if DBG
+ EnvironmentVariable = ArcGetEnvironmentVariable("HIGHESTFIT");
+ if (EnvironmentVariable != NULL) {
+ if (_stricmp(EnvironmentVariable, "TRUE") == 0) {
+ BlSetAllocationPolicy(BlAllocateHighestFit, BlAllocateHighestFit);
+ }
+ }
+#endif
+
+ //
+ // If we're going to page the kernel, calculate the amount of low
+ // memory we need to reserve for KSEG0. HighestKseg0Page-1 tells us
+ // the highest page actually used by blocks that must be in KSEG0.
+ // We round this up to the next legal BAT size.
+ //
+ // KSEG0 must be at least as big as the level 1 D-cache, because
+ // the HAL D-cache sweep routines fill the cache from KSEG0.
+ //
+
+ if (PageKernel) {
+
+ Kseg0Pages = PAGES(BlLoaderBlock->u.Ppc.MinimumBlockLength);
+ while (Kseg0Pages < PAGES(BlLoaderBlock->u.Ppc.FirstLevelDcacheSize)) {
+ Kseg0Pages <<= 1;
+ }
+ while (Kseg0Pages < HighestKseg0Page) {
+ Kseg0Pages <<= 1;
+ }
+ Kseg0Length = BYTES(Kseg0Pages);
+ BlLoaderBlock->u.Ppc.Kseg0Top = AddressFromPage(Kseg0Pages);
+ BlLog((LOG_ALL,"Highest KSEG0 page: %x, KSEG0 pages: %x",HighestKseg0Page,Kseg0Pages));
+
+ //
+ // KSEG0 must be at least as big as the level 1 D-cache, because
+ // the HAL D-cache sweep routines fille the cache from KSEG0.
+ //
+
+ //
+ // Ensure that we don't require a BAT bigger than the processor can
+ // handle.
+ //
+
+ if (Kseg0Length > BlLoaderBlock->u.Ppc.MaximumBlockLength) {
+ BlLog((LOG_ALL,"ACK! KSEG0 too big! %x vs. %x",
+ Kseg0Length,BlLoaderBlock->u.Ppc.MaximumBlockLength));
+ return ENOMEM;
+ }
+
+ //
+ // We should have allocated everything from very low memory. At the
+ // very least, there must not be any holes in the memory that we're
+ // going to map the KSEG0 BAT to, otherwise we'll have problems with
+ // speculative execution on 603.
+ //
+
+ if (ContiguousLowMemoryPages < Kseg0Pages) {
+ BlLog((LOG_ALL,"ACK! Not enough contiguous memory at 0! (%x, need %x)",
+ ContiguousLowMemoryPages,Kseg0Pages));
+ return ENOMEM;
+ }
+
+ //
+ // All remaining free memory in the range of KSEG0 must be marked as
+ // FirmwareTemporary so that we don't use it during boot. The OS
+ // will reclaim this memory (and map it outside of KSEG0) after
+ // booting.
+ //
+
+ NextEntry = BlLoaderBlock->MemoryDescriptorListHead.Flink;
+ while (NextEntry != &BlLoaderBlock->MemoryDescriptorListHead) {
+ NextDescriptor = CONTAINING_RECORD(NextEntry,
+ MEMORY_ALLOCATION_DESCRIPTOR,
+ ListEntry);
+
+ if (NextDescriptor->BasePage >= Kseg0Pages) {
+ break;
+ }
+ if (NextDescriptor->MemoryType == LoaderFree) {
+ HighPage = NextDescriptor->BasePage + NextDescriptor->PageCount;
+ HighPage = MIN(HighPage, Kseg0Pages);
+ BlLog((LOG_ALL,"Changing %x pages at %x to FirmwareTemporary",HighPage-NextDescriptor->BasePage,NextDescriptor->BasePage));
+ BlGenerateDescriptor(NextDescriptor,
+ LoaderFirmwareTemporary,
+ NextDescriptor->BasePage,
+ HighPage - NextDescriptor->BasePage);
+ }
+
+ NextEntry = NextEntry->Flink;
+ }
+
+ BlLogWaitForKeystroke();
+ }
+
+ BlLogMemoryDescriptors(LOG_ALL_W);
+ return ESUCCESS;
+}
+
+ARC_STATUS
+BlPpcInitialize (
+ VOID
+ )
+{
+ union {
+ PVR Pvr;
+ ULONG Ulong;
+ } Pvr;
+ BOOLEAN Is601;
+ BOOLEAN Is603;
+ BOOLEAN Is604;
+ BOOLEAN Is620;
+ ULONG MinBat;
+ ULONG MaxBat;
+ ULONG HptSize;
+ ULONG DcacheSize;
+ ULONG DcacheFill;
+ ULONG IcacheSize;
+ ULONG IcacheFill;
+ ULONG TlbSets;
+
+ Pvr.Ulong = KeGetPvr();
+ if (Pvr.Pvr.Version == 1) { // 601
+ MinBat = 128*KB;
+ MaxBat = 8*MB;
+ HptSize = 64*KB;
+ DcacheSize = 32*KB;
+ DcacheFill = 64;
+ IcacheSize = 32*KB;
+ IcacheFill = 64;
+ TlbSets = 128;
+ } else if (Pvr.Pvr.Version == 3) { // 603
+ MinBat = 128*KB;
+ MaxBat = 256*MB;
+ HptSize = 0;
+ DcacheSize = 8*KB;
+ DcacheFill = 32;
+ IcacheSize = 8*KB;
+ IcacheFill = 32;
+ TlbSets = 32;
+ } else if (Pvr.Pvr.Version == 4) { // 604
+ MinBat = 128*KB;
+ MaxBat = 256*MB;
+ HptSize = 64*KB;
+ DcacheSize = 16*KB;
+ DcacheFill = 32;
+ IcacheSize = 16*KB;
+ IcacheFill = 32;
+ TlbSets = 64;
+ } else if (Pvr.Pvr.Version == 6) { // 603+
+ MinBat = 128*KB;
+ MaxBat = 256*MB;
+ HptSize = 0;
+ DcacheSize = 16*KB;
+ DcacheFill = 32;
+ IcacheSize = 16*KB;
+ IcacheFill = 32;
+ TlbSets = 32;
+ } else if (Pvr.Pvr.Version == 7) { // 603++
+ MinBat = 128*KB;
+ MaxBat = 256*MB;
+ HptSize = 0;
+ DcacheSize = 16*KB;
+ DcacheFill = 32;
+ IcacheSize = 16*KB;
+ IcacheFill = 32;
+ TlbSets = 32;
+ } else if (Pvr.Pvr.Version == 8) { // Arthur or 613
+ MinBat = 128*KB;
+ MaxBat = 256*MB;
+ HptSize = 64*KB;
+ DcacheSize = 32*KB;
+ DcacheFill = 32;
+ IcacheSize = 32*KB;
+ IcacheFill = 32;
+ TlbSets = 64;
+ } else if (Pvr.Pvr.Version == 9) { // 604+
+ MinBat = 128*KB;
+ MaxBat = 256*MB;
+ HptSize = 64*KB;
+ DcacheSize = 32*KB;
+ DcacheFill = 32;
+ IcacheSize = 32*KB;
+ IcacheFill = 32;
+ TlbSets = 64;
+ } else if (Pvr.Pvr.Version == 20) { // 620+
+ MinBat = 128*KB;
+ MaxBat = 256*MB;
+ HptSize = 256*KB;
+ DcacheSize = 32*KB;
+ DcacheFill = 64;
+ IcacheSize = 32*KB;
+ IcacheFill = 64;
+ TlbSets = 64;
+ } else {
+ return EINVAL;
+ }
+
+ BlLoaderBlock->u.Ppc.MinimumBlockLength = MinBat;
+ BlLoaderBlock->u.Ppc.MaximumBlockLength = MaxBat;
+ BlLoaderBlock->u.Ppc.HashedPageTableSize = PAGES(HptSize);
+ BlLoaderBlock->u.Ppc.FirstLevelDcacheSize = DcacheSize;
+ BlLoaderBlock->u.Ppc.FirstLevelDcacheFillSize = DcacheFill;
+ BlLoaderBlock->u.Ppc.FirstLevelIcacheSize = IcacheSize;
+ BlLoaderBlock->u.Ppc.FirstLevelIcacheFillSize = IcacheFill;
+ BlLoaderBlock->u.Ppc.NumberCongruenceClasses = TlbSets;
+
+ BlLoaderBlock->u.Ppc.MajorVersion = 2;
+ BlLoaderBlock->u.Ppc.MinorVersion = 0;
+
+ return BlPpcMemoryInitialize();
+}
+
diff --git a/private/ntos/boot/lib/ppc/query.s b/private/ntos/boot/lib/ppc/query.s
new file mode 100644
index 000000000..130e9ce24
--- /dev/null
+++ b/private/ntos/boot/lib/ppc/query.s
@@ -0,0 +1,103 @@
+// TITLE("Query Implemention and Revision Information")
+//++
+//
+// Copyright (c) 1994 International Buisness Machines Corporation
+// Copyright (c) 1994 Microsoft Corporation
+//
+// Module Name:
+//
+// query.s
+//
+// Abstract:
+//
+// This module implements code to query type and revision information.
+//
+// Author:
+//
+// Peter L. Johnston (plj@vnet.ibm.com) August 1994
+//
+// Environment:
+//
+// User mode.
+//
+// Revision History:
+//
+//--
+
+#include "ksppc.h"
+
+//++
+//
+// VOID
+// BlQueryImplementationAndRevision (
+// OUT PULONG ProcessorId,
+// OUT PULONG ProcessorRev
+// )
+//
+// Routine Description:
+//
+// This function returns the implementation and revision of the host
+// processor and floating coprocessor.
+//
+// Arguments:
+//
+// ProcessorId (r3) - Supplies a pointer to a variable that receives the
+// processor id.
+//
+// ProcessorRev (r4) - Supplies a pointer to a variable that receives the
+// processor revision.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(BlQueryImplementationAndRevision)
+
+ mfpvr r.5 // get processor type and revision
+ rlwinm r.6, r.5, 0, 0x0000ffff // isolate revision
+ rlwinm r.5, r.5, 16, 0x0000ffff // isolate type
+ stw r.6, 0(r.4) // store revision
+ stw r.5, 0(r.3) // store type
+
+ LEAF_EXIT(BlQueryImplementationAndRevision)
+
+#if DBG
+ LEAF_ENTRY(GetSegmentRegisters)
+ subi r3,r3,4
+ mfsr r4,0
+ stwu r4,4(r3)
+ mfsr r4,1
+ stwu r4,4(r3)
+ mfsr r4,2
+ stwu r4,4(r3)
+ mfsr r4,3
+ stwu r4,4(r3)
+ mfsr r4,4
+ stwu r4,4(r3)
+ mfsr r4,5
+ stwu r4,4(r3)
+ mfsr r4,6
+ stwu r4,4(r3)
+ mfsr r4,7
+ stwu r4,4(r3)
+ mfsr r4,8
+ stwu r4,4(r3)
+ mfsr r4,9
+ stwu r4,4(r3)
+ mfsr r4,10
+ stwu r4,4(r3)
+ mfsr r4,11
+ stwu r4,4(r3)
+ mfsr r4,12
+ stwu r4,4(r3)
+ mfsr r4,13
+ stwu r4,4(r3)
+ mfsr r4,14
+ stwu r4,4(r3)
+ mfsr r4,15
+ stwu r4,4(r3)
+ LEAF_EXIT(GetSegmentRegisters)
+#endif
+
diff --git a/private/ntos/boot/lib/ppc/sources b/private/ntos/boot/lib/ppc/sources
new file mode 100644
index 000000000..a886eee2e
--- /dev/null
+++ b/private/ntos/boot/lib/ppc/sources
@@ -0,0 +1,5 @@
+PPC_SOURCES=ppc\ntsetup.c \
+ ppc\query.s \
+ ppc\stubs.c \
+ ppc\xxchkstk.s
+
diff --git a/private/ntos/boot/lib/ppc/stubs.c b/private/ntos/boot/lib/ppc/stubs.c
new file mode 100644
index 000000000..2839f5744
--- /dev/null
+++ b/private/ntos/boot/lib/ppc/stubs.c
@@ -0,0 +1,244 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ stubs.c
+
+Abstract:
+
+ This module implements stub routines for the boot code.
+
+Author:
+
+ David N. Cutler (davec) 7-Nov-1990
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+--*/
+
+#include "ntos.h"
+
+//
+// Define global data.
+//
+
+//ULONG BlDcacheFillSize = 32;
+
+VOID
+KeBugCheck (
+ IN ULONG BugCheckCode
+ )
+
+/*++
+
+Routine Description:
+
+ This function crashes the system in a controlled manner.
+
+Arguments:
+
+ BugCheckCode - Supplies the reason for the bug check.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Print out the bug check code and break.
+ //
+
+ DbgPrint("\n*** BugCheck (%lx) ***\n\n", BugCheckCode);
+ while(TRUE) {
+ DbgBreakPoint();
+ };
+ return;
+}
+
+LARGE_INTEGER
+KeQueryPerformanceCounter (
+ OUT PLARGE_INTEGER Frequency OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a stub for the kernel debugger and always returns a
+ value of zero.
+
+Arguments:
+
+ Frequency - Supplies an optional pointer to a variable which receives
+ the performance counter frequency in Hertz.
+
+Return Value:
+
+ A value of zero is returned.
+
+--*/
+
+{
+
+ LARGE_INTEGER Counter;
+
+ //
+ // Return the current system time as the function value.
+ //
+
+ Counter.LowPart = 0;
+ Counter.HighPart = 0;
+ return Counter;
+}
+
+VOID
+KeStallExecutionProcessor (
+ IN ULONG MicroSeconds
+ )
+
+/*++
+
+Routine Description:
+
+ This function stalls execution for the specified number of microseconds.
+
+Arguments:
+
+ MicroSeconds - Supplies the number of microseconds that execution is to be
+ stalled.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ULONG Index;
+ ULONG Limit;
+ PULONG Store;
+ ULONG Value;
+
+ //
+ // ****** begin temporary code ******
+ //
+ // This code must be replaced with a smarter version. For now it assumes
+ // an execution rate of 40,000,000 instructions per second and 4 instructions
+ // per iteration.
+ //
+
+ Store = &Value;
+ Limit = (MicroSeconds * 40 / 4);
+ for (Index = 0; Index < Limit; Index += 1) {
+ *Store = Index;
+ }
+ return;
+}
+
+PVOID
+MmDbgReadCheck (
+ IN PVOID VirtualAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the phyiscal address for a virtual address
+ which is valid (mapped) for read access.
+
+Arguments:
+
+ VirtualAddress - Supplies the virtual address to check.
+
+Return Value:
+
+ Returns NULL if the address is not valid or readable, otherwise
+ returns the physical address of the corresponding virtual address.
+
+--*/
+
+{
+
+ return VirtualAddress;
+}
+
+PVOID
+MmDbgTranslatePhysicalAddress (
+ IN PHYSICAL_ADDRESS PhysicalAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the phyiscal address for a physical address
+ which is valid (mapped).
+
+Arguments:
+
+ PhysicalAddress - Supplies the physical address to check.
+
+Return Value:
+
+ Returns NULL if the address is not valid or readable, otherwise
+ returns the physical address of the corresponding virtual address.
+
+--*/
+
+{
+
+ return (PVOID)PhysicalAddress.LowPart;
+}
+
+PVOID
+MmDbgWriteCheck (
+ IN PVOID VirtualAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the phyiscal address for a virtual address
+ which is valid (mapped) for write access.
+
+Arguments:
+
+ VirtualAddress - Supplies the virtual address to check.
+
+Return Value:
+
+ Returns NULL if the address is not valid or readable, otherwise
+ returns the physical address of the corresponding virtual address.
+
+--*/
+
+{
+ return VirtualAddress;
+}
+
+VOID
+RtlAssert(
+ IN PVOID FailedAssertion,
+ IN PVOID FileName,
+ IN ULONG LineNumber,
+ IN PCHAR Message OPTIONAL
+ )
+{
+
+ DbgPrint( "\n*** Assertion failed\n");
+ while (TRUE) {
+ DbgBreakPoint();
+ }
+}
diff --git a/private/ntos/boot/lib/ppc/xxchkstk.s b/private/ntos/boot/lib/ppc/xxchkstk.s
new file mode 100644
index 000000000..9ab9d66b1
--- /dev/null
+++ b/private/ntos/boot/lib/ppc/xxchkstk.s
@@ -0,0 +1,51 @@
+// TITLE("Runtime Stack Checking")
+//++
+//
+// Copyright (c) 1992 Microsoft Corporation
+//
+// Module Name:
+//
+// xxchkstk.s
+//
+// Abstract:
+//
+// This module implements a stub routine for runtime stack checking.
+//
+// Author:
+//
+// David N. Cutler (davec) 21-Sep-1992
+//
+// Environment:
+//
+// User mode.
+//
+// Revision History:
+//
+//--
+
+#include "ksppc.h"
+
+//++
+//
+// VOID
+// _RtlCheckStack (
+// IN ULONG Allocation
+// )
+//
+// Routine Description:
+//
+// This function provides a stub routine for runtime stack checking.
+//
+// Arguments:
+//
+// Allocation (t8) - Supplies the size of the allocation in bytes.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(_RtlCheckStack)
+
+ LEAF_EXIT(_RtlCheckStack)
diff --git a/private/ntos/boot/lib/scsiboot.c b/private/ntos/boot/lib/scsiboot.c
new file mode 100644
index 000000000..ac6b2813f
--- /dev/null
+++ b/private/ntos/boot/lib/scsiboot.c
@@ -0,0 +1,5588 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ scsiboot.c
+
+Abstract:
+
+ This is the NT SCSI port driver.
+
+Author:
+
+ Mike Glass
+ Jeff Havens
+
+Environment:
+
+ kernel mode only
+
+Notes:
+
+ This module is linked into the kernel.
+
+Revision History:
+
+--*/
+
+#if !defined(DECSTATION)
+
+#include "stdarg.h"
+#include "stdio.h"
+#if defined(_MIPS_)
+#include "..\fw\mips\fwp.h"
+#elif defined(_ALPHA_)
+#include "bldr.h"
+#elif defined(_PPC_)
+#include "..\fw\ppc\fwp.h"
+#else
+#include "bootx86.h"
+#endif
+#include "scsi.h"
+#include "scsiboot.h"
+#include "pci.h"
+
+#if DBG
+ULONG ScsiDebug = 0;
+#endif
+
+ULONG ScsiPortCount;
+PDEVICE_OBJECT ScsiPortDeviceObject[MAXIMUM_NUMBER_OF_SCSIPORT_OBJECTS];
+PINQUIRYDATA InquiryDataBuffer;
+FULL_SCSI_REQUEST_BLOCK PrimarySrb;
+FULL_SCSI_REQUEST_BLOCK RequestSenseSrb;
+FULL_SCSI_REQUEST_BLOCK AbortSrb;
+
+//
+// Function declarations
+//
+
+ARC_STATUS
+ScsiPortDispatch(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+VOID
+ScsiPortExecute(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+VOID
+ScsiPortStartIo (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+BOOLEAN
+ScsiPortInterrupt(
+ IN PKINTERRUPT InterruptObject,
+ IN PDEVICE_OBJECT DeviceObject
+ );
+
+VOID
+ScsiPortCompletionDpc(
+ IN PKDPC Dpc,
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ );
+
+VOID
+ScsiPortTickHandler(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PVOID Context
+ );
+
+IO_ALLOCATION_ACTION
+ScsiPortAllocationRoutine (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID MapRegisterBase,
+ IN PVOID Context
+ );
+
+ARC_STATUS
+IssueInquiry(
+ IN PDEVICE_EXTENSION deviceExtension,
+ IN PLUNINFO LunInfo
+ );
+
+VOID
+IssueRequestSense(
+ IN PDEVICE_EXTENSION deviceExtension,
+ IN PSCSI_REQUEST_BLOCK FailingSrb
+ );
+
+VOID
+ScsiPortInternalCompletion(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp,
+ PVOID Context
+ );
+
+PSCSI_BUS_SCAN_DATA
+ScsiBusScan(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN UCHAR ScsiBus,
+ IN UCHAR InitiatorBusId
+ );
+
+PLOGICAL_UNIT_EXTENSION
+CreateLogicalUnitExtension(
+ IN PDEVICE_EXTENSION DeviceExtension
+ );
+
+BOOLEAN
+SpStartIoSynchronized (
+ PVOID ServiceContext
+ );
+
+VOID
+IssueAbortRequest(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN PIRP FailingIrp
+ );
+
+VOID
+SpCheckResetDelay(
+ IN PDEVICE_EXTENSION deviceExtension
+ );
+
+IO_ALLOCATION_ACTION
+SpBuildScatterGather(
+ IN struct _DEVICE_OBJECT *DeviceObject,
+ IN struct _IRP *Irp,
+ IN PVOID MapRegisterBase,
+ IN PVOID Context
+ );
+
+BOOLEAN
+SpGetInterruptState(
+ IN PVOID ServiceContext
+ );
+
+VOID
+SpTimerDpc(
+ IN PKDPC Dpc,
+ IN PVOID Context,
+ IN PVOID SystemContext1,
+ IN PVOID SystemContext2
+ );
+
+PLOGICAL_UNIT_EXTENSION
+GetLogicalUnitExtension(
+ PDEVICE_EXTENSION DeviceExtension,
+ UCHAR TargetId
+ );
+
+NTSTATUS
+SpInitializeConfiguration(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN PHW_INITIALIZATION_DATA HwInitData,
+ OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ IN BOOLEAN InitialCall
+ );
+
+NTSTATUS
+SpGetCommonBuffer(
+ PDEVICE_EXTENSION DeviceExtension,
+ ULONG NonCachedExtensionSize
+ );
+
+BOOLEAN
+GetPciConfiguration(
+ PDRIVER_OBJECT DriverObject,
+ PDEVICE_OBJECT DeviceObject,
+ PHW_INITIALIZATION_DATA HwInitializationData,
+ PPORT_CONFIGURATION_INFORMATION ConfigInformation,
+ PVOID RegistryPath,
+ PULONG BusNumber,
+ PULONG SlotNumber,
+ PULONG FunctionNumber
+ );
+
+#ifdef i386
+ULONG
+HalpGetCmosData(
+ IN ULONG SourceLocation,
+ IN ULONG SourceAddress,
+ IN PVOID ReturnBuffer,
+ IN ULONG ByteCount
+ );
+#endif
+
+
+//
+// Routines start
+//
+
+ULONG
+ScsiPortInitialize(
+ IN PVOID Argument1,
+ IN PVOID Argument2,
+ IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
+ IN PVOID HwContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the port driver.
+
+Arguments:
+
+ Argument1 - Pointer to driver object created by system
+ HwInitializationData - Miniport initialization structure
+ HwContext - Value passed to miniport driver's config routine
+
+Return Value:
+
+ The function value is the final status from the initialization operation.
+
+--*/
+
+{
+ PDRIVER_OBJECT driverObject = Argument1;
+ PDEVICE_EXTENSION deviceExtension;
+ PDEVICE_OBJECT deviceObject;
+ PORT_CONFIGURATION_INFORMATION configInfo;
+ KEVENT allocateAdapterEvent;
+ ULONG ExtensionAllocationSize;
+ ULONG j;
+ UCHAR scsiBus;
+ PULONG scsiPortNumber;
+ ULONG numberOfPageBreaks;
+ PIO_SCSI_CAPABILITIES capabilities;
+ BOOLEAN callAgain;
+ DEVICE_DESCRIPTION deviceDescription;
+ ARC_CODES status;
+ ULONG busNumber = 0;
+ ULONG slotNumber = 0;
+ ULONG functionNumber = 0;
+ BOOLEAN foundOne = FALSE;
+
+ UNREFERENCED_PARAMETER(Argument2);
+
+ if (HwInitializationData->HwInitializationDataSize > sizeof(HW_INITIALIZATION_DATA)) {
+
+ DebugPrint((0,"ScsiPortInitialize: Miniport driver wrong version\n"));
+ return EBADF;
+ }
+
+ //
+ // Check that each required entry is not NULL.
+ //
+
+ if ((!HwInitializationData->HwInitialize) ||
+ (!HwInitializationData->HwFindAdapter) ||
+ (!HwInitializationData->HwResetBus)) {
+
+ DebugPrint((0,
+ "ScsiPortInitialize: Miniport driver missing required entry\n"));
+
+ return EBADF;
+ }
+
+CallAgain:
+
+ //
+ // Get the configuration information
+ //
+
+ scsiPortNumber = &ScsiPortCount;
+
+ //
+ // Determine if there is room for the next port device object.
+ //
+
+ if (*scsiPortNumber >= MAXIMUM_NUMBER_OF_SCSIPORT_OBJECTS) {
+ return foundOne ? ESUCCESS : EIO;
+ }
+
+ //
+ // Determine size of extensions.
+ //
+
+ ExtensionAllocationSize = DEVICE_EXTENSION_SIZE +
+ HwInitializationData->DeviceExtensionSize + sizeof(DEVICE_OBJECT);
+
+ deviceObject = ExAllocatePool(NonPagedPool, ExtensionAllocationSize);
+
+ if (deviceObject == NULL) {
+ return ENOMEM;
+ }
+
+ RtlZeroMemory(deviceObject, ExtensionAllocationSize);
+
+ //
+ // Set up device extension pointers
+ //
+
+ deviceExtension = deviceObject->DeviceExtension = (PVOID) (deviceObject + 1);
+ deviceExtension->DeviceObject = deviceObject;
+
+ //
+ // Save the dependent driver routines in the device extension.
+ //
+
+ deviceExtension->HwInitialize = HwInitializationData->HwInitialize;
+ deviceExtension->HwStartIo = HwInitializationData->HwStartIo;
+ deviceExtension->HwInterrupt = HwInitializationData->HwInterrupt;
+ deviceExtension->HwReset = HwInitializationData->HwResetBus;
+ deviceExtension->HwDmaStarted = HwInitializationData->HwDmaStarted;
+ deviceExtension->HwLogicalUnitExtensionSize =
+ HwInitializationData->SpecificLuExtensionSize;
+
+ deviceExtension->HwDeviceExtension =
+ (PVOID)(deviceExtension + 1);
+
+ //
+ // Set indicater as to whether adapter needs kernel mapped buffers.
+ //
+
+ deviceExtension->MapBuffers = HwInitializationData->MapBuffers;
+
+ //
+ // Mark this object as supporting direct I/O so that I/O system
+ // will supply mdls in irps.
+ //
+
+ deviceObject->Flags |= DO_DIRECT_IO;
+
+ //
+ // Check if miniport driver requires any noncached memory.
+ // SRB extensions will come from zoned memory. A page is
+ // allocated as it is the smallest unit of noncached memory
+ // allocation.
+ //
+
+ deviceExtension->SrbExtensionSize = HwInitializationData->SrbExtensionSize;
+
+ //
+ // Get the miniport configuration information.
+ //
+
+ capabilities = &deviceExtension->Capabilities;
+
+ capabilities->Length = sizeof(IO_SCSI_CAPABILITIES);
+
+ callAgain = FALSE;
+
+ if (!NT_SUCCESS(SpInitializeConfiguration(
+ deviceExtension,
+ HwInitializationData,
+ &configInfo,
+ TRUE
+ ))) {
+
+ DebugPrint((2, "ScsiPortInitialize: No config info found\n"));
+ return(ENODEV);
+ }
+
+ configInfo.NumberOfAccessRanges = HwInitializationData->NumberOfAccessRanges;
+
+ configInfo.AccessRanges = ExAllocatePool(NonPagedPool,
+ sizeof(ACCESS_RANGE) *
+ HwInitializationData->NumberOfAccessRanges);
+
+ if (configInfo.AccessRanges == NULL) {
+ return ENOMEM;
+ }
+
+ RtlZeroMemory(configInfo.AccessRanges,
+ HwInitializationData->NumberOfAccessRanges * sizeof(ACCESS_RANGE));
+
+ //
+ // Initialize configuration information with slot information if PCI bus.
+ //
+
+ if (HwInitializationData->AdapterInterfaceType == PCIBus &&
+ HwInitializationData->VendorIdLength > 0 &&
+ HwInitializationData->DeviceIdLength > 0 &&
+ HwInitializationData->DeviceId &&
+ HwInitializationData->VendorId) {
+
+ if (!GetPciConfiguration(driverObject,
+ deviceObject,
+ HwInitializationData,
+ &configInfo,
+ Argument2,
+ &busNumber,
+ &slotNumber,
+ &functionNumber)) {
+
+ DebugPrint((1,
+ "ScsiPortInitialize: GetPciConfiguration failed\n"));
+ return foundOne ? ESUCCESS : EIO;
+ }
+ }
+
+ //
+ // Call miniport driver's find adapter routine to search for adapters.
+ //
+
+ if (HwInitializationData->HwFindAdapter(
+ deviceExtension->HwDeviceExtension, // DeviceExtension
+ HwContext, // HwContext
+ NULL, // BusInformation
+ NULL, // ArgumentString
+ &configInfo, // ConfigurationInformation
+ &callAgain // Again
+ ) != SP_RETURN_FOUND) {
+
+ return foundOne ? ESUCCESS : EIO;
+ }
+
+ DebugPrint((1,"ScsiPortInitialize: SCSI adapter IRQ is %d\n",
+ configInfo.BusInterruptLevel));
+
+ DebugPrint((1,"ScsiPortInitialize: SCSI adapter ID is %d\n",
+ configInfo.InitiatorBusId[0]));
+
+ deviceExtension->NumberOfBuses = configInfo.NumberOfBuses;
+
+ //
+ // Free the pointer to the bus data at map register base. This was
+ // allocated by ScsiPortGetBusData.
+ //
+
+ if (deviceExtension->MapRegisterBase != NULL) {
+ ExFreePool(deviceExtension->MapRegisterBase);
+ }
+
+ //
+ // Get the adapter object for this card.
+ //
+
+ if ( deviceExtension->DmaAdapterObject == NULL &&
+ (configInfo.Master || configInfo.DmaChannel != 0xFFFFFFFF) ) {
+
+ deviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
+ deviceDescription.DmaChannel = configInfo.DmaChannel;
+ deviceDescription.InterfaceType = configInfo.AdapterInterfaceType;
+ deviceDescription.BusNumber = configInfo.SystemIoBusNumber;
+ deviceDescription.DmaWidth = configInfo.DmaWidth;
+ deviceDescription.DmaSpeed = configInfo.DmaSpeed;
+ deviceDescription.DmaPort = configInfo.DmaPort;
+ deviceDescription.MaximumLength = configInfo.MaximumTransferLength;
+ deviceDescription.ScatterGather = configInfo.ScatterGather;
+ deviceDescription.Master = configInfo.Master;
+ deviceDescription.AutoInitialize = FALSE;
+ deviceDescription.DemandMode = FALSE;
+
+ // BugBug: Make the 0x11000 a define when there is one.
+ if (configInfo.MaximumTransferLength > 0x11000) {
+
+ deviceDescription.MaximumLength = 0x11000;
+
+ } else {
+
+ deviceDescription.MaximumLength = configInfo.MaximumTransferLength;
+
+ }
+
+ deviceExtension->DmaAdapterObject = HalGetAdapter(
+ &deviceDescription,
+ &numberOfPageBreaks
+ );
+
+ //
+ // Set maximum number of page breaks.
+ //
+
+ if (numberOfPageBreaks > configInfo.NumberOfPhysicalBreaks) {
+ capabilities->MaximumPhysicalPages = configInfo.NumberOfPhysicalBreaks;
+ } else {
+ capabilities->MaximumPhysicalPages = numberOfPageBreaks;
+ }
+
+ }
+
+ //
+ // Allocate memory for the non cached extension if it has not already been
+ // allocated.
+ //
+
+ if (deviceExtension->SrbExtensionSize != 0 &&
+ deviceExtension->SrbExtensionZonePool == NULL) {
+
+ status = SpGetCommonBuffer(deviceExtension, 0);
+
+ if (status != ESUCCESS) {
+
+ return(status);
+ }
+ }
+
+ capabilities->Length = sizeof(IO_SCSI_CAPABILITIES);
+ capabilities->MaximumTransferLength = configInfo.MaximumTransferLength;
+ DebugPrint((1,
+ "Maximum physical page breaks = %d. Maximum transfer length = %x\n",
+ capabilities->MaximumPhysicalPages,
+ capabilities->MaximumTransferLength));
+
+ if (HwInitializationData->ReceiveEvent) {
+ capabilities->SupportedAsynchronousEvents |=
+ SRBEV_SCSI_ASYNC_NOTIFICATION;
+ }
+
+ capabilities->TaggedQueuing = HwInitializationData->TaggedQueuing;
+ capabilities->AdapterScansDown = configInfo.AdapterScansDown;
+ capabilities->AlignmentMask = configInfo.AlignmentMask;
+
+ //
+ // Make sure maximum nuber of pages is set to a reasonable value.
+ // This occurs for mini-ports with no Dma adapter.
+ //
+
+ if (capabilities->MaximumPhysicalPages == 0) {
+
+ capabilities->MaximumPhysicalPages =
+ ROUND_TO_PAGES(capabilities->MaximumTransferLength) + 1;
+
+ //
+ // Honor any limit requested by the mini-port.
+ //
+
+ if (configInfo.NumberOfPhysicalBreaks < capabilities->MaximumPhysicalPages) {
+
+ capabilities->MaximumPhysicalPages =
+ configInfo.NumberOfPhysicalBreaks;
+ }
+ }
+
+ //
+ // Get maximum target IDs.
+ //
+
+ if (configInfo.MaximumNumberOfTargets > SCSI_MAXIMUM_TARGETS_PER_BUS) {
+ deviceExtension->MaximumTargetIds = SCSI_MAXIMUM_TARGETS_PER_BUS;
+ } else {
+ deviceExtension->MaximumTargetIds =
+ configInfo.MaximumNumberOfTargets;
+ }
+
+ if (deviceExtension->DmaAdapterObject != NULL &&
+ !HwInitializationData->NeedPhysicalAddresses) {
+
+ //
+ // Allocate the adapter object. For the port driver the adapter object
+ // and map registers are permentently allocated and used shared between
+ // all logical units. The adapter is allocated by initializing an event,
+ // calling IoAllocateAdapterChannel and waiting on the event. When the
+ // adapter and map registers are available, ScsiPortAllocationRoutine is
+ // called which set the event. In reality, all this takes zero time since
+ // the stuff is available immediately.
+ //
+ // Allocate the AdapterObject. The number of registers is equal to the
+ // maximum transfer length supported by the adapter + 1. This insures
+ // that there will always be a sufficient number of registers.
+ //
+ /* TODO: Fix this for the case when there is no maximum transfer length. */
+
+ IoAllocateAdapterChannel(
+ deviceExtension->DmaAdapterObject,
+ deviceObject,
+ capabilities->MaximumPhysicalPages,
+ ScsiPortAllocationRoutine,
+ &allocateAdapterEvent
+ );
+
+ //
+ // Wait for adapter object.
+ //
+
+ ASSERT(deviceExtension->MapRegisterBase);
+
+ deviceExtension->MasterWithAdapter = FALSE;
+
+ } else if (deviceExtension->DmaAdapterObject != NULL) {
+
+ //
+ // This SCSI adapter is a master with an adapter so a scatter/gather
+ // list needs to be allocated for each transfer.
+ //
+
+ deviceExtension->MasterWithAdapter = TRUE;
+
+ } else {
+
+ deviceExtension->MasterWithAdapter = FALSE;
+
+ } // end if (deviceExtension->DmaAdapterObject != NULL)
+
+ //
+ // Call the hardware dependent driver to do its initialization.
+ //
+
+ if (!KeSynchronizeExecution(
+ deviceExtension->InterruptObject,
+ deviceExtension->HwInitialize,
+ deviceExtension->HwDeviceExtension
+ )) {
+
+ DebugPrint((1,"ScsiPortInitialize: initialization failed\n"));
+
+ return ENODEV;
+ }
+
+ //
+ // Allocate properly aligned INQUIRY buffer.
+ //
+
+ InquiryDataBuffer = ExAllocatePool(NonPagedPool, INQUIRYDATABUFFERSIZE);
+
+ if (InquiryDataBuffer == NULL) {
+ return(ENOMEM);
+ }
+
+ //
+ // Reset the scsi bus.
+ //
+
+ if (!deviceExtension->HwReset(
+ deviceExtension->HwDeviceExtension,
+ 0)){
+
+ DebugPrint((1,"Reset SCSI bus failed\n"));
+ }
+
+ //
+ // Call the interupt handler for a few microseconds to clear any reset
+ // interrupts.
+ //
+
+ for (j = 0; j < 1000 * 100; j++) {
+
+ FwStallExecution(10);
+ if (deviceExtension->HwInterrupt != NULL) {
+ deviceExtension->HwInterrupt(deviceExtension->HwDeviceExtension);
+ }
+ }
+
+ deviceExtension->PortTimeoutCounter = PD_TIMER_RESET_HOLD_TIME;
+ SpCheckResetDelay( deviceExtension );
+
+ //
+ // Find devices on each SCSI bus.
+ //
+
+ //
+ // Allocate buffer for SCSI bus scan information.
+ //
+
+ deviceExtension->ScsiInfo = ExAllocatePool(NonPagedPool,
+ deviceExtension->NumberOfBuses * sizeof(PSCSI_BUS_SCAN_DATA) +
+ 4);
+
+ if (deviceExtension->ScsiInfo) {
+
+ deviceExtension->ScsiInfo->NumberOfBuses = deviceExtension->NumberOfBuses;
+
+ //
+ // Find devices on each SCSI bus.
+ //
+
+ for (scsiBus = 0; scsiBus < deviceExtension->NumberOfBuses; scsiBus++) {
+ deviceExtension->ScsiInfo->BusScanData[scsiBus] =
+ ScsiBusScan(deviceExtension,
+ scsiBus,
+ configInfo.InitiatorBusId[scsiBus]);
+ }
+ }
+
+ //
+ // Save the device object for use by the driver.
+ //
+
+ ScsiPortDeviceObject[*scsiPortNumber] = deviceObject;
+
+ //
+ // Bump SCSI host bus adapters count.
+ //
+
+ (*scsiPortNumber)++;
+
+ foundOne = TRUE;
+
+ //
+ // If the adapter wants to be called again with the same configuration data
+ // then start over from the beginning again.
+ //
+
+ if (callAgain) {
+ goto CallAgain;
+ }
+
+ return ESUCCESS;
+
+} // end ScsiPortInitialize()
+
+IO_ALLOCATION_ACTION
+ScsiPortAllocationRoutine (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID MapRegisterBase,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This function is called by IoAllocateAdapterChannel when sufficent resources
+ are available to the driver. This routine saves the MapRegisterBase in the
+ device object and set the event pointed to by the context parameter.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object to which the adapter is being
+ allocated.
+
+ Irp - Unused.
+
+ MapRegisterBase - Supplied by the Io subsystem for use in IoMapTransfer.
+
+ Context - Supplies a pointer to an event which is set to indicate the
+ AdapterObject has been allocated.
+
+Return Value:
+
+ KeepObject - Indicates the adapter and mapregisters should remain allocated
+ after return.
+
+--*/
+
+{
+ ((PDEVICE_EXTENSION) DeviceObject->DeviceExtension)->MapRegisterBase =
+ MapRegisterBase;
+
+ UNREFERENCED_PARAMETER(Irp);
+ UNREFERENCED_PARAMETER(Context);
+
+ return(KeepObject);
+}
+
+IO_ALLOCATION_ACTION
+SpBuildScatterGather(
+ IN struct _DEVICE_OBJECT *DeviceObject,
+ IN struct _IRP *Irp,
+ IN PVOID MapRegisterBase,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This function is called by the I/O system when an adapter object and map
+ registers have been allocated. This routine then builds a scatter/gather
+ list for use by the mini-port driver. Next it sets the timeout and
+ the current Irp for the logical unit. Finally it calls the mini-port
+ StartIo routine. Once that routines complete, this routine will return
+ requesting that the adapter be freed and but the registers remain allocated.
+ The registers will be freed the request completes.
+
+Arguments:
+
+ DeviceObject - Supplies a pointer to the port driver device object.
+
+ Irp - Supplies a pointer to the current Irp.
+
+ MapRegisterBase - Supplies a context pointer to be used with calls the
+ adapter object routines.
+
+ Context - Supplies a pointer to the logical unit structure.
+
+Return Value:
+
+ Returns DeallocateObjectKeepRegisters so that the adapter object can be
+ used by other logical units.
+
+--*/
+
+{
+ BOOLEAN writeToDevice;
+ PIO_STACK_LOCATION irpstack = IoGetCurrentIrpStackLocation(Irp);
+ PLOGICAL_UNIT_EXTENSION logicalUnit;
+ PSCSI_REQUEST_BLOCK srb;
+ PSRB_SCATTER_GATHER scatterList;
+ ULONG totalLength;
+
+ logicalUnit = Context;
+ srb = (PSCSI_REQUEST_BLOCK)irpstack->Parameters.Others.Argument1;
+ scatterList = logicalUnit->ScatterGather;
+ totalLength = 0;
+
+ //
+ // Save the MapRegisterBase for later use to deallocate the map registers.
+ //
+
+ logicalUnit->MapRegisterBase = MapRegisterBase;
+
+ //
+ // Build the scatter/gather list by looping throught the transfer calling
+ // I/O map transfer.
+ //
+
+ writeToDevice = srb->SrbFlags & SRB_FLAGS_DATA_OUT ? TRUE : FALSE;
+
+ while (totalLength < srb->DataTransferLength) {
+
+ //
+ // Request that the rest of the transfer be mapped.
+ //
+
+ scatterList->Length = srb->DataTransferLength - totalLength;
+
+ //
+ // Since we are a master call I/O map transfer with a NULL adapter.
+ //
+
+ scatterList->PhysicalAddress = IoMapTransfer(
+ NULL,
+ Irp->MdlAddress,
+ MapRegisterBase,
+ (PCCHAR) srb->DataBuffer + totalLength,
+ &scatterList->Length,
+ writeToDevice
+ ).LowPart;
+
+ totalLength += scatterList->Length;
+ scatterList++;
+ }
+
+ //
+ // Set request timeout value from Srb SCSI extension in Irp.
+ //
+
+ logicalUnit->RequestTimeoutCounter = srb->TimeOutValue;
+
+ //
+ // Set current request for this logical unit.
+ //
+
+ logicalUnit->CurrentRequest = Irp;
+
+ /* TODO: Check the return value. */
+ KeSynchronizeExecution(
+ ((PDEVICE_EXTENSION) DeviceObject->DeviceExtension)->InterruptObject,
+ SpStartIoSynchronized,
+ DeviceObject
+ );
+
+ return(DeallocateObjectKeepRegisters);
+
+}
+
+VOID
+ScsiPortExecute(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine calls the start I/O routine an waits for the request to
+ complete. During the wait for complete the interrupt routine is called,
+ also the timer routines are called at the appropriate times. After the
+ request completes a check is made to determine if an request sense needs
+ to be issued.
+
+Arguments:
+
+ DeviceObject - Supplies pointer to Adapter device object.
+
+ Irp - Supplies a pointer to an IRP.
+
+Return Value:
+
+ Nothing.
+
+--*/
+
+{
+ ULONG milliSecondTime;
+ ULONG secondTime;
+ ULONG completionDelay;
+ PDEVICE_EXTENSION deviceExtension;
+ PIO_STACK_LOCATION irpstack = IoGetCurrentIrpStackLocation(Irp);
+ PSCSI_REQUEST_BLOCK srb = (PSCSI_REQUEST_BLOCK)irpstack->Parameters.Others.Argument1;
+ PVOID logicalUnit;
+
+ deviceExtension = DeviceObject->DeviceExtension;
+ logicalUnit = GetLogicalUnitExtension(deviceExtension, srb->TargetId);
+
+ if (logicalUnit == NULL) {
+ Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
+ srb->SrbStatus = SRB_STATUS_NO_DEVICE;
+ return;
+ }
+
+ //
+ // Make sure the adapter is ready to accept requests.
+ //
+
+ SpCheckResetDelay( deviceExtension );
+
+ //
+ // Mark IRP as pending.
+ //
+
+ Irp->PendingReturned = TRUE;
+
+ //
+ // Start the request.
+ //
+
+ ScsiPortStartIo( DeviceObject, Irp);
+
+ //
+ // The completion delay controls how long interrupts are serviced after
+ // a request has been completed. This allows interrupts which occur after
+ // a completion to be serviced.
+ //
+
+ completionDelay = COMPLETION_DELAY;
+
+ //
+ // Wait for the IRP to complete.
+ //
+
+ while (Irp->PendingReturned && completionDelay) {
+
+ //
+ // Wait 1 second then call the scsi port timer routine.
+ //
+
+ for (secondTime = 0; secondTime < 1000/ 250; secondTime++) {
+
+ for (milliSecondTime = 0; milliSecondTime < (250 * 1000 / PD_INTERLOOP_STALL); milliSecondTime++) {
+
+ ScsiPortInterrupt(NULL, DeviceObject);
+
+ if (!Irp->PendingReturned) {
+ if (completionDelay-- == 0) {
+ goto done;
+ }
+ }
+
+ if (deviceExtension->Flags & PD_ENABLE_CALL_REQUEST) {
+
+ //
+ // Call the mini-port requested routine.
+ //
+
+ deviceExtension->Flags &= ~PD_ENABLE_CALL_REQUEST;
+ deviceExtension->HwRequestInterrupt(deviceExtension->HwDeviceExtension);
+
+ if (deviceExtension->Flags & PD_DISABLE_CALL_REQUEST) {
+
+ deviceExtension->Flags &= ~(PD_DISABLE_INTERRUPTS | PD_DISABLE_CALL_REQUEST);
+ deviceExtension->HwRequestInterrupt(deviceExtension->HwDeviceExtension);
+
+ }
+ }
+
+
+ if (deviceExtension->Flags & PD_CALL_DMA_STARTED) {
+
+ deviceExtension->Flags &= ~PD_CALL_DMA_STARTED;
+
+ //
+ // Notify the mini-port driver that the DMA has been
+ // started.
+ //
+
+ if (deviceExtension->HwDmaStarted) {
+ KeSynchronizeExecution(
+ &deviceExtension->InterruptObject,
+ (PKSYNCHRONIZE_ROUTINE) deviceExtension->HwDmaStarted,
+ deviceExtension->HwDeviceExtension
+ );
+ }
+
+ }
+
+ FwStallExecution(PD_INTERLOOP_STALL);
+
+ //
+ // Check the miniport timer.
+ //
+
+ if (deviceExtension->TimerValue != 0) {
+
+ deviceExtension->TimerValue--;
+
+ if (deviceExtension->TimerValue == 0) {
+
+ //
+ // The timer timed out so called requested timer routine.
+ //
+
+ deviceExtension->HwTimerRequest(deviceExtension->HwDeviceExtension);
+ }
+ }
+ }
+ }
+
+ ScsiPortTickHandler(DeviceObject, NULL);
+ }
+
+done:
+
+ if (!NT_SUCCESS(Irp->IoStatus.Status)) {
+ PIO_STACK_LOCATION irpstack = IoGetCurrentIrpStackLocation(Irp);
+ PSCSI_REQUEST_BLOCK Srb = (PSCSI_REQUEST_BLOCK)irpstack->Parameters.Others.Argument1;
+
+ //
+ // Determine if a REQUEST SENSE command needs to be done.
+ // Check that a CHECK_CONDITION was received, an autosense has not
+ // been done already, and that autosense has been requested.
+ //
+
+ if (srb->ScsiStatus == SCSISTAT_CHECK_CONDITION &&
+ !(srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) &&
+ srb->SenseInfoBuffer) {
+
+ //
+ // Call IssueRequestSense and it will complete the request after
+ // the REQUEST SENSE completes.
+ //
+
+ IssueRequestSense(deviceExtension, Srb);
+ }
+ }
+}
+
+VOID
+ScsiPortStartIo (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+ DeviceObject - Supplies pointer to Adapter device object.
+ Irp - Supplies a pointer to an IRP.
+
+Return Value:
+
+ Nothing.
+
+--*/
+
+{
+ PIO_STACK_LOCATION irpstack = IoGetCurrentIrpStackLocation(Irp);
+ PSCSI_REQUEST_BLOCK Srb = (PSCSI_REQUEST_BLOCK)irpstack->Parameters.Others.Argument1;
+ PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
+ PLOGICAL_UNIT_EXTENSION logicalUnit;
+ PFULL_SCSI_REQUEST_BLOCK FullSrb;
+ NTSTATUS status;
+
+ DebugPrint((3,"ScsiPortStartIo: Enter routine\n"));
+
+ FullSrb = CONTAINING_RECORD(Srb, FULL_SCSI_REQUEST_BLOCK, Srb);
+
+ if (deviceExtension->SrbExtensionZonePool && (Srb->SrbExtension == NULL
+ || deviceExtension->SrbExtensionSize > FullSrb->SrbExtensionSize)) {
+
+ //
+ // Allocate SRB extension from zone.
+ //
+
+ Srb->SrbExtension = deviceExtension->SrbExtensionPointer;
+
+ (PCCHAR) deviceExtension->SrbExtensionPointer +=
+ deviceExtension->SrbExtensionSize;
+
+ FullSrb->SrbExtensionSize = deviceExtension->SrbExtensionSize;
+
+ if ((ULONG) deviceExtension->SrbExtensionPointer >
+ (ULONG) deviceExtension->NonCachedExtension) {
+ DebugPrint((0, "NtLdr: ScsiPortStartIo: Srb extension overflow. Too many srb extension allocated.\n"));
+ }
+
+ DebugPrint((3,"ExInterlockedAllocateFromZone: %lx\n",
+ Srb->SrbExtension));
+
+ DebugPrint((3,"Srb %lx\n",Srb));
+
+
+ }
+
+ //
+ // Get logical unit extension.
+ //
+
+ logicalUnit = GetLogicalUnitExtension(deviceExtension, Srb->TargetId);
+
+ //
+ // Flush the data buffer if necessary.
+ //
+
+ if (Srb->SrbFlags & (SRB_FLAGS_DATA_IN | SRB_FLAGS_DATA_OUT)) {
+
+ if (Srb->DataTransferLength > deviceExtension->Capabilities.MaximumTransferLength) {
+
+ DebugPrint((1, "Scsiboot: ScsiPortStartIo Length Exceeds limit %x, %x\n",
+ Srb->DataTransferLength,
+ deviceExtension->Capabilities.MaximumTransferLength));
+ }
+
+ KeFlushIoBuffers(
+ Irp->MdlAddress,
+ Srb->SrbFlags & SRB_FLAGS_DATA_IN ? TRUE : FALSE,
+ TRUE
+ );
+
+ //
+ // Determine if this adapter needs map registers
+ //
+
+ if (deviceExtension->MasterWithAdapter) {
+
+ //
+ // Calculate the number of map registers needed for this transfer.
+ //
+
+ logicalUnit->NumberOfMapRegisters = ADDRESS_AND_SIZE_TO_SPAN_PAGES(
+ Srb->DataBuffer,
+ Srb->DataTransferLength
+ );
+
+ //
+ // Allocate the adapter channel with sufficient map registers
+ // for the transfer.
+ //
+
+ status = IoAllocateAdapterChannel(
+ deviceExtension->DmaAdapterObject, // AdapterObject
+ DeviceObject, // DeviceObject.
+ logicalUnit->NumberOfMapRegisters, // NumberOfMapRegisters
+ SpBuildScatterGather, // ExecutionRoutine
+ logicalUnit // Context
+ );
+
+ if (!NT_SUCCESS(status)) {
+
+ ;
+ }
+
+ //
+ // The execution routine called by IoAllocateChannel will do the
+ // rest of the work so just return.
+ //
+
+ return;
+ }
+ }
+
+ //
+ // Set request timeout value from Srb SCSI extension in Irp.
+ //
+
+ logicalUnit->RequestTimeoutCounter = Srb->TimeOutValue;
+
+ //
+ // Set current request for this logical unit.
+ //
+
+ logicalUnit->CurrentRequest = Irp;
+
+ /* TODO: Check the return value. */
+ KeSynchronizeExecution(
+ deviceExtension->InterruptObject,
+ SpStartIoSynchronized,
+ DeviceObject
+ );
+
+ return;
+
+} // end ScsiPortStartIO()
+
+
+BOOLEAN
+SpStartIoSynchronized (
+ PVOID ServiceContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine calls the dependent driver start io routine.
+
+Arguments:
+
+ ServiceContext - Supplies the pointer to the device object.
+
+Return Value:
+
+ Returns the value returned by the dependent start I/O routine.
+
+
+--*/
+
+{
+ PDEVICE_OBJECT DeviceObject = ServiceContext;
+ PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
+ PIO_STACK_LOCATION irpstack;
+ PSCSI_REQUEST_BLOCK Srb;
+
+ DebugPrint((3, "ScsiPortStartIoSynchronized: Enter routine\n"));
+
+ irpstack = IoGetCurrentIrpStackLocation(DeviceObject->CurrentIrp);
+ Srb = (PSCSI_REQUEST_BLOCK)irpstack->Parameters.Others.Argument1;
+
+ DebugPrint((3, "SpPortStartIoSynchronized: SRB %lx\n",
+ Srb));
+
+ DebugPrint((3, "SpPortStartIoSynchronized: IRP %lx\n",
+ DeviceObject->CurrentIrp));
+
+ //
+ // Disable all synchronous transfers.
+ //
+
+ Srb->SrbFlags |=
+ (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DISABLE_DISCONNECT | SRB_FLAGS_DISABLE_AUTOSENSE);
+
+ return deviceExtension->HwStartIo(
+ deviceExtension->HwDeviceExtension,
+ Srb
+ );
+
+} // end SpStartIoSynchronized()
+
+
+BOOLEAN
+ScsiPortInterrupt(
+ IN PKINTERRUPT Interrupt,
+ IN PDEVICE_OBJECT DeviceObject
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ Interrupt
+
+ Device Object
+
+Return Value:
+
+ Returns TRUE if interrupt expected.
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
+
+ UNREFERENCED_PARAMETER(Interrupt);
+
+ if (deviceExtension->Flags & PD_DISABLE_INTERRUPTS) {
+ return FALSE;
+ }
+
+ if (deviceExtension->HwInterrupt != NULL) {
+
+ if (deviceExtension->HwInterrupt(deviceExtension->HwDeviceExtension)) {
+
+ return TRUE;
+
+ } else {
+
+ return FALSE;
+ }
+ }
+
+ return(FALSE);
+
+} // end ScsiPortInterrupt()
+
+
+VOID
+ScsiPortCompletionDpc(
+ IN PKDPC Dpc,
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+ Dpc
+ DeviceObject
+ Irp - not used
+ Context - not used
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
+ PIO_STACK_LOCATION irpstack;
+ PSCSI_REQUEST_BLOCK Srb;
+ PLOGICAL_UNIT_EXTENSION luExtension;
+
+ UNREFERENCED_PARAMETER(Dpc);
+ UNREFERENCED_PARAMETER(Context);
+
+ DebugPrint((3, "ScsiPortCompletionDpc Entered\n"));
+
+ //
+ // Acquire the spinlock to protect the flags structure and the saved
+ // interrupt context.
+ //
+
+ KeAcquireSpinLock(&deviceExtension->SpinLock, &currentIrql);
+
+ //
+ // Check for a flush DMA adapter object request.
+ //
+
+ if (deviceExtension->InterruptFlags & PD_FLUSH_ADAPTER_BUFFERS) {
+
+ //
+ // Call IoFlushAdapterBuffers using the parameters saved from the last
+ // IoMapTransfer call.
+ //
+
+ IoFlushAdapterBuffers(
+ deviceExtension->DmaAdapterObject,
+ ((PIRP)deviceExtension->FlushAdapterParameters.Srb->OriginalRequest)
+ ->MdlAddress,
+ deviceExtension->MapRegisterBase,
+ deviceExtension->FlushAdapterParameters.LogicalAddress,
+ deviceExtension->FlushAdapterParameters.Length,
+ (BOOLEAN)(deviceExtension->FlushAdapterParameters.Srb->SrbFlags
+ & SRB_FLAGS_DATA_OUT ? TRUE : FALSE)
+ );
+
+ deviceExtension->InterruptFlags &= ~PD_FLUSH_ADAPTER_BUFFERS;
+ }
+
+ //
+ // Check for an IoMapTransfer DMA request.
+ //
+
+ if (deviceExtension->InterruptFlags & PD_MAP_TRANSFER) {
+
+ //
+ // Call IoMapTransfer using the parameters saved from the
+ // interrupt level.
+ //
+
+ IoMapTransfer(
+ deviceExtension->DmaAdapterObject,
+ ((PIRP)deviceExtension->MapTransferParameters.Srb->OriginalRequest)
+ ->MdlAddress,
+ deviceExtension->MapRegisterBase,
+ deviceExtension->MapTransferParameters.LogicalAddress,
+ &deviceExtension->MapTransferParameters.Length,
+ (BOOLEAN)(deviceExtension->MapTransferParameters.Srb->SrbFlags
+ & SRB_FLAGS_DATA_OUT ? TRUE : FALSE)
+ );
+
+ //
+ // Save the paramters for IoFlushAdapterBuffers.
+ //
+
+ deviceExtension->FlushAdapterParameters =
+ deviceExtension->MapTransferParameters;
+
+ deviceExtension->InterruptFlags &= ~PD_MAP_TRANSFER;
+ deviceExtension->Flags |= PD_CALL_DMA_STARTED;
+
+ }
+
+ //
+ // Process any completed requests.
+ //
+
+ while (deviceExtension->CompletedRequests != NULL) {
+
+ Irp = deviceExtension->CompletedRequests;
+ irpstack = IoGetCurrentIrpStackLocation(Irp);
+ Srb = (PSCSI_REQUEST_BLOCK)irpstack->Parameters.Others.Argument1;
+ luExtension =
+ GetLogicalUnitExtension(deviceExtension, Srb->TargetId);
+
+ DebugPrint((3, "ScsiPortCompletionDpc: SRB %lx\n", Srb));
+ DebugPrint((3, "ScsiPortCompletionDpc: IRP %lx\n", Irp));
+
+ //
+ // Remove the request from the linked-list.
+ //
+
+ deviceExtension->CompletedRequests =
+ irpstack->Parameters.Others.Argument3;
+
+ //
+ // Reset request timeout counter.
+ //
+
+ luExtension->RequestTimeoutCounter = -1;
+
+ //
+ // Flush the adapter buffers if necessary.
+ //
+
+ if (luExtension->MapRegisterBase) {
+
+ //
+ // Since we are a master call I/O flush adapter buffers with a NULL
+ // adapter.
+ //
+
+ IoFlushAdapterBuffers(
+ NULL,
+ Irp->MdlAddress,
+ luExtension->MapRegisterBase,
+ Srb->DataBuffer,
+ Srb->DataTransferLength,
+ (BOOLEAN) (Srb->SrbFlags & SRB_FLAGS_DATA_OUT ? TRUE : FALSE)
+ );
+
+ //
+ // Free the map registers.
+ //
+
+ IoFreeMapRegisters(
+ deviceExtension->DmaAdapterObject,
+ luExtension->MapRegisterBase,
+ luExtension->NumberOfMapRegisters
+ );
+
+ //
+ // Clear the MapRegisterBase.
+ //
+
+ luExtension->MapRegisterBase = NULL;
+
+ }
+
+ //
+ // Set IRP status. Class drivers will reset IRP status based
+ // on request sense if error.
+ //
+
+ if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SUCCESS) {
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ } else {
+ Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
+ }
+
+ //
+ // Move bytes transfered to IRP.
+ //
+
+ Irp->IoStatus.Information = Srb->DataTransferLength;
+
+ //
+ // If success then start next packet.
+ // Not starting packet effectively
+ // freezes the queue.
+ //
+
+ if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SUCCESS) {
+
+ DebugPrint((
+ 2,
+ "ScsiPortCompletionDpc: Iocompletion IRP %lx\n",
+ Irp));
+
+ //
+ // Free SrbExtension if allocated.
+ //
+
+ if (Srb->SrbExtension == (deviceExtension->SrbExtensionPointer -
+ deviceExtension->SrbExtensionSize) ) {
+
+ Srb->SrbExtension = NULL;
+
+ (PCCHAR) deviceExtension->SrbExtensionPointer -=
+ deviceExtension->SrbExtensionSize;
+ }
+
+ IoCompleteRequest(Irp, 2);
+
+ } else {
+
+ if ( Srb->ScsiStatus == SCSISTAT_BUSY &&
+ (luExtension->RetryCount++ < 20)) {
+ //
+ // If busy status is returned, then indicate that the logical
+ // unit is busy. The timeout code will restart the request
+ // when it fires. Reset the status to pending.
+ //
+ Srb->SrbStatus = SRB_STATUS_PENDING;
+ luExtension->CurrentRequest = Irp;
+ luExtension->Flags |= PD_LOGICAL_UNIT_IS_BUSY;
+
+ //
+ // Restore the data transfer length.
+ //
+
+ if (Irp->MdlAddress != NULL) {
+ Srb->DataTransferLength = Irp->MdlAddress->ByteCount;
+ }
+
+ DebugPrint((1, "ScsiPortCompletionDpc: Busy returned. Length = %lx\n", Srb->DataTransferLength));
+
+ } else {
+
+
+ DebugPrint((
+ 3,
+ "ScsiPortCompletionDpc: Iocompletion IRP %lx\n",
+ Irp));
+
+ //
+ // Free SrbExtension if allocated.
+ //
+
+ if (Srb->SrbExtension == (deviceExtension->SrbExtensionPointer -
+ deviceExtension->SrbExtensionSize) ) {
+
+ Srb->SrbExtension = NULL;
+
+ (PCCHAR) deviceExtension->SrbExtensionPointer -=
+ deviceExtension->SrbExtensionSize;
+ }
+
+ IoCompleteRequest(Irp, 2);
+ }
+ }
+ }
+
+ //
+ // Release the spinlock.
+ //
+
+ KeReleaseSpinLock(&deviceExtension->SpinLock, currentIrql);
+
+ return;
+
+} // end ScsiPortCompletionDpc()
+
+
+ARC_STATUS
+IssueInquiry(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN PLUNINFO LunInfo
+ )
+
+/*++
+
+Routine Description:
+
+ Build IRP, SRB and CDB for SCSI INQUIRY command.
+
+Arguments:
+
+ DeviceExtension - address of adapter's device object extension.
+ LunInfo - address of buffer for INQUIRY information.
+
+Return Value:
+
+ ARC_STATUS
+
+--*/
+
+{
+ PIRP irp;
+ PIO_STACK_LOCATION irpstack;
+ PCDB cdb;
+ PSCSI_REQUEST_BLOCK srb;
+ ARC_STATUS status;
+ ULONG retryCount = 0;
+
+ DebugPrint((3,"IssueInquiry: Enter routine\n"));
+
+ if (InquiryDataBuffer == NULL) {
+ return ENOMEM;
+ }
+
+inquiryRetry:
+
+ //
+ // Build IRP for this request.
+ //
+
+ irp = InitializeIrp(
+ &PrimarySrb,
+ IRP_MJ_SCSI,
+ DeviceExtension->DeviceObject,
+ (PVOID)InquiryDataBuffer,
+ INQUIRYDATABUFFERSIZE
+ );
+
+ irpstack = IoGetNextIrpStackLocation(irp);
+
+ //
+ // Set major and minor codes.
+ //
+
+ irpstack->MajorFunction = IRP_MJ_SCSI;
+
+ //
+ // Fill in SRB fields.
+ //
+
+ irpstack->Parameters.Others.Argument1 = &PrimarySrb;
+ srb = &PrimarySrb.Srb;
+
+ srb->Length = sizeof(SCSI_REQUEST_BLOCK);
+ srb->PathId = LunInfo->PathId;
+ srb->TargetId = LunInfo->TargetId;
+ srb->Lun = LunInfo->Lun;
+
+ srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
+
+ srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DISABLE_DISCONNECT;
+
+ srb->SrbStatus = srb->ScsiStatus = 0;
+
+ srb->OriginalRequest = irp;
+
+ srb->NextSrb = 0;
+
+ //
+ // Set timeout to 5 seconds.
+ //
+
+ srb->TimeOutValue = 5;
+
+ srb->CdbLength = 6;
+
+ srb->SenseInfoBufferLength = 0;
+ srb->SenseInfoBuffer = 0;
+
+ srb->DataBuffer = MmGetMdlVirtualAddress(irp->MdlAddress);
+ srb->DataTransferLength = INQUIRYDATABUFFERSIZE;
+
+ cdb = (PCDB)srb->Cdb;
+
+ //
+ // Set CDB operation code.
+ //
+
+ cdb->CDB6INQUIRY.OperationCode = SCSIOP_INQUIRY;
+
+ //
+ // Set CDB LUN.
+ //
+
+ cdb->CDB6INQUIRY.LogicalUnitNumber = LunInfo->Lun;
+ cdb->CDB6INQUIRY.Reserved1 = 0;
+
+ //
+ // Set allocation length to inquiry data buffer size.
+ //
+
+ cdb->CDB6INQUIRY.AllocationLength = INQUIRYDATABUFFERSIZE;
+
+ //
+ // Zero reserve field and
+ // Set EVPD Page Code to zero.
+ // Set Control field to zero.
+ // (See SCSI-II Specification.)
+ //
+
+ cdb->CDB6INQUIRY.PageCode = 0;
+ cdb->CDB6INQUIRY.IReserved = 0;
+ cdb->CDB6INQUIRY.Control = 0;
+
+ //
+ // Call port driver to handle this request.
+ //
+
+ (VOID)IoCallDriver(DeviceExtension->DeviceObject, irp);
+
+
+ if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
+
+ DebugPrint((2,"IssueInquiry: Inquiry failed SRB status %x\n",
+ srb->SrbStatus));
+
+ //
+ // NOTE: if INQUIRY fails with a data underrun,
+ // indicate success and let the class drivers
+ // determine whether the inquiry information
+ // is useful.
+ //
+
+ if (SRB_STATUS(srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN) {
+
+ //
+ // Copy INQUIRY buffer to LUNINFO.
+ //
+
+ DebugPrint((1,"IssueInquiry: Data underrun at TID %d\n",
+ LunInfo->TargetId));
+
+ RtlMoveMemory(LunInfo->InquiryData,
+ InquiryDataBuffer,
+ INQUIRYDATABUFFERSIZE);
+
+ status = STATUS_SUCCESS;
+
+ } else if ((SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SELECTION_TIMEOUT) && (retryCount++ < 2)) {
+
+ //
+ // If the selection did not time out then retry the request.
+ //
+
+ DebugPrint((2,"IssueInquiry: Retry %d\n", retryCount));
+ goto inquiryRetry;
+
+ } else {
+
+ status = EIO;
+
+ }
+
+ } else {
+
+ //
+ // Copy INQUIRY buffer to LUNINFO.
+ //
+
+ RtlMoveMemory(LunInfo->InquiryData,
+ InquiryDataBuffer,
+ INQUIRYDATABUFFERSIZE);
+
+ status = STATUS_SUCCESS;
+ }
+
+ return status;
+
+} // end IssueInquiry()
+
+
+PSCSI_BUS_SCAN_DATA
+ScsiBusScan(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN UCHAR ScsiBus,
+ IN UCHAR InitiatorBusId
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+ DeviceExtension
+ ScsiBus
+
+Return Value:
+
+ SCSI configuration information
+
+
+--*/
+{
+ PSCSI_BUS_SCAN_DATA busScanData;
+ PLUNINFO lunInfo;
+ UCHAR target;
+ UCHAR device = 0;
+ PLOGICAL_UNIT_EXTENSION nextLogicalUnitExtension;
+
+ DebugPrint((3,"ScsiBusScan: Enter routine\n"));
+
+ busScanData = ExAllocatePool(NonPagedPool,
+ sizeof(SCSI_BUS_SCAN_DATA));
+
+ if (busScanData == NULL) {
+
+ //
+ // Insufficient system resources to complete bus scan.
+ //
+
+ return NULL;
+ }
+
+ RtlZeroMemory(busScanData,sizeof(SCSI_BUS_SCAN_DATA));
+
+ busScanData->Length = sizeof(SCSI_CONFIGURATION_INFO);
+
+ //
+ // Create first LUNINFO.
+ //
+
+ lunInfo = ExAllocatePool(NonPagedPool, sizeof(LUNINFO));
+
+ if (lunInfo == NULL) {
+
+ //
+ // Insufficient system resources to complete bus scan.
+ //
+
+ return NULL;
+ }
+
+ RtlZeroMemory(lunInfo, sizeof(LUNINFO));
+
+ //
+ // Create first logical unit extension.
+ //
+
+ nextLogicalUnitExtension = CreateLogicalUnitExtension(DeviceExtension);
+
+ if (nextLogicalUnitExtension == NULL) {
+ return(NULL);
+ }
+
+ //
+ // Link logical unit extension on list.
+ //
+
+ nextLogicalUnitExtension->NextLogicalUnit = DeviceExtension->LogicalUnitList;
+
+ DeviceExtension->LogicalUnitList = nextLogicalUnitExtension;
+
+ //
+ // Issue inquiry command to each target id to find devices.
+ //
+ // NOTE: Does not handle multiple logical units per target id.
+ //
+
+ for (target = DeviceExtension->MaximumTargetIds; target > 0; target--) {
+
+ if (InitiatorBusId == target-1) {
+ continue;
+ }
+
+ //
+ // Record address.
+ //
+
+ nextLogicalUnitExtension->PathId = lunInfo->PathId = ScsiBus;
+
+ nextLogicalUnitExtension->TargetId = lunInfo->TargetId = target-1;
+
+ nextLogicalUnitExtension->Lun = lunInfo->Lun = 0;
+
+ //
+ // Rezero hardware logigal unit extension if it's being recycled.
+ //
+
+ if (DeviceExtension->HwLogicalUnitExtensionSize) {
+
+ if (nextLogicalUnitExtension->SpecificLuExtension) {
+
+ RtlZeroMemory(nextLogicalUnitExtension->SpecificLuExtension,
+ DeviceExtension->HwLogicalUnitExtensionSize);
+ }
+
+ }
+
+ //
+ // Issue inquiry command.
+ //
+
+ DebugPrint((2,"ScsiBusScan: Try TargetId %d LUN 0\n", target-1));
+
+ if (IssueInquiry(DeviceExtension, lunInfo) == ESUCCESS) {
+
+ PINQUIRYDATA inquiryData = (PINQUIRYDATA)lunInfo->InquiryData;
+
+ //
+ // Make sure we can use the device.
+ //
+
+ if (inquiryData->DeviceTypeQualifier & 0x04) {
+
+ //
+ // This device is not supported; continue looking for
+ // other devices.
+ //
+
+ continue;
+ }
+
+ DebugPrint((1,
+ "ScsiBusScan: Found Device %d at TID %d LUN %d\n",
+ device,
+ lunInfo->TargetId,
+ lunInfo->Lun));
+
+ //
+ // Link LUN information on list.
+ //
+
+ lunInfo->NextLunInfo = busScanData->LunInfoList;
+ busScanData->LunInfoList = lunInfo;
+
+ //
+ // This buffer is used. Get another.
+ //
+
+ lunInfo = ExAllocatePool(NonPagedPool, sizeof(LUNINFO));
+
+ if (lunInfo == NULL) {
+
+ //
+ // Insufficient system resources to complete bus scan.
+ //
+
+ return busScanData;
+ }
+
+ RtlZeroMemory(lunInfo, sizeof(LUNINFO));
+
+ //
+ // Current logical unit extension claimed.
+ // Create next logical unit.
+ //
+
+ nextLogicalUnitExtension =
+ CreateLogicalUnitExtension(DeviceExtension);
+
+ if (nextLogicalUnitExtension == NULL) {
+ return busScanData;
+ }
+
+ //
+ // Link logical unit extension on list.
+ //
+
+ nextLogicalUnitExtension->NextLogicalUnit =
+ DeviceExtension->LogicalUnitList;
+
+ DeviceExtension->LogicalUnitList = nextLogicalUnitExtension;
+
+ device++;
+ }
+
+ } // end for (target ...
+
+ //
+ // Remove unused logicalunit extension from list.
+ //
+
+ DeviceExtension->LogicalUnitList =
+ DeviceExtension->LogicalUnitList->NextLogicalUnit;
+
+ ExFreePool(nextLogicalUnitExtension);
+ ExFreePool(lunInfo);
+
+ busScanData->NumberOfLogicalUnits = device;
+ DebugPrint((1,
+ "ScsiBusScan: Found %d devices on SCSI bus %d\n",
+ device,
+ ScsiBus));
+
+ return busScanData;
+
+} // end ScsiBusScan()
+
+
+PLOGICAL_UNIT_EXTENSION
+CreateLogicalUnitExtension(
+ IN PDEVICE_EXTENSION DeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ Create logical unit extension.
+
+Arguments:
+
+ DeviceExtension
+ PathId
+
+Return Value:
+
+ Logical unit extension
+
+
+--*/
+{
+ PLOGICAL_UNIT_EXTENSION logicalUnitExtension;
+
+ //
+ // Create logical unit extension and link in chain.
+ //
+
+ logicalUnitExtension =
+ ExAllocatePool(NonPagedPool, sizeof(LOGICAL_UNIT_EXTENSION));
+
+ if (logicalUnitExtension == NULL) {
+ return(NULL);
+ }
+
+ //
+ // Zero logical unit extension.
+ //
+
+ RtlZeroMemory(logicalUnitExtension, sizeof(LOGICAL_UNIT_EXTENSION));
+
+ //
+ // Allocate miniport driver logical unit extension if necessary.
+ //
+
+ if (DeviceExtension->HwLogicalUnitExtensionSize) {
+
+ logicalUnitExtension->SpecificLuExtension =
+ ExAllocatePool(NonPagedPool,
+ DeviceExtension->HwLogicalUnitExtensionSize);
+
+ if (logicalUnitExtension->SpecificLuExtension == NULL) {
+ return(NULL);
+ }
+
+ //
+ // Zero hardware logical unit extension.
+ //
+
+ RtlZeroMemory(logicalUnitExtension->SpecificLuExtension,
+ DeviceExtension->HwLogicalUnitExtensionSize);
+ }
+
+ //
+ // Set timer counters in LogicalUnits to -1 to indicate no
+ // outstanding requests.
+ //
+
+ logicalUnitExtension->RequestTimeoutCounter = -1;
+
+ //
+ // Clear the current request field.
+ //
+
+ logicalUnitExtension->CurrentRequest = NULL;
+
+ return logicalUnitExtension;
+
+} // end CreateLogicalUnitExtension()
+
+
+//
+// Routines providing service to hardware dependent driver.
+//
+
+SCSI_PHYSICAL_ADDRESS
+ScsiPortGetPhysicalAddress(
+ IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb,
+ IN PVOID VirtualAddress,
+ OUT ULONG *Length
+)
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension =
+ ((PDEVICE_EXTENSION) HwDeviceExtension) - 1;
+ PSRB_SCATTER_GATHER scatterList;
+ PIRP irp;
+ PMDL mdl;
+ ULONG byteOffset;
+ ULONG whichPage;
+ PULONG pages;
+ ULONG address;
+
+ if (Srb == NULL) {
+
+ if (deviceExtension->SrbExtensionZonePool) {
+
+ address = (PUCHAR) VirtualAddress - (PUCHAR) deviceExtension->SrbExtensionZonePool +
+ deviceExtension->PhysicalZoneBase;
+
+ } else {
+
+ address = MmGetPhysicalAddress(VirtualAddress).LowPart;
+ }
+
+ //
+ // Return the requested length.
+ //
+
+ } else if (deviceExtension->MasterWithAdapter) {
+
+ //
+ // A scatter/gather list has already been allocated use it to determine
+ // the physical address and length. Get the scatter/gather list.
+ //
+
+ scatterList = GetLogicalUnitExtension(deviceExtension, Srb->TargetId)
+ ->ScatterGather;
+
+ //
+ // Calculate byte offset into the data buffer.
+ //
+
+ byteOffset = (PCHAR) VirtualAddress - (PCHAR) Srb->DataBuffer;
+
+ //
+ // Find the appropirate entry in the scatter/gatter list.
+ //
+
+ while (byteOffset >= scatterList->Length) {
+
+ byteOffset -= scatterList->Length;
+ scatterList++;
+ }
+
+ //
+ // Calculate the physical address and length to be returned.
+ //
+
+ *Length = scatterList->Length - byteOffset;
+ return(ScsiPortConvertUlongToPhysicalAddress(scatterList->PhysicalAddress + byteOffset));
+
+ } else {
+
+ //
+ // Get IRP from SRB.
+ //
+
+ irp = Srb->OriginalRequest;
+
+ //
+ // Get MDL from IRP.
+ //
+
+ mdl = irp->MdlAddress;
+
+ //
+ // Calculate byte offset from
+ // beginning of first physical page.
+ //
+
+ byteOffset = (PCHAR)VirtualAddress - (PCHAR)mdl->StartVa;
+
+ //
+ // Calculate which physical page.
+ //
+
+ whichPage = byteOffset >> PAGE_SHIFT;
+
+ //
+ // Calculate beginning of physical page array.
+ //
+
+ pages = (PULONG)(mdl + 1);
+
+ //
+ // Calculate physical address.
+ //
+
+ address = (pages[whichPage] << PAGE_SHIFT) +
+ BYTE_OFFSET(VirtualAddress);
+
+ //
+ // Assume the buffer is contiguous. Just return the requested length.
+ //
+ }
+
+ return ScsiPortConvertUlongToPhysicalAddress(address);
+
+} // end ScsiPortGetPhysicalAddress()
+
+
+PVOID
+ScsiPortGetVirtualAddress(
+ IN PVOID HwDeviceExtension,
+ IN SCSI_PHYSICAL_ADDRESS PhysicalAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is returns a virtual address associated with a
+ physical address, if the physical address was obtained by a
+ call to ScsiPortGetPhysicalAddress.
+
+Arguments:
+
+ PhysicalAddress
+
+Return Value:
+
+ Virtual address if physical page hashed.
+ NULL if physical page not found in hash.
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension =
+ ((PDEVICE_EXTENSION) HwDeviceExtension) - 1;
+ PVOID address;
+
+
+
+ address = ScsiPortConvertPhysicalAddressToUlong(PhysicalAddress)
+ - deviceExtension->PhysicalZoneBase +
+ (PUCHAR)deviceExtension->SrbExtensionZonePool;
+
+ return address;
+
+} // end ScsiPortGetVirtualAddress()
+
+
+PVOID
+ScsiPortGetLogicalUnit(
+ IN PVOID HwDeviceExtension,
+ IN UCHAR PathId,
+ IN UCHAR TargetId,
+ IN UCHAR Lun
+ )
+
+/*++
+
+Routine Description:
+
+ Walk port driver's logical unit extension list searching
+ for entry.
+
+Arguments:
+
+ HwDeviceExtension - The port driver's device extension follows
+ the miniport's device extension and contains a pointer to
+ the logical device extension list.
+
+ PathId, TargetId and Lun - identify which logical unit on the
+ SCSI buses.
+
+Return Value:
+
+ If entry found return miniport driver's logical unit extension.
+ Else, return NULL.
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension;
+ PLOGICAL_UNIT_EXTENSION logicalUnit;
+
+ //
+ // Get pointer to port driver device extension.
+ //
+
+ deviceExtension = (PDEVICE_EXTENSION)HwDeviceExtension -1;
+
+ //
+ // Get pointer to logical unit list.
+ //
+
+ logicalUnit = deviceExtension->LogicalUnitList;
+
+ //
+ // Walk list looking at target id for requested logical unit extension.
+ //
+
+ while (logicalUnit != NULL) {
+
+ if ((logicalUnit->TargetId == TargetId) &&
+ (logicalUnit->PathId == PathId) &&
+ (logicalUnit->Lun == Lun)) {
+
+ //
+ // Logical unit extension found.
+ // Return specific logical unit extension.
+ //
+
+ return logicalUnit->SpecificLuExtension;
+ }
+
+ //
+ // Get next logical unit.
+ //
+
+ logicalUnit = logicalUnit->NextLogicalUnit;
+ }
+
+ //
+ // Requested logical unit extension not found.
+ //
+
+ return NULL;
+
+} // end ScsiPortGetLogicalUnit()
+
+VOID
+ScsiPortNotification(
+ IN SCSI_NOTIFICATION_TYPE NotificationType,
+ IN PVOID HwDeviceExtension,
+ ...
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension =
+ (PDEVICE_EXTENSION) HwDeviceExtension - 1;
+ PIO_STACK_LOCATION irpstack;
+ PLOGICAL_UNIT_EXTENSION logicalUnit;
+ PSCSI_REQUEST_BLOCK srb;
+ va_list(ap);
+
+ va_start(ap, HwDeviceExtension);
+
+ switch (NotificationType) {
+
+ case NextLuRequest:
+ case NextRequest:
+
+ //
+ // Start next packet on adapter's queue.
+ //
+
+ deviceExtension->InterruptFlags |= PD_READY_FOR_NEXT_REQUEST;
+ break;
+
+ case RequestComplete:
+
+ srb = va_arg(ap, PSCSI_REQUEST_BLOCK);
+
+ if (srb->SrbStatus == SRB_STATUS_ERROR) {
+ }
+
+ //
+ // Link the completed request into a forward-linked list of IRPs.
+ //
+
+ irpstack = IoGetCurrentIrpStackLocation(
+ ((PIRP) srb->OriginalRequest)
+ );
+
+ irpstack->Parameters.Others.Argument3 =
+ deviceExtension->CompletedRequests;
+
+ deviceExtension->CompletedRequests = srb->OriginalRequest;
+
+ //
+ // Set logical unit current request to NULL
+ // to prevent race condition.
+ //
+
+ logicalUnit = GetLogicalUnitExtension(deviceExtension, srb->TargetId);
+
+ logicalUnit->CurrentRequest = NULL;
+
+ break;
+
+ case ResetDetected:
+
+ deviceExtension->PortTimeoutCounter = PD_TIMER_RESET_HOLD_TIME;
+ break;
+
+ case CallDisableInterrupts:
+
+ ASSERT(deviceExtension->Flags & PD_DISABLE_INTERRUPTS);
+
+ //
+ // The mini-port wants us to call the specified routine
+ // with interrupts disabled. This is done after the current
+ // HwRequestInterrutp routine completes. Indicate the call is
+ // needed and save the routine to be called.
+ //
+
+ deviceExtension->Flags |= PD_DISABLE_CALL_REQUEST;
+
+ deviceExtension->HwRequestInterrupt = va_arg(ap, PHW_INTERRUPT);
+
+ break;
+
+ case CallEnableInterrupts:
+
+ ASSERT(!(deviceExtension->Flags & PD_DISABLE_INTERRUPTS));
+
+ //
+ // The mini-port wants us to call the specified routine
+ // with interrupts enabled this is done from the DPC.
+ // Disable calls to the interrupt routine, indicate the call is
+ // needed and save the routine to be called.
+ //
+
+ deviceExtension->Flags |= PD_DISABLE_INTERRUPTS | PD_ENABLE_CALL_REQUEST;
+
+ deviceExtension->HwRequestInterrupt = va_arg(ap, PHW_INTERRUPT);
+
+ break;
+
+ case RequestTimerCall:
+
+ deviceExtension->HwTimerRequest = va_arg(ap, PHW_INTERRUPT);
+ deviceExtension->TimerValue = va_arg(ap, ULONG);
+
+ if (deviceExtension->TimerValue) {
+
+ //
+ // Round up the timer value to the stall time.
+ //
+
+ deviceExtension->TimerValue = (deviceExtension->TimerValue
+ + PD_INTERLOOP_STALL - 1)/ PD_INTERLOOP_STALL;
+ }
+
+ break;
+ }
+
+ va_end(ap);
+
+ //
+ // Check to see if the last DPC has been processed yet. If so
+ // queue another DPC.
+ //
+
+ ScsiPortCompletionDpc(
+ NULL, // Dpc
+ deviceExtension->DeviceObject, // DeviceObject
+ NULL, // Irp
+ NULL // Context
+ );
+
+} // end ScsiPortNotification()
+
+
+VOID
+ScsiPortFlushDma(
+ IN PVOID HwDeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ This routine checks to see if the perivious IoMapTransfer has been done
+ started. If it has not, then the PD_MAP_TRANSER flag is cleared, and the
+ routine returns; otherwise, this routine schedules a DPC which will call
+ IoFlushAdapter buffers.
+
+Arguments:
+
+ HwDeviceExtension - Supplies a the hardware device extension for the
+ host bus adapter which will be doing the data transfer.
+
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PDEVICE_EXTENSION deviceExtension;
+
+ deviceExtension = ((PDEVICE_EXTENSION) HwDeviceExtension) - 1;
+
+ if (deviceExtension->InterruptFlags & PD_MAP_TRANSFER) {
+
+ //
+ // The transfer has not been started so just clear the map transfer
+ // flag and return.
+ //
+
+ deviceExtension->InterruptFlags &= ~PD_MAP_TRANSFER;
+ return;
+ }
+
+ deviceExtension->InterruptFlags |= PD_FLUSH_ADAPTER_BUFFERS;
+
+ //
+ // Check to see if the last DPC has been processed yet. If so
+ // queue another DPC.
+ //
+
+ ScsiPortCompletionDpc(
+ NULL, // Dpc
+ deviceExtension->DeviceObject, // DeviceObject
+ NULL, // Irp
+ NULL // Context
+ );
+
+ return;
+
+}
+
+VOID
+ScsiPortIoMapTransfer(
+ IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb,
+ IN PVOID LogicalAddress,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ Saves the parameters for the call to IoMapTransfer and schedules the DPC
+ if necessary.
+
+Arguments:
+
+ HwDeviceExtension - Supplies a the hardware device extension for the
+ host bus adapter which will be doing the data transfer.
+
+ Srb - Supplies the particular request that data transfer is for.
+
+ LogicalAddress - Supplies the logical address where the transfer should
+ begin.
+
+ Length - Supplies the maximum length in bytes of the transfer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension;
+
+ deviceExtension = ((PDEVICE_EXTENSION) HwDeviceExtension) - 1;
+
+ //
+ // Make sure this host bus adapter has an Dma adapter object.
+ //
+
+ if (deviceExtension->DmaAdapterObject == NULL) {
+ //
+ // No DMA adapter, no work.
+ //
+ return;
+ }
+
+ deviceExtension->MapTransferParameters.Srb = Srb;
+ deviceExtension->MapTransferParameters.LogicalAddress = LogicalAddress;
+ deviceExtension->MapTransferParameters.Length = Length;
+
+ deviceExtension->InterruptFlags |= PD_MAP_TRANSFER;
+
+ //
+ // Check to see if the last DPC has been processed yet. If so
+ // queue another DPC.
+ //
+
+ ScsiPortCompletionDpc(
+ NULL, // Dpc
+ deviceExtension->DeviceObject, // DeviceObject
+ NULL, // Irp
+ NULL // Context
+ );
+
+} // end ScsiPortIoMapTransfer()
+
+
+VOID
+IssueRequestSense(
+ IN PDEVICE_EXTENSION deviceExtension,
+ IN PSCSI_REQUEST_BLOCK FailingSrb
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates a REQUEST SENSE request and uses IoCallDriver to
+ renter the driver. The completion routine cleans up the data structures
+ and processes the logical unit queue according to the flags.
+
+ A pointer to failing SRB is stored at the end of the request sense
+ Srb, so that the completion routine can find it.
+
+Arguments:
+
+ DeviceExension - Supplies a pointer to the device extension for this
+ SCSI port.
+
+ FailingSrb - Supplies a pointer to the request that the request sense
+ is being done for.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIO_STACK_LOCATION irpstack;
+ PIRP Irp;
+ PSCSI_REQUEST_BLOCK Srb;
+ PCDB cdb;
+ PVOID *Pointer;
+
+ //
+ // Allocate Srb from non-paged pool
+ // plus room for a pointer to the failing IRP.
+ // Since this routine is in an error-handling
+ // path and a shortterm allocation
+ // NonPagedMustSucceed is requested.
+ //
+
+ Srb = &RequestSenseSrb.Srb;
+
+ //
+ // Allocate an IRP to issue the REQUEST SENSE request.
+ //
+
+ Irp = InitializeIrp(
+ &RequestSenseSrb,
+ IRP_MJ_READ,
+ deviceExtension->DeviceObject,
+ FailingSrb->SenseInfoBuffer,
+ FailingSrb->SenseInfoBufferLength
+ );
+
+ irpstack = IoGetNextIrpStackLocation(Irp);
+
+ irpstack->MajorFunction = IRP_MJ_SCSI;
+
+ //
+ // Save the Failing SRB after the request sense Srb.
+ //
+
+ Pointer = (PVOID *) (Srb+1);
+ *Pointer = FailingSrb;
+
+ //
+ // Build the REQUEST SENSE CDB.
+ //
+
+ Srb->CdbLength = 6;
+ cdb = (PCDB)Srb->Cdb;
+
+ cdb->CDB6INQUIRY.OperationCode = SCSIOP_REQUEST_SENSE;
+ cdb->CDB6INQUIRY.LogicalUnitNumber = 0;
+ cdb->CDB6INQUIRY.Reserved1 = 0;
+ cdb->CDB6INQUIRY.PageCode = 0;
+ cdb->CDB6INQUIRY.IReserved = 0;
+ cdb->CDB6INQUIRY.AllocationLength =
+ (UCHAR)FailingSrb->SenseInfoBufferLength;
+ cdb->CDB6INQUIRY.Control = 0;
+
+ //
+ // Save SRB address in next stack for port driver.
+ //
+
+ irpstack->Parameters.Others.Argument1 = (PVOID)Srb;
+
+ //
+ // Set up IRP Address.
+ //
+
+ Srb->OriginalRequest = Irp;
+
+ Srb->NextSrb = 0;
+
+ //
+ // Set up SCSI bus address.
+ //
+
+ Srb->TargetId = FailingSrb->TargetId;
+ Srb->Lun = FailingSrb->Lun;
+ Srb->PathId = FailingSrb->PathId;
+ Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
+ Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
+
+ //
+ // Set timeout value to 2 seconds.
+ //
+
+ Srb->TimeOutValue = 2;
+
+ //
+ // Disable auto request sense.
+ //
+
+ Srb->SenseInfoBufferLength = 0;
+
+ //
+ // Sense buffer is in stack.
+ //
+
+ Srb->SenseInfoBuffer = NULL;
+
+ //
+ // Set read and bypass frozen queue bits in flags.
+ //
+
+ //
+ // Set a speical flags to indicate the logical unit queue should be by
+ // passed and that no queue processing should be done when the request
+ // completes.
+ //
+
+ Srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_BYPASS_FROZEN_QUEUE |
+ SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DISABLE_DISCONNECT;
+
+ Srb->DataBuffer = FailingSrb->SenseInfoBuffer;
+
+ //
+ // Set the transfer length.
+ //
+
+ Srb->DataTransferLength = FailingSrb->SenseInfoBufferLength;
+
+ //
+ // Zero out status.
+ //
+
+ Srb->ScsiStatus = Srb->SrbStatus = 0;
+
+ (VOID)IoCallDriver(deviceExtension->DeviceObject, Irp);
+
+ ScsiPortInternalCompletion(deviceExtension->DeviceObject, Irp, Srb);
+
+ return;
+
+} // end IssueRequestSense()
+
+
+VOID
+ScsiPortInternalCompletion(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp,
+ PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+ Device object
+ IRP
+ Context - pointer to SRB
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSCSI_REQUEST_BLOCK srb = Context;
+ PIO_STACK_LOCATION irpstack = IoGetCurrentIrpStackLocation(Irp);
+ PSCSI_REQUEST_BLOCK failingSrb;
+ PIRP failingIrp;
+
+ UNREFERENCED_PARAMETER(DeviceObject);
+
+ //
+ // Request sense completed. If successful or data over/underrun
+ // get the failing SRB and indicate that the sense information
+ // is valid. The class driver will check for underrun and determine
+ // if there is enough sense information to be useful.
+ //
+
+ if ((SRB_STATUS(srb->SrbStatus) == SRB_STATUS_SUCCESS) ||
+ (SRB_STATUS(srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN)) {
+
+ //
+ // Get a pointer to failing Irp and Srb.
+ //
+
+ failingSrb = *((PVOID *) (srb+1));
+ failingIrp = failingSrb->OriginalRequest;
+
+ //
+ // Report sense buffer is valid.
+ //
+
+ failingSrb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID;
+
+ //
+ // Copy bytes transferred to failing SRB
+ // request sense length field to communicate
+ // to the class drivers the number of valid
+ // sense bytes.
+ //
+
+ failingSrb->SenseInfoBufferLength = (UCHAR) srb->DataTransferLength;
+
+ }
+
+} // ScsiPortInternalCompletion()
+
+
+VOID
+ScsiPortTickHandler(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension =
+ (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
+ PLOGICAL_UNIT_EXTENSION logicalUnit;
+
+ UNREFERENCED_PARAMETER(Context);
+
+ logicalUnit = deviceExtension->LogicalUnitList;
+
+ //
+ // NOTE: The use of Current request needs to be synchronized with the
+ // clearing of current request.
+ //
+
+ while (logicalUnit != NULL) {
+
+ //
+ // Check for busy requests.
+ //
+
+ if (logicalUnit->Flags & PD_LOGICAL_UNIT_IS_BUSY) {
+
+ DebugPrint((1,"ScsiPortTickHandler: Retrying busy status request\n"));
+
+ //
+ // Clear the busy flag and retry the request.
+ //
+
+ logicalUnit->Flags &= ~PD_LOGICAL_UNIT_IS_BUSY;
+
+ ScsiPortStartIo(DeviceObject, logicalUnit->CurrentRequest);
+
+ } else if (logicalUnit->RequestTimeoutCounter == 0) {
+
+ //
+ // Request timed out.
+ //
+
+ DebugPrint((1, "ScsiPortTickHandler: Request timed out\n"));
+
+ //
+ // Reset request timeout counter to unused state.
+ //
+
+ logicalUnit->RequestTimeoutCounter = -1;
+
+ //
+ // Build and send request to abort command.
+ //
+
+ IssueAbortRequest(deviceExtension, logicalUnit->CurrentRequest);
+ } else if (logicalUnit->RequestTimeoutCounter != -1) {
+
+ DebugPrint((1, "ScsiPortTickHandler: Timeout value %lx\n",logicalUnit->RequestTimeoutCounter));
+ logicalUnit->RequestTimeoutCounter--;
+ }
+
+ logicalUnit = logicalUnit->NextLogicalUnit;
+ }
+
+ return;
+
+} // end ScsiPortTickHandler()
+
+
+VOID
+IssueAbortRequest(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN PIRP FailingIrp
+ )
+
+/*++
+
+Routine Description:
+
+ A request timed out and to clear the request at the HBA
+ an ABORT request is issued. But first, if the request
+ that timed out was an ABORT command, then reset the
+ adapter instead.
+
+Arguments:
+
+ DeviceExension - Supplies a pointer to the device extension for this
+ SCSI port.
+
+ FailingIrp - Supplies a pointer to the request that is to be aborted.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ULONG j;
+
+ //
+ // A request to abort failed.
+ // Need to reset the adapter.
+ //
+
+ DebugPrint((1,"IssueAbort: Request timed out, resetting the bus.\n"));
+
+
+ if (!DeviceExtension->HwReset(
+ DeviceExtension->HwDeviceExtension,
+ 0)){
+
+ DebugPrint((1,"Reset SCSI bus failed\n"));
+ }
+
+ //
+ // Call the interupt handler for a few microseconds to clear any reset
+ // interrupts.
+ //
+
+ for (j = 0; j < 1000 * 100; j++) {
+
+ FwStallExecution(10);
+ if (DeviceExtension->HwInterrupt != NULL) {
+ DeviceExtension->HwInterrupt(DeviceExtension->HwDeviceExtension);
+ }
+
+ }
+
+ DeviceExtension->PortTimeoutCounter = PD_TIMER_RESET_HOLD_TIME;
+ SpCheckResetDelay( DeviceExtension );
+
+ return;
+
+
+} // end IssueAbortRequest()
+
+
+VOID
+SpCheckResetDelay(
+ IN PDEVICE_EXTENSION deviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ If there is a pending reset delay, this routine stalls the execution
+ for the specified number of seconds. During the delay the timer
+ routines are called at the appropriate times.
+
+Arguments:
+
+ DeviceExension - Supplies a pointer to the device extension for this
+ SCSI port.
+
+Return Value:
+
+ Nothing.
+
+--*/
+
+{
+ ULONG milliSecondTime;
+
+ //
+ // Check if the adapter is ready to accept requests.
+ //
+
+ while (deviceExtension->PortTimeoutCounter) {
+
+ deviceExtension->PortTimeoutCounter--;
+
+ //
+ // One second delay.
+ //
+
+ for ( milliSecondTime = 0;
+ milliSecondTime < ((1000*1000)/PD_INTERLOOP_STALL);
+ milliSecondTime++ ) {
+
+ FwStallExecution(PD_INTERLOOP_STALL);
+
+ //
+ // Check the miniport timer.
+ //
+
+ if (deviceExtension->TimerValue != 0) {
+
+ deviceExtension->TimerValue--;
+
+ if (deviceExtension->TimerValue == 0) {
+
+ //
+ // The timer timed out so called requested timer routine.
+ //
+
+ deviceExtension->HwTimerRequest(deviceExtension->HwDeviceExtension);
+ }
+ }
+ }
+ }
+
+ return;
+}
+
+BOOLEAN
+SpGetInterruptState(
+ IN PVOID ServiceContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine saves the InterruptFlags, MapTransferParameters and
+ CompletedRequests fields and clears the InterruptFlags.
+
+Arguments:
+
+ ServiceContext - Supplies a pointer to the device extension for this
+ SCSI port.
+
+Return Value:
+
+ Always returns TRUE.
+
+Notes:
+
+ Called via KeSynchronizeExecution.
+
+--*/
+{
+ PDEVICE_EXTENSION deviceExtension = ServiceContext;
+
+ //
+ // Move the interrupt state to save area.
+ //
+
+ deviceExtension->InterruptFlags = deviceExtension->InterruptFlags;
+ deviceExtension->CompletedRequests = deviceExtension->CompletedRequests;
+ deviceExtension->MapTransferParameters = deviceExtension->MapTransferParameters;
+
+ //
+ // Clear the interrupt state.
+ //
+
+ deviceExtension->InterruptFlags = 0;
+ deviceExtension->CompletedRequests = NULL;
+
+ return(TRUE);
+}
+
+VOID
+ScsiPortLogError(
+ IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb OPTIONAL,
+ IN UCHAR PathId,
+ IN UCHAR TargetId,
+ IN UCHAR Lun,
+ IN ULONG ErrorCode,
+ IN ULONG UniqueId
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates an error log entry, copies the supplied text
+ to it, and requests that it be written to the error log file.
+
+Arguments:
+
+ DeviceExtenson - Supplies the HBA mini-port driver's adapter data storage.
+
+ TargetId, Lun and PathId - specify device address on a SCSI bus.
+
+ ErrorCode - Supplies an error code indicating the type of error.
+
+ UniqueId - Supplies a unique identifier for the error.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PCHAR errorCodeString;
+
+ switch (ErrorCode) {
+ case SP_BUS_PARITY_ERROR:
+ errorCodeString = "SCSI bus partity error";
+ break;
+
+ case SP_UNEXPECTED_DISCONNECT:
+ errorCodeString = "Unexpected disconnect";
+ break;
+
+ case SP_INVALID_RESELECTION:
+ errorCodeString = "Invalid reselection";
+ break;
+
+ case SP_BUS_TIME_OUT:
+ errorCodeString = "SCSI bus time out";
+ break;
+
+ case SP_PROTOCOL_ERROR:
+ errorCodeString = "SCSI protocol error";
+ break;
+
+ case SP_INTERNAL_ADAPTER_ERROR:
+ errorCodeString = "Internal adapter error";
+ break;
+
+ default:
+ errorCodeString = "Unknown error code";
+ break;
+
+ }
+
+ DebugPrint((1,"\n\nLogErrorEntry: Logging SCSI error packet. ErrorCode = %s.\n",
+ errorCodeString));
+ DebugPrint((1,
+ "PathId = %2x, TargetId = %2x, Lun = %2x, UniqueId = %x.\n\n",
+ PathId,
+ TargetId,
+ Lun,
+ UniqueId));
+
+#if DBG
+#ifdef PAUSE
+ if (ScsiDebug > 0) {
+ DebugPrint((1, "Hit any key.\n"));
+ PAUSE;
+ }
+#endif
+#endif
+
+ return;
+
+} // end ScsiPortLogError()
+
+
+VOID
+ScsiPortCompleteRequest(
+ IN PVOID HwDeviceExtension,
+ IN UCHAR PathId,
+ IN UCHAR TargetId,
+ IN UCHAR Lun,
+ IN UCHAR SrbStatus
+ )
+
+/*++
+
+Routine Description:
+
+ Complete all active requests for the specified logical unit.
+
+Arguments:
+
+ DeviceExtenson - Supplies the HBA mini-port driver's adapter data storage.
+
+ TargetId, Lun and PathId - specify device address on a SCSI bus.
+
+ SrbStatus - Status to be returned in each completed SRB.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension =
+ ((PDEVICE_EXTENSION) HwDeviceExtension) - 1;
+ PSCSI_REQUEST_BLOCK Srb;
+ PSCSI_REQUEST_BLOCK failingSrb;
+ PLOGICAL_UNIT_EXTENSION luExtension;
+ PIRP nextIrp;
+ PIO_STACK_LOCATION irpstack;
+
+ UNREFERENCED_PARAMETER(PathId);
+ UNREFERENCED_PARAMETER(Lun);
+
+ if (TargetId == (UCHAR)(-1)) {
+
+ //
+ // Complete requests for all units on this bus.
+ //
+
+ luExtension = deviceExtension->LogicalUnitList;
+
+ while (luExtension != NULL) {
+
+ //
+ // Complete requests until queue is empty.
+ //
+
+ if ((nextIrp = luExtension->CurrentRequest) != NULL &&
+ !(luExtension->Flags & PD_LOGICAL_UNIT_IS_BUSY)) {
+
+ //
+ // Get SRB address from current IRP stack.
+ //
+
+ irpstack = IoGetCurrentIrpStackLocation(nextIrp);
+
+ Srb = (PSCSI_REQUEST_BLOCK)irpstack->Parameters.Others.Argument1;
+
+ //
+ // Just in case this is an abort request,
+ // get pointer to failingSrb.
+ //
+
+ failingSrb = Srb->NextSrb;
+
+ //
+ // Update SRB status.
+ //
+
+ Srb->SrbStatus = SrbStatus;
+
+ //
+ // Indicate no bytes transferred.
+ //
+
+ Srb->DataTransferLength = 0;
+
+ //
+ // Set IRP status.
+ //
+
+ nextIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
+
+ //
+ // Move bytes transferred to IRP.
+ //
+
+ nextIrp->IoStatus.Information = Srb->DataTransferLength;
+
+ //
+ // Call notification routine.
+ //
+
+ ScsiPortNotification(RequestComplete,
+ (PVOID)HwDeviceExtension,
+ Srb);
+
+ if (failingSrb) {
+
+ //
+ // This was an abort request. The failing
+ // SRB must also be completed.
+ //
+
+ failingSrb->SrbStatus = SrbStatus;
+ failingSrb->DataTransferLength = 0;
+
+ //
+ // Get IRP from SRB.
+ //
+
+ nextIrp = failingSrb->OriginalRequest;
+
+ //
+ // Set IRP status.
+ //
+
+ nextIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
+
+ //
+ // Move bytes transferred to IRP.
+ //
+
+ nextIrp->IoStatus.Information =
+ failingSrb->DataTransferLength;
+
+ //
+ // Call notification routine.
+ //
+
+ ScsiPortNotification(RequestComplete,
+ (PVOID)HwDeviceExtension,
+ failingSrb);
+ }
+
+ } // end if
+
+ luExtension = luExtension->NextLogicalUnit;
+
+ } // end while
+
+ } else {
+
+ //
+ // Complete all requests for this logical unit.
+ //
+
+ luExtension =
+ GetLogicalUnitExtension(deviceExtension, TargetId);
+
+ //
+ // Complete requests until queue is empty.
+ //
+
+ if ((nextIrp = luExtension->CurrentRequest) != NULL) {
+
+ //
+ // Get SRB address from current IRP stack.
+ //
+
+ irpstack = IoGetCurrentIrpStackLocation(nextIrp);
+
+ Srb = (PSCSI_REQUEST_BLOCK)irpstack->Parameters.Others.Argument1;
+
+ //
+ // Update SRB status.
+ //
+
+ Srb->SrbStatus = SrbStatus;
+
+ //
+ // Indicate no bytes transferred.
+ //
+
+ Srb->DataTransferLength = 0;
+
+ //
+ // Set IRP status.
+ //
+
+ nextIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
+
+ //
+ // Move bytes transferred to IRP.
+ //
+
+ nextIrp->IoStatus.Information = Srb->DataTransferLength;
+
+ //
+ // Call notification routine.
+ //
+
+ ScsiPortNotification(RequestComplete,
+ (PVOID)HwDeviceExtension,
+ Srb);
+
+ } // end while
+
+ } // end if ... else
+
+ return;
+
+
+} // end ScsiPortCompleteRequest()
+
+
+VOID
+ScsiPortMoveMemory(
+ IN PVOID WriteBuffer,
+ IN PVOID ReadBuffer,
+ IN ULONG Length
+ )
+
+/*++
+
+Routine Description:
+
+ Copy from one buffer into another.
+
+Arguments:
+
+ ReadBuffer - source
+ WriteBuffer - destination
+ Length - number of bytes to copy
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ RtlMoveMemory(WriteBuffer, ReadBuffer, Length);
+
+} // end ScsiPortMoveMemory()
+
+
+VOID
+ScsiPortStallExecution(
+ ULONG Delay
+ )
+/*++
+
+Routine Description:
+
+ Wait number of microseconds in tight processor loop.
+
+Arguments:
+
+ Delay - number of microseconds to wait.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ FwStallExecution(Delay);
+
+} // end ScsiPortStallExecution()
+
+
+PLOGICAL_UNIT_EXTENSION
+GetLogicalUnitExtension(
+ PDEVICE_EXTENSION deviceExtension,
+ UCHAR TargetId
+ )
+
+/*++
+
+Routine Description:
+
+ Walk logical unit extension list looking for
+ extension with matching target id.
+
+Arguments:
+
+ deviceExtension
+ TargetId
+
+Return Value:
+
+ Requested logical unit extension if found,
+ else NULL.
+
+--*/
+
+{
+ PLOGICAL_UNIT_EXTENSION logicalUnit = deviceExtension->LogicalUnitList;
+
+ while (logicalUnit != NULL) {
+
+ if (logicalUnit->TargetId == TargetId) {
+
+ return logicalUnit;
+ }
+
+ logicalUnit = logicalUnit->NextLogicalUnit;
+ }
+
+ //
+ // Logical unit extension not found.
+ //
+
+ return (PLOGICAL_UNIT_EXTENSION)NULL;
+
+} // end GetLogicalUnitExtension()
+
+#if DBG
+
+
+VOID
+ScsiDebugPrint(
+ ULONG DebugPrintLevel,
+ PCCHAR DebugMessage,
+ ...
+ )
+
+/*++
+
+Routine Description:
+
+ Debug print for all SCSI drivers
+
+Arguments:
+
+ Debug print level between 0 and 3, with 3 being the most verbose.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ va_list ap;
+
+ va_start( ap, DebugMessage );
+
+ if (DebugPrintLevel <= ScsiDebug) {
+
+ char buffer[128];
+
+ vsprintf(buffer, DebugMessage, ap);
+ DbgPrint(buffer);
+ DbgPrint("\r");
+ }
+
+ va_end(ap);
+}
+
+#else
+
+//
+// ScsiDebugPrint stub
+//
+
+VOID
+ScsiDebugPrint(
+ ULONG DebugPrintLevel,
+ PCCHAR DebugMessage,
+ ...
+ )
+{
+}
+
+#endif
+
+
+UCHAR
+ScsiPortReadPortUchar(
+ IN PUCHAR Port
+ )
+
+/*++
+
+Routine Description:
+
+ Read from the specificed port address.
+
+Arguments:
+
+ Port - Supplies a pointer to the port address.
+
+Return Value:
+
+ Returns the value read from the specified port address.
+
+--*/
+
+{
+
+#ifdef MIPS
+
+ return(READ_REGISTER_UCHAR(Port));
+
+#else
+
+ return(READ_PORT_UCHAR(Port));
+
+#endif
+}
+
+USHORT
+ScsiPortReadPortUshort(
+ IN PUSHORT Port
+ )
+
+/*++
+
+Routine Description:
+
+ Read from the specificed port address.
+
+Arguments:
+
+ Port - Supplies a pointer to the port address.
+
+Return Value:
+
+ Returns the value read from the specified port address.
+
+--*/
+
+{
+
+#ifdef MIPS
+
+ return(READ_REGISTER_USHORT(Port));
+
+#else
+
+ return(READ_PORT_USHORT(Port));
+
+#endif
+}
+
+ULONG
+ScsiPortReadPortUlong(
+ IN PULONG Port
+ )
+
+/*++
+
+Routine Description:
+
+ Read from the specificed port address.
+
+Arguments:
+
+ Port - Supplies a pointer to the port address.
+
+Return Value:
+
+ Returns the value read from the specified port address.
+
+--*/
+
+{
+
+#ifdef MIPS
+
+ return(READ_REGISTER_ULONG(Port));
+
+#else
+
+ return(READ_PORT_ULONG(Port));
+
+#endif
+}
+
+UCHAR
+ScsiPortReadRegisterUchar(
+ IN PUCHAR Register
+ )
+
+/*++
+
+Routine Description:
+
+ Read from the specificed register address.
+
+Arguments:
+
+ Register - Supplies a pointer to the register address.
+
+Return Value:
+
+ Returns the value read from the specified register address.
+
+--*/
+
+{
+
+ return(READ_REGISTER_UCHAR(Register));
+
+}
+
+USHORT
+ScsiPortReadRegisterUshort(
+ IN PUSHORT Register
+ )
+
+/*++
+
+Routine Description:
+
+ Read from the specificed register address.
+
+Arguments:
+
+ Register - Supplies a pointer to the register address.
+
+Return Value:
+
+ Returns the value read from the specified register address.
+
+--*/
+
+{
+
+ return(READ_REGISTER_USHORT(Register));
+
+}
+
+ULONG
+ScsiPortReadRegisterUlong(
+ IN PULONG Register
+ )
+
+/*++
+
+Routine Description:
+
+ Read from the specificed register address.
+
+Arguments:
+
+ Register - Supplies a pointer to the register address.
+
+Return Value:
+
+ Returns the value read from the specified register address.
+
+--*/
+
+{
+
+ return(READ_REGISTER_ULONG(Register));
+
+}
+
+VOID
+ScsiPortReadRegisterBufferUchar(
+ IN PUCHAR Register,
+ IN PUCHAR Buffer,
+ IN ULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ Read a buffer of unsigned bytes from the specified register address.
+
+Arguments:
+
+ Register - Supplies a pointer to the port address.
+ Buffer - Supplies a pointer to the data buffer area.
+ Count - The count of items to move.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ READ_REGISTER_BUFFER_UCHAR(Register, Buffer, Count);
+
+}
+
+VOID
+ScsiPortReadRegisterBufferUshort(
+ IN PUSHORT Register,
+ IN PUSHORT Buffer,
+ IN ULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ Read a buffer of unsigned shorts from the specified register address.
+
+Arguments:
+
+ Register - Supplies a pointer to the port address.
+ Buffer - Supplies a pointer to the data buffer area.
+ Count - The count of items to move.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ READ_REGISTER_BUFFER_USHORT(Register, Buffer, Count);
+
+}
+
+VOID
+ScsiPortReadRegisterBufferUlong(
+ IN PULONG Register,
+ IN PULONG Buffer,
+ IN ULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ Read a buffer of unsigned longs from the specified register address.
+
+Arguments:
+
+ Register - Supplies a pointer to the port address.
+ Buffer - Supplies a pointer to the data buffer area.
+ Count - The count of items to move.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ READ_REGISTER_BUFFER_ULONG(Register, Buffer, Count);
+
+}
+
+VOID
+ScsiPortWritePortUchar(
+ IN PUCHAR Port,
+ IN UCHAR Value
+ )
+
+/*++
+
+Routine Description:
+
+ Write to the specificed port address.
+
+Arguments:
+
+ Port - Supplies a pointer to the port address.
+
+ Value - Supplies the value to be written.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+#ifdef MIPS
+
+ WRITE_REGISTER_UCHAR(Port, Value);
+
+#else
+
+ WRITE_PORT_UCHAR(Port, Value);
+
+#endif
+}
+
+VOID
+ScsiPortWritePortUshort(
+ IN PUSHORT Port,
+ IN USHORT Value
+ )
+
+/*++
+
+Routine Description:
+
+ Write to the specificed port address.
+
+Arguments:
+
+ Port - Supplies a pointer to the port address.
+
+ Value - Supplies the value to be written.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+#ifdef MIPS
+
+ WRITE_REGISTER_USHORT(Port, Value);
+
+#else
+
+ WRITE_PORT_USHORT(Port, Value);
+
+#endif
+}
+
+VOID
+ScsiPortWritePortUlong(
+ IN PULONG Port,
+ IN ULONG Value
+ )
+
+/*++
+
+Routine Description:
+
+ Write to the specificed port address.
+
+Arguments:
+
+ Port - Supplies a pointer to the port address.
+
+ Value - Supplies the value to be written.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+#ifdef MIPS
+
+ WRITE_REGISTER_ULONG(Port, Value);
+
+#else
+
+ WRITE_PORT_ULONG(Port, Value);
+
+#endif
+}
+
+VOID
+ScsiPortWriteRegisterUchar(
+ IN PUCHAR Register,
+ IN UCHAR Value
+ )
+
+/*++
+
+Routine Description:
+
+ Write to the specificed register address.
+
+Arguments:
+
+ Register - Supplies a pointer to the register address.
+
+ Value - Supplies the value to be written.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ WRITE_REGISTER_UCHAR(Register, Value);
+
+}
+
+VOID
+ScsiPortWriteRegisterUshort(
+ IN PUSHORT Register,
+ IN USHORT Value
+ )
+
+/*++
+
+Routine Description:
+
+ Write to the specificed register address.
+
+Arguments:
+
+ Register - Supplies a pointer to the register address.
+
+ Value - Supplies the value to be written.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ WRITE_REGISTER_USHORT(Register, Value);
+
+}
+
+VOID
+ScsiPortWriteRegisterUlong(
+ IN PULONG Register,
+ IN ULONG Value
+ )
+
+/*++
+
+Routine Description:
+
+ Write to the specificed register address.
+
+Arguments:
+
+ Register - Supplies a pointer to the register address.
+
+ Value - Supplies the value to be written.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ WRITE_REGISTER_ULONG(Register, Value);
+
+}
+
+VOID
+ScsiPortWriteRegisterBufferUchar(
+ IN PUCHAR Register,
+ IN PUCHAR Buffer,
+ IN ULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ Write a buffer of unsigned bytes from the specified register address.
+
+Arguments:
+
+ Register - Supplies a pointer to the port address.
+ Buffer - Supplies a pointer to the data buffer area.
+ Count - The count of items to move.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ WRITE_REGISTER_BUFFER_UCHAR(Register, Buffer, Count);
+
+}
+
+VOID
+ScsiPortWriteRegisterBufferUshort(
+ IN PUSHORT Register,
+ IN PUSHORT Buffer,
+ IN ULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ Write a buffer of unsigned shorts from the specified register address.
+
+Arguments:
+
+ Register - Supplies a pointer to the port address.
+ Buffer - Supplies a pointer to the data buffer area.
+ Count - The count of items to move.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ WRITE_REGISTER_BUFFER_USHORT(Register, Buffer, Count);
+
+}
+
+VOID
+ScsiPortWriteRegisterBufferUlong(
+ IN PULONG Register,
+ IN PULONG Buffer,
+ IN ULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ Write a buffer of unsigned longs from the specified register address.
+
+Arguments:
+
+ Register - Supplies a pointer to the port address.
+ Buffer - Supplies a pointer to the data buffer area.
+ Count - The count of items to move.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ WRITE_REGISTER_BUFFER_ULONG(Register, Buffer, Count);
+
+}
+
+SCSI_PHYSICAL_ADDRESS
+ScsiPortConvertUlongToPhysicalAddress(
+ ULONG UlongAddress
+ )
+
+{
+ SCSI_PHYSICAL_ADDRESS physicalAddress;
+
+ physicalAddress.HighPart = 0;
+ physicalAddress.LowPart = UlongAddress;
+ return(physicalAddress);
+}
+
+#undef ScsiPortConvertPhysicalAddressToUlong
+
+ULONG
+ScsiPortConvertPhysicalAddressToUlong(
+ SCSI_PHYSICAL_ADDRESS Address
+ )
+{
+
+ return(Address.LowPart);
+}
+
+
+
+PIRP
+InitializeIrp(
+ PFULL_SCSI_REQUEST_BLOCK FullSrb,
+ CCHAR MajorFunction,
+ PVOID DeviceObject,
+ PVOID Buffer,
+ ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ This funcition builds an IRP for use by the SCSI port driver and builds a
+ MDL list.
+
+Arguments:
+
+ FullSrb - Supplies a pointer to the full srb structure which contains the
+ Irp and Mdl.
+
+ MajorFunction - Supplies the major function code to initialize the Irp
+ entry.
+
+ DeviceObject - Supplies the device Object pointer to initialize the Irp
+ with.
+
+ Buffer - Supplies the virual address of the buffer for which the
+ Mdl should be built.
+
+ Length - Supplies the size of buffer for which the Mdl should be built.
+
+Return Value:
+
+ Returns a pointer to the initialized IRP.
+
+--*/
+
+{
+ PIRP irp;
+ PMDL mdl;
+ PULONG pageFrame;
+ ULONG frameNumber;
+ ULONG index;
+ ULONG numberOfPages;
+
+ irp = &FullSrb->Irp;
+ mdl = &FullSrb->Mdl;
+
+ irp->Tail.Overlay.CurrentStackLocation = &FullSrb->IrpStack[IRP_STACK_SIZE];
+
+ if (Buffer != NULL && Length != 0) {
+
+ //
+ // Build the memory descriptor list.
+ //
+
+ irp->MdlAddress = mdl;
+ mdl->Next = NULL;
+ mdl->Size = sizeof(MDL) +
+ ADDRESS_AND_SIZE_TO_SPAN_PAGES(Buffer, Length) * sizeof(ULONG);
+ mdl->StartVa = (PVOID)PAGE_ALIGN(Buffer);
+ mdl->ByteCount = Length;
+ mdl->ByteOffset = BYTE_OFFSET(Buffer);
+ mdl->MappedSystemVa = Buffer;
+ mdl->MdlFlags = MDL_MAPPED_TO_SYSTEM_VA;
+ pageFrame = (PULONG)(mdl + 1);
+ frameNumber = (ULONG)(MmGetPhysicalAddress(mdl->StartVa).QuadPart >> PAGE_SHIFT);
+ numberOfPages = (mdl->ByteCount +
+ mdl->ByteOffset + PAGE_SIZE - 1) >> PAGE_SHIFT;
+ for (index = 0; index < numberOfPages; index += 1) {
+ *pageFrame++ = frameNumber++;
+ }
+
+ } else {
+ irp->MdlAddress = NULL;
+ }
+
+ return(irp);
+}
+
+PVOID
+ScsiPortGetDeviceBase(
+ IN PVOID HwDeviceExtension,
+ IN INTERFACE_TYPE BusType,
+ IN ULONG SystemIoBusNumber,
+ SCSI_PHYSICAL_ADDRESS IoAddress,
+ ULONG NumberOfBytes,
+ BOOLEAN InMemorySpace
+ )
+
+/*++
+
+Routine Description:
+
+ This routine maps an IO address to system address space.
+ Use ScsiPortFreeDeviceBase to unmap address.
+
+Arguments:
+
+ HwDeviceExtension - used to find port device extension.
+ BusType - what type of bus - eisa, mca, isa
+ SystemIoBusNumber - which IO bus (for machines with multiple buses).
+ IoAddress - base device address to be mapped.
+ NumberOfBytes - number of bytes for which address is valid.
+
+Return Value:
+
+ Mapped address
+
+--*/
+
+{
+ PHYSICAL_ADDRESS cardAddress;
+ ULONG addressSpace = InMemorySpace;
+ PVOID mappedAddress;
+
+ if (!HalTranslateBusAddress(
+ BusType, // AdapterInterfaceType
+ SystemIoBusNumber, // SystemIoBusNumber
+ IoAddress, // Bus Address
+ &addressSpace, // AddressSpace
+ &cardAddress // Translated address
+ )) {
+ return NULL;
+ }
+
+ //
+ // Map the device base address into the virtual address space
+ // if the address is in memory space.
+ //
+
+ if (!addressSpace) {
+
+ mappedAddress = MmMapIoSpace(cardAddress,
+ NumberOfBytes,
+ FALSE);
+
+
+ } else {
+
+ mappedAddress = (PVOID)cardAddress.LowPart;
+ }
+
+ return mappedAddress;
+
+} // end ScsiPortGetDeviceBase()
+
+VOID
+ScsiPortFreeDeviceBase(
+ IN PVOID HwDeviceExtension,
+ IN PVOID MappedAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine unmaps an IO address that has been previously mapped
+ to system address space using ScsiPortGetDeviceBase().
+
+Arguments:
+
+ HwDeviceExtension - used to find port device extension.
+ MappedAddress - address to unmap.
+ NumberOfBytes - number of bytes mapped.
+ InIoSpace - addresses in IO space don't get mapped.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER(HwDeviceExtension);
+ UNREFERENCED_PARAMETER(MappedAddress);
+
+ return;
+
+} // end ScsiPortFreeDeviceBase()
+
+ARC_STATUS
+GetAdapterCapabilities(
+ IN PDEVICE_OBJECT PortDeviceObject,
+ OUT PIO_SCSI_CAPABILITIES *PortCapabilities
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+ Status is returned.
+
+--*/
+
+{
+ *PortCapabilities = &((PDEVICE_EXTENSION)PortDeviceObject->DeviceExtension)
+ ->Capabilities;
+
+ return(ESUCCESS);
+} // end GetAdapterCapabilities()
+
+
+ARC_STATUS
+GetInquiryData(
+ IN PDEVICE_OBJECT PortDeviceObject,
+ OUT PSCSI_CONFIGURATION_INFO *ConfigInfo
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a request to a port driver to return
+ configuration information.
+
+Arguments:
+
+ The address of the configuration information is returned in
+ the formal parameter ConfigInfo.
+
+Return Value:
+
+ Status is returned.
+
+--*/
+{
+ *ConfigInfo = ((PDEVICE_EXTENSION)PortDeviceObject->DeviceExtension)
+ ->ScsiInfo;
+ return(ESUCCESS);
+} // end GetInquiryData()
+
+NTSTATUS
+SpInitializeConfiguration(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN PHW_INITIALIZATION_DATA HwInitData,
+ OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ IN BOOLEAN InitialCall
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes the port configuration information structure.
+ Any necessary information is extracted from the registery.
+
+Arguments:
+
+ DeviceExtension - Supplies the device extension.
+
+ HwInitializationData - Supplies the initial miniport data.
+
+ ConfigInfo - Supplies the configuration information to be
+ initialized.
+
+ InitialCall - Indicates that this is first call to this function.
+ If InitialCall is FALSE, then the perivous configuration information
+ is used to determine the new information.
+
+Return Value:
+
+ Returns a status indicating the success or fail of the initializaiton.
+
+--*/
+
+{
+#ifdef i386
+ extern ULONG MachineType;
+#endif
+
+ ULONG j;
+
+ //
+ // If this is the initial call then zero the information and set
+ // the structure to the uninitialized values.
+ //
+
+ if (InitialCall) {
+
+ RtlZeroMemory(ConfigInfo, sizeof(PORT_CONFIGURATION_INFORMATION));
+
+ ConfigInfo->Length = sizeof(PORT_CONFIGURATION_INFORMATION);
+ ConfigInfo->AdapterInterfaceType = HwInitData->AdapterInterfaceType;
+ ConfigInfo->InterruptMode = Latched;
+ ConfigInfo->MaximumTransferLength = 0xffffffff;
+ ConfigInfo->NumberOfPhysicalBreaks = 0xffffffff;
+ ConfigInfo->DmaChannel = 0xffffffff;
+ ConfigInfo->NumberOfAccessRanges = HwInitData->NumberOfAccessRanges;
+ ConfigInfo->MaximumNumberOfTargets = 8;
+
+#if defined(_MIPS_) || defined(_ALPHA_) || defined(_PPC_)
+ {
+ PCONFIGURATION_COMPONENT Component;
+ PCM_SCSI_DEVICE_DATA ScsiDeviceData;
+ UCHAR Buffer[sizeof(CM_PARTIAL_RESOURCE_LIST) +
+ (sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * 5) +
+ sizeof(CM_SCSI_DEVICE_DATA)];
+ PCM_PARTIAL_RESOURCE_LIST Descriptor = (PCM_PARTIAL_RESOURCE_LIST)&Buffer;
+ ULONG Count;
+ ULONG ScsiHostId;
+
+ if (((Component = ArcGetComponent("scsi(0)")) != NULL) &&
+ (Component->Class == AdapterClass) && (Component->Type == ScsiAdapter) &&
+ (ArcGetConfigurationData((PVOID)Descriptor, Component) == ESUCCESS) &&
+ ((Count = Descriptor->Count) < 6)) {
+
+ ScsiDeviceData = (PCM_SCSI_DEVICE_DATA)&Descriptor->PartialDescriptors[Count];
+
+ if (ScsiDeviceData->HostIdentifier > 7) {
+ ScsiHostId = 7;
+ } else {
+ ScsiHostId = ScsiDeviceData->HostIdentifier;
+ }
+ } else {
+ ScsiHostId = 7;
+ }
+
+ for (j = 0; j < 8; j++) {
+ ConfigInfo->InitiatorBusId[j] = ScsiHostId;
+ }
+ }
+
+#else
+
+ for (j = 0; j < 8; j++) {
+ ConfigInfo->InitiatorBusId[j] = ~0;
+ }
+
+#endif
+
+#if defined(i386)
+ switch (HwInitData->AdapterInterfaceType) {
+ case Isa:
+ if ((MachineType & 0xff) == MACHINE_TYPE_ISA) {
+ return(STATUS_SUCCESS);
+ }
+ case Eisa:
+ if ((MachineType & 0xff) == MACHINE_TYPE_EISA) {
+ return(STATUS_SUCCESS);
+ } else {
+ return(STATUS_DEVICE_DOES_NOT_EXIST);
+ }
+ case MicroChannel:
+ if ((MachineType & 0xff) == MACHINE_TYPE_MCA) {
+ return(STATUS_SUCCESS);
+ } else {
+ return(STATUS_DEVICE_DOES_NOT_EXIST);
+ }
+ case PCIBus:
+ return(STATUS_SUCCESS);
+ default:
+ return(STATUS_DEVICE_DOES_NOT_EXIST);
+ }
+#elif defined(_MIPS_)
+ if (HwInitData->AdapterInterfaceType != Internal) {
+ return(STATUS_DEVICE_DOES_NOT_EXIST);
+ }
+#elif defined(_ALPHA_)
+ if ( (HwInitData->AdapterInterfaceType != Internal) &&
+ (HwInitData->AdapterInterfaceType != Eisa) &&
+ (HwInitData->AdapterInterfaceType != PCIBus) &&
+ (HwInitData->AdapterInterfaceType != Isa) ) {
+ return(STATUS_DEVICE_DOES_NOT_EXIST);
+ }
+#elif defined(_PPC_)
+ if ( (HwInitData->AdapterInterfaceType != Internal) &&
+ (HwInitData->AdapterInterfaceType != Eisa) &&
+ (HwInitData->AdapterInterfaceType != Isa) ) {
+ return(STATUS_DEVICE_DOES_NOT_EXIST);
+ }
+#endif
+
+ return(STATUS_SUCCESS);
+
+ } else {
+
+ return(STATUS_DEVICE_DOES_NOT_EXIST);
+ }
+}
+
+
+NTSTATUS
+SpGetCommonBuffer(
+ PDEVICE_EXTENSION DeviceExtension,
+ ULONG NonCachedExtensionSize
+ )
+/*++
+
+Routine Description:
+
+ This routine determines the required size of the common buffer. Allocates
+ the common buffer and finally sets up the srb extension zone. This routine
+ expects that the adapter object has already been allocated.
+
+Arguments:
+
+ DeviceExtension - Supplies a pointer to the device extension.
+
+ NonCachedExtensionSize - Supplies the size of the noncached device
+ extension for the mini-port driver.
+
+Return Value:
+
+ Returns the status of the allocate operation.
+
+--*/
+
+{
+ PHYSICAL_ADDRESS pAddress;
+ PVOID buffer;
+ ULONG length;
+ ULONG blockSize;
+
+ //
+ // Calculate the block size for the zone elements based on the Srb
+ // Extension.
+ //
+
+ blockSize = DeviceExtension->SrbExtensionSize;
+
+ //
+ // Last three bits of blocksize must be zero.
+ // Round blocksize up.
+ //
+
+ blockSize = (blockSize + 7) & ~7;
+
+ length = NonCachedExtensionSize + blockSize * MINIMUM_SRB_EXTENSIONS;
+
+ //
+ // Round the length up to a page size, since HalGetCommonBuffer allocates
+ // in pages anyway.
+ //
+
+ length = ROUND_TO_PAGES(length);
+
+ //
+ // Allocate one page for noncached deviceextension
+ // and srbextension zoned pool.
+ //
+
+ if (DeviceExtension->DmaAdapterObject == NULL) {
+
+ //
+ // Since there is no adapter just allocate from non-paged pool.
+ //
+
+ if (buffer = MmAllocateNonCachedMemory(length)) {
+ DeviceExtension->PhysicalZoneBase = MmGetPhysicalAddress(buffer).LowPart;
+ }
+
+ } else {
+#ifdef AXP_FIRMWARE
+ buffer = HalAllocateCommonBuffer(DeviceExtension->DmaAdapterObject,
+ length,
+ &pAddress,
+ FALSE );
+ DeviceExtension->PhysicalZoneBase = pAddress.LowPart;
+#else
+ if (buffer = MmAllocateNonCachedMemory(length)) {
+ DeviceExtension->PhysicalZoneBase = MmGetPhysicalAddress(buffer).LowPart;
+ }
+#endif
+ }
+
+ if (buffer == NULL) {
+ return ENOMEM;
+ }
+
+ //
+ // Truncate Physical address to 32 bits.
+ //
+ // Determine length and starting address of zone.
+ // If noncached device extension required then
+ // subtract size from page leaving rest for zone.
+ //
+
+
+ length -= NonCachedExtensionSize;
+
+ DeviceExtension->NonCachedExtension = (PUCHAR)buffer + length;
+
+ if (DeviceExtension->SrbExtensionSize) {
+
+ //
+ // Get block size.
+ //
+
+ blockSize = DeviceExtension->SrbExtensionSize;
+
+ //
+ // Record starting virtual address of zone.
+ //
+
+ DeviceExtension->SrbExtensionZonePool = buffer;
+ DeviceExtension->SrbExtensionPointer = buffer;
+ DeviceExtension->SrbExtensionSize = blockSize;
+
+
+ } else {
+ DeviceExtension->SrbExtensionZonePool = NULL;
+ }
+
+ return(ESUCCESS);
+}
+
+PVOID
+ScsiPortGetUncachedExtension(
+ IN PVOID HwDeviceExtension,
+ IN PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ IN ULONG NumberOfBytes
+ )
+/*++
+
+Routine Description:
+
+ This function allocates a common buffer to be used as the uncached device
+ extension for the mini-port driver. This function will also allocate any
+ required SRB extensions. The DmaAdapter is allocated if it has not been
+ allocated previously.
+
+Arguments:
+
+ DeviceExtension - Supplies a pointer to the mini-ports device extension.
+
+ ConfigInfo - Supplies a pointer to the partially initialized configuraiton
+ information. This is used to get an DMA adapter object.
+
+ NumberOfBytes - Supplies the size of the extension which needs to be
+ allocated
+
+Return Value:
+
+ A pointer to the uncached device extension or NULL if the extension could
+ not be allocated or was previously allocated.
+
+--*/
+
+{
+ DEVICE_DESCRIPTION deviceDescription;
+ PDEVICE_EXTENSION deviceExtension =
+ ((PDEVICE_EXTENSION) HwDeviceExtension) - 1;
+ NTSTATUS status;
+ ULONG numberOfPageBreaks;
+
+ //
+ // Make sure that an common buffer has not already been allocated.
+ //
+
+ if (deviceExtension->SrbExtensionZonePool != NULL) {
+ return(NULL);
+ }
+
+ if ( deviceExtension->DmaAdapterObject == NULL ) {
+
+ RtlZeroMemory( &deviceDescription, sizeof(DEVICE_DESCRIPTION) );
+
+ deviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
+ deviceDescription.DmaChannel = ConfigInfo->DmaChannel;
+ deviceDescription.InterfaceType = ConfigInfo->AdapterInterfaceType;
+ deviceDescription.BusNumber = ConfigInfo->SystemIoBusNumber;
+ deviceDescription.DmaWidth = ConfigInfo->DmaWidth;
+ deviceDescription.DmaSpeed = ConfigInfo->DmaSpeed;
+ deviceDescription.DmaPort = ConfigInfo->DmaPort;
+ deviceDescription.Dma32BitAddresses = ConfigInfo->Dma32BitAddresses;
+ deviceDescription.MaximumLength = ConfigInfo->MaximumTransferLength;
+ deviceDescription.ScatterGather = ConfigInfo->ScatterGather;
+ deviceDescription.Master = ConfigInfo->Master;
+ deviceDescription.AutoInitialize = FALSE;
+ deviceDescription.DemandMode = FALSE;
+
+ // BugBug: Make the 0x11000 a define when there is one.
+ if (ConfigInfo->MaximumTransferLength > 0x11000) {
+
+ deviceDescription.MaximumLength = 0x11000;
+
+ } else {
+
+ deviceDescription.MaximumLength = ConfigInfo->MaximumTransferLength;
+
+ }
+
+ deviceExtension->DmaAdapterObject = HalGetAdapter(
+ &deviceDescription,
+ &numberOfPageBreaks
+ );
+
+ //
+ // Set maximum number of page breaks.
+ //
+
+ if (numberOfPageBreaks > ConfigInfo->NumberOfPhysicalBreaks) {
+ deviceExtension->Capabilities.MaximumPhysicalPages =
+ ConfigInfo->NumberOfPhysicalBreaks;
+ } else {
+ deviceExtension->Capabilities.MaximumPhysicalPages =
+ numberOfPageBreaks;
+ }
+
+ }
+
+ //
+ // Allocate the common buffer.
+ //
+
+ status = SpGetCommonBuffer( deviceExtension, NumberOfBytes);
+
+ if (status != ESUCCESS) {
+ return(NULL);
+ }
+
+ return(deviceExtension->NonCachedExtension);
+}
+
+ULONG
+ScsiPortGetBusData(
+ IN PVOID DeviceExtension,
+ IN ULONG BusDataType,
+ IN ULONG SystemIoBusNumber,
+ IN ULONG SlotNumber,
+ IN PVOID Buffer,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ The function returns the bus data for an adapter slot or CMOS address.
+
+Arguments:
+
+ BusDataType - Supplies the type of bus.
+
+ BusNumber - Indicates which bus.
+
+ Buffer - Supplies the space to store the data.
+
+ Length - Supplies a count in bytes of the maximum amount to return.
+
+Return Value:
+
+ Returns the amount of data stored into the buffer.
+
+--*/
+
+{
+ ULONG DataLength = 0;
+
+ PDEVICE_EXTENSION deviceExtension =
+ (PDEVICE_EXTENSION) DeviceExtension - 1;
+
+ //
+ // If the length is non-zero, the the requested data.
+ //
+
+ if (Length != 0) {
+
+ return( HalGetBusData( BusDataType,
+ SystemIoBusNumber,
+ SlotNumber,
+ Buffer,
+ Length
+ ));
+ }
+
+ //
+ // Free any previously allocated data.
+ //
+
+ if (deviceExtension->MapRegisterBase != NULL) {
+ ExFreePool(deviceExtension->MapRegisterBase);
+ }
+
+ if (BusDataType == EisaConfiguration) {
+
+#if 0
+ //
+ // Deteremine the length to allocate based on the number of functions
+ // for the slot.
+ //
+
+ Length = HalGetBusData( BusDataType,
+ SystemIoBusNumber,
+ SlotNumber,
+ &slotInformation,
+ sizeof(CM_EISA_SLOT_INFORMATION));
+
+
+ if (Length < sizeof(CM_EISA_SLOT_INFORMATION)) {
+
+ //
+ // The data is messed up since this should never occur
+ //
+
+ DebugPrint((1, "ScsiPortGetBusData: Slot information not returned. Length = %d\n", Length));
+ return(0);
+ }
+
+ //
+ // Calculate the required length based on the number of functions.
+ //
+
+ Length = sizeof(CM_EISA_SLOT_INFORMATION) +
+ (sizeof(CM_EISA_FUNCTION_INFORMATION) * slotInformation.NumberFunctions);
+
+#else
+
+ //
+ // Since the loader does not really support freeing data and the EISA
+ // configuration data can be very large. Hal get bus data has be changed
+ // to accept a length of zero for EIAS configuration data.
+ //
+
+ DataLength = HalGetBusData( BusDataType,
+ SystemIoBusNumber,
+ SlotNumber,
+ Buffer,
+ Length
+ );
+
+ DebugPrint((1, "ScsiPortGetBusData: Returning data. Length = %d\n", DataLength));
+ return(DataLength);
+#endif
+
+ } else {
+
+ Length = PAGE_SIZE;
+ }
+
+ deviceExtension->MapRegisterBase = ExAllocatePool(NonPagedPool, Length);
+
+ if (deviceExtension->MapRegisterBase == NULL) {
+ DebugPrint((1, "ScsiPortGetBusData: Memory allocation failed. Length = %d\n", Length));
+ return(0);
+ }
+
+ //
+ // Return the pointer to the mini-port driver.
+ //
+
+ *((PVOID *)Buffer) = deviceExtension->MapRegisterBase;
+
+ DataLength = HalGetBusData( BusDataType,
+ SystemIoBusNumber,
+ SlotNumber,
+ deviceExtension->MapRegisterBase,
+ Length
+ );
+
+ return(DataLength);
+}
+
+PSCSI_REQUEST_BLOCK
+ScsiPortGetSrb(
+ IN PVOID HwDeviceExtension,
+ IN UCHAR PathId,
+ IN UCHAR TargetId,
+ IN UCHAR Lun,
+ IN LONG QueueTag
+ )
+
+/*++
+
+Routine Description:
+
+ This routine retrieves an active SRB for a particuliar logical unit.
+
+Arguments:
+
+ HwDeviceExtension
+ PathId, TargetId, Lun - identify logical unit on SCSI bus.
+ QueueTag - -1 indicates request is not tagged.
+
+Return Value:
+
+ SRB, if one exists. Otherwise, NULL.
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension =
+ ((PDEVICE_EXTENSION) HwDeviceExtension) - 1;
+ PLOGICAL_UNIT_EXTENSION luExtension;
+ PIRP irp;
+ PIO_STACK_LOCATION irpstack;
+
+
+ luExtension = GetLogicalUnitExtension(deviceExtension, TargetId);
+
+
+ if (luExtension == NULL) {
+ return(NULL);
+ }
+
+ irp = luExtension->CurrentRequest;
+ irpstack = IoGetCurrentIrpStackLocation(irp);
+ return ((PSCSI_REQUEST_BLOCK)irpstack->Parameters.Others.Argument1);
+
+} // end ScsiPortGetSrb()
+
+BOOLEAN
+ScsiPortValidateRange(
+ IN PVOID HwDeviceExtension,
+ IN INTERFACE_TYPE BusType,
+ IN ULONG SystemIoBusNumber,
+ IN SCSI_PHYSICAL_ADDRESS IoAddress,
+ IN ULONG NumberOfBytes,
+ IN BOOLEAN InIoSpace
+ )
+
+/*++
+
+Routine Description:
+
+ This routine should take an IO range and make sure that it is not already
+ in use by another adapter. This allows miniport drivers to probe IO where
+ an adapter could be, without worrying about messing up another card.
+
+Arguments:
+
+ HwDeviceExtension - Used to find scsi managers internal structures
+ BusType - EISA, PCI, PC/MCIA, MCA, ISA, what?
+ SystemIoBusNumber - Which system bus?
+ IoAddress - Start of range
+ NumberOfBytes - Length of range
+ InIoSpace - Is range in IO space?
+
+Return Value:
+
+ TRUE if range not claimed by another driver.
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension =
+ ((PDEVICE_EXTENSION) HwDeviceExtension) - 1;
+
+ //
+ // This is not implemented in NT.
+ //
+
+ return TRUE;
+}
+
+VOID
+ScsiPortReadPortBufferUchar(
+ IN PUCHAR Port,
+ IN PUCHAR Buffer,
+ IN ULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ Read a buffer of unsigned bytes from the specified port address.
+
+Arguments:
+
+ Port - Supplies a pointer to the port address.
+ Buffer - Supplies a pointer to the data buffer area.
+ Count - The count of items to move.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ READ_PORT_BUFFER_UCHAR(Port, Buffer, Count);
+
+}
+
+VOID
+ScsiPortReadPortBufferUshort(
+ IN PUSHORT Port,
+ IN PUSHORT Buffer,
+ IN ULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ Read a buffer of unsigned shorts from the specified port address.
+
+Arguments:
+
+ Port - Supplies a pointer to the port address.
+ Buffer - Supplies a pointer to the data buffer area.
+ Count - The count of items to move.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ READ_PORT_BUFFER_USHORT(Port, Buffer, Count);
+
+}
+
+VOID
+ScsiPortReadPortBufferUlong(
+ IN PULONG Port,
+ IN PULONG Buffer,
+ IN ULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ Read a buffer of unsigned longs from the specified port address.
+
+Arguments:
+
+ Port - Supplies a pointer to the port address.
+ Buffer - Supplies a pointer to the data buffer area.
+ Count - The count of items to move.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ READ_PORT_BUFFER_ULONG(Port, Buffer, Count);
+
+}
+
+VOID
+ScsiPortWritePortBufferUchar(
+ IN PUCHAR Port,
+ IN PUCHAR Buffer,
+ IN ULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ Write a buffer of unsigned bytes from the specified port address.
+
+Arguments:
+
+ Port - Supplies a pointer to the port address.
+ Buffer - Supplies a pointer to the data buffer area.
+ Count - The count of items to move.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ WRITE_PORT_BUFFER_UCHAR(Port, Buffer, Count);
+
+}
+
+VOID
+ScsiPortWritePortBufferUshort(
+ IN PUSHORT Port,
+ IN PUSHORT Buffer,
+ IN ULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ Write a buffer of unsigned shorts from the specified port address.
+
+Arguments:
+
+ Port - Supplies a pointer to the port address.
+ Buffer - Supplies a pointer to the data buffer area.
+ Count - The count of items to move.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ WRITE_PORT_BUFFER_USHORT(Port, Buffer, Count);
+
+}
+
+VOID
+ScsiPortWritePortBufferUlong(
+ IN PULONG Port,
+ IN PULONG Buffer,
+ IN ULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ Write a buffer of unsigned longs from the specified port address.
+
+Arguments:
+
+ Port - Supplies a pointer to the port address.
+ Buffer - Supplies a pointer to the data buffer area.
+ Count - The count of items to move.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ WRITE_PORT_BUFFER_ULONG(Port, Buffer, Count);
+
+}
+
+
+BOOLEAN
+GetPciConfiguration(
+ PDRIVER_OBJECT DriverObject,
+ PDEVICE_OBJECT DeviceObject,
+ PHW_INITIALIZATION_DATA HwInitializationData,
+ PPORT_CONFIGURATION_INFORMATION ConfigInformation,
+ PVOID RegistryPath,
+ PULONG BusNumber,
+ PULONG SlotNumber,
+ PULONG FunctionNumber
+ )
+
+/*++
+
+Routine Description:
+
+ Walk PCI slot information looking for Vendor and Product ID matches.
+ Get slot information for matches and register with hal for the resources.
+
+Arguments:
+
+ DriverObject - Miniport driver object.
+ DeviceObject - Represents this adapter.
+ HwInitializationData - Miniport description.
+ ConfigInformation - Template for configuration information passed to a
+ miniport driver via the FindAdapter routine.
+ RegistryPath - Service key path.
+ BusNumber - Starting PCI bus for this search.
+ SlotNumber - Starting slot number for this search.
+ FunctionNumber - Starting function number for this search.
+
+Return Value:
+
+ TRUE if card found. BusNumber and Slotnumber will return values that
+ should be used to continue the search for additional cards, when a card
+ is found.
+
+--*/
+
+{
+ PCI_SLOT_NUMBER slotData;
+ PPCI_COMMON_CONFIG pciData;
+ ULONG pciBuffer;
+ ULONG pciBus;
+ ULONG slotNumber;
+ ULONG functionNumber;
+ ULONG i;
+ ULONG length;
+ ULONG rangeNumber = 0;
+ PACCESS_RANGE accessRange;
+ BOOLEAN moreSlots = TRUE;
+ ULONG status;
+ PCM_RESOURCE_LIST resourceList;
+ PCM_PARTIAL_RESOURCE_DESCRIPTOR resourceDescriptor;
+ UNICODE_STRING unicodeString;
+ UCHAR vendorString[5];
+ UCHAR deviceString[5];
+
+ pciData = (PPCI_COMMON_CONFIG)&pciBuffer;
+
+ //
+ //
+ // typedef struct _PCI_SLOT_NUMBER {
+ // union {
+ // struct {
+ // ULONG DeviceNumber:5;
+ // ULONG FunctionNumber:3;
+ // ULONG Reserved:24;
+ // } bits;
+ // ULONG AsULONG;
+ // } u;
+ // } PCI_SLOT_NUMBER, *PPCI_SLOT_NUMBER;
+ //
+
+ slotData.u.AsULONG = 0;
+
+ //
+ // Search each PCI bus.
+ //
+
+ for (pciBus = *BusNumber; moreSlots && pciBus < 256; pciBus++) {
+
+ //
+ // Look at each device.
+ //
+
+ for (slotNumber = *SlotNumber;
+ moreSlots && slotNumber < 32;
+ slotNumber++) {
+
+ slotData.u.bits.DeviceNumber = slotNumber;
+
+ //
+ // Look at each function.
+ //
+
+ for (functionNumber = *FunctionNumber;
+ moreSlots && functionNumber < 8;
+ functionNumber++) {
+
+ slotData.u.bits.FunctionNumber = functionNumber;
+ length = HalGetBusDataByOffset (
+ PCIConfiguration,
+ pciBus,
+ slotData.u.AsULONG,
+ pciData,
+ 0,
+ sizeof(ULONG));
+
+ if (length == 0) {
+
+ //
+ // Out of PCI buses, all done.
+ //
+
+ moreSlots = FALSE;
+ break;
+ }
+
+ if (pciData->VendorID == PCI_INVALID_VENDORID) {
+
+ //
+ // No PCI device, or no more functions on device
+ // move to next PCI device.
+ //
+
+ break;
+ }
+
+ //
+ // Translate hex ids to strings.
+ //
+
+ sprintf(vendorString, "%04x", pciData->VendorID);
+ sprintf(deviceString, "%04x", pciData->DeviceID);
+
+ DebugPrint((1,
+ "GetPciConfiguration: Bus %x Slot %x Function %x Vendor %s Product %s\n",
+ pciBus,
+ slotNumber,
+ functionNumber,
+ vendorString,
+ deviceString));
+
+ //
+ // Compare strings.
+ //
+
+ if (strncmp(vendorString,
+ HwInitializationData->VendorId,
+ HwInitializationData->VendorIdLength) ||
+ strncmp(deviceString,
+ HwInitializationData->DeviceId,
+ HwInitializationData->DeviceIdLength)) {
+
+ //
+ // Not our PCI device. Try next device/function
+ //
+
+ continue;
+ }
+
+ //
+ // This is the miniport drivers slot. Allocate the
+ // resources.
+ //
+
+ RtlInitUnicodeString(&unicodeString, L"ScsiAdapter");
+
+
+ status = HalAssignSlotResources(RegistryPath,
+ &unicodeString,
+ DriverObject,
+ DeviceObject,
+ PCIBus,
+ pciBus,
+ slotData.u.AsULONG,
+ &resourceList);
+
+ if (!NT_SUCCESS(status)) {
+ break;
+ }
+
+ //
+ // Walk resource list to update configuration information.
+ //
+
+ for (i = 0;
+ i < resourceList->List->PartialResourceList.Count;
+ i++) {
+
+ //
+ // Get resource descriptor.
+ //
+
+ resourceDescriptor =
+ &resourceList->List->PartialResourceList.PartialDescriptors[i];
+
+ //
+ // Check for interrupt descriptor.
+ //
+
+ if (resourceDescriptor->Type == CmResourceTypeInterrupt) {
+ ConfigInformation->BusInterruptLevel =
+ resourceDescriptor->u.Interrupt.Level;
+ ConfigInformation->BusInterruptVector =
+ resourceDescriptor->u.Interrupt.Vector;
+
+ //
+ // Check interrupt mode.
+ //
+
+ if ((resourceDescriptor->Flags ==
+ CM_RESOURCE_INTERRUPT_LATCHED)) {
+ ConfigInformation->InterruptMode = Latched;
+ } else if (resourceDescriptor->Flags ==
+ CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE) {
+ ConfigInformation->InterruptMode = LevelSensitive;
+ }
+ }
+
+ //
+ // Check for port descriptor.
+ //
+
+ if (resourceDescriptor->Type == CmResourceTypePort) {
+
+ //
+ // Verify range count does not exceed what the
+ // miniport indicated.
+ //
+
+ if (HwInitializationData->NumberOfAccessRanges > rangeNumber) {
+
+ //
+ // Get next access range.
+ //
+
+ accessRange =
+ &((*(ConfigInformation->AccessRanges))[rangeNumber]);
+
+ accessRange->RangeStart =
+ resourceDescriptor->u.Port.Start;
+ accessRange->RangeLength =
+ resourceDescriptor->u.Port.Length;
+
+ accessRange->RangeInMemory = FALSE;
+ rangeNumber++;
+ }
+ }
+
+ //
+ // Check for memory descriptor.
+ //
+
+ if (resourceDescriptor->Type == CmResourceTypeMemory) {
+
+ //
+ // Verify range count does not exceed what the
+ // miniport indicated.
+ //
+
+ if (HwInitializationData->NumberOfAccessRanges > rangeNumber) {
+
+ //
+ // Get next access range.
+ //
+
+ accessRange =
+ &((*(ConfigInformation->AccessRanges))[rangeNumber]);
+
+ accessRange->RangeStart =
+ resourceDescriptor->u.Memory.Start;
+ accessRange->RangeLength =
+ resourceDescriptor->u.Memory.Length;
+
+ accessRange->RangeInMemory = TRUE;
+ rangeNumber++;
+ }
+ }
+
+ //
+ // Check for DMA descriptor.
+ //
+
+ if (resourceDescriptor->Type == CmResourceTypeDma) {
+ ConfigInformation->DmaChannel =
+ resourceDescriptor->u.Dma.Channel;
+ ConfigInformation->DmaPort =
+ resourceDescriptor->u.Dma.Port;
+ }
+
+ } // next resource descriptor
+
+ ExFreePool(resourceList);
+
+ //
+ // Update bus and slot numbers.
+ //
+
+ *BusNumber = pciBus;
+ *SlotNumber = slotNumber;
+ *FunctionNumber = functionNumber + 1;
+ ConfigInformation->SystemIoBusNumber = pciBus;
+ ConfigInformation->SlotNumber = slotData.u.AsULONG;
+
+ ConfigInformation->SlotNumber = slotData.u.AsULONG;
+
+ return TRUE;
+
+ } // next PCI function
+
+ *FunctionNumber = 0;
+
+ } // next PCI slot
+
+ *SlotNumber = 0;
+
+ } // next PCI bus
+
+ return FALSE;
+
+} // GetPciConfiguration()
+
+
+ULONG
+ScsiPortSetBusDataByOffset(
+ IN PVOID DeviceExtension,
+ IN ULONG BusDataType,
+ IN ULONG SystemIoBusNumber,
+ IN ULONG SlotNumber,
+ IN PVOID Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ The function returns writes bus data to a specific offset within a slot.
+
+Arguments:
+
+ DeviceExtension - State information for a particular adapter.
+
+ BusDataType - Supplies the type of bus.
+
+ SystemIoBusNumber - Indicates which system IO bus.
+
+ SlotNumber - Indicates which slot.
+
+ Buffer - Supplies the data to write.
+
+ Offset - Byte offset to begin the write.
+
+ Length - Supplies a count in bytes of the maximum amount to return.
+
+Return Value:
+
+ Number of bytes written.
+
+--*/
+
+{
+ return(HalSetBusDataByOffset(BusDataType,
+ SystemIoBusNumber,
+ SlotNumber,
+ Buffer,
+ Offset,
+ Length));
+
+} // end ScsiPortSetBusDataByOffset()
+
+#endif /* DECSTATION */
diff --git a/private/ntos/boot/lib/scsidisk.c b/private/ntos/boot/lib/scsidisk.c
new file mode 100644
index 000000000..157c558a5
--- /dev/null
+++ b/private/ntos/boot/lib/scsidisk.c
@@ -0,0 +1,3225 @@
+#if defined(JAZZ) || defined(i386) || defined(_ALPHA_)
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ scsidisk.c
+
+Abstract:
+
+ This module implements the hard disk boot driver for the Jazz system.
+
+Author:
+
+ Jeff Havens (jhavens) 8-12-1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+
+#ifdef MIPS
+#include "..\fw\mips\fwp.h"
+#undef KeGetDcacheFillSize
+#define KeGetDcacheFillSize() BlDcacheFillSize
+#elif defined(_ALPHA_)
+#include "..\fw\alpha\fwp.h"
+#undef KeGetDcacheFillSize
+#define KeGetDcacheFillSize() BlDcacheFillSize
+#else
+#include "bootx86.h"
+#undef KeGetDcacheFillSize
+#define KeGetDcacheFillSize() 4
+#endif
+#include "ntdddisk.h"
+#include "scsi.h"
+#include "scsiboot.h"
+#include "stdio.h"
+#include "string.h"
+
+#if defined(SETUP) && i386
+#include "spscsi.h"
+#endif
+
+
+
+//
+// SCSI driver constants.
+//
+
+#define MAXIMUM_NUMBER_SECTORS 128 // maximum number of transfer sector
+#define MAXIMUM_NUMBER_RETRIES 8 // maximum number of read/write retries
+#define MAXIMUM_SECTOR_SIZE 2048 // define the maximum supported sector size
+#define MODE_DATA_SIZE 192
+#define HITACHI_MODE_DATA_SIZE 12
+
+CHAR ScsiTempBuffer[MAXIMUM_SECTOR_SIZE + 128];
+
+
+//
+// Define device driver prototypes.
+//
+
+NTSTATUS
+ScsiDiskBootPartitionOpen(
+ IN ULONG FileId,
+ IN UCHAR DeviceUnit,
+ IN UCHAR PartitionNumber
+ );
+
+ARC_STATUS
+ScsiDiskClose (
+ IN ULONG FileId
+ );
+
+ARC_STATUS
+ScsiDiskMount (
+ IN PCHAR MountPath,
+ IN MOUNT_OPERATION Operation
+ );
+
+ARC_STATUS
+ScsiDiskOpen (
+ IN PCHAR OpenPath,
+ IN OPEN_MODE OpenMode,
+ OUT PULONG FileId
+ );
+
+ARC_STATUS
+ScsiDiskRead (
+ IN ULONG FileId,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ );
+
+ARC_STATUS
+ScsiDiskGetReadStatus (
+ IN ULONG FileId
+ );
+
+ARC_STATUS
+ScsiDiskSeek (
+ IN ULONG FileId,
+ IN PLARGE_INTEGER Offset,
+ IN SEEK_MODE SeekMode
+ );
+
+ARC_STATUS
+ScsiDiskWrite (
+ IN ULONG FileId,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ );
+
+ARC_STATUS
+ScsiDiskGetFileInformation (
+ IN ULONG FileId,
+ OUT PFILE_INFORMATION Finfo
+ );
+
+NTSTATUS
+ScsiDiskBootIO (
+ IN PMDL MdlAddress,
+ IN ULONG LogicalBlock,
+ IN PPARTITION_CONTEXT PartitionContext,
+ IN BOOLEAN Operation
+ );
+
+VOID
+ScsiDiskBootSetup (
+ VOID
+ );
+
+VOID
+ScsiPortExecute(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+VOID
+ScsiDiskStartUnit(
+ IN PPARTITION_CONTEXT PartitionContext
+ );
+
+VOID
+ScsiDiskStartUnit(
+ IN PPARTITION_CONTEXT PartitionContext
+ );
+
+VOID
+ScsiDiskFilterBad(
+ IN PPARTITION_CONTEXT PartitionContext
+ );
+
+ULONG
+ClassModeSense(
+ IN PPARTITION_CONTEXT Context,
+ IN PCHAR ModeSenseBuffer,
+ IN ULONG Length,
+ IN UCHAR PageMode
+ );
+
+PVOID
+ClassFindModePage(
+ IN PCHAR ModeSenseBuffer,
+ IN ULONG Length,
+ IN UCHAR PageMode
+ );
+BOOLEAN
+IsFloppyDevice(
+ PPARTITION_CONTEXT Context
+ );
+
+BOOLEAN
+CheckFileId(
+ ULONG FileId
+ );
+
+
+//
+// Define static data.
+//
+
+BL_DEVICE_ENTRY_TABLE ScsiDiskEntryTable = {
+ ScsiDiskClose,
+ ScsiDiskMount,
+ ScsiDiskOpen,
+ ScsiDiskRead,
+ ScsiDiskGetReadStatus,
+ ScsiDiskSeek,
+ ScsiDiskWrite,
+ ScsiDiskGetFileInformation,
+ (PARC_SET_FILE_INFO_ROUTINE)NULL
+ };
+
+
+//
+// Global poiter for buffers.
+//
+
+PREAD_CAPACITY_DATA ReadCapacityBuffer;
+PUCHAR SenseInfoBuffer;
+
+#define SECTORS_IN_LOGICAL_VOLUME 0x20
+
+
+ARC_STATUS
+ScsiDiskGetFileInformation (
+ IN ULONG FileId,
+ OUT PFILE_INFORMATION Finfo
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns information on the scsi partition.
+
+Arguments:
+
+ FileId - Supplies the file table index.
+
+ Finfo - Supplies a pointer to where the File Informatino is stored.
+
+Return Value:
+
+ ESUCCESS is returned.
+
+--*/
+
+{
+
+ PPARTITION_CONTEXT Context;
+
+ RtlZeroMemory(Finfo, sizeof(FILE_INFORMATION));
+
+ Context = &BlFileTable[FileId].u.PartitionContext;
+
+ Finfo->StartingAddress.QuadPart = Context->StartingSector;
+ Finfo->StartingAddress.QuadPart <<= Context->SectorShift;
+
+ Finfo->EndingAddress.QuadPart = Finfo->StartingAddress.QuadPart + Context->PartitionLength.QuadPart;
+
+ Finfo->Type = DiskPeripheral;
+
+ return ESUCCESS;
+}
+
+
+ARC_STATUS
+ScsiDiskClose (
+ IN ULONG FileId
+ )
+
+/*++
+
+Routine Description:
+
+ This function closes the file table entry specified by the file id.
+
+Arguments:
+
+ FileId - Supplies the file table index.
+
+Return Value:
+
+ ESUCCESS is returned.
+
+--*/
+
+{
+
+ BlFileTable[FileId].Flags.Open = 0;
+ return ESUCCESS;
+}
+
+ARC_STATUS
+ScsiDiskMount (
+ IN PCHAR MountPath,
+ IN MOUNT_OPERATION Operation
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ return ESUCCESS;
+}
+
+ARC_STATUS
+ScsiDiskOpen (
+ IN PCHAR OpenPath,
+ IN OPEN_MODE OpenMode,
+ OUT PULONG FileId
+ )
+
+/*++
+
+Routine Description:
+
+ This routine fills in the file table entry. In particular the Scsi address
+ of the device is determined from the name. The block size of device is
+ queried from the target controller, and the partition information is read
+ from the device.
+
+Arguments:
+
+ OpenPath - Supplies the name of the device being opened.
+
+ OpenMode - Unused.
+
+ FileId - Supplies the index to the file table entry to be initialized.
+
+Return Value:
+
+ Retruns the arc status of the operation.
+
+--*/
+
+{
+ ULONG Partition;
+ ULONG Id;
+ BOOLEAN IsCdRom;
+ BOOLEAN IsFloppy;
+ PPARTITION_CONTEXT Context;
+
+ Context = &BlFileTable[*FileId].u.PartitionContext;
+
+ //
+ // Determine the scsi port device object.
+ //
+
+ if (FwGetPathMnemonicKey(OpenPath, "scsi", &Id)) {
+ return ENODEV;
+ }
+
+ if (ScsiPortDeviceObject[Id] == NULL) {
+ return ENODEV;
+ }
+
+ Context->PortDeviceObject = ScsiPortDeviceObject[Id];
+
+ //
+ // Get the logical unit, path Id and target id from the name.
+ // NOTE: FwGetPathMnemonicKey returns 0 for success.
+ //
+
+ if (FwGetPathMnemonicKey(OpenPath, "rdisk", &Id)) {
+ if (FwGetPathMnemonicKey(OpenPath, "fdisk", &Id)) {
+ return ENODEV;
+ } else {
+ IsFloppy = TRUE;
+ }
+ } else {
+ IsFloppy = FALSE;
+ }
+
+ //
+ // Booting is only allowed on LUN 0 since the scsibus
+ // scan in the loader only searches for LUN 0.
+ //
+
+ if (Id != 0) {
+ return ENODEV;
+ }
+
+ Context->DiskId = (UCHAR)Id;
+
+ if (!FwGetPathMnemonicKey(OpenPath, "cdrom", &Id)) {
+ IsCdRom = TRUE;
+ } else if (!FwGetPathMnemonicKey(OpenPath, "disk", &Id)) {
+ IsCdRom = FALSE;
+ } else {
+ return ENODEV;
+ }
+
+ Context->PathId = (UCHAR)(Id / SCSI_MAXIMUM_TARGETS_PER_BUS);
+
+ Context->TargetId = (UCHAR)(Id % SCSI_MAXIMUM_TARGETS_PER_BUS);
+
+ //
+ // Initialize any bad devices.
+ //
+
+ ScsiDiskFilterBad(Context);
+
+ //
+ // Read the capacity of the disk to determine the block size.
+ //
+
+ if (ReadDriveCapacity(Context)) {
+ return ENODEV;
+ }
+
+ //
+ // This is all that needs to be done for floppies and harddisks.
+ //
+
+ if (IsCdRom || IsFloppy) {
+ return(ESUCCESS);
+ }
+
+ if (FwGetPathMnemonicKey(OpenPath,
+ "partition",
+ &Partition
+ )) {
+ return ENODEV;
+ }
+
+ if (Partition != 0) {
+ if (ScsiDiskBootPartitionOpen(*FileId,0,(UCHAR)Partition) != STATUS_SUCCESS) {
+ return ENODEV;
+ }
+ }
+ //
+ // Initialize partition table
+ //
+ return ESUCCESS;
+}
+
+ARC_STATUS
+ScsiDiskRead (
+ IN ULONG FileId,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ This function reads data from the hard disk starting at the position
+ specified in the file table.
+
+
+Arguments:
+
+ FileId - Supplies the file table index.
+
+ Buffer - Supplies a poiner to the buffer that receives the data
+ read.
+
+ Length - Supplies the number of bytes to be read.
+
+ Count - Supplies a pointer to a variable that receives the number of
+ bytes actually read.
+
+Return Value:
+
+ The read operation is performed and the read completion status is
+ returned.
+
+--*/
+
+
+{
+
+ ARC_STATUS ArcStatus;
+ ULONG FrameNumber;
+ ULONG Index;
+ ULONG Limit;
+ PMDL MdlAddress;
+ UCHAR MdlBuffer[sizeof(MDL) + ((64 / 4) + 1) * sizeof(ULONG)];
+ NTSTATUS NtStatus;
+ ULONG NumberOfPages;
+ PULONG PageFrame;
+ ULONG Offset;
+ LARGE_INTEGER Position;
+ LARGE_INTEGER LogicalBlock;
+ PCHAR TempPointer;
+ PIO_SCSI_CAPABILITIES PortCapabilities;
+ ULONG adapterLimit;
+ ULONG alignmentMask;
+ ULONG SectorSize;
+ ULONG TransferCount;
+ ULONG BytesToTransfer;
+
+ //
+ // If the requested size of the transfer is zero return ESUCCESS
+ //
+ if (Length==0) {
+ return ESUCCESS;
+ }
+
+ if (!CheckFileId(FileId)) {
+ return(ENODEV);
+ }
+
+ //
+ // Compute a Dcache aligned pointer into the temporary buffer.
+ //
+
+ TempPointer = (PVOID)((ULONG)(ScsiTempBuffer +
+ KeGetDcacheFillSize() - 1) & ~(KeGetDcacheFillSize() - 1));
+
+
+ //
+ // Calculate the actual sector size.
+ //
+
+ SectorSize = 1 << BlFileTable[FileId].u.PartitionContext.SectorShift;
+
+ ArcStatus = GetAdapterCapabilities(
+ BlFileTable[FileId].u.PartitionContext.PortDeviceObject,
+ &PortCapabilities
+ );
+
+ if (ArcStatus != ESUCCESS) {
+
+ adapterLimit = 0x10000;
+ alignmentMask = KeGetDcacheFillSize();
+
+ } else {
+
+ if (PortCapabilities->MaximumTransferLength < 0x1000 ||
+ PortCapabilities->MaximumTransferLength > 0x10000) {
+
+ adapterLimit = 0x10000;
+
+ } else {
+
+ adapterLimit = PortCapabilities->MaximumTransferLength;
+
+ }
+
+ alignmentMask = PortCapabilities->AlignmentMask;
+ }
+
+ //
+ // If the current position is not at a sector boundary or if the data
+ // buffer is not properly aligned, then read the first sector separately
+ // and copy the data.
+ //
+
+ Offset = BlFileTable[FileId].Position.LowPart & (SectorSize - 1);
+ *Count = 0;
+ while (Offset != 0 || (ULONG) Buffer & alignmentMask) {
+
+ Position = BlFileTable[FileId].Position;
+ BlFileTable[FileId].Position.QuadPart = Position.QuadPart - Offset;
+
+ ArcStatus = ScsiDiskRead(FileId, TempPointer, SectorSize, &TransferCount);
+ if (ArcStatus != ESUCCESS) {
+ BlFileTable[FileId].Position = Position;
+ return ArcStatus;
+ }
+
+ //
+ // Copy the data to the specified buffer.
+ //
+
+ if ((SectorSize - Offset) > Length) {
+ Limit = Offset + Length;
+
+ } else {
+ Limit = SectorSize;
+ }
+
+ for (Index = Offset; Index < Limit; Index += 1) {
+ ((PCHAR)Buffer)[Index - Offset] = TempPointer[Index];
+ }
+
+ //
+ // Update transfer parameters.
+ //
+
+ *Count += Limit - Offset;
+ Length -= Limit - Offset;
+ Buffer = (PVOID)((PCHAR)Buffer + Limit - Offset);
+ BlFileTable[FileId].Position.QuadPart = Position.QuadPart + (Limit - Offset);
+
+ Offset = BlFileTable[FileId].Position.LowPart & (SectorSize - 1);
+
+ if (Length == 0) {
+ break;
+ }
+
+ }
+
+ //
+ // The position is aligned on a sector boundary. Read as many sectors
+ // as possible in a contiguous run in 64Kb chunks.
+ //
+
+ BytesToTransfer = Length & (~(SectorSize - 1));
+ while (BytesToTransfer != 0) {
+
+ //
+ // The scsi controller doesn't support transfers bigger than 64Kb.
+ // Transfer the maximum number of bytes possible.
+ //
+
+ Limit = (BytesToTransfer > adapterLimit ? adapterLimit : BytesToTransfer);
+
+ //
+ // Build the memory descriptor list.
+ //
+
+
+ MdlAddress = (PMDL)&MdlBuffer[0];
+ MdlAddress->Next = NULL;
+ MdlAddress->Size = sizeof(MDL) +
+ ADDRESS_AND_SIZE_TO_SPAN_PAGES(Buffer, Limit) * sizeof(ULONG);
+ MdlAddress->StartVa = (PVOID)PAGE_ALIGN(Buffer);
+ MdlAddress->ByteCount = Limit;
+ MdlAddress->ByteOffset = BYTE_OFFSET(Buffer);
+ PageFrame = (PULONG)(MdlAddress + 1);
+ FrameNumber = (((ULONG)MdlAddress->StartVa) & 0x1fffffff) >> PAGE_SHIFT;
+ NumberOfPages = (MdlAddress->ByteCount +
+ MdlAddress->ByteOffset + PAGE_SIZE - 1) >> PAGE_SHIFT;
+ for (Index = 0; Index < NumberOfPages; Index += 1) {
+ *PageFrame++ = FrameNumber++;
+ }
+
+ //
+ // Flush I/O buffers and read from the boot device.
+ //
+
+ KeFlushIoBuffers(MdlAddress, TRUE, TRUE);
+ LogicalBlock.QuadPart = BlFileTable[FileId].Position.QuadPart >>
+ BlFileTable[FileId].u.PartitionContext.SectorShift;
+ LogicalBlock.LowPart += BlFileTable[FileId].u.PartitionContext.StartingSector;
+ NtStatus = ScsiDiskBootIO(MdlAddress,
+ LogicalBlock.LowPart,
+ &BlFileTable[FileId].u.PartitionContext,
+ TRUE);
+
+ if (NtStatus != ESUCCESS) {
+ return EIO;
+ }
+
+ *Count += Limit;
+ Length -= Limit;
+ Buffer = (PVOID)((PCHAR)Buffer + Limit);
+ BytesToTransfer -= Limit;
+ BlFileTable[FileId].Position.QuadPart = BlFileTable[FileId].Position.QuadPart + Limit;
+ }
+
+ //
+ // If there is any residual data to read, then read the last sector
+ // separately and copy the data.
+ //
+
+ if (Length != 0) {
+ Position = BlFileTable[FileId].Position;
+ ArcStatus = ScsiDiskRead(FileId, TempPointer, SectorSize, &TransferCount);
+ if (ArcStatus != ESUCCESS) {
+ BlFileTable[FileId].Position = Position;
+ return ArcStatus;
+ }
+
+ //
+ // Copy the data to the specified buffer.
+ //
+ RtlCopyMemory(Buffer,TempPointer,Length);
+
+ //
+ // Update transfer parameters.
+ //
+
+ *Count += Length;
+ BlFileTable[FileId].Position.QuadPart = Position.QuadPart + Length;
+ }
+
+ return ESUCCESS;
+
+}
+
+ARC_STATUS
+ScsiDiskGetReadStatus (
+ IN ULONG FileId
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ return ESUCCESS;
+}
+
+ARC_STATUS
+ScsiDiskSeek (
+ IN ULONG FileId,
+ IN PLARGE_INTEGER Offset,
+ IN SEEK_MODE SeekMode
+ )
+
+/*++
+
+Routine Description:
+
+ This function sets the device position to the specified offset for
+ the specified file id.
+
+Arguments:
+
+ FileId - Supplies the file table index.
+
+ Offset - Supplies to new device position.
+
+ SeekMode - Supplies the mode for the position.
+
+Return Value:
+
+ ESUCCESS is returned.
+
+--*/
+
+{
+
+ //
+ // Set the current device position as specifed by the seek mode.
+ //
+
+ if (SeekMode == SeekAbsolute) {
+ BlFileTable[FileId].Position = *Offset;
+
+ } else if (SeekMode == SeekRelative) {
+ BlFileTable[FileId].Position.QuadPart = BlFileTable[FileId].Position.QuadPart + Offset->QuadPart;
+ }
+
+ return ESUCCESS;
+}
+
+ARC_STATUS
+ScsiDiskWrite (
+ IN ULONG FileId,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ This function writes data to the hard disk starting at the position
+ specified in the file table.
+
+
+Arguments:
+
+ FileId - Supplies the file table index.
+
+ Buffer - Supplies a poiner to the buffer that contains the write data.
+
+ Length - Supplies the number of bytes to be written.
+
+ Count - Supplies a pointer to a variable that receives the number of
+ bytes actually written.
+
+Return Value:
+
+ The write operation is performed and the write completion status is
+ returned.
+
+--*/
+
+{
+
+ ARC_STATUS ArcStatus;
+ ULONG FrameNumber;
+ ULONG Index;
+ ULONG Limit;
+ PMDL MdlAddress;
+ UCHAR MdlBuffer[sizeof(MDL) + ((64 / 4) + 1) * sizeof(ULONG)];
+ NTSTATUS NtStatus;
+ ULONG NumberOfPages;
+ ULONG Offset;
+ PULONG PageFrame;
+ LARGE_INTEGER Position;
+ LARGE_INTEGER WritePosition;
+ LARGE_INTEGER LogicalBlock;
+ CHAR TempBuffer[MAXIMUM_SECTOR_SIZE + 128];
+ PIO_SCSI_CAPABILITIES PortCapabilities;
+ ULONG adapterLimit;
+ PCHAR TempPointer;
+ ULONG SectorSize;
+ ULONG TransferCount;
+ ULONG BytesToTransfer;
+ ULONG alignmentMask;
+ //
+ // If the requested size of the transfer is zero return ESUCCESS
+ //
+
+ if (Length==0) {
+ return ESUCCESS;
+ }
+
+ if (!CheckFileId(FileId)) {
+ return(ENODEV);
+ }
+
+ //
+ // Compute a Dcache aligned pointer into the temporary buffer.
+ //
+
+ TempPointer = (PVOID)((ULONG)(TempBuffer +
+ KeGetDcacheFillSize() - 1) & ~(KeGetDcacheFillSize() - 1));
+
+
+ //
+ // Calculate the actual sector size.
+ //
+
+ SectorSize = 1 << BlFileTable[FileId].u.PartitionContext.SectorShift;
+
+ ArcStatus = GetAdapterCapabilities(
+ BlFileTable[FileId].u.PartitionContext.PortDeviceObject,
+ &PortCapabilities
+ );
+
+ if (ArcStatus != ESUCCESS) {
+
+ adapterLimit = 0x10000;
+ alignmentMask = KeGetDcacheFillSize();
+
+ } else {
+
+ if (PortCapabilities->MaximumTransferLength < 0x1000 ||
+ PortCapabilities->MaximumTransferLength > 0x10000) {
+
+ adapterLimit = 0x10000;
+
+ } else {
+
+ adapterLimit = PortCapabilities->MaximumTransferLength;
+
+ }
+
+ alignmentMask = PortCapabilities->AlignmentMask;
+ }
+
+ //
+ // If the current position is not at a sector boundary or if the data
+ // buffer is not properly aligned, then read the first sector separately
+ // and copy the data.
+ //
+
+ Offset = BlFileTable[FileId].Position.LowPart & (SectorSize - 1);
+ *Count = 0;
+ while (Offset != 0 || (ULONG) Buffer & alignmentMask) {
+
+ Position = BlFileTable[FileId].Position;
+ BlFileTable[FileId].Position.QuadPart = Position.QuadPart - Offset;
+ WritePosition = BlFileTable[FileId].Position;
+ ArcStatus = ScsiDiskRead(FileId, TempPointer, SectorSize, &TransferCount);
+ if (ArcStatus != ESUCCESS) {
+ BlFileTable[FileId].Position = Position;
+ return ArcStatus;
+ }
+ //
+ // Reset the position as it was before the read.
+ //
+
+ BlFileTable[FileId].Position = WritePosition;
+
+ //
+ // If the length of write is less than the number of bytes from
+ // the offset to the end of the sector, then copy only the number
+ // of bytes required to fulfil the request. Otherwise copy to the end
+ // of the sector and, read the remaining data.
+ //
+
+ if ((SectorSize - Offset) > Length) {
+ Limit = Offset + Length;
+
+ } else {
+ Limit = SectorSize;
+ }
+
+ //
+ // Merge the data from the specified buffer.
+ //
+ for (Index = Offset; Index < Limit; Index += 1) {
+ TempPointer[Index] = ((PCHAR)Buffer)[Index-Offset];
+ }
+
+ //
+ // Write the modified sector.
+ //
+ ArcStatus = ScsiDiskWrite(FileId, TempPointer, SectorSize, &TransferCount);
+
+ if (ArcStatus != ESUCCESS) {
+ return ArcStatus;
+ }
+
+ //
+ // Update transfer parameters.
+ //
+
+ *Count += Limit - Offset;
+ Length -= Limit - Offset;
+ Buffer = (PVOID)((PCHAR)Buffer + Limit - Offset);
+ BlFileTable[FileId].Position.QuadPart = Position.QuadPart + (Limit - Offset);
+
+ Offset = BlFileTable[FileId].Position.LowPart & (SectorSize - 1);
+
+ if (Length == 0) {
+ break;
+ }
+ }
+
+
+ //
+ // The position is aligned on a sector boundary. Write as many sectors
+ // as possible in a contiguous run.
+ //
+
+ BytesToTransfer = Length & (~(SectorSize - 1));
+ while (BytesToTransfer != 0) {
+
+ //
+ // The scsi controller doesn't support transfers bigger than 64Kb.
+ // Transfer the maximum number of bytes possible.
+ //
+ Limit = (BytesToTransfer > adapterLimit ? adapterLimit : BytesToTransfer);
+
+ //
+ // Build the memory descriptor list.
+ //
+
+ MdlAddress = (PMDL)&MdlBuffer[0];
+ MdlAddress->Next = NULL;
+ MdlAddress->Size = sizeof(MDL) +
+ ADDRESS_AND_SIZE_TO_SPAN_PAGES(Buffer, Limit) * sizeof(ULONG);
+ MdlAddress->StartVa = (PVOID)PAGE_ALIGN(Buffer);
+ MdlAddress->ByteCount = Limit;
+ MdlAddress->ByteOffset = BYTE_OFFSET(Buffer);
+ PageFrame = (PULONG)(MdlAddress + 1);
+ FrameNumber = (((ULONG)MdlAddress->StartVa) & 0x1fffffff) >> PAGE_SHIFT;
+ NumberOfPages = (MdlAddress->ByteCount +
+ MdlAddress->ByteOffset + PAGE_SIZE - 1) >> PAGE_SHIFT;
+ for (Index = 0; Index < NumberOfPages; Index += 1) {
+ *PageFrame++ = FrameNumber++;
+ }
+
+ //
+ // Flush I/O buffers and write to the boot device.
+ //
+
+ KeFlushIoBuffers(MdlAddress, FALSE, TRUE);
+ LogicalBlock.QuadPart = BlFileTable[FileId].Position.QuadPart >>
+ BlFileTable[FileId].u.PartitionContext.SectorShift;
+ LogicalBlock.LowPart += BlFileTable[FileId].u.PartitionContext.StartingSector;
+ NtStatus = ScsiDiskBootIO(MdlAddress,
+ LogicalBlock.LowPart,
+ &BlFileTable[FileId].u.PartitionContext,
+ FALSE);
+
+ if (NtStatus != ESUCCESS) {
+ return EIO;
+ }
+
+ *Count += Limit;
+ Length -= Limit;
+ Buffer = (PVOID)((PCHAR)Buffer + Limit);
+ BytesToTransfer -= Limit;
+ BlFileTable[FileId].Position.QuadPart = BlFileTable[FileId].Position.QuadPart + Limit;
+ }
+
+ //
+ // If there is any residual data to write, then read the last sector
+ // separately merge the write data and write it.
+ //
+
+ if (Length != 0) {
+ Position = BlFileTable[FileId].Position;
+ ArcStatus = ScsiDiskRead(FileId, TempPointer, SectorSize, &TransferCount);
+
+ //
+ // Reset the position as it was before the read.
+ //
+
+ BlFileTable[FileId].Position = Position;
+
+ if (ArcStatus != ESUCCESS) {
+ return ArcStatus;
+ }
+ //
+ // Merge the data with the read sector from the buffer.
+ //
+
+ for (Index = 0; Index < Length; Index += 1) {
+ TempPointer[Index] = ((PCHAR)Buffer)[Index];
+ }
+
+ //
+ // Write the merged sector
+ //
+
+ ArcStatus = ScsiDiskWrite(FileId, TempPointer, SectorSize, &TransferCount);
+
+ //
+ // Reset the postion.
+ //
+
+ BlFileTable[FileId].Position = Position;
+
+ //
+ // Update transfer parameters.
+ //
+
+ *Count += Length;
+
+ //
+ // Position is aligned to a sector boundary and Length is less than
+ // a sector, therefore the addition will never overflow.
+ //
+
+ BlFileTable[FileId].Position.LowPart += Length;
+ }
+
+ return ESUCCESS;
+
+}
+
+
+NTSTATUS
+ScsiDiskBootPartitionOpen(
+ IN ULONG FileId,
+ IN UCHAR DeviceUnit,
+ IN UCHAR PartitionNumber
+ )
+
+/*++
+
+Routine Description:
+
+ This is the initialization routine for the hard disk boot driver
+ for the given partition. It sets the partition info in the
+ FileTable at the specified index and initializes the Device entry
+ table to point to the table of ScsiDisk routines.
+
+ It reads the partition information until the requested partition
+ is found or no more partitions are defined.
+
+Arguments:
+
+ FileId - Supplies the file id for the file table entry.
+
+ DeviceUnit - Supplies the device number in the scis bus.
+
+ PartitionNumber - Supplies the partition number must be bigger than zero.
+ To get the size of the disk call ReadDriveCapacity.
+
+
+Return Value:
+
+ If a valid FAT file system structure is found on the hard disk, then
+ STATUS_SUCCESS is returned. Otherwise, STATUS_UNSUCCESSFUL is returned.
+
+--*/
+
+{
+
+ PMDL MdlAddress;
+ USHORT DataBuffer[MAXIMUM_SECTOR_SIZE / sizeof(USHORT) + 128];
+ PUSHORT DataPointer;
+ ULONG DummyMdl[(sizeof(MDL) + 16) / sizeof(ULONG)];
+ PULONG PageFrame;
+ PPARTITION_DESCRIPTOR Partition;
+ PPARTITION_CONTEXT Context;
+ ULONG PartitionLength;
+ ULONG StartingSector;
+ ULONG VolumeOffset;
+ NTSTATUS Status;
+ BOOLEAN PrimaryPartitionTable;
+ ULONG PartitionOffset=0;
+ ULONG PartitionIndex,PartitionCount=0;
+ ULONG SectorSize;
+
+ BlFileTable[FileId].Position.LowPart = 0;
+ BlFileTable[FileId].Position.HighPart = 0;
+
+ VolumeOffset=0;
+ PrimaryPartitionTable=TRUE;
+
+ Context = &BlFileTable[FileId].u.PartitionContext;
+
+ //
+ // Calculate the actual sector size
+ //
+
+ SectorSize = 1 << Context->SectorShift;
+
+ //
+ // Make the sector size the minimum of 512 or the sector size.
+ //
+
+ if (SectorSize < 512) {
+ SectorSize = 512;
+ }
+
+ //
+ // Align the buffer on a Dcache line size.
+ //
+
+ DataPointer = (PVOID) ((ULONG) ((PCHAR) DataBuffer +
+ KeGetDcacheFillSize() - 1) & ~(KeGetDcacheFillSize() - 1));
+
+ //
+ // Initialize a memory descriptor list to read the master boot record
+ // from the specified hard disk drive.
+ //
+
+ MdlAddress = (PMDL)&DummyMdl[0];
+ MdlAddress->StartVa = (PVOID)(((ULONG)DataPointer) & (~(PAGE_SIZE - 1)));
+ MdlAddress->ByteCount = SectorSize;
+ MdlAddress->ByteOffset = ((ULONG)DataPointer) & (PAGE_SIZE - 1);
+ PageFrame = (PULONG)(MdlAddress + 1);
+ *PageFrame++ = ((((ULONG)DataPointer) & 0x1fffffff) >> PAGE_SHIFT);
+ *PageFrame++ = ((((ULONG)DataPointer) & 0x1fffffff) >> PAGE_SHIFT) + 1;
+ do {
+ Status = ScsiDiskBootIO(MdlAddress,PartitionOffset,Context,TRUE);
+ if (NT_SUCCESS(Status) != FALSE) {
+
+ //
+ // If sector zero is not a master boot record, then return failure
+ // status. Otherwise return success.
+ //
+
+ if (*(DataPointer + BOOT_SIGNATURE_OFFSET) != BOOT_RECORD_SIGNATURE) {
+ DbgPrint("Boot record signature not found\n");
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ //
+ // Read the partition information until the four entries are
+ // checked or until we found the requested one.
+ //
+ Partition = (PPARTITION_DESCRIPTOR)(DataPointer+PARTITION_TABLE_OFFSET);
+ for (PartitionIndex=0;
+ PartitionIndex < NUM_PARTITION_TABLE_ENTRIES;
+ PartitionIndex++,Partition++) {
+ //
+ // Count first the partitions in the MBR. The units
+ // inside the extended partition are counted later.
+ //
+ if (!IsContainerPartition(Partition->PartitionType) &&
+ (Partition->PartitionType != PARTITION_ENTRY_UNUSED)) {
+ PartitionCount++; // another partition found.
+ }
+
+ //
+ // Check if the requested partition has already been found.
+ // set the partition info in the file table and return.
+ //
+ if (PartitionCount == (ULONG)PartitionNumber) {
+ StartingSector = (ULONG)(Partition->StartingSectorLsb0) |
+ (ULONG)(Partition->StartingSectorLsb1 << 8) |
+ (ULONG)(Partition->StartingSectorMsb0 << 16) |
+ (ULONG)(Partition->StartingSectorMsb1 << 24);
+ PartitionLength = (ULONG)(Partition->PartitionLengthLsb0) |
+ (ULONG)(Partition->PartitionLengthLsb1 << 8) |
+ (ULONG)(Partition->PartitionLengthMsb0 << 16) |
+ (ULONG)(Partition->PartitionLengthMsb1 << 24);
+
+ Context->PartitionLength.QuadPart = PartitionLength;
+ Context->PartitionLength.QuadPart <<= Context->SectorShift;
+ Context->StartingSector = PartitionOffset + StartingSector;
+ Context->EndingSector = Context->StartingSector + PartitionLength;
+ return Status;
+ }
+ }
+
+ //
+ // If requested partition was not yet found.
+ // Look for an extended partition.
+ //
+ Partition = (PPARTITION_DESCRIPTOR)(DataPointer + PARTITION_TABLE_OFFSET);
+ PartitionOffset = 0;
+ for (PartitionIndex=0;
+ PartitionIndex < NUM_PARTITION_TABLE_ENTRIES;
+ PartitionIndex++,Partition++) {
+ if (IsContainerPartition(Partition->PartitionType)) {
+ StartingSector = (ULONG)(Partition->StartingSectorLsb0) |
+ (ULONG)(Partition->StartingSectorLsb1 << 8) |
+ (ULONG)(Partition->StartingSectorMsb0 << 16) |
+ (ULONG)(Partition->StartingSectorMsb1 << 24);
+ PartitionOffset = VolumeOffset+StartingSector;
+ if (PrimaryPartitionTable) {
+ VolumeOffset = StartingSector;
+ }
+ break; // only one partition can be extended.
+ }
+ }
+ }
+ PrimaryPartitionTable=FALSE;
+ } while (PartitionOffset != 0);
+ return STATUS_UNSUCCESSFUL;
+}
+
+//
+// This silly callback messes a lot of things up. There is no clean definition
+// for it anywhere, so it has to be defined in all modules that reference it.
+//
+
+#ifndef SCSI_INFO_CALLBACK_DEFINED
+
+typedef
+VOID
+(*PSCSI_INFO_CALLBACK_ROUTINE) (
+ IN ULONG AdapterNumber,
+ IN ULONG ScsiId,
+ IN ULONG Lun,
+ IN BOOLEAN Cdrom
+ );
+#endif
+
+VOID
+HardDiskInitialize(
+ IN OUT PDRIVER_LOOKUP_ENTRY LookupTable,
+ IN ULONG Entries,
+ IN PSCSI_INFO_CALLBACK_ROUTINE DeviceFound
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the scsi controller and the
+ device entry table for the scsi driver.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG lookupTableIndex = 0;
+ ULONG scsiNumber;
+ ULONG busNumber;
+ PCHAR Identifier;
+ PLUNINFO lunInfo;
+ PSCSI_CONFIGURATION_INFO configInfo;
+ PSCSI_BUS_SCAN_DATA busScanData;
+ PDEVICE_EXTENSION scsiPort;
+ PINQUIRYDATA inquiryData;
+ PCONFIGURATION_COMPONENT RootComponent;
+ PCONFIGURATION_COMPONENT ScsiComponent;
+ PCONFIGURATION_COMPONENT ControllerComponent;
+ PCONFIGURATION_COMPONENT PeripheralComponent;
+ PCONFIGURATION_COMPONENT NextComponent;
+ CHAR ComponentPath[10];
+ CONFIGURATION_COMPONENT ControllerEntry;
+ CONFIGURATION_COMPONENT AdapterEntry;
+ CONFIGURATION_COMPONENT PeripheralEntry;
+ PARTITION_CONTEXT Context;
+ BOOLEAN IsFloppy;
+
+ RtlZeroMemory(&Context, sizeof(PARTITION_CONTEXT));
+
+ //
+ // Initialize the common buffers.
+ //
+
+ ReadCapacityBuffer = ExAllocatePool( NonPagedPool, sizeof(READ_CAPACITY_DATA));
+
+ SenseInfoBuffer = ExAllocatePool( NonPagedPool, SENSE_BUFFER_SIZE);
+
+ if (ReadCapacityBuffer == NULL || SenseInfoBuffer == NULL) {
+ return;
+ }
+
+ //
+ // Scan the scsi ports looking for disk devices.
+ //
+
+ for (scsiNumber = 0; ScsiPortDeviceObject[scsiNumber]; scsiNumber++) {
+
+ scsiPort = ScsiPortDeviceObject[scsiNumber]->DeviceExtension;
+ configInfo = scsiPort->ScsiInfo;
+ Context.PortDeviceObject = ScsiPortDeviceObject[scsiNumber];
+
+ //
+ // Search the configuration database for scsi disk and cdrom devices and
+ // delete them.
+ //
+
+ sprintf(ComponentPath,"scsi(%1d)", scsiNumber);
+ ScsiComponent = FwGetComponent(ComponentPath);
+
+ if (ScsiComponent != NULL) {
+ if (ScsiComponent->Type == ScsiAdapter) {
+ ControllerComponent = FwGetChild(ScsiComponent);
+
+ while (ControllerComponent != NULL) {
+ NextComponent = FwGetPeer(ControllerComponent);
+
+ if ((ControllerComponent->Type == DiskController) ||
+ (ControllerComponent->Type == CdromController)) {
+
+ PeripheralComponent = FwGetChild(ControllerComponent);
+ if (FwDeleteComponent(PeripheralComponent) == ESUCCESS) {
+ FwDeleteComponent(ControllerComponent);
+ }
+ }
+ ControllerComponent = NextComponent;
+ }
+ } else {
+ RootComponent = FwGetChild(NULL);
+ AdapterEntry.Class = AdapterClass;
+ AdapterEntry.Type = ScsiAdapter;
+ AdapterEntry.Flags.ReadOnly = 0;
+ AdapterEntry.Flags.Removable = 0;
+ AdapterEntry.Flags.ConsoleIn = 0;
+ AdapterEntry.Flags.ConsoleOut = 0;
+ AdapterEntry.Flags.Output = 1;
+ AdapterEntry.Flags.Input = 1;
+ AdapterEntry.Version = 0;
+ AdapterEntry.Revision = 0;
+ AdapterEntry.Key = scsiNumber;
+ AdapterEntry.AffinityMask = 0xffffffff;
+ AdapterEntry.ConfigurationDataLength = 0;
+ AdapterEntry.IdentifierLength = 0;
+ AdapterEntry.Identifier = 0;
+ ScsiComponent = FwAddChild(RootComponent, &AdapterEntry, NULL);
+ }
+ }
+
+ for (busNumber=0; busNumber < (ULONG)configInfo->NumberOfBuses; busNumber++) {
+
+ busScanData = configInfo->BusScanData[busNumber];
+
+ //
+ // Set LunInfo to beginning of list.
+ //
+
+ lunInfo = busScanData->LunInfoList;
+
+ while (lunInfo != NULL) {
+
+ inquiryData = (PVOID)lunInfo->InquiryData;
+
+ ScsiDebugPrint(3,"FindScsiDevices: Inquiry data at %lx\n",
+ inquiryData);
+
+ if ((inquiryData->DeviceType == DIRECT_ACCESS_DEVICE
+ || inquiryData->DeviceType == OPTICAL_DEVICE) &&
+ !lunInfo->DeviceClaimed) {
+
+ ScsiDebugPrint(1,
+ "FindScsiDevices: Vendor string is %.24s\n",
+ inquiryData->VendorId);
+
+ IsFloppy = FALSE;
+
+ //
+ // Create a dummy paritition context so that I/O can be
+ // done on the device. SendSrbSynchronous only uses the
+ // port device object pointer and the scsi address of the
+ // logical unit.
+ //
+
+ Context.PathId = lunInfo->PathId;
+ Context.TargetId = lunInfo->TargetId;
+ Context.DiskId = lunInfo->Lun;
+
+ //
+ // Create name for disk object.
+ //
+
+ LookupTable->DevicePath =
+ ExAllocatePool(NonPagedPool,
+ sizeof("scsi(%d)disk(%d)rdisk(%d)"));
+
+ if (LookupTable->DevicePath == NULL) {
+ return;
+ }
+
+ //
+ // If this is a removable. Check to see if the device is
+ // a floppy.
+ //
+
+ if (inquiryData->RemovableMedia &&
+ inquiryData->DeviceType == DIRECT_ACCESS_DEVICE &&
+ IsFloppyDevice(&Context) ) {
+
+ sprintf(LookupTable->DevicePath,
+ "scsi(%d)disk(%d)fdisk(%d)",
+ scsiNumber,
+ lunInfo->TargetId + lunInfo->PathId * SCSI_MAXIMUM_TARGETS_PER_BUS,
+ lunInfo->Lun
+ );
+
+ IsFloppy = TRUE;
+ } else {
+
+ sprintf(LookupTable->DevicePath,
+ "scsi(%d)disk(%d)rdisk(%d)",
+ scsiNumber,
+ lunInfo->TargetId + lunInfo->PathId * SCSI_MAXIMUM_TARGETS_PER_BUS,
+ lunInfo->Lun
+ );
+
+ if (DeviceFound) {
+ DeviceFound( scsiNumber,
+ lunInfo->TargetId + lunInfo->PathId * SCSI_MAXIMUM_TARGETS_PER_BUS,
+ lunInfo->Lun,
+ FALSE
+ );
+ }
+ }
+
+ LookupTable->DispatchTable = &ScsiDiskEntryTable;
+
+ //
+ // If the disk controller entry does not exist, add it to
+ // the configuration database.
+ //
+
+ ControllerComponent = FwGetComponent(LookupTable->DevicePath);
+
+ if (ControllerComponent != NULL) {
+ if (ControllerComponent->Type != DiskController) {
+
+ ControllerEntry.Class = ControllerClass;
+ ControllerEntry.Type = DiskController;
+ ControllerEntry.Flags.Failed = 0;
+ ControllerEntry.Flags.ReadOnly = 0;
+ ControllerEntry.Flags.Removable = 0;
+ ControllerEntry.Flags.ConsoleIn = 0;
+ ControllerEntry.Flags.ConsoleOut = 0;
+ ControllerEntry.Flags.Output = 1;
+ ControllerEntry.Flags.Input = 1;
+ ControllerEntry.Version = 0;
+ ControllerEntry.Revision = 0;
+ ControllerEntry.Key = lunInfo->TargetId + lunInfo->PathId * SCSI_MAXIMUM_TARGETS_PER_BUS;
+ ControllerEntry.AffinityMask = 0xffffffff;
+ ControllerEntry.ConfigurationDataLength = 0;
+
+ Identifier =
+ ExAllocatePool(NonPagedPool,
+ strlen(inquiryData->VendorId)
+ );
+
+ if (Identifier == NULL) {
+ return;
+ }
+
+ sprintf(Identifier,
+ "%s",
+ inquiryData->VendorId
+ );
+
+ ControllerEntry.IdentifierLength = strlen(Identifier);
+ ControllerEntry.Identifier = Identifier;
+
+ ControllerComponent = FwAddChild(ScsiComponent, &ControllerEntry, NULL);
+ }
+ }
+
+ //
+ // Add disk peripheral entry to the configuration database.
+ //
+
+ PeripheralEntry.Class = PeripheralClass;
+ PeripheralEntry.Type = IsFloppy ? FloppyDiskPeripheral : DiskPeripheral;
+ PeripheralEntry.Flags.Failed = 0;
+ PeripheralEntry.Flags.ReadOnly = 0;
+ PeripheralEntry.Flags.Removable = IsFloppy;
+ PeripheralEntry.Flags.ConsoleIn = 0;
+ PeripheralEntry.Flags.ConsoleOut = 0;
+ PeripheralEntry.Flags.Output = 1;
+ PeripheralEntry.Flags.Input = 1;
+ PeripheralEntry.Version = 0;
+ PeripheralEntry.Revision = 0;
+ PeripheralEntry.Key = lunInfo->Lun;
+ PeripheralEntry.AffinityMask = 0xffffffff;
+ PeripheralEntry.ConfigurationDataLength = 0;
+ PeripheralEntry.IdentifierLength = 0;
+ PeripheralEntry.Identifier = NULL;
+
+ FwAddChild(ControllerComponent, &PeripheralEntry, NULL);
+
+ //
+ // Increment to the next entry.
+ //
+
+ LookupTable++;
+ lookupTableIndex++;
+ if (lookupTableIndex >= Entries) {
+
+ //
+ // There is no more space in the caller provided buffer
+ // for disk information. Return.
+ //
+ return;
+ }
+
+ //
+ // Claim disk device by marking configuration
+ // record owned.
+ //
+
+ lunInfo->DeviceClaimed = TRUE;
+
+ }
+
+ if ((inquiryData->DeviceType == READ_ONLY_DIRECT_ACCESS_DEVICE) &&
+ (!lunInfo->DeviceClaimed)) {
+
+ ScsiDebugPrint(1,"FindScsiDevices: Vendor string is %s\n", inquiryData->VendorId);
+
+ //
+ // Create name for cdrom object.
+ //
+
+ LookupTable->DevicePath =
+ ExAllocatePool( NonPagedPool, sizeof("scsi(%d)cdrom(%d)fdisk(%d)"));
+
+ if (LookupTable->DevicePath == NULL) {
+ return;
+ }
+
+ sprintf(LookupTable->DevicePath,
+ "scsi(%d)cdrom(%d)fdisk(%d)",
+ scsiNumber,
+ lunInfo->TargetId + lunInfo->PathId * SCSI_MAXIMUM_TARGETS_PER_BUS,
+ lunInfo->Lun
+ );
+
+ LookupTable->DispatchTable = &ScsiDiskEntryTable;
+
+ if (DeviceFound) {
+ DeviceFound( scsiNumber,
+ lunInfo->TargetId + lunInfo->PathId * SCSI_MAXIMUM_TARGETS_PER_BUS,
+ lunInfo->Lun,
+ TRUE
+ );
+ }
+
+ //
+ // If the cdrom controller entry does not exist, add it to
+ // the configuration database.
+ //
+
+ ControllerComponent = FwGetComponent(LookupTable->DevicePath);
+
+ if (ControllerComponent != NULL) {
+ if (ControllerComponent->Type != CdromController) {
+
+ ControllerEntry.Class = ControllerClass;
+ ControllerEntry.Type = CdromController;
+ ControllerEntry.Flags.Failed = 0;
+ ControllerEntry.Flags.ReadOnly = 1;
+ ControllerEntry.Flags.Removable = 1;
+ ControllerEntry.Flags.ConsoleIn = 0;
+ ControllerEntry.Flags.ConsoleOut = 0;
+ ControllerEntry.Flags.Output = 0;
+ ControllerEntry.Flags.Input = 1;
+ ControllerEntry.Version = 0;
+ ControllerEntry.Revision = 0;
+ ControllerEntry.Key = lunInfo->TargetId + lunInfo->PathId * SCSI_MAXIMUM_TARGETS_PER_BUS;
+ ControllerEntry.AffinityMask = 0xffffffff;
+ ControllerEntry.ConfigurationDataLength = 0;
+
+ Identifier =
+ ExAllocatePool( NonPagedPool,
+ strlen(inquiryData->VendorId)
+ );
+
+ if (Identifier == NULL) {
+ return;
+ }
+
+ sprintf(Identifier,
+ inquiryData->VendorId
+ );
+
+ ControllerEntry.IdentifierLength = strlen(Identifier);
+ ControllerEntry.Identifier = Identifier;
+
+ ControllerComponent = FwAddChild(ScsiComponent, &ControllerEntry, NULL);
+ }
+ }
+
+ //
+ // Add disk peripheral entry to the configuration database.
+ //
+
+ PeripheralEntry.Class = PeripheralClass;
+ PeripheralEntry.Type = FloppyDiskPeripheral;
+ PeripheralEntry.Flags.Failed = 0;
+ PeripheralEntry.Flags.ReadOnly = 1;
+ PeripheralEntry.Flags.Removable = 1;
+ PeripheralEntry.Flags.ConsoleIn = 0;
+ PeripheralEntry.Flags.ConsoleOut = 0;
+ PeripheralEntry.Flags.Output = 0;
+ PeripheralEntry.Flags.Input = 1;
+ PeripheralEntry.Version = 0;
+ PeripheralEntry.Revision = 0;
+ PeripheralEntry.Key = lunInfo->Lun;
+ PeripheralEntry.AffinityMask = 0xffffffff;
+ PeripheralEntry.ConfigurationDataLength = 0;
+ PeripheralEntry.IdentifierLength = 0;
+ PeripheralEntry.Identifier = NULL;
+
+ FwAddChild(ControllerComponent, &PeripheralEntry, NULL);
+
+ //
+ // Increment to the next entry.
+ //
+
+ LookupTable++;
+ lookupTableIndex++;
+ if (lookupTableIndex >= Entries) {
+
+ //
+ // There is no more space in the caller provided buffer
+ // for disk information. Return.
+ //
+ return;
+ }
+
+
+ //
+ // Claim disk device by marking configuration
+ // record owned.
+ //
+
+ lunInfo->DeviceClaimed = TRUE;
+
+ }
+
+ //
+ // Get next LunInfo.
+ //
+
+ lunInfo = lunInfo->NextLunInfo;
+ }
+ }
+ }
+
+// ScsiDebugPrint(1,"FindScsiDevices: Hit any key\n");
+// PAUSE;
+
+}
+
+NTSTATUS
+ScsiDiskBootIO (
+ IN PMDL MdlAddress,
+ IN ULONG LogicalBlock,
+ IN PPARTITION_CONTEXT PartitionContext,
+ IN BOOLEAN Operation
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the read/write routine for the hard disk boot driver.
+
+Arguments:
+
+ MdlAddress - Supplies a pointer to an MDL for the IO operation.
+
+ LogicalBlock - Supplies the starting block number.
+
+ DeviceUnit - Supplies the SCSI Id number.
+
+ Operation - Specifies the IO operation to perform
+ TRUE = SCSI_READ
+ FALSE = SCSI_WRITE.
+
+Return Value:
+
+ The final status of the read operation (STATUS_UNSUCCESSFUL or
+ STATUS_SUCCESS).
+
+--*/
+
+{
+ ARC_STATUS Status;
+ PIRP Irp;
+ PIO_STACK_LOCATION NextIrpStack;
+ PSCSI_REQUEST_BLOCK Srb;
+ ULONG RetryCount = MAXIMUM_RETRIES;
+
+ //
+ // Check that the request is within the limits of the partition.
+ //
+ if (PartitionContext->StartingSector > LogicalBlock) {
+ return STATUS_UNSUCCESSFUL;
+ }
+ if (PartitionContext->EndingSector <
+ LogicalBlock + (MdlAddress->ByteCount >> PartitionContext->SectorShift)) {
+ return STATUS_UNSUCCESSFUL;
+ }
+
+Retry:
+
+ //
+ // Build the I/O Request.
+ //
+
+ Irp = BuildRequest(PartitionContext, MdlAddress, LogicalBlock, Operation);
+
+ NextIrpStack = IoGetNextIrpStackLocation(Irp);
+ Srb = NextIrpStack->Parameters.Others.Argument1;
+
+ //
+ // Call the port driver.
+ //
+
+ IoCallDriver(PartitionContext->PortDeviceObject, Irp);
+
+ //
+ // Check the status.
+ //
+
+ if (SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SUCCESS) {
+
+ //
+ // Determine the cause of the error.
+ //
+
+ if (InterpretSenseInfo(Srb, &Status, PartitionContext) && RetryCount--) {
+
+ goto Retry;
+ }
+
+ if (Status == EAGAIN) {
+ Status = EIO;
+ }
+
+ DebugPrint((1, "SCSI: Read request failed. Arc Status: %d, Srb Status: %x\n",
+ Status,
+ Srb->SrbStatus
+ ));
+
+ } else {
+
+ Status = ESUCCESS;
+
+ }
+
+ return(Status);
+}
+
+ARC_STATUS
+ReadDriveCapacity(
+ IN PPARTITION_CONTEXT PartitionContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a read capacity to a target id and returns
+ when it is complete.
+
+Arguments:
+
+Return Value:
+
+ Status is returned.
+
+--*/
+{
+ PCDB Cdb;
+ PSCSI_REQUEST_BLOCK Srb = &PrimarySrb.Srb;
+ ULONG LastSector;
+ ULONG retries = 1;
+ ARC_STATUS status;
+ ULONG BytesPerSector;
+
+ ScsiDebugPrint(3,"SCSI ReadCapacity: Enter routine\n");
+
+
+ //
+ // Build the read capacity CDB.
+ //
+
+ Srb->CdbLength = 10;
+ Cdb = (PCDB)Srb->Cdb;
+
+ //
+ // Zero CDB in SRB on stack.
+ //
+
+ RtlZeroMemory(Cdb, MAXIMUM_CDB_SIZE);
+
+ Cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;
+
+Retry:
+
+ status = SendSrbSynchronous(PartitionContext,
+ Srb,
+ ReadCapacityBuffer,
+ sizeof(READ_CAPACITY_DATA),
+ FALSE);
+
+ if (status == ESUCCESS) {
+
+#if 0
+ //
+ // Copy sector size from read capacity buffer to device extension
+ // in reverse byte order.
+ //
+
+ deviceExtension->DiskGeometry->BytesPerSector = 0;
+
+ ((PFOUR_BYTE)&deviceExtension->DiskGeometry->BytesPerSector)->Byte0 =
+ ((PFOUR_BYTE)&ReadCapacityBuffer->BytesPerBlock)->Byte3;
+
+ ((PFOUR_BYTE)&deviceExtension->DiskGeometry->BytesPerSector)->Byte1 =
+ ((PFOUR_BYTE)&ReadCapacityBuffer->BytesPerBlock)->Byte2;
+
+ if (BytesPerSector == 0) {
+
+ //
+ // Assume this is a brain dead cd-rom and the sector size is 2048.
+ //
+
+ BytesPerSector = 2048;
+
+ }
+
+ //
+ // Make sure the sector size is less than the maximum expected.
+ //
+
+ ASSERT(BytesPerSector <= MAXIMUM_SECTOR_SIZE);
+
+ if (BytesPerSector > MAXIMUM_SECTOR_SIZE) {
+ return(EINVAL);
+ }
+
+ //
+ // Copy last sector in reverse byte order.
+ //
+
+ ((PFOUR_BYTE)&LastSector)->Byte0 =
+ ((PFOUR_BYTE)&ReadCapacityBuffer->LogicalBlockAddress)->Byte3;
+
+ ((PFOUR_BYTE)&LastSector)->Byte1 =
+ ((PFOUR_BYTE)&ReadCapacityBuffer->LogicalBlockAddress)->Byte2;
+
+ ((PFOUR_BYTE)&LastSector)->Byte2 =
+ ((PFOUR_BYTE)&ReadCapacityBuffer->LogicalBlockAddress)->Byte1;
+
+ ((PFOUR_BYTE)&LastSector)->Byte3 =
+ ((PFOUR_BYTE)&ReadCapacityBuffer->LogicalBlockAddress)->Byte0;
+
+ //
+ // Calculate sector to byte shift.
+ //
+
+ WHICH_BIT(deviceExtension->DiskGeometry->BytesPerSector, deviceExtension->SectorShift);
+
+ ScsiDebugPrint(2,"SCSI ReadDriveCapacity: Sector size is %d\n",
+ deviceExtension->DiskGeometry->BytesPerSector);
+
+ ScsiDebugPrint(2,"SCSI ReadDriveCapacity: Number of Sectors is %d\n",
+ LastSector + 1);
+
+ //
+ // Calculate media capacity in bytes.
+ //
+
+ deviceExtension->PartitionLength = LastSector + 1;
+
+ deviceExtension->PartitionLength.QuadPart <<= deviceExtension->SectorShift.QuadPart;
+
+ //
+ // Assume media type is fixed disk.
+ //
+
+ deviceExtension->DiskGeometry->MediaType = FixedMedia;
+
+ //
+ // Assume sectors per track are 32;
+ //
+
+ deviceExtension->DiskGeometry->SectorsPerTrack = 32;
+
+ //
+ // Assume tracks per cylinder (number of heads) is 64.
+ //
+
+ deviceExtension->DiskGeometry->TracksPerCylinder = 64;
+#else
+
+ BytesPerSector = 0;
+
+ //
+ // Copy sector size from read capacity buffer to device extension
+ // in reverse byte order.
+ //
+
+ ((PFOUR_BYTE)&BytesPerSector)->Byte0 =
+ ((PFOUR_BYTE)&ReadCapacityBuffer->BytesPerBlock)->Byte3;
+
+ ((PFOUR_BYTE)&BytesPerSector)->Byte1 =
+ ((PFOUR_BYTE)&ReadCapacityBuffer->BytesPerBlock)->Byte2;
+
+ if (BytesPerSector == 0) {
+
+ //
+ // Assume this is a brain dead cd-rom and the sector size is 2048.
+ //
+
+ BytesPerSector = 2048;
+
+ }
+
+ //
+ // Calculate sector to byte shift.
+ //
+
+ WHICH_BIT(BytesPerSector, PartitionContext->SectorShift);
+
+ //
+ // Copy last sector in reverse byte order.
+ //
+
+ ((PFOUR_BYTE)&LastSector)->Byte0 =
+ ((PFOUR_BYTE)&ReadCapacityBuffer->LogicalBlockAddress)->Byte3;
+
+ ((PFOUR_BYTE)&LastSector)->Byte1 =
+ ((PFOUR_BYTE)&ReadCapacityBuffer->LogicalBlockAddress)->Byte2;
+
+ ((PFOUR_BYTE)&LastSector)->Byte2 =
+ ((PFOUR_BYTE)&ReadCapacityBuffer->LogicalBlockAddress)->Byte1;
+
+ ((PFOUR_BYTE)&LastSector)->Byte3 =
+ ((PFOUR_BYTE)&ReadCapacityBuffer->LogicalBlockAddress)->Byte0;
+
+
+ PartitionContext->PartitionLength.QuadPart = LastSector + 1;
+ PartitionContext->PartitionLength.QuadPart <<= PartitionContext->SectorShift;
+
+ PartitionContext->StartingSector=0;
+ PartitionContext->EndingSector = LastSector + 1;
+
+ ScsiDebugPrint(2,"SCSI ReadDriveCapacity: Sector size is %d\n",
+ BytesPerSector);
+
+ ScsiDebugPrint(2,"SCSI ReadDriveCapacity: Number of Sectors is %d\n",
+ LastSector + 1);
+
+
+#endif
+ }
+
+ if (status == EAGAIN || status == EBUSY) {
+
+ if (retries--) {
+
+ //
+ // Retry request.
+ //
+
+ goto Retry;
+ }
+ }
+
+ return status;
+
+} // end ReadDriveCapacity()
+
+
+ARC_STATUS
+SendSrbSynchronous(
+ PPARTITION_CONTEXT PartitionContext,
+ PSCSI_REQUEST_BLOCK Srb,
+ PVOID BufferAddress,
+ ULONG BufferLength,
+ BOOLEAN WriteToDevice
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by SCSI device controls to complete an
+ SRB and send it to the port driver synchronously (ie wait for
+ completion).
+ The CDB is already completed along with the SRB CDB size and
+ request timeout value.
+
+Arguments:
+
+ PartitionContext
+ SRB
+ Buffer address and length (if transfer)
+
+ WriteToDevice - Indicates the direction of the transfer.
+
+Return Value:
+
+ ARC_STATUS
+
+--*/
+
+{
+ PIRP Irp;
+ PIO_STACK_LOCATION IrpStack;
+ ULONG retryCount = 1;
+ ARC_STATUS status;
+
+ //
+ // Write length to SRB.
+ //
+
+ Srb->Length = SCSI_REQUEST_BLOCK_SIZE;
+
+ //
+ // Set SCSI bus address.
+ //
+
+ Srb->PathId = PartitionContext->PathId;
+ Srb->TargetId = PartitionContext->TargetId;
+ Srb->Lun = PartitionContext->DiskId;
+
+ Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
+
+ //
+ // Enable auto request sense.
+ //
+
+ Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
+
+ if (SenseInfoBuffer == NULL) {
+ DbgPrint("SendSrbSynchronous: Can't allocate request sense buffer\n");
+ return(ENOMEM);
+ }
+
+ Srb->SenseInfoBuffer = SenseInfoBuffer;
+
+ Srb->DataBuffer = BufferAddress;
+
+ //
+ // Start retries here.
+ //
+
+retry:
+
+ Irp = InitializeIrp(
+ &PrimarySrb,
+ IRP_MJ_SCSI,
+ PartitionContext->PortDeviceObject,
+ BufferAddress,
+ BufferLength
+ );
+
+ if (BufferAddress != NULL) {
+
+ if (WriteToDevice) {
+
+ Srb->SrbFlags = SRB_FLAGS_DATA_OUT;
+
+ } else {
+
+ Srb->SrbFlags = SRB_FLAGS_DATA_IN;
+
+ }
+
+ } else {
+
+ //
+ // Clear flags.
+ //
+
+ Srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER;
+ }
+
+ //
+ // Disable synchronous transfers.
+ //
+
+ Srb->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
+
+ //
+ // Set the transfer length.
+ //
+
+ Srb->DataTransferLength = BufferLength;
+
+ //
+ // Zero out status.
+ //
+
+ Srb->ScsiStatus = Srb->SrbStatus = 0;
+
+ //
+ // Get next stack location and
+ // set major function code.
+ //
+
+ IrpStack = IoGetNextIrpStackLocation(Irp);
+
+
+ //
+ // Set up SRB for execute scsi request.
+ // Save SRB address in next stack for port driver.
+ //
+
+ IrpStack->Parameters.Others.Argument1 = (PVOID)Srb;
+
+ //
+ // Set up IRP Address.
+ //
+
+ Srb->OriginalRequest = Irp;
+
+ Srb->NextSrb = 0;
+
+ //
+ // No need to check the following 2 returned statuses as
+ // SRB will have ending status.
+ //
+
+ (VOID)IoCallDriver(PartitionContext->PortDeviceObject, Irp);
+
+ //
+ // Check that request completed without error.
+ //
+
+ if (SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SUCCESS) {
+
+ //
+ // Update status and determine if request should be retried.
+ //
+
+ if (InterpretSenseInfo(Srb, &status, PartitionContext)) {
+
+ //
+ // If retries are not exhausted then
+ // retry this operation.
+ //
+
+ if (retryCount--) {
+ goto retry;
+ }
+ }
+
+ } else {
+
+ status = ESUCCESS;
+ }
+
+ return status;
+
+} // end SendSrbSynchronous()
+
+
+BOOLEAN
+InterpretSenseInfo(
+ IN PSCSI_REQUEST_BLOCK Srb,
+ OUT ARC_STATUS *Status,
+ PPARTITION_CONTEXT PartitionContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine interprets the data returned from the SCSI
+ request sense. It determines the status to return in the
+ IRP and whether this request can be retried.
+
+Arguments:
+
+ DeviceObject
+ SRB
+ ARC_STATUS to update IRP
+
+Return Value:
+
+ BOOLEAN TRUE: Drivers should retry this request.
+ FALSE: Drivers should not retry this request.
+
+--*/
+
+{
+ PSENSE_DATA SenseBuffer = Srb->SenseInfoBuffer;
+ BOOLEAN retry;
+
+ //
+ // Check that request sense buffer is valid.
+ //
+
+ if (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) {
+
+ ScsiDebugPrint(2,"InterpretSenseInfo: Error code is %x\n",
+ SenseBuffer->ErrorCode);
+
+ ScsiDebugPrint(2,"InterpretSenseInfo: Sense key is %x\n",
+ SenseBuffer->SenseKey);
+
+ ScsiDebugPrint(2,"InterpretSenseInfo: Additional sense code is %x\n",
+ SenseBuffer->AdditionalSenseCode);
+
+ ScsiDebugPrint(2,"InterpretSenseInfo: Additional sense code qualifier is %x\n",
+ SenseBuffer->AdditionalSenseCodeQualifier);
+
+ switch (SenseBuffer->SenseKey) {
+
+ case SCSI_SENSE_NOT_READY:
+
+ ScsiDebugPrint(1,"InterpretSenseInfo: Device not ready\n");
+
+ ScsiDebugPrint(1,"InterpretSenseInfo: Waiting for device\n");
+
+ *Status = EBUSY;
+
+ retry = TRUE;
+
+ switch (SenseBuffer->AdditionalSenseCode) {
+
+ case SCSI_ADSENSE_LUN_NOT_READY:
+
+ ScsiDebugPrint(1,"InterpretSenseInfo: Lun not ready\n");
+
+ switch (SenseBuffer->AdditionalSenseCodeQualifier) {
+
+ case SCSI_SENSEQ_BECOMING_READY:
+
+ ScsiDebugPrint(1,
+ "InterpretSenseInfo:"
+ " In process of becoming ready\n");
+
+ FwStallExecution( 1000 * 1000 * 3 );
+
+ break;
+
+ case SCSI_SENSEQ_MANUAL_INTERVENTION_REQUIRED:
+
+ ScsiDebugPrint(1,
+ "InterpretSenseInfo:"
+ " Manual intervention required\n");
+ *Status = (ARC_STATUS)STATUS_NO_MEDIA_IN_DEVICE;
+ retry = FALSE;
+ break;
+
+ case SCSI_SENSEQ_FORMAT_IN_PROGRESS:
+
+ ScsiDebugPrint(1,
+ "InterpretSenseInfo:"
+ " Format in progress\n");
+ retry = FALSE;
+ break;
+
+ default:
+
+ FwStallExecution( 1000 * 1000 * 3 );
+
+ //
+ // Try a start unit too.
+ //
+
+ case SCSI_SENSEQ_INIT_COMMAND_REQUIRED:
+
+ ScsiDebugPrint(1,
+ "InterpretSenseInfo:"
+ " Initializing command required\n");
+
+ //
+ // This sense code/additional sense code
+ // combination may indicate that the device
+ // needs to be started.
+ //
+
+ ScsiDiskStartUnit(PartitionContext);
+ break;
+
+ }
+
+ } // end switch
+
+ break;
+
+ case SCSI_SENSE_DATA_PROTECT:
+
+ ScsiDebugPrint(1,"InterpretSenseInfo: Media write protected\n");
+
+ *Status = EACCES;
+
+ retry = FALSE;
+
+ break;
+
+ case SCSI_SENSE_MEDIUM_ERROR:
+
+ ScsiDebugPrint(1,"InterpretSenseInfo: Bad media\n");
+ *Status = EIO;
+
+ retry = TRUE;
+
+ break;
+
+ case SCSI_SENSE_HARDWARE_ERROR:
+
+ ScsiDebugPrint(1,"InterpretSenseInfo: Hardware error\n");
+ *Status = EIO;
+
+ retry = TRUE;
+
+ break;
+
+ case SCSI_SENSE_ILLEGAL_REQUEST:
+
+ ScsiDebugPrint(1,"InterpretSenseInfo: Illegal SCSI request\n");
+
+ switch (SenseBuffer->AdditionalSenseCode) {
+
+ case SCSI_ADSENSE_ILLEGAL_COMMAND:
+ ScsiDebugPrint(1,"InterpretSenseInfo: Illegal command\n");
+ break;
+
+ case SCSI_ADSENSE_ILLEGAL_BLOCK:
+ ScsiDebugPrint(1,"InterpretSenseInfo: Illegal block address\n");
+ break;
+
+ case SCSI_ADSENSE_INVALID_LUN:
+ ScsiDebugPrint(1,"InterpretSenseInfo: Invalid LUN\n");
+ break;
+
+ case SCSI_ADSENSE_MUSIC_AREA:
+ ScsiDebugPrint(1,"InterpretSenseInfo: Music area\n");
+ break;
+
+ case SCSI_ADSENSE_DATA_AREA:
+ ScsiDebugPrint(1,"InterpretSenseInfo: Data area\n");
+ break;
+
+ case SCSI_ADSENSE_VOLUME_OVERFLOW:
+ ScsiDebugPrint(1,"InterpretSenseInfo: Volume overflow\n");
+
+ } // end switch ...
+
+ *Status = EINVAL;
+
+ retry = FALSE;
+
+ break;
+
+ case SCSI_SENSE_UNIT_ATTENTION:
+
+ ScsiDebugPrint(3,"InterpretSenseInfo: Unit attention\n");
+
+ switch (SenseBuffer->AdditionalSenseCode) {
+
+ case SCSI_ADSENSE_MEDIUM_CHANGED:
+ ScsiDebugPrint(1,"InterpretSenseInfo: Media changed\n");
+ break;
+
+ case SCSI_ADSENSE_BUS_RESET:
+ ScsiDebugPrint(1,"InterpretSenseInfo: Bus reset\n");
+
+ }
+
+ *Status = EAGAIN;
+
+ retry = TRUE;
+
+ break;
+
+ case SCSI_SENSE_ABORTED_COMMAND:
+
+ ScsiDebugPrint(1,"InterpretSenseInfo: Command aborted\n");
+
+ *Status = EIO;
+
+ retry = TRUE;
+
+ break;
+
+ case SCSI_SENSE_NO_SENSE:
+
+ ScsiDebugPrint(1,"InterpretSenseInfo: No specific sense key\n");
+
+ *Status = EIO;
+
+ retry = TRUE;
+
+ break;
+
+ default:
+
+ ScsiDebugPrint(1,"InterpretSenseInfo: Unrecognized sense code\n");
+
+ *Status = (ARC_STATUS)STATUS_UNSUCCESSFUL;
+
+ retry = TRUE;
+
+ } // end switch
+
+ } else {
+
+ //
+ // Request sense buffer not valid. No sense information
+ // to pinpoint the error. Return general request fail.
+ //
+
+ ScsiDebugPrint(1,"InterpretSenseInfo: Request sense info not valid\n");
+
+ *Status = EIO;
+
+ retry = TRUE;
+ }
+
+ //
+ // If this is the primary srb, then reinitialize any bad scsi devices.
+ //
+
+ if (Srb == &PrimarySrb.Srb) {
+
+ ScsiDiskFilterBad(PartitionContext);
+ }
+
+ return retry;
+
+} // end InterpretSenseInfo()
+
+
+VOID
+RetryRequest(
+ PPARTITION_CONTEXT PartitionContext,
+ PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+
+{
+ PIO_STACK_LOCATION NextIrpStack = IoGetNextIrpStackLocation(Irp);
+ PSCSI_REQUEST_BLOCK Srb = &PrimarySrb.Srb;
+ PMDL Mdl = Irp->MdlAddress;
+ ULONG TransferByteCount = Mdl->ByteCount;
+
+
+ //
+ // Reset byte count of transfer in SRB Extension.
+ //
+
+ Srb->DataTransferLength = TransferByteCount;
+
+ //
+ // Zero SRB statuses.
+ //
+
+ Srb->SrbStatus = Srb->ScsiStatus = 0;
+
+ //
+ // Set up major SCSI function.
+ //
+
+ NextIrpStack->MajorFunction = IRP_MJ_SCSI;
+
+ //
+ // Save SRB address in next stack for port driver.
+ //
+
+ NextIrpStack->Parameters.Others.Argument1 = (PVOID)Srb;
+
+ //
+ // Return the results of the call to the port driver.
+ //
+
+ (PVOID)IoCallDriver(PartitionContext->PortDeviceObject, Irp);
+
+ return;
+
+} // end RetryRequest()
+
+PIRP
+BuildRequest(
+ IN PPARTITION_CONTEXT PartitionContext,
+ IN PMDL Mdl,
+ IN ULONG LogicalBlockAddress,
+ IN BOOLEAN Operation
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+Note:
+
+If the IRP is for a disk transfer, the byteoffset field
+will already have been adjusted to make it relative to
+the beginning of the disk. In this way, this routine can
+be shared between the disk and cdrom class drivers.
+
+ - Operation TRUE specifies that this is a READ operation
+ FALSE specifies that this is a WRITE operation
+
+Return Value:
+
+--*/
+
+{
+ PIRP Irp = &PrimarySrb.Irp;
+ PIO_STACK_LOCATION NextIrpStack;
+ PSCSI_REQUEST_BLOCK Srb = &PrimarySrb.Srb;
+ PCDB Cdb;
+ USHORT TransferBlocks;
+
+ //
+ // Initialize the rest of the IRP.
+ //
+
+ Irp->MdlAddress = Mdl;
+
+ Irp->Tail.Overlay.CurrentStackLocation = &PrimarySrb.IrpStack[IRP_STACK_SIZE];
+
+ NextIrpStack = IoGetNextIrpStackLocation(Irp);
+
+ //
+ // Write length to SRB.
+ //
+
+ Srb->Length = SCSI_REQUEST_BLOCK_SIZE;
+
+ //
+ // Set up IRP Address.
+ //
+
+ Srb->OriginalRequest = Irp;
+
+ Srb->NextSrb = 0;
+
+ //
+ // Set up target id and logical unit number.
+ //
+
+ Srb->PathId = PartitionContext->PathId;
+ Srb->TargetId = PartitionContext->TargetId;
+ Srb->Lun = PartitionContext->DiskId;
+
+ Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
+
+ Srb->DataBuffer = MmGetMdlVirtualAddress(Mdl);
+
+ //
+ // Save byte count of transfer in SRB Extension.
+ //
+
+ Srb->DataTransferLength = Mdl->ByteCount;
+
+ //
+ // Indicate auto request sense by specifying buffer and size.
+ //
+
+ Srb->SenseInfoBuffer = SenseInfoBuffer;
+
+ Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
+
+ //
+ // Set timeout value in seconds.
+ //
+
+ Srb->TimeOutValue = SCSI_DISK_TIMEOUT;
+
+ //
+ // Zero statuses.
+ //
+
+ Srb->SrbStatus = Srb->ScsiStatus = 0;
+
+ //
+ // Indicate that 10-byte CDB's will be used.
+ //
+
+ Srb->CdbLength = 10;
+
+ //
+ // Fill in CDB fields.
+ //
+
+ Cdb = (PCDB)Srb->Cdb;
+
+ Cdb->CDB10.LogicalUnitNumber = PartitionContext->DiskId;
+
+ TransferBlocks = (USHORT)(Mdl->ByteCount >> PartitionContext->SectorShift);
+
+ //
+ // Move little endian values into CDB in big endian format.
+ //
+
+ Cdb->CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)&LogicalBlockAddress)->Byte3;
+ Cdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)&LogicalBlockAddress)->Byte2;
+ Cdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)&LogicalBlockAddress)->Byte1;
+ Cdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)&LogicalBlockAddress)->Byte0;
+
+ Cdb->CDB10.Reserved2 = 0;
+
+ Cdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)&TransferBlocks)->Byte1;
+ Cdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)&TransferBlocks)->Byte0;
+
+ Cdb->CDB10.Control = 0;
+
+ //
+ // Set transfer direction flag and Cdb command.
+ //
+
+ if (Operation) {
+ ScsiDebugPrint(3, "BuildRequest: Read Command\n");
+
+ Srb->SrbFlags = SRB_FLAGS_DATA_IN;
+
+ Cdb->CDB10.OperationCode = SCSIOP_READ;
+ } else {
+ ScsiDebugPrint(3, "BuildRequest: Write Command\n");
+
+ Srb->SrbFlags = SRB_FLAGS_DATA_OUT;
+
+ Cdb->CDB10.OperationCode = SCSIOP_WRITE;
+ }
+
+ //
+ // Disable synchronous transfers.
+ //
+
+ Srb->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
+
+ //
+ // Set up major SCSI function.
+ //
+
+ NextIrpStack->MajorFunction = IRP_MJ_SCSI;
+
+ //
+ // Save SRB address in next stack for port driver.
+ //
+
+ NextIrpStack->Parameters.Others.Argument1 = (PVOID)Srb;
+
+ return(Irp);
+
+} // end BuildRequest()
+
+VOID
+ScsiDiskStartUnit(
+ IN PPARTITION_CONTEXT PartitionContext
+ )
+
+/*++
+
+Routine Description:
+
+ Send command to SCSI unit to start or power up.
+ Because this command is issued asynchronounsly, that is without
+ waiting on it to complete, the IMMEDIATE flag is not set. This
+ means that the CDB will not return until the drive has powered up.
+ This should keep subsequent requests from being submitted to the
+ device before it has completely spun up.
+ This routine is called from the InterpretSense routine, when a
+ request sense returns data indicating that a drive must be
+ powered up.
+
+Arguments:
+
+ PartitionContext - structure containing pointer to port device driver.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PIO_STACK_LOCATION irpStack;
+ PIRP irp;
+ PSCSI_REQUEST_BLOCK srb = &AbortSrb.Srb;
+ PSCSI_REQUEST_BLOCK originalSrb = &PrimarySrb.Srb;
+ PCDB cdb;
+
+ ScsiDebugPrint(1,"StartUnit: Enter routine\n");
+
+ //
+ // Write length to SRB.
+ //
+
+ srb->Length = SCSI_REQUEST_BLOCK_SIZE;
+
+ //
+ // Set up SCSI bus address.
+ //
+
+ srb->PathId = originalSrb->PathId;
+ srb->TargetId = originalSrb->TargetId;
+ srb->Lun = originalSrb->Lun;
+
+ srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
+
+ //
+ // Zero out status.
+ //
+
+ srb->ScsiStatus = srb->SrbStatus = 0;
+
+ //
+ // Set timeout value large enough for drive to spin up.
+ // NOTE: This value is arbitrary.
+ //
+
+ srb->TimeOutValue = 30;
+
+ //
+ // Set the transfer length.
+ //
+
+ srb->DataTransferLength = 0;
+ srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER | SRB_FLAGS_DISABLE_AUTOSENSE;
+ srb->SenseInfoBufferLength = 0;
+ srb->SenseInfoBuffer = NULL;
+
+ //
+ // Build the start unit CDB.
+ //
+
+ srb->CdbLength = 6;
+ cdb = (PCDB)srb->Cdb;
+
+ RtlZeroMemory(cdb, sizeof(CDB));
+
+ cdb->CDB10.OperationCode = SCSIOP_START_STOP_UNIT;
+ cdb->START_STOP.Start = 1;
+
+ //
+ // Build the IRP
+ // to be sent to the port driver.
+ //
+
+ irp = InitializeIrp(
+ &AbortSrb,
+ IRP_MJ_SCSI,
+ PartitionContext->PortDeviceObject,
+ NULL,
+ 0
+ );
+
+ irpStack = IoGetNextIrpStackLocation(irp);
+
+ irpStack->MajorFunction = IRP_MJ_SCSI;
+
+ srb->OriginalRequest = irp;
+
+ //
+ // Save SRB address in next stack for port driver.
+ //
+
+ irpStack->Parameters.Others.Argument1 = srb;
+
+ //
+ // No need to check the following 2 returned statuses as
+ // SRB will have ending status.
+ //
+
+ IoCallDriver(PartitionContext->PortDeviceObject, irp);
+
+} // end StartUnit()
+
+ULONG
+ClassModeSense(
+ IN PPARTITION_CONTEXT Context,
+ IN PCHAR ModeSenseBuffer,
+ IN ULONG Length,
+ IN UCHAR PageMode
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a mode sense command to a target id and returns
+ when it is complete.
+
+Arguments:
+
+Return Value:
+
+ Length of the transferred data is returned.
+
+--*/
+{
+ PCDB cdb;
+ PSCSI_REQUEST_BLOCK Srb = &PrimarySrb.Srb;
+ ULONG retries = 1;
+ NTSTATUS status;
+
+ DebugPrint((3,"SCSI ModeSense: Enter routine\n"));
+
+ //
+ // Build the read capacity CDB.
+ //
+
+ Srb->CdbLength = 6;
+ cdb = (PCDB)Srb->Cdb;
+
+ //
+ // Set timeout value.
+ //
+
+ Srb->TimeOutValue = 2;
+
+ RtlZeroMemory(cdb, MAXIMUM_CDB_SIZE);
+
+ cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
+ cdb->MODE_SENSE.PageCode = PageMode;
+ cdb->MODE_SENSE.AllocationLength = (UCHAR)Length;
+
+Retry:
+
+ status = SendSrbSynchronous(Context,
+ Srb,
+ ModeSenseBuffer,
+ Length,
+ FALSE);
+
+
+ if (status == EAGAIN || status == EBUSY) {
+
+ //
+ // Routine SendSrbSynchronous does not retry
+ // requests returned with this status.
+ // Read Capacities should be retried
+ // anyway.
+ //
+
+ if (retries--) {
+
+ //
+ // Retry request.
+ //
+
+ goto Retry;
+ }
+ } else if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN) {
+ status = STATUS_SUCCESS;
+ }
+
+ if (NT_SUCCESS(status)) {
+ return(Srb->DataTransferLength);
+ } else {
+ return(0);
+ }
+
+} // end ClassModeSense()
+
+PVOID
+ClassFindModePage(
+ IN PCHAR ModeSenseBuffer,
+ IN ULONG Length,
+ IN UCHAR PageMode
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans through the mode sense data and finds the requested
+ mode sense page code.
+
+Arguments:
+ ModeSenseBuffer - Supplies a pointer to the mode sense data.
+
+ Length - Indicates the length of valid data.
+
+ PageMode - Supplies the page mode to be searched for.
+
+Return Value:
+
+ A pointer to the the requested mode page. If the mode page was not found
+ then NULL is return.
+
+--*/
+{
+ PUCHAR limit;
+
+ limit = ModeSenseBuffer + Length;
+
+ //
+ // Skip the mode select header and block descriptors.
+ //
+
+ if (Length < sizeof(MODE_PARAMETER_HEADER)) {
+ return(NULL);
+ }
+
+ ModeSenseBuffer += sizeof(MODE_PARAMETER_HEADER) +
+ ((PMODE_PARAMETER_HEADER) ModeSenseBuffer)->BlockDescriptorLength;
+
+ //
+ // ModeSenseBuffer now points at pages walk the pages looking for the
+ // requested page until the limit is reached.
+ //
+
+ while (ModeSenseBuffer < limit) {
+
+ if (((PMODE_DISCONNECT_PAGE) ModeSenseBuffer)->PageCode == PageMode) {
+ return(ModeSenseBuffer);
+ }
+
+ //
+ // Adavance to the next page.
+ //
+
+ ModeSenseBuffer += ((PMODE_DISCONNECT_PAGE) ModeSenseBuffer)->PageLength + 2;
+ }
+
+ return(NULL);
+
+}
+
+BOOLEAN
+IsFloppyDevice(
+ PPARTITION_CONTEXT Context
+ )
+/*++
+
+Routine Description:
+
+ The routine performs the necessary functioons to determinee if a device is
+ really a floppy rather than a harddisk. This is done by a mode sense
+ command. First, a check is made to see if the medimum type is set. Second
+ a check is made for the flexible parameters mode page.
+
+Arguments:
+
+ Context - Supplies the device object to be tested.
+
+Return Value:
+
+ Return TRUE if the indicated device is a floppy.
+
+--*/
+{
+
+ PVOID modeData;
+ PUCHAR pageData;
+ ULONG length;
+
+ modeData = ExAllocatePool(NonPagedPoolCacheAligned, MODE_DATA_SIZE);
+
+ if (modeData == NULL) {
+ return(FALSE);
+ }
+
+ RtlZeroMemory(modeData, MODE_DATA_SIZE);
+
+ length = ClassModeSense(Context,
+ modeData,
+ MODE_DATA_SIZE,
+ MODE_SENSE_RETURN_ALL);
+
+ if (length < sizeof(MODE_PARAMETER_HEADER)) {
+
+ //
+ // Retry the request in case of a check condition.
+ //
+
+ length = ClassModeSense(Context,
+ modeData,
+ MODE_DATA_SIZE,
+ MODE_SENSE_RETURN_ALL);
+
+ if (length < sizeof(MODE_PARAMETER_HEADER)) {
+
+ ExFreePool(modeData);
+ return(FALSE);
+
+ }
+ }
+#if 0
+ if (((PMODE_PARAMETER_HEADER) modeData)->MediumType >= MODE_FD_SINGLE_SIDE
+ && ((PMODE_PARAMETER_HEADER) modeData)->MediumType <= MODE_FD_MAXIMUM_TYPE) {
+
+ DebugPrint((1, "Scsidisk: MediumType value %2x, This is a floppy.\n", ((PMODE_PARAMETER_HEADER) modeData)->MediumType));
+ ExFreePool(modeData);
+ return(TRUE);
+ }
+#endif
+
+ //
+ // Look for the flexible disk mode page.
+ //
+
+ pageData = ClassFindModePage( modeData, length, MODE_PAGE_FLEXIBILE);
+
+ if (pageData != NULL) {
+
+ DebugPrint((1, "Scsidisk: Flexible disk page found, This is a floppy.\n"));
+ ExFreePool(modeData);
+ return(TRUE);
+
+ }
+
+ ExFreePool(modeData);
+ return(FALSE);
+
+} // end IsFloppyDevice()
+
+VOID
+ScsiDiskFilterBad(
+ IN PPARTITION_CONTEXT PartitionContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine looks for SCSI units which need special initialization
+ to operate correctly.
+
+Arguments:
+
+ PartitionContext - structure containing pointer to port device driver.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PSCSI_REQUEST_BLOCK srb = &AbortSrb.Srb;
+ PCDB cdb;
+ PDEVICE_EXTENSION scsiPort;
+ PSCSI_CONFIGURATION_INFO configInfo;
+ PSCSI_BUS_SCAN_DATA busScanData;
+ PUCHAR modePage;
+ ULONG busNumber;
+ PLUNINFO lunInfo;
+ PINQUIRYDATA inquiryData;
+
+ ScsiDebugPrint(3,"FilterBad: Enter routine\n");
+
+ scsiPort = PartitionContext->PortDeviceObject->DeviceExtension;
+ configInfo = scsiPort->ScsiInfo;
+
+ //
+ // Search the configuration database for scsi disk and cdrom devices
+ // which require special initializaion.
+ //
+
+ for (busNumber=0; busNumber < (ULONG)configInfo->NumberOfBuses; busNumber++) {
+
+ busScanData = configInfo->BusScanData[busNumber];
+
+ //
+ // Set LunInfo to beginning of list.
+ //
+
+ lunInfo = busScanData->LunInfoList;
+
+ while (lunInfo != NULL) {
+
+ inquiryData = (PVOID)lunInfo->InquiryData;
+
+ //
+ // Determin if this is the correct lun.
+ //
+
+ if (PartitionContext->PathId == lunInfo->PathId &&
+ PartitionContext->TargetId == lunInfo->TargetId &&
+ PartitionContext->DiskId == lunInfo->Lun) {
+
+ goto FoundOne;
+ }
+
+ //
+ // Get next LunInfo.
+ //
+
+ lunInfo = lunInfo->NextLunInfo;
+ }
+ }
+
+ return;
+
+FoundOne:
+
+
+
+ //
+ // Zero out status.
+ //
+
+ srb->ScsiStatus = srb->SrbStatus = 0;
+
+ //
+ // Set timeout value.
+ //
+
+ srb->TimeOutValue = 2;
+
+ //
+ // Look for a bad devices.
+ //
+
+ if (strncmp(inquiryData->VendorId, "HITACHI CDR-1750S", strlen("HITACHI CDR-1750S")) == 0 ||
+ strncmp(inquiryData->VendorId, "HITACHI CDR-3650/1650S", strlen("HITACHI CDR-3650/1650S")) == 0) {
+
+ ScsiDebugPrint(1, "ScsiDiskFilterBad: Found Hitachi CDR-1750S.\n");
+
+ //
+ // Found a bad HITACHI cd-rom. These devices do not work with PIO
+ // adapters when read-ahead is enabled. Read-ahead is disabled by
+ // a mode select command. The mode select page code is zero and the
+ // length is 6 bytes. All of the other bytes should be zero.
+ //
+
+ modePage = ExAllocatePool(NonPagedPool, HITACHI_MODE_DATA_SIZE);
+
+ if (modePage == NULL) {
+ return;
+ }
+
+ RtlZeroMemory(modePage, HITACHI_MODE_DATA_SIZE);
+
+ //
+ // Set the page length field to 6.
+ //
+
+ modePage[5] = 6;
+
+ //
+ // Build the mode select CDB.
+ //
+
+ srb->CdbLength = 6;
+ cdb = (PCDB)srb->Cdb;
+
+ RtlZeroMemory(cdb, sizeof(CDB));
+
+ cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
+ cdb->MODE_SELECT.ParameterListLength = HITACHI_MODE_DATA_SIZE;
+
+ //
+ // Send the request to the device.
+ //
+
+ SendSrbSynchronous(PartitionContext,
+ srb,
+ modePage,
+ HITACHI_MODE_DATA_SIZE,
+ TRUE);
+
+ ExFreePool(modePage);
+ }
+
+} // end ScsiDiskFilterBad()
+
+BOOLEAN
+CheckFileId(
+ ULONG FileId
+ )
+{
+
+ if (BlFileTable[FileId].u.PartitionContext.PortDeviceObject != NULL) {
+ return TRUE;
+ }
+
+#if 0
+ DbgPrint("\n\rScsidisk: Bad file id passed to read or write. FileId = %lx\n", FileId);
+ DbgPrint("Start sector = %lx; Ending sector = %lx; Disk Id = %x; DeviceUnit = %x\n",
+ BlFileTable[FileId].u.PartitionContext.StartingSector,
+ BlFileTable[FileId].u.PartitionContext.EndingSector,
+ BlFileTable[FileId].u.PartitionContext.DiskId,
+ BlFileTable[FileId].u.PartitionContext.DeviceUnit
+ );
+
+ DbgPrint("Target Id = %d; Path Id = %d; Sector Shift = %lx; Size = %lx\n",
+ BlFileTable[FileId].u.PartitionContext.TargetId,
+ BlFileTable[FileId].u.PartitionContext.PathId,
+ BlFileTable[FileId].u.PartitionContext.SectorShift,
+ BlFileTable[FileId].u.PartitionContext.Size
+ );
+
+ DbgPrint("Hit any key\n");
+ while(!GET_KEY());
+#endif
+ return FALSE;
+
+}
+
+
+#endif
diff --git a/private/ntos/boot/lib/sources b/private/ntos/boot/lib/sources
new file mode 100644
index 000000000..f41e96cd2
--- /dev/null
+++ b/private/ntos/boot/lib/sources
@@ -0,0 +1,56 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=boot
+
+TARGETNAME=boot
+TARGETPATH=..\obj
+TARGETTYPE=LIBRARY
+
+!IF $(ALPHA)
+INCLUDES=\nt\public\sdk\inc;..\inc;..\..\inc;..\..\fastfat;..\..\cdfs;..\..\cntfs;..\..\config;..\..\fw\alpha
+!ELSE
+INCLUDES=\nt\public\sdk\inc;..\inc;..\..\inc;..\..\fastfat;..\..\cdfs;..\..\cntfs;..\..\config
+!ENDIF
+
+C_DEFINES=$(C_DEFINES) -D_NTSYSTEM_
+
+SOURCES=arcdisk.c \
+ blmemory.c \
+ blbind.c \
+ blconfig.c \
+ blio.c \
+ blload.c \
+ blres.c \
+ etfsboot.c \
+ fatboot.c \
+ ntfsboot.c \
+ hpfsboot.c \
+ cdfsboot.c \
+ nlsboot.c \
+ peldr.c \
+ bllog.c \
+ blmisc.c
+
diff --git a/private/ntos/boot/makefil0 b/private/ntos/boot/makefil0
new file mode 100644
index 000000000..9bcbdbaf9
--- /dev/null
+++ b/private/ntos/boot/makefil0
@@ -0,0 +1,106 @@
+!INCLUDE $(NTMAKEENV)\makefile.plt
+
+#
+# Only want to build the boot code on x86 machines.
+# Even on x86 machines, don't bother building on standard US builds
+# (just use the pre-built us version).
+#
+
+BUILD_BOOTCODE=1
+
+!IFNDEF LANGUAGE
+LANGUAGE=usa
+BUILD_BOOTCODE=0
+!ENDIF
+
+#
+# Boot code header file generation.
+# Boot code for each filesystem is placed in a header file
+# in sdk\inc.
+#
+
+FATFILE=$(BASEDIR)\public\sdk\inc\bootfat.h
+HPFSFILE=$(BASEDIR)\public\sdk\inc\boothpfs.h
+NTFSFILE=$(BASEDIR)\public\sdk\inc\bootntfs.h
+ETFSFILE=$(BASEDIR)\public\sdk\inc\bootetfs.h
+MBRFILE=$(BASEDIR)\public\sdk\inc\bootmbr.h
+
+FATCODE=bootcode\fat\i386
+HPFSCODE=bootcode\hpfs\i386
+NTFSCODE=bootcode\ntfs\i386
+ETFSCODE=bootcode\etfs\i386
+MBRCODE=bootcode\mbr\i386
+
+#
+# Targets
+#
+all: $(FATFILE) $(HPFSFILE) $(NTFSFILE) $(ETFSFILE) $(MBRFILE)
+!IF "$(BUILDMSG)" != ""
+ echo $(BUILDMSG)
+!ENDIF
+
+clean: cleansub all
+
+cleansub:
+ -erase $(FATFILE)
+ -erase $(HPFSFILE)
+ -erase $(NTFSFILE)
+ -erase $(MBRFILE)
+ -erase $(ETFSFILE)
+
+!IF $(BUILD_BOOTCODE)
+
+$(FATFILE): $(FATCODE)\fatboot.asm $(FATCODE)\$(LANGUAGE)\fatboot.inc
+ masm -I$(FATCODE)\$(LANGUAGE) $(FATCODE)\fatboot.asm;
+ link_60 /tiny fatboot.obj;
+ bin2c fatboot.com 512 0 512 $(FATFILE) FatBootCode
+ del fatboot.obj fatboot.com
+
+$(HPFSFILE): $(HPFSCODE)\pinboot.asm $(HPFSCODE)\$(LANGUAGE)\pinboot.inc \
+ $(HPFSCODE)\buf.inc $(HPFSCODE)\chain.inc $(HPFSCODE)\const.inc \
+ $(HPFSCODE)\dir.inc $(HPFSCODE)\dirent.inc $(HPFSCODE)\fnode.inc \
+ $(HPFSCODE)\filemode.inc $(HPFSCODE)\fsstat.inc $(HPFSCODE)\macro.inc \
+ $(HPFSCODE)\misc.inc $(HPFSCODE)\superb.inc $(HPFSCODE)\tables.inc \
+ $(HPFSCODE)\volume.inc
+ masm -I$(HPFSCODE)\$(LANGUAGE) -I$(HPFSCODE) $(HPFSCODE)\pinboot.asm;
+ link_60 /tiny pinboot.obj;
+ bin2c pinboot.com 8192 0 8192 $(HPFSFILE) HpfsBootCode
+ del pinboot.obj pinboot.com
+
+$(NTFSFILE): $(NTFSCODE)\ntfsboot.asm $(NTFSCODE)\ntfs.inc $(NTFSCODE)\$(LANGUAGE)\ntfsboot.inc
+ masm -I$(NTFSCODE)\$(LANGUAGE) -I$(NTFSCODE) $(NTFSCODE)\ntfsboot.asm;
+ link_60 /tiny ntfsboot.obj;
+ bin2c ntfsboot.com 8192 0 8192 $(NTFSFILE) NtfsBootCode
+ del ntfsboot.obj ntfsboot.com
+
+$(ETFSFILE): $(ETFSCODE)\etfsboot.asm $(ETFSCODE)\$(LANGUAGE)\etfsboot.inc
+ masm -I$(ETFSCODE)\$(LANGUAGE) $(ETFSCODE)\etfsboot.asm;
+ link_60 /tiny etfsboot.obj;
+ bin2c etfsboot.com 2048 0 2048 $(ETFSFILE) EtfsBootCode
+ del etfsboot.obj
+
+$(MBRFILE): $(MBRCODE)\x86mboot.asm $(MBRCODE)\$(LANGUAGE)\x86mboot.msg
+ masm -I$(MBRCODE)\$(LANGUAGE) $(MBRCODE)\x86mboot.asm;
+ link_60 /tiny x86mboot.obj;
+ bin2c x86mboot.com 512 0 512 $(MBRFILE) x86BootCode
+ del x86mboot.obj x86mboot.com
+
+!ELSE
+
+$(FATFILE): $(FATCODE)\$(LANGUAGE)\bootfat.h
+ copy $(FATCODE)\$(LANGUAGE)\bootfat.h $(FATFILE)
+
+$(HPFSFILE): $(HPFSCODE)\$(LANGUAGE)\boothpfs.h
+ copy $(HPFSCODE)\$(LANGUAGE)\boothpfs.h $(HPFSFILE)
+
+$(NTFSFILE): $(NTFSCODE)\$(LANGUAGE)\bootntfs.h
+ copy $(NTFSCODE)\$(LANGUAGE)\bootntfs.h $(NTFSFILE)
+
+$(ETFSFILE): $(ETFSCODE)\$(LANGUAGE)\bootetfs.h
+ copy $(ETFSCODE)\$(LANGUAGE)\bootetfs.h $(ETFSFILE)
+
+$(MBRFILE): $(MBRCODE)\$(LANGUAGE)\bootmbr.h
+ copy $(MBRCODE)\$(LANGUAGE)\bootmbr.h $(MBRFILE)
+
+!ENDIF
+
diff --git a/private/ntos/boot/setup/alpha/sources b/private/ntos/boot/setup/alpha/sources
new file mode 100644
index 000000000..d7b073b4b
--- /dev/null
+++ b/private/ntos/boot/setup/alpha/sources
@@ -0,0 +1,5 @@
+ALPHA_SOURCES=arcdtect.c
+
+
+NTTARGETFILES=obj\alpha\setupldr
+
diff --git a/private/ntos/boot/setup/alphaldr.rsp b/private/ntos/boot/setup/alphaldr.rsp
new file mode 100644
index 000000000..0e4de61df
--- /dev/null
+++ b/private/ntos/boot/setup/alphaldr.rsp
@@ -0,0 +1,17 @@
+-machine:alpha
+-force:multiple
+-rom
+-nodefaultlib
+-debug:notmapped
+-debugtype:coff
+-align:0x200
+-fixed
+-base:0x80600000
+-entry:SlInit
+-map:obj\alpha\setupldr.map
+obj\alpha\setupldr.lib
+obj\alpha\setupldr.res
+..\obj\alpha\boot.lib
+..\..\obj\alpha\ke.lib
+..\..\rtl\obj\alpha\bldrrtl.lib
+..\..\..\..\public\sdk\lib\alpha\libcntpr.lib
diff --git a/private/ntos/boot/setup/arcdisp.c b/private/ntos/boot/setup/arcdisp.c
new file mode 100644
index 000000000..77f0a4c5b
--- /dev/null
+++ b/private/ntos/boot/setup/arcdisp.c
@@ -0,0 +1,1762 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ arcdisp.c
+
+Abstract:
+
+ This module provides code for managing screen output on an ARC-compliant
+ system.
+
+Author:
+
+ John Vert (jvert) 6-Oct-1993
+
+Revision History:
+
+ John Vert (jvert) 6-Oct-1993
+ Taken from old 1.0 splib sources
+
+--*/
+#include "setupldr.h"
+#include "stdio.h"
+
+//
+// The screen is divided into 3 areas: the header area, the status area,
+// and the client area. The header area basically always says "Windows NT
+// Setup". The status area is always 1 line high and displayed using a
+// different attribute (black on gray).
+//
+
+
+#define HEADER_HEIGHT 3
+#define MAX_STATUS 200 // allow up to 1600 horizontal res.
+
+#define SCREEN_SIZE (ScreenWidth*ScreenHeight)
+
+
+ULONG ScreenWidth=80;
+ULONG ScreenHeight=25;
+ULONG ScreenX=0,ScreenY=0;
+UCHAR CurAttribute = DEFATT;
+CHAR MessageBuffer[1024];
+
+//
+// private function prototypes
+//
+VOID
+SlpDrawMenu(
+ IN ULONG X,
+ IN ULONG Y,
+ IN ULONG TopItem,
+ IN ULONG Height,
+ IN PSL_MENU Menu
+ );
+
+VOID
+SlpDrawMenuItem(
+ IN ULONG X,
+ IN ULONG Y,
+ IN ULONG TopItem,
+ IN ULONG Height,
+ IN ULONG Item,
+ IN PSL_MENU Menu
+ );
+
+VOID
+SlpSizeMessage(
+ IN PCHAR Message,
+ OUT PULONG Lines,
+ OUT PULONG MaxLength,
+ OUT ULONG LineLength[],
+ OUT PCHAR LineText[]
+ );
+
+
+
+PSL_MENU
+SlCreateMenu(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Allocates and initializes a new menu structure.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ Pointer to the new menu structure if successful.
+
+ NULL on failure
+
+--*/
+{
+ PSL_MENU p;
+
+ p=BlAllocateHeap(sizeof(SL_MENU));
+ if (p==NULL) {
+ return(NULL);
+ }
+ p->ItemCount = 0;
+ p->Width = 0;
+ InitializeListHead(&p->ItemListHead);
+ return(p);
+}
+
+
+BOOLEAN
+SlGetMenuItemIndex(
+ IN PSL_MENU Menu,
+ IN PCHAR Text,
+ OUT PULONG Index
+ )
+
+/*++
+
+Routine Description:
+
+ Given the text of a menu item, returns the index of that item.
+
+Arguments:
+
+ Menu - Supplies the menu
+
+ Text - Supplies the text to search for.
+
+ Index - Returns the index of the text in the menu
+
+Return Value:
+
+ TRUE - Item was found.
+
+ FALSE - Item was not found
+
+--*/
+
+{
+ ULONG i;
+ PSL_MENUITEM Item;
+
+ //
+ // Find first item to display
+ //
+ Item = CONTAINING_RECORD(Menu->ItemListHead.Flink,
+ SL_MENUITEM,
+ ListEntry);
+
+ i=0;
+ while ( Item != CONTAINING_RECORD(&Menu->ItemListHead,
+ SL_MENUITEM,
+ ListEntry)) {
+ if (_stricmp(Item->Text,Text)==0) {
+ *Index = i;
+ return(TRUE);
+ }
+
+ Item = CONTAINING_RECORD(Item->ListEntry.Flink,
+ SL_MENUITEM,
+ ListEntry);
+ ++i;
+
+ }
+ return(FALSE);
+}
+
+
+PVOID
+SlGetMenuItem(
+ IN PSL_MENU Menu,
+ IN ULONG Item
+ )
+
+/*++
+
+Routine Description:
+
+ Given an item index, returns the data associated with that item.
+
+Arguments:
+
+ Menu - Supplies the menu structure.
+
+ Item - Supplies the item index.
+
+Return Value:
+
+ The data associated with the given item.
+
+--*/
+
+{
+ ULONG i;
+ PSL_MENUITEM MenuItem;
+
+ //
+ // Find item to return
+ //
+ MenuItem = CONTAINING_RECORD(Menu->ItemListHead.Flink,
+ SL_MENUITEM,
+ ListEntry);
+
+ for (i=0;i<Item;i++) {
+ MenuItem = CONTAINING_RECORD(MenuItem->ListEntry.Flink,
+ SL_MENUITEM,
+ ListEntry);
+
+#if DBG
+ if (&MenuItem->ListEntry == &Menu->ItemListHead) {
+ SlError(Item);
+ return(NULL);
+ }
+#endif
+ }
+ return(MenuItem->Data);
+
+}
+
+
+ULONG
+SlAddMenuItem(
+ PSL_MENU Menu,
+ PCHAR Text,
+ PVOID Data,
+ ULONG Attributes
+ )
+
+/*++
+
+Routine Description:
+
+ Adds an item to the menu
+
+Arguments:
+
+ Menu - Supplies a pointer to the menu the item will be added to
+
+ Text - Supplies the text to be displayed in the menu
+
+ Data - Supplies a pointer to the data to be returned when the item
+ is selected.
+
+ Attributes - Supplies any attributes for the item.
+
+Return Value:
+
+ The Selection index if successful
+
+ -1 on failure
+
+--*/
+{
+ PSL_MENUITEM NewItem;
+ ULONG Length;
+
+ NewItem = BlAllocateHeap(sizeof(SL_MENUITEM));
+ if (NewItem==NULL) {
+ SlError(0);
+ return((ULONG)-1);
+ }
+ InsertTailList(&Menu->ItemListHead, &NewItem->ListEntry);
+ Menu->ItemCount += 1;
+
+ NewItem->Text = Text;
+ NewItem->Data = Data;
+ NewItem->Attributes = Attributes;
+ Length = strlen(Text);
+ if (Length > Menu->Width) {
+ Menu->Width = Length;
+ }
+ return(Menu->ItemCount - 1);
+}
+
+
+ULONG
+SlDisplayMenu(
+ IN ULONG HeaderId,
+ IN PSL_MENU Menu,
+ IN OUT PULONG Selection
+ )
+
+/*++
+
+Routine Description:
+
+ Displays a menu and allows the user to pick a selection
+
+Arguments:
+
+ HeaderId - Supplies the message ID of the prompt header
+ to be displayed above the menu.
+
+ Menu - Supplies a pointer to the menu to be displayed
+
+ Selection - Supplies the index of the default item.
+ Returns the index of the selected item.
+
+Return Value:
+
+ Key that terminated the menu display.
+
+--*/
+{
+ LONG X, Y;
+ ULONG Height;
+ ULONG Width;
+ ULONG TopItem;
+ ULONG c;
+ ULONG PreviousSelection;
+ ULONG Sel;
+ PCHAR Header;
+ ULONG HeaderLines;
+ ULONG MaxHeaderLength;
+ PCHAR HeaderText[20];
+ ULONG HeaderLength[20];
+ ULONG MaxMenuHeight;
+ ULONG i;
+ ULONG Count;
+
+ Header = BlFindMessage(HeaderId);
+
+ SlpSizeMessage(Header,
+ &HeaderLines,
+ &MaxHeaderLength,
+ HeaderLength,
+ HeaderText);
+
+ X = (ScreenWidth-MaxHeaderLength)/2;
+ for (i=0;i<HeaderLines;i++) {
+ SlPositionCursor(X,i+4);
+ ArcWrite(ARC_CONSOLE_OUTPUT,HeaderText[i],HeaderLength[i],&Count);
+ }
+
+ if (MaxHeaderLength > ScreenWidth) {
+ MaxHeaderLength = ScreenWidth;
+ }
+
+ Width = Menu->Width+4;
+ if (Width > ScreenWidth) {
+ Width=ScreenWidth;
+ }
+
+ MaxMenuHeight = ScreenHeight-(HeaderLines+13);
+
+ Height = Menu->ItemCount+2;
+ if (Height > MaxMenuHeight) {
+ Height = MaxMenuHeight;
+ }
+
+ X = ((ScreenWidth - Width)/2 > 0) ? (ScreenWidth-Width)/2 : 0;
+ Y = (MaxMenuHeight - Height)/2 + HeaderLines + 4;
+
+ TopItem = 0;
+ Sel = *Selection;
+ //
+ // Make sure default item is in view;
+ //
+ if (Sel >= Height - 2) {
+ TopItem = Sel - Height + 3;
+ }
+
+ SlpDrawMenu(X,Y,
+ TopItem,
+ Height,
+ Menu);
+
+ //
+ // highlight default selection
+ //
+ SlSetCurrentAttribute(INVATT);
+ SlpDrawMenuItem(X,Y,
+ TopItem,
+ Height,
+ Sel,
+ Menu);
+ SlSetCurrentAttribute(DEFATT);
+ SlFlushConsoleBuffer();
+ do {
+ c = SlGetChar();
+ PreviousSelection = Sel;
+ SlpDrawMenuItem(X, Y,
+ TopItem,
+ Height,
+ Sel,
+ Menu);
+
+ switch (c) {
+ case SL_KEY_UP:
+ if(Sel > 0) {
+ Sel--;
+ }
+ break;
+
+ case SL_KEY_DOWN:
+ if(Sel < Menu->ItemCount - 1) {
+ Sel++;
+ }
+ break;
+
+ case SL_KEY_HOME:
+ Sel = 0;
+ break;
+
+ case SL_KEY_END:
+ Sel = Menu->ItemCount - 1;
+ break;
+
+ case SL_KEY_PAGEUP:
+ if (Menu->ItemCount > Height) {
+ if (Sel > Height) {
+ Sel -= Height;
+ } else {
+ Sel = 0;
+ }
+ }
+ break;
+
+ case SL_KEY_PAGEDOWN:
+ if (Menu->ItemCount > Height) {
+ Sel += Height;
+ if (Sel >= Menu->ItemCount) {
+ Sel = Menu->ItemCount - 1;
+ }
+ }
+ break;
+
+ case SL_KEY_F1:
+ case SL_KEY_F3:
+ case ASCI_CR:
+ case ASCI_ESC:
+ *Selection = Sel;
+ return(c);
+
+ }
+
+ if (Sel < TopItem) {
+ TopItem = Sel;
+ SlpDrawMenu(X, Y,
+ TopItem,
+ Height,
+ Menu);
+ } else if (Sel > TopItem+Height-3) {
+ TopItem = Sel - Height + 3;
+ SlpDrawMenu(X, Y,
+ TopItem,
+ Height,
+ Menu);
+ }
+ //
+ // highlight default selection
+ //
+ SlSetCurrentAttribute(INVATT);
+ SlpDrawMenuItem(X,Y,
+ TopItem,
+ Height,
+ Sel,
+ Menu);
+ SlSetCurrentAttribute(DEFATT);
+
+
+ } while ( TRUE );
+
+}
+
+
+
+VOID
+SlpDrawMenu(
+ IN ULONG X,
+ IN ULONG Y,
+ IN ULONG TopItem,
+ IN ULONG Height,
+ IN PSL_MENU Menu
+ )
+
+/*++
+
+Routine Description:
+
+ Displays the menu on the screen
+
+Arguments:
+
+ X - Supplies X coordinate of upper-left corner of menu
+
+ Y - Supplies Y coordinate of upper-left corner of menu
+
+ TopItem - Supplies index of item at the top of the menu
+
+ Height - Supplies the height of the menu
+
+ Menu - Supplies the menu to be displayed
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG i;
+ PSL_MENUITEM Item;
+ ULONG Count;
+ CHAR Output[80];
+ ULONG Length;
+ ULONG MenuWidth;
+
+ MenuWidth = Menu->Width+4;
+ Output[0]=GetGraphicsChar(GraphicsCharDoubleRightDoubleDown);
+ for (i=1;i<MenuWidth-1;i++) {
+ Output[i]=GetGraphicsChar(GraphicsCharDoubleHorizontal);
+ }
+ Output[MenuWidth-1]=GetGraphicsChar(GraphicsCharDoubleLeftDoubleDown);
+ SlPositionCursor(X,Y);
+ ArcWrite(ARC_CONSOLE_OUTPUT,Output,MenuWidth,&Count);
+ //
+ // Find first item to display
+ //
+ Item = CONTAINING_RECORD(Menu->ItemListHead.Flink,
+ SL_MENUITEM,
+ ListEntry);
+
+ for (i=0;i<TopItem;i++) {
+ Item = CONTAINING_RECORD(Item->ListEntry.Flink,
+ SL_MENUITEM,
+ ListEntry);
+ }
+
+ //
+ // Display items
+ //
+ Output[0]=
+ Output[MenuWidth-1]=GetGraphicsChar(GraphicsCharDoubleVertical);
+ for (i=Y+1;i<Y+Height-1;i++) {
+ RtlFillMemory(Output+1,MenuWidth-2,' ');
+ SlPositionCursor(X, i);
+
+ if (&Item->ListEntry != &Menu->ItemListHead) {
+ Length = strlen(Item->Text);
+ RtlCopyMemory(Output+2,Item->Text,Length);
+ Item = CONTAINING_RECORD(Item->ListEntry.Flink,
+ SL_MENUITEM,
+ ListEntry);
+ }
+ ArcWrite(ARC_CONSOLE_OUTPUT,Output,MenuWidth,&Count);
+ }
+ Output[0]=GetGraphicsChar(GraphicsCharDoubleRightDoubleUp);
+ for (i=1;i<MenuWidth-1;i++) {
+ Output[i]=GetGraphicsChar(GraphicsCharDoubleHorizontal);
+ }
+ Output[MenuWidth-1]=GetGraphicsChar(GraphicsCharDoubleLeftDoubleUp);
+ SlPositionCursor(X,Y+Height-1);
+ ArcWrite(ARC_CONSOLE_OUTPUT,Output,MenuWidth,&Count);
+}
+
+
+VOID
+SlpDrawMenuItem(
+ IN ULONG X,
+ IN ULONG Y,
+ IN ULONG TopItem,
+ IN ULONG Height,
+ IN ULONG Item,
+ IN PSL_MENU Menu
+ )
+
+/*++
+
+Routine Description:
+
+ Redraws the given item
+
+Arguments:
+
+ X - Supplies X coordinate of upper-left corner of menu
+
+ Y - Supplies Y coordinate of upper-left corner of menu
+
+ TopItem - Supplies index of item at the top of the menu
+
+ Height - Supplies the height of the menu
+
+ Item - Supplies the index of the item to be redrawn
+
+ Menu - Supplies the menu to be displayed
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG i;
+ PSL_MENUITEM MenuItem;
+ ULONG Count;
+ CHAR Width[80];
+
+ //
+ // Find item to display
+ //
+ MenuItem = CONTAINING_RECORD(Menu->ItemListHead.Flink,
+ SL_MENUITEM,
+ ListEntry);
+
+ for (i=0;i<Item;i++) {
+ MenuItem = CONTAINING_RECORD(MenuItem->ListEntry.Flink,
+ SL_MENUITEM,
+ ListEntry);
+
+#if DBG
+ if (&MenuItem->ListEntry == &Menu->ItemListHead) {
+ SlError(Item);
+ }
+#endif
+ }
+
+ RtlFillMemory(Width,Menu->Width,' ');
+ RtlCopyMemory(Width,MenuItem->Text,strlen(MenuItem->Text));
+ SlPositionCursor(X+2, Y+(Item-TopItem)+1);
+ ArcWrite(ARC_CONSOLE_OUTPUT,Width,Menu->Width,&Count);
+}
+
+
+
+VOID
+SlInitDisplay(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Clears the screen and does some initialization of global variables based
+ on the ARC display information.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PARC_DISPLAY_STATUS DisplayStatus;
+
+ //
+ // Check to see if this version of the ARC firmware is revision 2 or above.
+ //
+ // If not, we default to 80x25
+ //
+ if ((SYSTEM_BLOCK->Version > 1) ||
+ ((SYSTEM_BLOCK->Version == 1) && (SYSTEM_BLOCK->Revision >= 2))) {
+
+ //
+ // Additional checks are required on 1.2 firmware, since some
+ // 1.2 firmware does not implement ArcGetDisplayStatus
+ //
+ if ((SYSTEM_BLOCK->FirmwareVectorLength > (ULONG)GetDisplayStatusRoutine*sizeof(PVOID)) &&
+ (SYSTEM_BLOCK->FirmwareVector[GetDisplayStatusRoutine] != NULL)) {
+ DisplayStatus = ArcGetDisplayStatus(ARC_CONSOLE_OUTPUT);
+
+ ScreenWidth = DisplayStatus->CursorMaxXPosition;
+ ScreenHeight = DisplayStatus->CursorMaxYPosition;
+ }
+ }
+
+ SlSetCurrentAttribute(DEFATT);
+ SlClearDisplay();
+}
+
+
+VOID
+SlPrint(
+ IN PCHAR FormatString,
+ ...
+ )
+{
+ va_list arglist;
+ CHAR text[MAX_STATUS+1];
+ ULONG Count,Length;
+ ULONG MaxWidth = ScreenWidth - 2;
+
+ if (MaxWidth > MAX_STATUS) {
+ MaxWidth = MAX_STATUS;
+ }
+
+ va_start(arglist,FormatString);
+ Length = _vsnprintf(text,MaxWidth*sizeof(CHAR),FormatString,arglist);
+ text[MaxWidth] = 0;
+
+ ArcWrite(ARC_CONSOLE_OUTPUT,text,Length,&Count);
+ va_end(arglist);
+}
+
+
+VOID
+SlClearDisplay(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Clears the entire display, including header, client area, and status line.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ SlClearClientArea();
+ SlWriteHeaderText(0);
+ SlWriteStatusText("");
+
+}
+
+ARC_STATUS
+SlClearClientArea(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Clears the client area of the screen. Does not disturb the header or
+ status areas.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ always ESUCCESS
+
+--*/
+
+{
+ USHORT i;
+
+ for(i=HEADER_HEIGHT; i<ScreenHeight-1; i++) {
+ SlPositionCursor(0,i);
+ SlClearToEol();
+ }
+
+ //
+ // home cursor
+ //
+
+ SlPositionCursor(0,0);
+ return(ESUCCESS);
+}
+
+
+ARC_STATUS
+SlClearToEol(
+ VOID
+ )
+{
+ SlPrint(ASCI_CSI_OUT "2K");
+ return(ESUCCESS);
+}
+
+
+VOID
+SlGetCursorPosition(
+ OUT unsigned *x,
+ OUT unsigned *y
+ )
+{
+ *x = ScreenX;
+ *y = ScreenY;
+}
+
+
+ARC_STATUS
+SlPositionCursor(
+ IN unsigned x,
+ IN unsigned y
+ )
+{
+ //
+ // clip to screen
+ //
+
+ if(x>=ScreenWidth) {
+ x = ScreenWidth-1;
+ }
+
+ if(y>=ScreenHeight) {
+ y = ScreenHeight-1;
+ }
+
+ ScreenX = x;
+ ScreenY = y;
+
+ SlPrint(ASCI_CSI_OUT "%d;%dH",y+1,x+1);
+ return(ESUCCESS);
+}
+
+
+ARC_STATUS
+SlWriteString(
+ IN PUCHAR s
+ )
+{
+ PUCHAR p = s,q;
+ BOOLEAN done = FALSE;
+ ULONG len,count;
+
+ do {
+ q = p;
+ while((*q != '\0') && (*q != '\n')) {
+ q++;
+ }
+ if(*q == '\0') {
+ done = TRUE;
+ } else {
+ *q = '\0';
+ }
+ len = q - p;
+
+ ArcWrite(ARC_CONSOLE_OUTPUT,p,len,&count);
+
+ ScreenX += len;
+
+ if(!done) {
+ ArcWrite(ARC_CONSOLE_OUTPUT,"\r\n",2,&count);
+ ScreenX = 0;
+ ScreenY++;
+ if(ScreenY == ScreenHeight) {
+ ScreenY = ScreenHeight-1;
+ }
+ *q = '\n';
+ }
+ p = q + 1;
+ } while(!done);
+
+ return(ESUCCESS);
+}
+
+
+VOID
+SlSetCurrentAttribute(
+ IN UCHAR Attribute
+ )
+{
+ CurAttribute = Attribute;
+
+ SlPrint(ASCI_CSI_OUT "0m" ASCI_CSI_OUT "3%dm" ASCI_CSI_OUT "4%dm",
+ Attribute & 7, // foreground color
+ (Attribute >> 4) & 7 // background color
+ );
+
+ if(Attribute & ATT_FG_INTENSE) {
+ SlPrint(ASCI_CSI_OUT "1m");
+ }
+}
+
+
+VOID
+SlWriteHeaderText(
+ IN ULONG MsgId
+ )
+
+/*++
+
+Routine Description:
+
+ Updates the header on the screen with a given string
+
+Arguments:
+
+ MsgId - Supplies the message ID of the new string to be displayed. This should
+ be just one line long. If it is 0, the header is cleared.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ int i;
+
+ for(i=HEADER_HEIGHT-1; i>=0; i--) {
+ SlPositionCursor(0,i);
+ SlClearToEol();
+ }
+
+ if (MsgId != 0) {
+ SlWriteString(BlFindMessage(MsgId));
+ }
+}
+
+//
+// Stores the current status text. The size is the screen width, plus the
+// terminating nul char.
+//
+CHAR StatusText[MAX_STATUS];
+
+UCHAR StatusAttribute = DEFSTATTR;
+
+VOID
+SlSetStatusAttribute(
+ IN UCHAR Attribute
+ )
+{
+ StatusAttribute = Attribute;
+}
+
+
+VOID
+SlWriteStatusText(
+ IN PCHAR Text
+ )
+
+/*++
+
+Routine Description:
+
+ Updates the status area on the screen with a given string
+
+Arguments:
+
+ Text - Supplies the new text for the status area.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ UCHAR AttributeSave = CurAttribute;
+ CHAR *p;
+ ULONG Count;
+ ULONG MaxWidth = ScreenWidth - 2;
+
+ if (MaxWidth > MAX_STATUS) {
+ MaxWidth = MAX_STATUS;
+ }
+
+ RtlFillMemory(StatusText,sizeof(StatusText),' ');
+
+ //
+ // Strip cr/lf as we copy the status text into the status text buffer.
+ //
+ p = StatusText;
+ Count = 0;
+ while((Count < MaxWidth) && *Text) {
+ if((*Text != '\r') && (*Text != '\n')) {
+ *p++ = *Text;
+ Count++;
+ }
+ Text++;
+ }
+
+ SlSetCurrentAttribute(StatusAttribute);
+ SlPositionCursor(0,ScreenHeight-1);
+ ArcWrite(ARC_CONSOLE_OUTPUT," ",2,&Count);
+ SlPositionCursor(2,ScreenHeight-1);
+ ArcWrite(ARC_CONSOLE_OUTPUT,StatusText,MaxWidth*sizeof(CHAR),&Count);
+ SlSetCurrentAttribute(AttributeSave);
+ SlPositionCursor(0,5);
+}
+
+
+VOID
+SlGetStatusText(
+ OUT PCHAR Text
+ )
+{
+ RtlCopyMemory(Text,StatusText,sizeof(StatusText));
+}
+
+
+
+#if DBG
+VOID
+SlWriteDbgText(
+ IN PCHAR text
+ )
+{
+ UCHAR SavedAttribute = CurAttribute;
+
+ SlPositionCursor(0,0);
+ CurAttribute = ATT_FG_YELLOW | ATT_BG_RED | ATT_FG_INTENSE;
+
+ SlClearToEol();
+ SlWriteString(text);
+
+ CurAttribute = SavedAttribute;
+}
+#endif
+
+
+VOID
+SlFlushConsoleBuffer(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine flushes the console buffer, so that we don't have any
+ pre-existing keypresses in the buffer when we prompt the user to
+ 'press any key to continue.'
+
+Arguments:
+
+ NONE
+
+Return Value:
+
+ NONE
+
+--*/
+
+{
+ UCHAR c;
+ ULONG count;
+
+ while(ArcGetReadStatus(ARC_CONSOLE_INPUT) == ESUCCESS) {
+ ArcRead(ARC_CONSOLE_INPUT, &c, 1, &count);
+ }
+}
+
+
+ULONG
+SlGetChar(
+ VOID
+ )
+{
+ UCHAR c;
+ ULONG count;
+
+
+ ArcRead(ARC_CONSOLE_INPUT,&c,1,&count);
+
+ if(c == ASCI_CSI_IN) {
+
+ ArcRead(ARC_CONSOLE_INPUT,&c,1,&count);
+
+ switch(c) {
+
+ //
+ // see ntos\fw\mips\fwsignal.c!TranslateScanCode() for these codes.
+ // Additional codes that might be useful someday:
+ // left=C, right=D, insert=@, delete=P
+ //
+
+ case 'A': // up arrow
+ return(SL_KEY_UP);
+
+ case 'B': // down arrow
+ return(SL_KEY_DOWN);
+
+ case 'H': // home
+ return(SL_KEY_HOME);
+
+ case 'K': // end
+ return(SL_KEY_END);
+
+ case '?': // page up
+ return(SL_KEY_PAGEUP);
+
+ case '/': // page down
+ return(SL_KEY_PAGEDOWN);
+
+ case 'O': // function keys
+
+ ArcRead(ARC_CONSOLE_INPUT,&c,1,&count);
+
+ //
+ // F1=P, F2=Q, F3=w, F4 =x, F5 =t, F6 =u
+ // F7=q, F8=r, F9=p, F10=m, F11=A, F12=B
+ //
+ // Note: as of 12/15/92, f11 and f12 were commented out in the
+ // firmware sources so are probably never returned.
+ //
+
+ switch(c) {
+
+ case 'P':
+ return(SL_KEY_F1);
+
+ case 'w':
+ return(SL_KEY_F3);
+
+ case 't':
+ return(SL_KEY_F5);
+
+ case 'u':
+ return(SL_KEY_F6);
+
+ default:
+ return(0);
+ }
+
+ default:
+ return(0);
+ }
+
+ } else {
+ if(c == ASCI_LF) {
+ c = ASCI_CR;
+ }
+ return((ULONG)c);
+ }
+}
+
+
+BOOLEAN
+SlPromptForDisk(
+ IN PCHAR DiskName,
+ IN BOOLEAN IsCancellable
+ )
+
+/*++
+
+Routine Description:
+
+ This routine prompts a user to insert a given diskette #, or to abort the
+ Setup process.
+
+ The status line will be erased.
+
+Arguments:
+
+ DiskName - Supplies the name of the disk to be inserted.
+
+ IsCancellable - Supplies flag indicating whether prompt may be cancelled.
+
+Return Value:
+
+ TRUE - The user has pressed OK
+
+ FALSE - The user has pressed CANCEL
+
+--*/
+
+{
+ ULONG msg;
+ ULONG y;
+ ULONG Key;
+ PCHAR StatusText;
+ PCHAR PleaseWait;
+ ULONG i;
+ CHAR DiskNameDisplayed[81];
+ BOOLEAN Repaint=TRUE;
+
+ SlWriteStatusText("");
+
+ if(IsCancellable) {
+ msg = SL_NEXT_DISK_PROMPT_CANCELLABLE;
+ } else {
+ msg = SL_NEXT_DISK_PROMPT;
+ }
+ StatusText = BlFindMessage(msg);
+ if(StatusText == NULL) {
+ SlError(msg);
+ return(FALSE);
+ }
+
+ PleaseWait = BlFindMessage(SL_PLEASE_WAIT);
+ if(PleaseWait == NULL) {
+ SlError(SL_PLEASE_WAIT);
+ return(FALSE);
+ }
+
+ //
+ // Get first line of DiskName and save it in DiskNameDisplayed (limit to 80 chars)
+ //
+ for(i = 0;
+ ((i < 80) && DiskName[i] && (DiskName[i] != '\r') && (DiskName[i] != '\n'));
+ i++)
+ {
+ DiskNameDisplayed[i] = DiskName[i];
+ }
+ DiskNameDisplayed[i] = '\0';
+
+ do {
+ if (Repaint) {
+ SlClearClientArea();
+ y = SlDisplayMessageBox(SL_MSG_INSERT_DISK);
+ SlPositionCursor((ScreenWidth-i)/2,y+2);
+ SlWriteString(DiskNameDisplayed);
+ SlWriteStatusText(StatusText);
+ }
+ Repaint = FALSE;
+ SlFlushConsoleBuffer();
+ Key = SlGetChar();
+
+ if (Key == ASCI_CR) {
+ SlClearClientArea();
+ SlWriteStatusText(PleaseWait);
+ return(TRUE);
+ } else if (Key == SL_KEY_F3) {
+ SlConfirmExit();
+ Repaint=TRUE;
+ } else if((Key == ASCI_ESC) && IsCancellable) {
+ SlWriteStatusText("");
+ SlClearClientArea();
+ return FALSE;
+ }
+ } while ( TRUE );
+}
+
+
+VOID
+SlConfirmExit(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Routine to be called when user presses F3. Confirms that he really wants
+ to exit by popping up a dialog. DOES NOT RETURN if user chooses to exit.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG c;
+ CHAR OldStatus[MAX_STATUS];
+ PCHAR StatusText;
+
+ SlGetStatusText(OldStatus);
+
+ SlClearClientArea();
+
+ SlSetCurrentAttribute(DEFDLGATT);
+
+ SlDisplayMessageBox(SL_MSG_EXIT_DIALOG);
+
+ SlSetCurrentAttribute(DEFATT);
+
+ SlFlushConsoleBuffer();
+
+ while(1) {
+ c = SlGetChar();
+ if(c == ASCI_CR) {
+ SlWriteStatusText(OldStatus);
+ return;
+ }
+ if(c == SL_KEY_F3) {
+ StatusText = BlFindMessage(SL_REBOOT_PROMPT);
+ SlClearClientArea();
+#ifdef i386
+ SlDisplayMessageBox(SL_SCRN_TEXTSETUP_EXITED);
+#else
+ SlDisplayMessageBox(SL_SCRN_TEXTSETUP_EXITED_ARC);
+#endif
+ SlWriteStatusText(StatusText);
+
+ SlFlushConsoleBuffer();
+ while(SlGetChar() != ASCI_CR);
+ ArcRestart();
+ }
+ }
+}
+
+
+
+VOID
+SlFriendlyError(
+ IN ULONG uStatus,
+ IN PCHAR pchBadFile,
+ IN ULONG uLine,
+ IN PCHAR pchCodeFile
+ )
+
+/*++
+
+Routine Description:
+
+ This is called when an error occurs. It puts up a
+ message box, displays an informative message, and allows
+ the user to continue. It is intended to give friendlier
+ messages than the SlError macro, in the cases where SlError
+ gets passed ARC error codes.
+
+ The status text line will be erased.
+
+Arguments:
+
+ uStatus - ARC error code
+
+ pchBadFile - Name of file causing error (Must be given for handled
+ ARC codes. Optional for unhandled codes.)
+
+ uLine - Line # in source code file where error occurred (only
+ used for unhandled codes.)
+
+ pchCodeFile - Name of souce code file where error occurred (only
+ used for unhandled codes.)
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG uMsg;
+
+ SlClearClientArea();
+ switch(uStatus) {
+ case EBADF:
+ case EINVAL: // image corrupt
+ uMsg = SL_WARNING_IMG_CORRUPT;
+ break;
+
+ case EIO: // i/o error
+ uMsg = SL_WARNING_IOERR;
+ break;
+
+ case ENOENT: // file not found
+ uMsg = SL_WARNING_NOFILE;
+ break;
+
+ case ENOMEM: // insufficient memory
+ uMsg = SL_WARNING_NOMEM;
+ break;
+
+ case EACCES: // unrecognized file system
+ uMsg = SL_WARNING_BAD_FILESYS;
+ break;
+
+ default: // then get SlError() behavior (with optional bad file name)
+ if(pchBadFile) { // include error-causing file's name
+ SlMessageBox(
+ SL_WARNING_ERROR_WFILE,
+ pchBadFile,
+ uStatus,
+ uLine,
+ pchCodeFile
+ );
+ } else {
+ SlMessageBox(
+ SL_WARNING_ERROR,
+ uStatus,
+ uLine,
+ pchCodeFile
+ );
+ }
+ return;
+ }
+ SlMessageBox(
+ uMsg,
+ pchBadFile
+ );
+}
+
+VOID
+SlMessageBox(
+ IN ULONG MessageId,
+ ...
+ )
+
+/*++
+
+Routine Description:
+
+ This is called when an error occurs. It puts up a
+ message box, displays an informative message, and allows
+ the user to continue.
+
+ The status text line will be erased.
+
+Arguments:
+
+ MessageId - Supplies ID of message box to be presented.
+
+ any sprintf-compatible arguments to be inserted in the
+ message box.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ va_list args;
+
+ SlClearClientArea();
+ va_start(args, MessageId);
+ SlGenericMessageBox(MessageId, &args, NULL, NULL, NULL, NULL, TRUE);
+ va_end(args);
+
+ SlFlushConsoleBuffer();
+ SlGetChar();
+}
+
+
+ULONG
+SlDisplayMessageBox(
+ IN ULONG MessageId,
+ ...
+ )
+
+/*++
+
+Routine Description:
+
+ Just puts a message box up on the screen and returns.
+
+ The status text line will be erased.
+
+Arguments:
+
+ MessageId - Supplies ID of message box to be presented.
+
+ any sprintf-compatible arguments to be inserted in the
+ message box.
+
+Return Value:
+
+ Y position of top line of message box
+
+--*/
+
+{
+ ULONG y;
+ va_list args;
+
+ va_start(args, MessageId);
+ SlGenericMessageBox(MessageId, &args, NULL, NULL, &y, NULL, TRUE);
+ va_end(args);
+
+ return(y);
+}
+
+
+VOID
+SlFatalError(
+ IN ULONG MessageId,
+ ...
+ )
+
+/*++
+
+Routine Description:
+
+ This is called when a fatal error occurs. It clears the client
+ area, puts up a message box, displays the fatal error message, and
+ allows the user to press a key to reboot.
+
+ The status text line will be erased.
+
+Arguments:
+
+ MessageId - Supplies ID of message box to be presented.
+
+ any sprintf-compatible arguments to be inserted in the
+ message box.
+
+Return Value:
+
+ Does not return.
+
+--*/
+
+{
+ va_list args;
+ ULONG x,y;
+ PUCHAR Text;
+
+ SlClearClientArea();
+
+ Text = BlFindMessage(MessageId);
+ if(Text) {
+
+ va_start(args, MessageId);
+
+ _vsnprintf(MessageBuffer, sizeof(MessageBuffer), Text, args);
+
+ //
+ // Add a blank line, then concatenate the 'Can't continue' text.
+ //
+ strcat(MessageBuffer, "\r\n");
+
+ Text = BlFindMessage(SL_CANT_CONTINUE);
+ if(Text) {
+ strcat(MessageBuffer, Text);
+ }
+
+ Text = BlAllocateHeap((strlen(MessageBuffer)+1) * sizeof(CHAR));
+ strcpy(Text, MessageBuffer);
+
+ //
+ // Note that MessageId and args won't be used, since we're
+ // passing in our Text pointer.
+ //
+ SlGenericMessageBox(MessageId, &args, Text, &x, NULL, &y, TRUE);
+
+ va_end(args);
+
+ } else {
+ SlError(MessageId);
+ }
+
+ SlFlushConsoleBuffer();
+ SlGetChar();
+ ArcRestart();
+}
+
+
+VOID
+SlGenericMessageBox(
+ IN ULONG MessageId, OPTIONAL
+ IN va_list *args, OPTIONAL
+ IN PCHAR Message, OPTIONAL
+ IN OUT PULONG xLeft, OPTIONAL
+ IN OUT PULONG yTop, OPTIONAL
+ OUT PULONG yBottom, OPTIONAL
+ IN BOOLEAN bCenterMsg
+ )
+
+/*++
+
+Routine Description:
+
+ Formats and displays a message box. The longest line in the string
+ of characters will be centered on the screen if bCenterMsg is TRUE.
+
+ The status text line will be erased.
+
+Arguments:
+
+ NOTE: Either the MessageId/args pair or the Message string must be
+ specified. Message string will be used if non-NULL.
+
+ MessageId - Supplies the MessageId that will be looked up to provide
+ a NULL-terminated string of characters.
+ Each \r\n delimited string will be displayed on its own line.
+
+ args - Supplies the argument list that will be passed to vsprintf.
+
+ Message - Supplies the actual text of the message to be displayed
+
+ xLeft - If bCenterMsg is FALSE, then xLeft is used for the starting x
+ coordinate of the message (if specified, otherwise, x = 1).
+ Also, if specified, it receives the x coordinate of the left edge
+ of all lines that were displayed.
+
+ yTop - If bCenterMsg is FALSE, then yTop is used for the starting y
+ coordinate of the message (if specified, otherwise, y = 3).
+ Also, if specified, receives the y coordinate of the top line where
+ the message box was displayed.
+
+ yBottom - if specified, receives the y coordinate of the bottom line of
+ the message box.
+
+ bCenterMsg - if TRUE, center message on the screen.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PCHAR p;
+ ULONG NumLines;
+ ULONG MaxLength;
+ ULONG x;
+ ULONG y;
+ ULONG i;
+ PCHAR Line[20];
+ ULONG LineLength[20];
+ ULONG Count;
+
+ if(!Message) { // then look up the message
+ p=BlFindMessage(MessageId);
+ if (p==NULL) {
+ SlError(MessageId);
+ x=3;
+ y=ScreenHeight/2;
+ NumLines=0;
+ } else {
+ _vsnprintf(MessageBuffer,sizeof(MessageBuffer),p,*args);
+ Message = MessageBuffer;
+ }
+ } else {
+ //
+ // Just make p non-NULL, so we'll know it's OK to continue.
+ //
+ p = Message;
+ }
+
+ if(p) {
+
+ SlWriteStatusText(""); // Clear status bar
+
+ SlpSizeMessage(Message,
+ &NumLines,
+ &MaxLength,
+ LineLength,
+ Line);
+
+ if (MaxLength > ScreenWidth) {
+ MaxLength = ScreenWidth;
+ }
+
+ if(bCenterMsg) {
+ x = (ScreenWidth-MaxLength)/2;
+ y = (ScreenHeight-NumLines)/2;
+ } else {
+ if(xLeft) {
+ x = *xLeft;
+ } else {
+ x = 1;
+ }
+
+ if(yTop) {
+ y = *yTop;
+ } else {
+ y = 3;
+ }
+ }
+ }
+
+ for (i=0; i<NumLines; i++) {
+ SlPositionCursor(x, y+i);
+ ArcWrite(ARC_CONSOLE_OUTPUT,Line[i],LineLength[i],&Count);
+ }
+
+ if(xLeft) {
+ *xLeft = x;
+ }
+
+ if(yTop) {
+ *yTop = y;
+ }
+
+ if(yBottom) {
+ *yBottom = NumLines ? y+NumLines-1 : 0;
+ }
+}
+
+
+VOID
+SlpSizeMessage(
+ IN PCHAR Message,
+ OUT PULONG Lines,
+ OUT PULONG MaxLength,
+ OUT ULONG LineLength[],
+ OUT PCHAR LineText[]
+ )
+
+/*++
+
+Routine Description:
+
+ This routine walks down a message and determines the number of
+ lines and the maximum line length.
+
+Arguments:
+
+ Message - Supplies a pointer to a null-terminated message
+
+ Lines - Returns the number of lines
+
+ MaxLength - Returns the length of the longest line.
+
+ LineLength - Supplies a pointer to an array of ULONGs
+ Returns a filled in array containing the
+ length of each line.
+
+ LineText - Supplies a pointer to an array of PCHARs
+ Returns a filled in array containing a
+ pointer to the start of each line.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PCHAR p;
+ ULONG NumLines;
+ ULONG Length;
+
+ p = Message;
+ NumLines = 0;
+ *MaxLength = 0;
+ Length = 0;
+
+ //
+ // walk through the string, determining the number of lines
+ // and the length of the longest line.
+ //
+ LineText[0]=p;
+ while (*p != '\0') {
+ if ((*p == '\r') && (*(p+1) == '\n')) {
+ //
+ // End of a line.
+ //
+
+ if (Length > *MaxLength) {
+ *MaxLength = Length;
+ }
+ LineLength[NumLines] = Length;
+ ++NumLines;
+ Length = 0;
+ p += 2;
+ LineText[NumLines] = p;
+
+ } else {
+ ++Length;
+ ++p;
+
+ if (*p == '\0') {
+
+ //
+ // End of the message.
+ //
+
+ if (Length > *MaxLength) {
+ *MaxLength = Length;
+ }
+ LineLength[NumLines] = Length;
+ ++NumLines;
+ }
+ }
+ }
+
+ *Lines = NumLines;
+
+}
diff --git a/private/ntos/boot/setup/arcdtect.c b/private/ntos/boot/setup/arcdtect.c
new file mode 100644
index 000000000..df7880041
--- /dev/null
+++ b/private/ntos/boot/setup/arcdtect.c
@@ -0,0 +1,553 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ arcdtect.c
+
+Abstract:
+
+ Provides HAL and SCSI detection for ARC-compliant machines.
+
+Author:
+
+ John Vert (jvert) 21-Oct-1993
+
+Revision History:
+
+--*/
+#include "setupldr.h"
+#include <stdlib.h>
+
+
+//
+// Stuff used for detecting video
+//
+#define MAX_VIDEO_ADAPTERS 5
+ULONG VideoAdapterCount;
+PCONFIGURATION_COMPONENT_DATA VideoAdapter[MAX_VIDEO_ADAPTERS];
+
+VOID
+DecideVideoAdapter(
+ VOID
+ );
+
+BOOLEAN FoundUnknownScsi;
+
+//
+// private function prototypes
+//
+PCHAR
+SlpSearchSection(
+ IN PCHAR SectionName,
+ IN PCHAR TargetName
+ );
+
+BOOLEAN
+EnumerateSCSIAdapters(
+ IN PCONFIGURATION_COMPONENT_DATA ConfigData
+ );
+
+BOOLEAN
+EnumerateVideoAdapters(
+ IN PCONFIGURATION_COMPONENT_DATA ConfigData
+ );
+
+
+PCHAR
+SlDetectHal(
+ IN PSETUP_LOADER_BLOCK SetupBlock
+ )
+
+/*++
+
+Routine Description:
+
+ Determines the canonical short machine name for the HAL to be loaded for
+ this machine.
+
+ It does this by enumerating the [Map.Computer] section of the INF file and
+ comparing the strings there with the computer description in the ARC tree.
+
+ [Map.Computer]
+ msjazz_up = *Jazz
+ desksta1_up = "DESKTECH-ARCStation I"
+ pica61_up = "PICA-61"
+ duo_mp = *Duo
+
+ [Map.Computer]
+ DECjensen = "DEC-20Jensen"
+ DECjensen = "DEC-10Jensen"
+
+Arguments:
+
+ SetupBlock - Supplies a pointer to the Setup loader block.
+
+Return Value:
+
+ PCHAR - pointer to canonical shortname for the machine.
+ NULL - the type of machine could not be determined.
+
+--*/
+
+{
+ PCONFIGURATION_COMPONENT_DATA Node;
+ PCHAR MachineName;
+
+ //
+ // Find the system description node
+ //
+ Node = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
+ SystemClass,
+ ArcSystem,
+ NULL);
+ if (Node==NULL) {
+ SlError(0);
+ return(NULL);
+ }
+
+ MachineName = Node->ComponentEntry.Identifier;
+
+ return(MachineName ? SlpSearchSection("Map.Computer", MachineName) : NULL);
+}
+
+
+VOID
+SlDetectScsi(
+ IN PSETUP_LOADER_BLOCK SetupBlock
+ )
+/*++
+
+Routine Description:
+
+ Detects SCSI adapters on an ARC machine by walking the ARC firmware tree.
+
+ Fills in the appropriate entries in the setuploaderblock
+
+
+Arguments:
+
+ SetupBlock - Supplies a pointer to the setup loader block.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ FoundUnknownScsi = FALSE;
+
+ BlSearchConfigTree(BlLoaderBlock->ConfigurationRoot,
+ AdapterClass,
+ ScsiAdapter,
+ (ULONG)-1,
+ EnumerateSCSIAdapters);
+ if (FoundUnknownScsi) {
+ //
+ // We found at least one scsi device we didn't recognize,
+ // so force the OEM selection menu.
+ //
+ PromptOemScsi=TRUE;
+ }
+
+ SetupBlock->ScalarValues.LoadedScsi = 1;
+}
+
+
+BOOLEAN
+EnumerateSCSIAdapters(
+ IN PCONFIGURATION_COMPONENT_DATA ConfigData
+ )
+
+/*++
+
+Routine Description:
+
+ Callback function for enumerating SCSI adapters in the ARC tree.
+
+ Adds the SCSI adapter that was found to the list of detected SCSI devices.
+
+Arguments:
+
+ ConfigData - Supplies a pointer to the ARC node of the SCSI adapter.
+
+Return Value:
+
+ TRUE - continue searching
+
+ FALSE - some error, abort the search
+
+--*/
+
+{
+ PDETECTED_DEVICE ScsiDevice;
+ PCHAR AdapterName;
+ ULONG Ordinal;
+ PCHAR ScsiFileName;
+ PCHAR ScsiDescription;
+ SCSI_INSERT_STATUS sis;
+
+ AdapterName = SlpSearchSection("Map.SCSI",ConfigData->ComponentEntry.Identifier);
+ if (AdapterName==NULL) {
+ //
+ // We found an adapter in the ARC tree, but it is not one of the ones
+ // specified in our INF file, so trigger the prompt for an OEM driver
+ // disk.
+ //
+
+ FoundUnknownScsi = TRUE;
+ return(TRUE);
+ }
+
+ //
+ // Find this adapter's ordinal within the Scsi.Load section of txtsetup.sif
+ //
+ Ordinal = SlGetSectionKeyOrdinal(InfFile, "Scsi.Load", AdapterName);
+ if(Ordinal == (ULONG)-1) {
+ FoundUnknownScsi = TRUE;
+ return(TRUE);
+ }
+
+ //
+ // Find the driver filename
+ //
+ ScsiFileName = SlGetSectionKeyIndex(InfFile,
+ "Scsi.Load",
+ AdapterName,
+ SIF_FILENAME_INDEX);
+ if(!ScsiFileName) {
+ FoundUnknownScsi = TRUE;
+ return(TRUE);
+ }
+
+ //
+ // Create a new detected device entry.
+ //
+ if((sis = SlInsertScsiDevice(Ordinal, &ScsiDevice)) == ScsiInsertError) {
+ SlFriendlyError(ENOMEM, "SCSI detection", 0, NULL);
+ return(FALSE);
+ }
+
+ if(sis == ScsiInsertExisting) {
+#if DBG
+ //
+ // Sanity check to make sure we're talking about the same driver
+ //
+ if(_strcmpi(ScsiDevice->BaseDllName, ScsiFileName)) {
+ SlError(400);
+ return FALSE;
+ }
+#endif
+ } else {
+ //
+ // Find the driver description
+ //
+ ScsiDescription = SlGetIniValue(InfFile,
+ "SCSI",
+ AdapterName,
+ AdapterName);
+
+ ScsiDevice->IdString = AdapterName;
+ ScsiDevice->Description = ScsiDescription;
+ ScsiDevice->ThirdPartyOptionSelected = FALSE;
+ ScsiDevice->FileTypeBits = 0;
+ ScsiDevice->Files = NULL;
+ ScsiDevice->BaseDllName = ScsiFileName;
+ }
+
+ return(TRUE);
+}
+
+VOID
+SlDetectVideo(
+ IN PSETUP_LOADER_BLOCK SetupBlock
+ )
+/*++
+
+Routine Description:
+
+ Detects video adapters on an ARC machine by walking the ARC firmware tree.
+
+ Fills in the appropriate entries in the setuploaderblock
+
+
+Arguments:
+
+ SetupBlock - Supplies a pointer to the setup loader block.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // On arc machines, there is no default video type.
+ //
+ SetupBlock->VideoDevice.Next = NULL;
+ SetupBlock->VideoDevice.IdString = NULL;
+ SetupBlock->VideoDevice.ThirdPartyOptionSelected = FALSE;
+ SetupBlock->VideoDevice.FileTypeBits = 0;
+ SetupBlock->VideoDevice.Files = NULL;
+ SetupBlock->VideoDevice.BaseDllName = NULL;
+ SetupBlock->Monitor = NULL;
+ SetupBlock->MonitorId = NULL;
+
+ BlSearchConfigTree(BlLoaderBlock->ConfigurationRoot,
+ ControllerClass,
+ DisplayController,
+ (ULONG)-1,
+ EnumerateVideoAdapters);
+
+ DecideVideoAdapter();
+}
+
+
+BOOLEAN
+EnumerateVideoAdapters(
+ IN PCONFIGURATION_COMPONENT_DATA ConfigData
+ )
+
+/*++
+
+Routine Description:
+
+ Callback function for enumerating video adapters in the ARC tree.
+
+ Adds the video adapter that was found to the setup block.
+
+Arguments:
+
+ ConfigData - Supplies a pointer to the ARC node of the display adapter.
+
+Return Value:
+
+ TRUE - continue searching
+
+ FALSE - some error, abort the search
+
+--*/
+
+{
+ //
+ // Just remember this guy for later.
+ //
+ if(VideoAdapterCount < MAX_VIDEO_ADAPTERS) {
+ VideoAdapter[VideoAdapterCount++] = ConfigData;
+ }
+ return(TRUE);
+}
+
+
+VOID
+DecideVideoAdapter(
+ VOID
+ )
+{
+ IN PCONFIGURATION_COMPONENT_DATA ConfigData;
+ PCHAR AdapterName,MonitorId;
+ PCONFIGURATION_COMPONENT_DATA MonitorData;
+ PMONITOR_CONFIGURATION_DATA Monitor;
+ CHAR ArcPath[256];
+ CHAR ConsoleOut[256];
+ PCHAR p,q;
+ ULONG u;
+
+ if(VideoAdapterCount) {
+ //
+ // The first thing we want to do is to see whether any of the
+ // adapters we found match the value of the CONSOLEOUT nvram var.
+ // If so then use that node for detection. Before comparing we have to
+ // change all instances of () to (0) in the value of CONSOLEOUT.
+ //
+ ConfigData = NULL;
+ if(p = ArcGetEnvironmentVariable("CONSOLEOUT")) {
+ strncpy(ArcPath,p,sizeof(ArcPath)-1);
+ ArcPath[sizeof(ArcPath)-1] = 0;
+ ConsoleOut[0] = 0;
+ for(p=ArcPath; q=strstr(p,"()"); p=q+2) {
+ *q = 0;
+ strcat(ConsoleOut,p);
+ strcat(ConsoleOut,"(0)");
+ }
+ strcat(ConsoleOut,p);
+
+ //
+ // Finally, we need to truncate the consoleout variable after
+ // the video adapter, if any.
+ //
+ _strlwr(ConsoleOut);
+ if(p = strstr(ConsoleOut,")video(")) {
+ *(p+sizeof(")video(")+1) = 0;
+ }
+
+ for(u=0; u<VideoAdapterCount; u++) {
+
+ ArcPath[0] = 0;
+ BlGetPathnameFromComponent(VideoAdapter[u],ArcPath);
+
+ if(!_stricmp(ConsoleOut,ArcPath)) {
+ ConfigData = VideoAdapter[u];
+ break;
+ }
+ }
+ }
+
+ //
+ // If we didn't find a match for CONSOLEOUT then use the last node
+ // we found in the tree scan.
+ //
+ if(!ConfigData) {
+ ConfigData = VideoAdapter[VideoAdapterCount-1];
+ }
+
+ AdapterName = SlpSearchSection("Map.Display",ConfigData->ComponentEntry.Identifier);
+ if (AdapterName==NULL) {
+ //
+ // We found a display adapter in the ARC tree, but it is not one of the ones
+ // specified in our INF file, so trigger the prompt for an OEM driver
+ // disk.
+ //
+
+ PromptOemVideo = TRUE;
+ return;
+ }
+
+ BlLoaderBlock->SetupLoaderBlock->VideoDevice.IdString = AdapterName;
+ BlLoaderBlock->SetupLoaderBlock->VideoDevice.Description = NULL;
+ BlLoaderBlock->SetupLoaderBlock->VideoDevice.ThirdPartyOptionSelected = FALSE;
+ BlLoaderBlock->SetupLoaderBlock->VideoDevice.FileTypeBits = 0;
+ BlLoaderBlock->SetupLoaderBlock->VideoDevice.Files = NULL;
+ BlLoaderBlock->SetupLoaderBlock->VideoDevice.BaseDllName = NULL;
+
+ //
+ // If there is a monitor peripheral associated with this device,
+ // capture its configuration data. Otherwise, let Setup assume an
+ // appropriate default.
+ //
+
+ MonitorData = ConfigData->Child;
+ if (MonitorData==NULL) {
+ BlLoaderBlock->SetupLoaderBlock->Monitor = NULL;
+ BlLoaderBlock->SetupLoaderBlock->MonitorId = NULL;
+ } else {
+ Monitor = BlAllocateHeap(MonitorData->ComponentEntry.ConfigurationDataLength);
+ if (Monitor==NULL) {
+ SlFriendlyError(ENOMEM, "video detection", 0, NULL);
+ return;
+ }
+ MonitorId = BlAllocateHeap(MonitorData->ComponentEntry.IdentifierLength+1);
+ if (MonitorId==NULL) {
+ SlFriendlyError(ENOMEM, "video detection", 0, NULL);
+ return;
+ }
+
+ strncpy(MonitorId,
+ MonitorData->ComponentEntry.Identifier,
+ MonitorData->ComponentEntry.IdentifierLength);
+
+ MonitorId[MonitorData->ComponentEntry.IdentifierLength] = 0;
+
+ RtlCopyMemory((PVOID)Monitor,
+ MonitorData->ConfigurationData,
+ MonitorData->ComponentEntry.ConfigurationDataLength);
+
+ BlLoaderBlock->SetupLoaderBlock->Monitor = Monitor;
+ BlLoaderBlock->SetupLoaderBlock->MonitorId = MonitorId;
+ }
+ }
+}
+
+
+
+PCHAR
+SlpSearchSection(
+ IN PCHAR SectionName,
+ IN PCHAR TargetName
+ )
+
+/*++
+
+Routine Description:
+
+ Searches a section in the INF file to match a name from the ARC identifier
+ with the canonical shortname.
+
+ If a string starts with *, then use strstr to find it in the node's id
+ string, else use strcmpi.
+
+ [Map.Computer]
+ msjazz_up = *Jazz
+ desksta1_up = "DESKTECH-ARCStation I"
+ pica61_up = "PICA-61"
+ duo_mp = *Duo
+
+ [Map.Computer]
+ DECjensen = "DEC-20Jensen"
+ DECjensen = "DEC-10Jensen"
+
+Arguments:
+
+ SectionName - Supplies the name of the section ("Map.Computer")
+
+ TargetName - Supplies the ARC string to be matched ("DEC-20Jensen")
+
+Return Value:
+
+ NULL - No match was found.
+
+ PCHAR - Pointer to the canonical shortname of the device.
+
+--*/
+
+{
+ ULONG i;
+ PCHAR SearchName;
+
+ //
+ // Enumerate the entries in the section. If the 0 value
+ // begins with a *, then see if the system name contains the string that
+ // follows. Otherwise, do a case-insensitive compare on the name.
+ //
+ for (i=0;;i++) {
+ SearchName = SlGetSectionLineIndex(InfFile,
+ SectionName,
+ i,
+ 0);
+ if (SearchName==NULL) {
+ //
+ // we have enumerated the entire section without finding a match,
+ // return failure.
+ //
+ return(NULL);
+ }
+
+ if (SearchName[0]=='*') {
+ if (strstr(TargetName,SearchName+1) != 0) {
+ //
+ // we have a match
+ //
+ break;
+ }
+ } else {
+ if (_stricmp(TargetName, SearchName) == 0) {
+ //
+ // we have a match
+ //
+ break;
+ }
+ }
+ }
+
+ //
+ // i is the index into the section of the short machine name
+ //
+ return(SlGetKeyName(InfFile,
+ SectionName,
+ i));
+
+
+}
diff --git a/private/ntos/boot/setup/config.c b/private/ntos/boot/setup/config.c
new file mode 100644
index 000000000..cddeddc3b
--- /dev/null
+++ b/private/ntos/boot/setup/config.c
@@ -0,0 +1,126 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ config.c
+
+Abstract:
+
+ This module contains code for interpreting and manipulating the ARC
+ firmware configuration tree in various ways.
+
+Author:
+
+ John Vert (jvert) 7-Oct-1993
+
+Environment:
+
+ Runs in the ARC environment.
+
+Revision History:
+
+--*/
+#include "setupldr.h"
+#include "stdio.h"
+
+#define MAX_FLOPPIES 4
+
+PCONFIGURATION_COMPONENT_DATA FloppyData[MAX_FLOPPIES];
+ULONG NumFloppies=0;
+
+//
+// definition for function callbacks
+//
+
+//
+// Local prototypes
+//
+
+BOOLEAN
+EnumerateFloppies(
+ IN PCONFIGURATION_COMPONENT_DATA ConfigData
+ );
+
+
+
+BOOLEAN
+SlFindFloppy(
+ IN ULONG FloppyNumber,
+ OUT PCHAR ArcName
+ )
+
+/*++
+
+Routine Description:
+
+ Given a floppy number (0, 1, etc.) this routine computes the appropriate
+ ARC name.
+
+Arguments:
+
+ FloppyNumber - Supplies the floppy number.
+
+ ArcName - Returns the ARC name of the specified floppy device
+
+Return Value:
+
+ TRUE - Floppy exists in the ARC firmware tree.
+
+ FALSE - Floppy was not found.
+
+--*/
+
+{
+ if (NumFloppies==0) {
+ BlSearchConfigTree(BlLoaderBlock->ConfigurationRoot,
+ PeripheralClass,
+ FloppyDiskPeripheral,
+ (ULONG)-1,
+ EnumerateFloppies);
+ }
+
+ if (FloppyNumber >= NumFloppies) {
+ SlFatalError(SL_FLOPPY_NOT_FOUND,NumFloppies,FloppyNumber);
+ }
+
+ BlGetPathnameFromComponent(FloppyData[FloppyNumber],
+ ArcName);
+ return(TRUE);
+}
+
+
+BOOLEAN
+EnumerateFloppies(
+ IN PCONFIGURATION_COMPONENT_DATA ConfigData
+ )
+
+/*++
+
+Routine Description:
+
+ Callback routine for enumerating all the floppies in the ARC config tree.
+
+Arguments:
+
+ ConfigData - Supplies a pointer to the floppies ARC component data.
+
+Return Value:
+
+ TRUE - continue searching
+
+ FALSE - stop searching tree.
+
+--*/
+
+{
+ if (NumFloppies == MAX_FLOPPIES) {
+ return(FALSE);
+ }
+
+ FloppyData[NumFloppies++] = ConfigData;
+
+ return(TRUE);
+}
+
diff --git a/private/ntos/boot/setup/i386/cpu386.asm b/private/ntos/boot/setup/i386/cpu386.asm
new file mode 100644
index 000000000..e1d1c1866
--- /dev/null
+++ b/private/ntos/boot/setup/i386/cpu386.asm
@@ -0,0 +1,82 @@
+ title "Processor type and stepping detection"
+;++
+;
+; Copyright (c) 1989 Microsoft Corporation
+;
+; Module Name:
+;
+; cpu.asm
+;
+; Abstract:
+;
+; This module implements the assembley code necessary to determine
+; cpu type and stepping information.
+;
+; Author:
+;
+; Shie-Lin Tzong (shielint) 28-Oct-1991.
+;
+; Environment:
+;
+; 80x86
+;
+; Revision History:
+;
+;--
+
+.386p
+_TEXT SEGMENT DWORD PUBLIC 'CODE'
+ ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+CR0_AM equ 40000h
+EFLAGS_AC equ 40000h
+
+;++
+;
+; BOOLEAN
+; SlIs386(
+; VOID
+; )
+;
+; Routine Description:
+;
+; This function determines whether the processor we're running on
+; is a 386. If not a 386, it is assumed that the processor is
+; a 486 or greater.
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; (al) = 1 - processor is a 386
+; (al) = 0 - processor is a 486 or greater.
+;
+;--
+ public _SlIs386@0
+_SlIs386@0 proc
+
+ mov eax,cr0
+ push eax ; save current cr0
+ and eax,not CR0_AM ; mask out alignment check bit
+ mov cr0,eax ; disable alignment check
+ pushfd ; save flags
+ pushfd ; turn on alignment check bit in
+ or dword ptr [esp],EFLAGS_AC ; a copy of the flags register
+ popfd ; and try to load flags
+ pushfd
+ pop ecx ; get new flags into ecx
+ popfd ; restore original flags
+ pop eax ; restore original cr0
+ mov cr0,eax
+ xor al,al ; prepare for return, assume not 386
+ and ecx,EFLAGS_AC ; did AC bit get set?
+ jnz short @f ; yes, we don't have a 386
+ inc al ; we have a 386
+@@: ret
+
+_SlIs386@0 endp
+
+_TEXT ends
+ end
diff --git a/private/ntos/boot/setup/i386/detmach.asm b/private/ntos/boot/setup/i386/detmach.asm
new file mode 100644
index 000000000..903576897
--- /dev/null
+++ b/private/ntos/boot/setup/i386/detmach.asm
@@ -0,0 +1,386 @@
+SETUP equ 1
+
+;**
+;
+; Machine-specific detection code
+;
+;--
+
+.386p
+
+include hal386.inc
+include callconv.inc
+
+ EXTRNP _HalpMapPhysicalMemory,2
+
+;
+; Include SystemPro detection code
+;
+SYSTEMPRO equ 1
+include halsp\i386\spdetect.asm
+
+
+;
+; Include Wyse7000 detection code
+;
+
+include halwyse7\i386\wydetect.asm
+
+;
+; Include Olivetti LSX 5030 detection code
+;
+
+include haloli\i386\olidtect.asm
+
+
+
+_TEXT SEGMENT DWORD PUBLIC 'CODE'
+ ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+;
+; Thunk functions.
+; Equivalent Hal functions which various detection code may use
+;
+
+;++
+;
+; CMOS space read functions.
+;
+;--
+
+CMOSAddressPort equ 70H
+CMOSDataPort equ 71H
+
+CMOSExAddressLSBPort equ 74H
+CMOSExAddressMSBPort equ 75H
+CMOSExDataPort equ 76H
+
+;++
+;
+; VOID
+; ReadCMOS(
+; ULONG StartingOffset
+; ULONG Count
+; PUCHAR ReturnValuePtr
+; )
+;
+; Read CMOS starting at the given offset for the given number of
+; bytes putting the bytes read into the buffer pointed to by the
+; given address.
+;
+; Arguments:
+;
+; StartingOffset : where to start in CMOS
+;
+; Count : how many bytes to read
+;
+; ReturnValuePtr : where to put bytes read
+;
+; Returns:
+; None.
+;
+;--
+StartingOffset equ 2*4[ebp]
+Count equ 3*4[ebp]
+ReturnValuePtr equ 4*4[ebp]
+
+cPublicProc _ReadCMOS,3
+
+ push ebp
+ mov ebp, esp
+ push ebx ; caller's reg
+ push edi ; caller's reg
+
+ mov ebx, StartingOffset
+ mov ecx, Count
+ mov edi, ReturnValuePtr
+
+ align dword
+NextByte:
+ cmp bh, 0
+ jne ExCMOSRead
+
+ mov al, bl
+ out CMOSAddressPort, al
+ in al, CMOSDataPort
+ mov [edi], al
+
+ add ebx, 1
+ add edi, 1
+ sub ecx, 1
+ jg NextByte
+
+ pop edi ; restore caller's reg
+ pop ebx ; restore caller's reg
+ pop ebp
+ stdRET _ReadCmos
+
+ align dword
+ExCMOSRead:
+
+ mov al, bl
+ out CMOSExAddressLSBPort, al
+ mov al, bh
+ out CMOSExAddressMSBPort, al
+ in al, CMOSExDataPort
+ mov [edi], al
+
+ add ebx, 1
+ add edi, 1
+ sub ecx, 1
+ jg ExCMOSRead
+
+ pop edi ; restore caller's reg
+ pop ebx ; restore caller's reg
+ pop ebp
+ stdRET _ReadCMOS
+
+stdENDP _ReadCMOS
+
+
+; 486 C step CPU detection code.
+
+CR0_ET equ 10h
+CR0_TS equ 08H
+CR0_EM equ 04H
+CR0_MP equ 02H
+
+;
+; The following equates define the control bits of EFALGS register
+;
+
+EFLAGS_AC equ 40000h
+EFLAGS_ID equ 200000h
+
+;
+; Constants for Floating Point test
+;
+
+REALLONG_LOW equ 00000000
+REALLONG_HIGH equ 3FE00000h
+PSEUDO_DENORMAL_LOW equ 00000000h
+PSEUDO_DENORMAL_MID equ 80000000h
+PSEUDO_DENORMAL_HIGH equ 0000h
+
+;
+; Define the iret frame
+;
+
+IretFrame struc
+
+IretEip dd 0
+IretCs dd 0
+IretEFlags dd 0
+
+IretFrame ends
+
+;++
+;
+; BOOLEAN
+; Detect486CStep (
+; IN PBOOLEAN Dummy
+; )
+;
+; Routine Description:
+;
+; Returns TRUE if the processor is a 486 C stepping. We detect the CPU
+; in order to use a specific HAL. This HAL attempts to work around
+; a 486 C stepping bug which the normal HAL tends to aggravate.
+;
+
+cPublicProc _Detect486CStep,1
+ push edi
+ push esi
+ push ebx ; Save C registers
+ mov eax, cr0
+ push eax
+ pushfd ; save Cr0 & flags
+
+ pop ebx ; Get flags into eax
+ push ebx ; Save original flags
+
+ mov ecx, ebx
+ xor ecx, EFLAGS_AC ; flip AC bit
+ push ecx
+ popfd ; load it into flags
+ pushfd ; re-save flags
+ pop ecx ; get flags into eax
+ cmp ebx, ecx ; did bit stay flipped?
+ je short Not486C ; No, then this is a 386
+
+ mov ecx, ebx
+ xor ecx, EFLAGS_ID ; flip ID bit
+ push ecx
+ popfd ; load it into flags
+ pushfd ; re-save flags
+ pop ecx ; get flags into eax
+ cmp ebx, ecx ; did bit stay flipped?
+ jne short Not486C ; Yes, then this >= 586
+
+ mov eax, cr0
+ and eax, NOT (CR0_ET+CR0_MP+CR0_TS+CR0_EM)
+ mov cr0, eax
+
+ call IsNpxPresent ; Check if cpu has coprocessor support?
+ or ax, ax
+ jz short Is486C ; it is actually 486sx, assume C step
+
+ call Check486CStepping ; Check for <= C stepping
+ jnc short Not486C ; if nc, it is NOT a C stepping
+
+Is486C:
+ mov eax, 1 ; Return TRUE
+ jmp short DetectCpuExit
+
+Not486C:
+ xor eax, eax
+
+DetectCpuExit:
+ popfd
+ pop ebx
+ mov cr0, ebx
+ pop ebx
+ pop esi
+ pop edi
+ stdRET _Detect486CStep
+
+stdENDP _Detect486CStep
+
+;++
+;
+; BOOLEAN
+; Check486CStepping (
+; VOID
+; )
+;
+; Routine Description:
+;
+; This routine checks for 486 C Stepping.
+;
+; This routine takes advantage of the fact that FSCALE produces
+; wrong result with Denormal or Pseudo-denormal operand on 486
+; C and earlier steps.
+;
+; If the value contained in ST(1), second location in the floating
+; point stack, is between 1 and 11, and the value in ST, top of the
+; floating point stack, is either a pseudo-denormal number or a
+; denormal number with the underflow exception unmasked, the FSCALE
+; instruction produces an incorrect result.
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; Carry Flag clear if D or later stepping.
+; Carry Flag set if C stepping.
+;
+;--
+
+FpControl equ [ebp - 2]
+RealLongSt1 equ [ebp - 10]
+PseudoDenormal equ [ebp - 20]
+FscaleResult equ [ebp - 30]
+
+ public Check486CStepping
+Check486CStepping proc
+
+ push ebp
+ mov ebp, esp
+ sub esp, 30 ; Allocate space for temp real variables
+
+;
+; Initialize the local FP variables to predefined values.
+; RealLongSt1 = 1.0 * (2 ** -1) = 0.5 in normalized double precision FP form
+; PseudoDenormal = a unsupported format by IEEE.
+; Sign bit = 0
+; Exponent = 000000000000000B
+; Significand = 100000...0B
+; FscaleResult = The result of FSCALE instruction. Depending on 486 step,
+; the value will be different:
+; Under C and earlier steps, 486 returns the original value
+; in ST as the result. The correct returned value should be
+; original significand and an exponent of 0...01.
+;
+
+ mov dword ptr RealLongSt1, REALLONG_LOW
+ mov dword ptr RealLongSt1 + 4, REALLONG_HIGH
+ mov dword ptr PseudoDenormal, PSEUDO_DENORMAL_LOW
+ mov dword ptr PseudoDenormal + 4, PSEUDO_DENORMAL_MID
+ mov word ptr PseudoDenormal + 8, PSEUDO_DENORMAL_HIGH
+
+.387
+ fnstcw FpControl ; Get FP control word
+ or word ptr FpControl, 0FFh ; Mask all the FP exceptions
+ fldcw FpControl ; Set FP control
+
+ fld qword ptr RealLongSt1 ; 0 < ST(1) = RealLongSt1 < 1
+ fld tbyte ptr PseudoDenormal; Denormalized operand. Note, i486
+ ; won't report denormal exception
+ ; on 'FLD' instruction.
+ ; ST(0) = Extended Denormalized operand
+ fscale ; try to trigger 486Cx errata
+ fstp tbyte ptr FscaleResult ; Store ST(0) in FscaleResult
+ cmp word ptr FscaleResult + 8, PSEUDO_DENORMAL_HIGH
+ ; Is Exponent changed?
+ jz short c4ds00 ; if z, no, it is C step
+ clc
+ jmp short c4ds10
+c4ds00: stc
+c4ds10: mov esp, ebp
+ pop ebp
+ ret
+
+Check486CStepping endp
+
+;++
+;
+; BOOLEAN
+; IsNpxPresent(
+; VOID
+; );
+;
+; Routine Description:
+;
+; This routine determines if there is any Numeric coprocessor
+; present.
+;
+; Arguments:
+;
+; None.
+;
+; Return:
+;
+; TRUE - If NPX is present. Else a value of FALSE is returned.
+;
+;--
+
+ public IsNpxPresent
+IsNpxPresent proc near
+
+ push ebp ; Save caller's bp
+ xor edx, edx
+.287
+ fninit ; Initialize NPX
+ mov ecx, 5A5A5A5Ah ; Put non-zero value
+ push ecx ; into the memory we are going to use
+ mov ebp, esp
+ fnstsw word ptr [ebp] ; Retrieve status - must use non-wait
+ cmp byte ptr [ebp], 0 ; All bits cleared by fninit?
+ jne Inp10
+
+ mov edx, 1
+
+Inp10:
+ pop eax ; clear scratch value
+ pop ebp ; Restore caller's bp
+ mov eax, edx
+ ret
+
+IsNpxPresent endp
+
+
+_TEXT ENDS
+
+ END
diff --git a/private/ntos/boot/setup/i386/detsup.c b/private/ntos/boot/setup/i386/detsup.c
new file mode 100644
index 000000000..38472f3fe
--- /dev/null
+++ b/private/ntos/boot/setup/i386/detsup.c
@@ -0,0 +1,184 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ detsup.c
+
+Abstract:
+
+ Various detection code is included from the HALs and this module
+ includes compatible functions for setup
+
+Revision History:
+
+--*/
+
+#include "setupldr.h"
+#define _NTHAL_
+#define _HALI_
+
+//
+// Include NCR detection code
+//
+
+#define SETUP
+
+#include "halx86\i386\ncrdetct.c"
+
+//
+// Include AST detection code
+//
+
+#define ASTMP 1
+#include "halast\i386\astdetct.c"
+
+//
+// Include Corollary detection code
+//
+
+#include "halcbus\i386\cbdetect.c"
+
+//
+// Include MPS 1.1 detection code
+//
+
+#include "halmps\i386\mpdetect.c"
+
+//
+// Thunk functions.
+// Equivalent Hal functions which various detection code may use
+//
+
+
+
+PVOID
+HalpMapPhysicalMemory(
+ IN PVOID PhysicalAddress,
+ IN ULONG NumberPages
+ )
+
+/*++
+
+Routine Description:
+
+ This routine maps physical memory into the area of virtual memory.
+
+Arguments:
+
+ PhysicalAddress - Supplies the physical address of the start of the
+ area of physical memory to be mapped.
+
+ NumberPages - Supplies the number of pages contained in the area of
+ physical memory to be mapped.
+
+Return Value:
+
+ PVOID - Virtual address at which the requested block of physical memory
+ was mapped
+
+--*/
+{
+ extern PHARDWARE_PTE HalPT;
+ ULONG PageFrame;
+ ULONG i, j, PagesMapped;
+
+ PageFrame = ((ULONG) PhysicalAddress) >> PAGE_SHIFT;
+ if (PageFrame >= 1 && PageFrame+NumberPages < 0x1000) {
+ //
+ // The lower 16M is 'identity' mapped with the physical addresses.
+ //
+
+ return PhysicalAddress;
+ }
+
+ //
+ // Map a pointer to the address requested
+ //
+
+ for (i=0; i <= 1024-NumberPages; i++) {
+ for (j=0; j < NumberPages; j++) {
+ if ( ((PULONG)HalPT)[i+j] ) {
+ break;
+ }
+ }
+
+ if (j == NumberPages) {
+ for (j=0; j<NumberPages; j++) {
+ HalPT[i+j].PageFrameNumber = PageFrame+j;
+ HalPT[i+j].Valid = 1;
+ HalPT[i+j].Write = 1;
+ }
+
+ j = 0xffc00000 | (i<<12) | (((ULONG) PhysicalAddress) & 0xfff);
+ return (PVOID) j;
+ }
+ }
+
+ SlFatalError((ULONG)PhysicalAddress);
+ return NULL;
+}
+
+
+PVOID
+HalpMapPhysicalMemoryWriteThrough(
+ IN PVOID PhysicalAddress,
+ IN ULONG NumberPages
+ )
+
+/*++
+
+Routine Description:
+
+ This routine maps physical memory into the area of virtual memory.
+
+Arguments:
+
+ PhysicalAddress - Supplies the physical address of the start of the
+ area of physical memory to be mapped.
+
+ NumberPages - Supplies the number of pages contained in the area of
+ physical memory to be mapped.
+
+Return Value:
+
+ PVOID - Virtual address at which the requested block of physical memory
+ was mapped
+
+--*/
+{
+ extern PHARDWARE_PTE HalPT;
+ ULONG PageFrame;
+ ULONG i, j, PagesMapped;
+
+ PageFrame = ((ULONG) PhysicalAddress) >> PAGE_SHIFT;
+
+ //
+ // Map a pointer to the address requested
+ //
+
+ for (i=0; i <= 1024-NumberPages; i++) {
+ for (j=0; j < NumberPages; j++) {
+ if ( ((PULONG)HalPT)[i+j] ) {
+ break;
+ }
+ }
+
+ if (j == NumberPages) {
+ for (j=0; j<NumberPages; j++) {
+ HalPT[i+j].PageFrameNumber = PageFrame+j;
+ HalPT[i+j].Valid = 1;
+ HalPT[i+j].Write = 1;
+ HalPT[i+j].WriteThrough = 1;
+ HalPT[i+j].CacheDisable = 1;
+ }
+
+ j = 0xffc00000 | (i<<12) | (((ULONG) PhysicalAddress) & 0xfff);
+ return (PVOID) j;
+ }
+ }
+
+ SlFatalError((ULONG)PhysicalAddress);
+ return NULL;
+}
diff --git a/private/ntos/boot/setup/i386/initx86.c b/private/ntos/boot/setup/i386/initx86.c
new file mode 100644
index 000000000..21ec34f2a
--- /dev/null
+++ b/private/ntos/boot/setup/i386/initx86.c
@@ -0,0 +1,126 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ initx86.c
+
+Abstract:
+
+ Does any x86-specific initialization, then starts the common ARC setupldr
+
+Author:
+
+ John Vert (jvert) 14-Oct-1993
+
+Revision History:
+
+--*/
+//#include "setupldr.h"
+#include "bldrx86.h"
+#include "msgs.h"
+
+ARC_STATUS
+SlInit(
+ IN ULONG Argc,
+ IN PCHAR Argv[],
+ IN PCHAR Envp[]
+ );
+
+BOOLEAN
+BlDetectHardware(
+ IN ULONG DriveId,
+ IN PCHAR LoadOptions
+ );
+
+
+VOID
+BlStartup(
+ IN PCHAR PartitionName
+ )
+
+/*++
+
+Routine Description:
+
+ Does x86-specific initialization, particularly running NTDETECT, then
+ calls to the common setupldr.
+
+Arguments:
+
+ PartitionName - Supplies the ARC name of the partition (or floppy) that
+ setupldr was loaded from.
+
+Return Value:
+
+ Does not return
+
+--*/
+
+{
+ PCHAR Argv[4];
+ CHAR SetupLoadFileName[100];
+ ARC_STATUS Status;
+ ULONG DriveId;
+ VOID AbiosInitDataStructures(VOID);
+
+ AbiosInitDataStructures();
+
+#ifdef DOUBLESPACE_LEGAL
+ //
+ // Instruct the boot loader I/O system to look for
+ // files in a \dblspace.000 cvf. We do this here so that
+ // we can get everything we need, starting with ntdetect.com,
+ // from the doublespace part of floppy 1.
+ //
+ // If files aren't in a dblspace.000 cvf, the i/o system will
+ // look for them on the host partition itself so setting this
+ // here has no bad effects (except perhaps for performance).
+ //
+ BlSetAutoDoubleSpace(TRUE);
+#endif
+
+ //
+ // Open the boot partition so we can load NTDETECT off it.
+ //
+ Status = ArcOpen(PartitionName, ArcOpenReadOnly, &DriveId);
+ if (Status != ESUCCESS) {
+ BlPrint(BlFindMessage(SL_DRIVE_ERROR),PartitionName);
+ return;
+ }
+
+ //
+ // Initialize dbcs font and display.
+ //
+ TextGrInitialize(DriveId);
+
+ BlPrint(BlFindMessage(SL_NTDETECT_MSG));
+
+ if (!BlDetectHardware(DriveId, NULL)) {
+ BlPrint(BlFindMessage(SL_NTDETECT_FAILURE));
+ return;
+ }
+
+ //
+ // detect HAL here.
+ //
+
+ //
+ // Create arguments, call off to setupldr
+ //
+ strcpy(SetupLoadFileName, PartitionName);
+ strcat(SetupLoadFileName, "\\SETUPLDR");
+
+ Argv[0]=SetupLoadFileName;
+ Status = SlInit(1, Argv, NULL);
+
+ //
+ // We should never return here, something
+ // horrible has happened.
+ //
+ while (TRUE) {
+ }
+
+ return;
+}
diff --git a/private/ntos/boot/setup/i386/setupldr.def b/private/ntos/boot/setup/i386/setupldr.def
new file mode 100644
index 000000000..6801acdb3
--- /dev/null
+++ b/private/ntos/boot/setup/i386/setupldr.def
@@ -0,0 +1,58 @@
+NAME osloader
+
+EXPORTS
+ BlLoadImage
+ BlpBindImportName
+ BlAllocateAlignedDescriptor
+ BlOpen
+ BlClose
+ BlRead
+ BlWrite
+ BlGetFileInformation
+ BlSetFileInformation
+
+ RtlAssert
+ ScsiDebugPrint
+ ScsiPortInitialize
+ ScsiPortFreeDeviceBase
+ ScsiPortGetDeviceBase
+ ScsiPortGetLogicalUnit
+ ScsiPortGetPhysicalAddress
+ ScsiPortGetSrb
+ ScsiPortGetUncachedExtension
+ ScsiPortGetVirtualAddress
+ ScsiPortFlushDma
+ ScsiPortIoMapTransfer
+ ScsiPortNotification
+ ScsiPortLogError
+ ScsiPortCompleteRequest
+ ScsiPortMoveMemory
+ ScsiPortReadPortUchar
+ ScsiPortReadPortUshort
+ ScsiPortReadPortUlong
+ ScsiPortReadRegisterUchar
+ ScsiPortReadRegisterUshort
+ ScsiPortReadRegisterUlong
+ ScsiPortReadRegisterBufferUchar
+ ScsiPortReadRegisterBufferUshort
+ ScsiPortReadRegisterBufferUlong
+ ScsiPortReadPortBufferUchar
+ ScsiPortReadPortBufferUshort
+ ScsiPortReadPortBufferUlong
+ ScsiPortStallExecution
+ ScsiPortWritePortUchar
+ ScsiPortWritePortUshort
+ ScsiPortWritePortUlong
+ ScsiPortWriteRegisterUchar
+ ScsiPortWriteRegisterUshort
+ ScsiPortWriteRegisterUlong
+ ScsiPortWriteRegisterBufferUchar
+ ScsiPortWriteRegisterBufferUshort
+ ScsiPortWriteRegisterBufferUlong
+ ScsiPortWritePortBufferUchar
+ ScsiPortWritePortBufferUshort
+ ScsiPortWritePortBufferUlong
+ ScsiPortConvertUlongToPhysicalAddress
+ ScsiPortConvertPhysicalAddressToUlong
+ ScsiPortGetBusData
+ ScsiPortSetBusDataByOffset
diff --git a/private/ntos/boot/setup/i386/sources b/private/ntos/boot/setup/i386/sources
new file mode 100644
index 000000000..694d9de90
--- /dev/null
+++ b/private/ntos/boot/setup/i386/sources
@@ -0,0 +1,9 @@
+i386_SOURCES=i386\initx86.c \
+ i386\x86dtect.c \
+ i386\detmach.asm \
+ i386\detsup.c \
+ i386\cpu386.asm
+
+C_DEFINES=$(C_DEFINES) -DELTORITO
+
+NTTARGETFILES=obj\i386\setupldr.bin obj\i386\setupldr.lib
diff --git a/private/ntos/boot/setup/i386/x86dtect.c b/private/ntos/boot/setup/i386/x86dtect.c
new file mode 100644
index 000000000..936df8166
--- /dev/null
+++ b/private/ntos/boot/setup/i386/x86dtect.c
@@ -0,0 +1,363 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ detecthw.c
+
+Abstract:
+
+ Routines for determining which drivers/HAL need to be loaded.
+
+Author:
+
+ John Vert (jvert) 20-Oct-1993
+
+Revision History:
+
+--*/
+#include "setupldr.h"
+
+
+//
+// detection function prototypes
+//
+ULONG DetectSystemPro(PBOOLEAN);
+ULONG DetectWyse7(PBOOLEAN);
+ULONG NCRDeterminePlatform(PBOOLEAN);
+ULONG Detect486CStep(PBOOLEAN);
+ULONG DetectOlivettiMp(PBOOLEAN);
+ULONG DetectAST(PBOOLEAN);
+ULONG DetectCbusII(PBOOLEAN);
+ULONG DetectUPMPS(PBOOLEAN);
+ULONG DetectMPS(PBOOLEAN);
+ULONG DetectTrue(PBOOLEAN);
+
+typedef struct _HAL_DETECT_ENTRY {
+ INTERFACE_TYPE BusType;
+ ULONG (*DetectFunction)(PBOOLEAN);
+ PCHAR Shortname;
+} HAL_DETECT_ENTRY, *PHAL_DETECT_ENTRY;
+
+HAL_DETECT_ENTRY DetectHal[] = {
+
+// First check for a HAL to match some specific hardware.
+ Eisa, DetectWyse7, "Wyse7000_mp",
+ MicroChannel, NCRDeterminePlatform, "ncr3x_mp",
+ Eisa, DetectOlivettiMp, "oli5030_mp",
+ Eisa, DetectAST, "astmf_mp",
+ Eisa, DetectCbusII, "cbus2_mp",
+ Isa, DetectCbusII, "cbus2_mp",
+ MicroChannel, DetectCbusII, "cbusmc_mp",
+ Eisa, DetectMPS, "mps_mp",
+ Isa, DetectMPS, "mps_mp",
+ MicroChannel, DetectMPS, "mps_mca_mp",
+ Eisa, DetectUPMPS, "mps_up",
+ Isa, DetectUPMPS, "mps_up",
+ Eisa, DetectSystemPro, "syspro_mp", // check SystemPro last
+
+// Before using default HAL make sure we don't need a special one
+ Isa, Detect486CStep, "486c_up",
+ Eisa, Detect486CStep, "486c_up",
+
+// Use default hal for given bus type...
+ Isa, DetectTrue, "e_isa_up",
+ Eisa, DetectTrue, "e_isa_up",
+ MicroChannel, DetectTrue, "mca_up",
+
+ 0, NULL, NULL
+};
+
+
+PCHAR
+SlDetectHal(
+ IN PSETUP_LOADER_BLOCK SetupBlock
+ )
+
+/*++
+
+Routine Description:
+
+ Determines which HAL to load, fills in the SetupBlock appropriately,
+ and returns the filename.
+
+Arguments:
+
+ SetupBlock - Supplies a pointer to the Setup loader block
+
+Return Value:
+
+ PCHAR - pointer to the filename of the HAL to be loaded.
+
+--*/
+
+{
+ PCONFIGURATION_COMPONENT_DATA Adapter;
+ INTERFACE_TYPE BusType;
+ BOOLEAN IsMpMachine;
+ ULONG i;
+ PCHAR MachineShortname;
+
+ //
+ // Determine the bus type by searching the ARC configuration tree
+ //
+
+ BusType = Isa;
+
+ //
+ // Check for Eisa
+ //
+
+ Adapter = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
+ AdapterClass,
+ EisaAdapter,
+ NULL);
+ if (Adapter != NULL) {
+ BusType = Eisa;
+ }
+
+ //
+ // Check for MCA
+ //
+
+ Adapter = NULL;
+ for (; ;) {
+ Adapter = KeFindConfigurationNextEntry (
+ BlLoaderBlock->ConfigurationRoot,
+ AdapterClass,
+ MultiFunctionAdapter,
+ NULL,
+ &Adapter
+ );
+ if (!Adapter) {
+ break;
+ }
+
+ if (_stricmp(Adapter->ComponentEntry.Identifier,"MCA")==0) {
+ BusType = MicroChannel;
+ break;
+ }
+ }
+
+ //
+ // Now go figure out machine and hal type.
+ //
+
+ for (i=0;;i++) {
+ if (DetectHal[i].DetectFunction == NULL) {
+ //
+ // We reached the end of the list without
+ // figuring it out!
+ //
+ SlFatalError(i);
+ return(NULL);
+ }
+
+ if ((DetectHal[i].BusType == BusType) ||
+ (DetectHal[i].BusType == Internal)) {
+
+ IsMpMachine = FALSE;
+ if ((DetectHal[i].DetectFunction)(&IsMpMachine) != 0) {
+
+ //
+ // Found the correct HAL.
+ //
+
+ MachineShortname = DetectHal[i].Shortname;
+ break;
+ }
+ }
+ }
+
+ return(MachineShortname);
+}
+
+
+ULONG
+DetectTrue(
+ OUT PBOOLEAN IsMP
+)
+/*++
+
+Routine Description:
+
+ To Return TRUE
+
+Return Value:
+
+ TRUE
+
+--*/
+{
+ return TRUE;
+}
+
+
+VOID
+SlDetectScsi(
+ IN PSETUP_LOADER_BLOCK SetupBlock
+ )
+
+/*++
+
+Routine Description:
+
+ SCSI detection routine for x86 machines.
+
+Arguments:
+
+ SetupBlock - Supplies the Setup loader block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PVOID SifHandle;
+ PCHAR p;
+ ULONG LineCount,u;
+ PDETECTED_DEVICE ScsiDevice;
+ ULONG Ordinal;
+ PCHAR ScsiFileName;
+ PCHAR ScsiDescription;
+ SCSI_INSERT_STATUS sis;
+
+ extern BOOLEAN LoadScsiMiniports;
+
+ //
+ // If winnt.sif wasn't loaded, assume it's not a winnt setup
+ // and therefore not unattended setup, and we detect no scsi
+ // in this case on x86.
+ //
+ if(WinntSifHandle == NULL) {
+ return;
+ } else {
+ SifHandle = WinntSifHandle;
+ }
+
+ //
+ // If it's a floppyless setup, then the default is to load all
+ // known scsi miniports. If it's not a floppyless setup,
+ // the default is to load no miniports.
+ //
+ p = SlGetSectionKeyIndex(SifHandle,"Data","Floppyless",0);
+ if(p && (*p != '0')) {
+
+ //
+ // Even if no miniport drivers are loaded, we want to indicate that
+ // we "detected scsi".
+ //
+ SetupBlock->ScalarValues.LoadedScsi = 1;
+
+ LineCount = SlCountLinesInSection(SifHandle,"DetectedMassStorage");
+ if(LineCount == (ULONG)(-1)) {
+ //
+ // Section does not exist -- load all known miniports.
+ // Setting this flag will cause all known miniports to be loaded
+ // (see ..\setup.c).
+ //
+ LoadScsiMiniports = TRUE;
+ } else {
+
+ for(u=0; u<LineCount; u++) {
+
+ if(p = SlGetSectionLineIndex(SifHandle,"DetectedMassStorage",u,0)) {
+ //
+ // Find this adapter's ordinal within the Scsi.Load section of txtsetup.sif
+ //
+ Ordinal = SlGetSectionKeyOrdinal(InfFile, "Scsi.Load", p);
+ if(Ordinal == (ULONG)-1) {
+ continue;
+ }
+
+ //
+ // Find the driver filename
+ //
+ ScsiFileName = SlGetSectionKeyIndex(InfFile,
+ "Scsi.Load",
+ p,
+ SIF_FILENAME_INDEX);
+ if(!ScsiFileName) {
+ continue;
+ }
+
+ //
+ // Create a new detected device entry.
+ //
+ if((sis = SlInsertScsiDevice(Ordinal, &ScsiDevice)) == ScsiInsertError) {
+ SlFriendlyError(ENOMEM, "SCSI detection", 0, NULL);
+ return;
+ }
+
+ if(sis == ScsiInsertExisting) {
+#if DBG
+ //
+ // Sanity check to make sure we're talking about the same driver
+ //
+ if(_strcmpi(ScsiDevice->BaseDllName, ScsiFileName)) {
+ SlError(400);
+ return;
+ }
+#endif
+ } else {
+ //
+ // Find the driver description
+ //
+ ScsiDescription = SlGetIniValue(InfFile,
+ "SCSI",
+ p,
+ p);
+
+ ScsiDevice->IdString = p;
+ ScsiDevice->Description = ScsiDescription;
+ ScsiDevice->ThirdPartyOptionSelected = FALSE;
+ ScsiDevice->FileTypeBits = 0;
+ ScsiDevice->Files = NULL;
+ ScsiDevice->BaseDllName = ScsiFileName;
+ }
+ }
+ }
+ }
+ }
+}
+
+
+VOID
+SlDetectVideo(
+ IN PSETUP_LOADER_BLOCK SetupBlock
+ )
+
+/*++
+
+Routine Description:
+
+ Video detection routine for x86 machines.
+
+ Currently, no video detection is done on x86 machines, this just fills
+ in the appropriate fields in the setuploaderblock that say "VGA"
+
+Arguments:
+
+ SetupBlock - Supplies the Setup loader block
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ SetupBlock->VideoDevice.Next = NULL;
+ SetupBlock->VideoDevice.IdString = SlCopyString("VGA");
+ SetupBlock->VideoDevice.ThirdPartyOptionSelected = FALSE;
+ SetupBlock->VideoDevice.FileTypeBits = 0;
+ SetupBlock->VideoDevice.Files = NULL;
+ SetupBlock->VideoDevice.BaseDllName = NULL;
+ SetupBlock->Monitor = NULL;
+ SetupBlock->MonitorId = NULL;
+ return;
+}
diff --git a/private/ntos/boot/setup/ilinkldr.rsp b/private/ntos/boot/setup/ilinkldr.rsp
new file mode 100644
index 000000000..5a5fb3ca5
--- /dev/null
+++ b/private/ntos/boot/setup/ilinkldr.rsp
@@ -0,0 +1,19 @@
+-machine:i386
+-force:multiple
+-rom
+-nodefaultlib
+-debug:none
+-debugtype:coff
+-align:4096
+-fixed
+-base:0x300000
+-entry:NtProcessStartup@4
+-map:obj\i386\setupldr.map
+obj\i386\setupldr.lib
+obj\i386\setupldr.res
+..\obj\i386\boot.lib
+obj\i386\sldr.exp
+..\..\..\..\public\sdk\lib\i386\libcntpr.lib
+..\..\..\..\public\sdk\lib\i386\int64.lib
+..\..\obj\i386\ke.lib
+..\..\rtl\obj\i386\bldrrtl.lib
diff --git a/private/ntos/boot/setup/makefile b/private/ntos/boot/setup/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/boot/setup/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/boot/setup/makefile.inc b/private/ntos/boot/setup/makefile.inc
new file mode 100644
index 000000000..1542159fd
--- /dev/null
+++ b/private/ntos/boot/setup/makefile.inc
@@ -0,0 +1,63 @@
+!IFNDEF LANGUAGE
+LANGUAGE=usa
+!ENDIF
+
+
+msgs.rc msgs.h msg00001.bin: msgs.$(LANGUAGE)
+ mc -v msgs.$(LANGUAGE)
+
+!IF $(386)
+
+SETUPLDR=obj\i386\setupldr.lib ..\obj\i386\boot.lib obj\i386\sldr.exp
+
+obj\i386\setupldr.res: msgs.$(LANGUAGE)
+
+obj\i386\setupldr.exe: $(SETUPLDR) makefile.inc ilinkldr.rsp
+ -link -out:obj\i386\setupldr.exe $(LINK_LIB_IGNORE_FLAG) @ilinkldr.rsp
+
+obj\i386\sldr.exp: i386\setupldr.def
+ lib -machine:i386 -out:obj\i386\sldr.lib -def:i386\setupldr.def ..\obj\i386\boot.lib
+
+!IFNDEF NTVERSION
+STARTUP=i386\startup\a20.asm \
+ i386\startup\abios.inc \
+ i386\startup\abiosa.asm \
+ i386\startup\backend.asm \
+ i386\startup\constant.h \
+ i386\startup\display.c \
+ i386\startup\eisac.c \
+ i386\startup\eisaa.asm \
+ i386\startup\eisa.h \
+ i386\startup\eisa.inc \
+ i386\startup\exp.asm \
+ i386\startup\global.h \
+ i386\startup\macro.inc \
+ i386\startup\main.c \
+ i386\startup\memmap.h \
+ i386\startup\memmap.inc \
+ i386\startup\su.asm \
+ i386\startup\su.h \
+ i386\startup\su.inc \
+ i386\startup\sudata.asm \
+ i386\startup\trap.asm \
+ i386\startup\trapdump.c \
+ i386\startup\types.h
+
+!ENDIF
+
+obj\i386\setupldr.bin: obj\i386\setupldr.exe ..\startup\obj\i386\startup.com makefile.inc
+ -copy /b ..\startup\obj\i386\startup.com+obj\i386\setupldr.exe obj\i386\setupldr.bin
+!IFDEF _NT386TREE
+ binplace obj\i386\setupldr.bin
+!ENDIF
+
+!ELSE
+
+SETUPLDR=obj\$(TARGET_DIRECTORY)\setupldr.lib ..\obj\$(TARGET_DIRECTORY)\boot.lib
+
+obj\$(TARGET_DIRECTORY)\setupldr.res: msgs.$(LANGUAGE)
+
+obj\$(TARGET_DIRECTORY)\setupldr: $(SETUPLDR) makefile.inc
+ -link -out:obj\$(TARGET_DIRECTORY)\setupldr $(LINK_LIB_IGNORE_FLAG) @$(TARGET_DIRECTORY)ldr.rsp
+ -binplace obj\$(TARGET_DIRECTORY)\setupldr
+!ENDIF
diff --git a/private/ntos/boot/setup/mips/sources b/private/ntos/boot/setup/mips/sources
new file mode 100644
index 000000000..79a40a614
--- /dev/null
+++ b/private/ntos/boot/setup/mips/sources
@@ -0,0 +1,5 @@
+MIPS_SOURCES=arcdtect.c
+
+
+NTTARGETFILES=obj\mips\setupldr
+
diff --git a/private/ntos/boot/setup/mipsldr.rsp b/private/ntos/boot/setup/mipsldr.rsp
new file mode 100644
index 000000000..49b93ff38
--- /dev/null
+++ b/private/ntos/boot/setup/mipsldr.rsp
@@ -0,0 +1,17 @@
+-machine:mips
+-force:multiple
+-rom
+-nodefaultlib
+-debug:notmapped
+-debugtype:coff
+-align:0x200
+-fixed
+-entry:SlInit
+-base:0x80600000,0x80660000
+-map:obj\mips\setupldr.map
+obj\mips\setupldr.lib
+obj\mips\setupldr.res
+..\obj\mips\boot.lib
+..\..\obj\mips\ke.lib
+..\..\rtl\obj\mips\bldrrtl.lib
+..\..\..\..\public\sdk\lib\mips\libcntpr.lib
diff --git a/private/ntos/boot/setup/msgs.usa b/private/ntos/boot/setup/msgs.usa
new file mode 100644
index 000000000..ba4baa661
--- /dev/null
+++ b/private/ntos/boot/setup/msgs.usa
@@ -0,0 +1,474 @@
+;/*++
+;
+;Copyright (c) 1991 Microsoft Corporation
+;
+;Module Name:
+;
+; msgs.h
+;
+;Abstract:
+;
+; This file contains the message definitions for setupldr
+;
+;Author:
+;
+; John Vert (jvert) 12-Nov-1993
+;
+;Revision History:
+;
+;Notes:
+;
+; This file is generated from msgs.mc
+;
+;--*/
+;
+;#ifndef _SETUPLDR_MSG_
+;#define _SETUPLDR_MSG_
+;
+;
+
+MessageID=9000 SymbolicName=SL_MSG_FIRST
+Language=English
+.
+
+
+MessageID=9001 SymbolicName=SL_SCRN_WELCOME
+Language=English
+Welcome to Windows NT Setup
+
+ Press ENTER to continue
+
+ Press F3 to Exit
+.
+
+MessageID=9002 SymbolicName=SL_WELCOME_HEADER
+Language=English
+
+ Windows NT Setup
+ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
+.
+
+MessageID=9003 SymbolicName=SL_TOTAL_SETUP_DEATH
+Language=English
+Setup failed. Press any key to restart your computer.
+.
+
+MessageID=9004 SymbolicName=SL_FILE_LOAD_MESSAGE
+Language=English
+Setup is loading files (%s)...
+.
+
+MessageID=9005 SymbolicName=SL_OTHER_SELECTION
+Language=English
+Other (requires an OEM driver diskette)
+.
+
+MessageID=9006 SymbolicName=SL_SELECT_DRIVER_PROMPT
+Language=English
+ENTER=Select ESC=Cancel F3=Exit
+.
+
+MessageID=9007 SymbolicName=SL_NEXT_DISK_PROMPT_CANCELLABLE
+Language=English
+ENTER=Continue ESC=Cancel F3=Exit
+.
+
+MessageID=9008 SymbolicName=SL_OEM_DISK_PROMPT
+Language=English
+Manufacturer-supplied hardware support disk
+.
+
+MessageID=9009 SymbolicName=SL_MSG_INSERT_DISK
+Language=English
+Please insert the disk labeled
+
+
+
+ into Drive A:
+
+ * Press ENTER when ready.
+.
+
+MessageID=9010 SymbolicName=SL_MSG_EXIT_DIALOG
+Language=English
+ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
+º Windows NT Version 4.00 is not completely set up º
+º on your system. If you quit Setup now, you will º
+º need to run Setup again to set up Windows NT. º
+º º
+º * Press ENTER to continue Setup. º
+º * Press F3 to quit Setup. º
+ÇÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄĶ
+º F3=Exit ENTER=Continue º
+ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ
+.
+
+MessageID=9011 SymbolicName=SL_NEXT_DISK_PROMPT
+Language=English
+ENTER=Continue F3=Exit
+.
+
+MessageID=9012 SymbolicName=SL_NTDETECT_PROMPT
+Language=English
+
+Setup is inspecting your computer's hardware configuration...
+
+.
+
+MessageID=9013 SymbolicName=SL_KERNEL_NAME
+Language=English
+Windows NT Executive
+.
+
+MessageID=9014 SymbolicName=SL_HAL_NAME
+Language=English
+Hardware Abstraction Layer
+.
+
+MessageID=9015 SymbolicName=SL_PAL_NAME
+Language=English
+Windows NT Processor Extensions
+.
+
+MessageID=9016 SymbolicName=SL_HIVE_NAME
+Language=English
+Windows NT Configuration Data
+.
+
+MessageID=9017 SymbolicName=SL_NLS_NAME
+Language=English
+Locale-Specific Data
+.
+
+MessageID=9018 SymbolicName=SL_OEM_FONT_NAME
+Language=English
+Setup Font
+.
+
+MessageID=9019 SymbolicName=SL_SETUP_NAME
+Language=English
+Windows NT Setup
+.
+
+MessageID=9020 SymbolicName=SL_FLOPPY_NAME
+Language=English
+Floppy Disk Driver
+.
+
+MessageID=9021 SymbolicName=SL_KBD_NAME
+Language=English
+Keyboard Driver
+.
+
+MessageID=9121 SymbolicName=SL_FAT_NAME
+Language=English
+FAT File System
+.
+
+MessageID=9022 SymbolicName=SL_SCSIPORT_NAME
+Language=English
+SCSI Port Driver
+.
+
+MessageID=9023 SymbolicName=SL_VIDEO_NAME
+Language=English
+Video Driver
+.
+
+MessageID=9024 SymbolicName=SL_STATUS_REBOOT
+Language=English
+Press any key to restart your computer.
+.
+
+MessageID=9025 SymbolicName=SL_WARNING_ERROR
+Language=English
+An unexpected error (%d) occurred at
+line %d in %s.
+
+Press any key to continue.
+.
+
+MessageID=9026 SymbolicName=SL_FLOPPY_NOT_FOUND
+Language=English
+Only %d floppy drives were found,
+the system was trying to find drive %d.
+.
+
+MessageID=9027 SymbolicName=SL_NO_MEMORY
+Language=English
+The system has run out of memory at
+line %d in file %s
+.
+
+MessageID=9028 SymbolicName=SL_IO_ERROR
+Language=English
+The system encountered an I/O error
+accessing %s.
+.
+
+MessageID=9029 SymbolicName=SL_BAD_INF_SECTION
+Language=English
+Section %s of the INF file is invalid
+.
+
+MessageID=9030 SymbolicName=SL_BAD_INF_LINE
+Language=English
+Line %d of the INF file is invalid
+.
+
+MessageID=9031 SymbolicName=SL_BAD_INF_FILE
+Language=English
+INF file %s is corrupt or missing.
+.
+
+MessageID=9032 SymbolicName=SL_FILE_LOAD_FAILED
+Language=English
+File %s could not be loaded.
+The error code is %d
+.
+
+MessageID=9033 SymbolicName=SL_INF_ENTRY_MISSING
+Language=English
+The entry "%s" in the [%s] section
+of the INF file is corrupt or missing.
+.
+
+MessageID=9034 SymbolicName=SL_PLEASE_WAIT
+Language=English
+Please wait...
+.
+
+MessageID=9035 SymbolicName=SL_CANT_CONTINUE
+Language=English
+Setup cannot continue. Press any key to exit.
+.
+
+MessageID=9036 SymbolicName=SL_PROMPT_SCSI
+Language=English
+Select the SCSI Adapter you want from the following list, or select "Other"
+if you have a device support disk provided by an adapter manufacturer.
+
+.
+
+MessageID=9037 SymbolicName=SL_PROMPT_OEM_SCSI
+Language=English
+You have chosen to configure a SCSI Adapter for use with Windows NT,
+using a device support disk provided by an adapter manufacturer.
+
+Select the SCSI Adapter you want from the following list, or press ESC
+to return to the previous screen.
+
+.
+MessageID=9038 SymbolicName=SL_PROMPT_HAL
+Language=English
+Setup could not determine the type of computer you have, or you have
+chosen to manually specify the computer type.
+
+Select the computer type from the following list, or select "Other"
+if you have a device support disk provided by your computer manufacturer.
+
+.
+
+MessageID=9039 SymbolicName=SL_PROMPT_OEM_HAL
+Language=English
+You have chosen to configure a computer for use with Windows NT,
+using a device support disk provided by the computer's manufacturer.
+
+Select the computer type from the following list, or press ESC
+to return to the previous screen.
+
+.
+
+MessageID=9040 SymbolicName=SL_PROMPT_VIDEO
+Language=English
+Setup could not determine the type of video adapter installed in the system.
+
+Select the video Adapter you want from the following list, or select "Other"
+if you have a device support disk provided by an adapter manufacturer.
+
+.
+
+MessageID=9041 SymbolicName=SL_PROMPT_OEM_VIDEO
+Language=English
+You have chosen to configure a video Adapter for use with Windows NT,
+using a device support disk provided by an adapter manufacturer.
+
+Select the video Adapter you want from the following list, or press ESC
+to return to the previous screen.
+
+.
+
+MessageID=9042 SymbolicName=SL_WARNING_ERROR_WFILE
+Language=English
+File %s caused an unexpected error (%d) at
+line %d in %s.
+
+Press any key to continue.
+.
+
+MessageID=9043 SymbolicName=SL_WARNING_IMG_CORRUPT
+Language=English
+The file %s is corrupted.
+
+Press any key to continue.
+.
+
+MessageID=9044 SymbolicName=SL_WARNING_IOERR
+Language=English
+An I/O error occurred on file %s.
+
+Press any key to continue.
+.
+
+MessageID=9045 SymbolicName=SL_WARNING_NOFILE
+Language=English
+The file %s could not be found.
+
+Press any key to continue.
+.
+
+MessageID=9046 SymbolicName=SL_WARNING_NOMEM
+Language=English
+Insufficient memory for %s.
+
+Press any key to continue.
+.
+
+MessageID=9047 SymbolicName=SL_DRIVE_ERROR
+Language=English
+SETUPLDR: Couldn't open drive %s
+.
+
+MessageID=9048 SymbolicName=SL_NTDETECT_MSG
+Language=English
+
+Setup is inspecting your computer's hardware configuration...
+
+.
+
+MessageID=9049 SymbolicName=SL_NTDETECT_FAILURE
+Language=English
+NTDETECT failed
+.
+
+MessageId=9050 SymbolicName=SL_SCRN_TEXTSETUP_EXITED
+Language=English
+Windows NT has not been installed.
+
+If there is a floppy disk inserted in drive A:, remove it.
+
+Press ENTER to restart your computer.
+.
+
+MessageId=9051 SymbolicName=SL_SCRN_TEXTSETUP_EXITED_ARC
+Language=English
+Windows NT has not been installed.
+
+Press ENTER to restart your computer.
+.
+
+MessageID=9052 SymbolicName=SL_REBOOT_PROMPT
+Language=English
+ENTER=Restart Computer
+.
+
+MessageID=9053 SymbolicName=SL_WARNING_SIF_NO_DRIVERS
+Language=English
+Setup could not find any drivers associated with your selection.
+
+Press any key to continue.
+.
+
+MessageID=9054 SymbolicName=SL_WARNING_SIF_NO_COMPONENT
+Language=English
+The disk you have supplied does not provide any relevant support files.
+
+Press any key to continue.
+.
+
+MessageID=9055 SymbolicName=SL_WARNING_BAD_FILESYS
+Language=English
+This disk cannot be read because it contains an unrecognized file system.
+
+Press any key to continue.
+.
+
+MessageID=9056 SymbolicName=SL_BAD_UNATTENDED_SCRIPT_FILE
+Language=English
+The entry
+
+"%s"
+
+in the unattended script file doesn't exist
+in the [%s] section of the INF file %s.
+.
+
+;//
+;// The following three messages are used to provide the same mnemonic
+;// keypress as is used in the Additional SCSI screen in setupdd.sys
+;// (see setup\textmode\user\msg.mc--SP_MNEMONICS and SP_MNEMONICS_INFO)
+;// The single character specified in SL_SCSI_SELECT_MNEMONIC must be
+;// the same as that listed in the status text of SL_SCSI_SELECT_PROMPT
+;// (and also referenced in the SL_SCSI_SELECT_MESSAGE_2).
+;//
+MessageID=9060 SymbolicName=SL_SCSI_SELECT_MNEMONIC
+Language=English
+S
+.
+
+MessageID=9061 SymbolicName=SL_SCSI_SELECT_PROMPT
+Language=English
+S=Specify Additional Device ENTER=Continue F3=Exit
+.
+
+MessageID=9062 SymbolicName=SL_SCSI_SELECT_MESSAGE_2
+Language=English
+ * To specify additional SCSI adapters, CD-ROM drives, or special
+ disk controllers for use with Windows NT, including those for which
+ you have a device support disk from a mass storage device
+ manufacturer, press S.
+
+ * If you do not have any device support disks from a mass storage
+ device manufacturer, or do not want to specify additional
+ mass storage devices for use with Windows NT, press ENTER.
+.
+
+MessageID=9063 SymbolicName=SL_SCSI_SELECT_MESSAGE_1
+Language=English
+Setup could not determine the type of one or more mass storage devices
+installed in your system, or you have chosen to manually specify an adapter.
+Currently, Setup will load support for the following mass storage devices(s):
+.
+
+MessageID=9064 SymbolicName=SL_SCSI_SELECT_MESSAGE_3
+Language=English
+Setup will load support for the following mass storage device(s):
+.
+
+MessageID=9065 SymbolicName=SL_SCSI_SELECT_ERROR
+Language=English
+Setup was unable to load support for the mass storage device you specified.
+Currently, Setup will load support for the following mass storage devices(s):
+.
+
+MessageID=9066 SymbolicName=SL_TEXT_ANGLED_NONE
+Language=English
+<none>
+.
+
+MessageID=9067 SymbolicName=SL_TEXT_SCSI_UNNAMED
+Language=English
+<unnamed adapter>
+.
+
+MessageID=9068 SymbolicName=SL_TEXT_OTHER_DRIVER
+Language=English
+Other
+.
+
+MessageID=9069 SymbolicName=SL_TEXT_REQUIRES_486
+Language=English
+Windows NT requires an 80486 or later processor.
+.
+
+;#endif // _SETUPLDR_MSG_
diff --git a/private/ntos/boot/setup/oemdisk.c b/private/ntos/boot/setup/oemdisk.c
new file mode 100644
index 000000000..657c02e2f
--- /dev/null
+++ b/private/ntos/boot/setup/oemdisk.c
@@ -0,0 +1,1953 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ oemdisk.c
+
+Abstract:
+
+ Provides routines for handling OEM disks for video, SCSI miniport, and HAL.
+
+ Currently used only on ARC machines.
+
+Author:
+
+ John Vert (jvert) 4-Dec-1993
+
+Revision History:
+
+ John Vert (jvert) 4-Dec-1993
+ created
+
+--*/
+#include <setupbat.h>
+#include "setupldr.h"
+#include "stdio.h"
+#include <ctype.h>
+
+#if DBG
+
+#define DIAGOUT(x) SlPrint x
+
+#else
+
+#define DIAGOUT(x)
+
+#endif
+
+BOOLEAN PromptOemHal=FALSE;
+BOOLEAN PromptOemScsi=FALSE;
+BOOLEAN PromptOemVideo=FALSE;
+PVOID PreInstallOemInfHandle = NULL;
+
+PCHAR FloppyDiskPath;
+extern PCHAR BootPath;
+extern ULONG BootDeviceId;
+extern PVOID InfFile;
+
+typedef struct _MENU_ITEM_DATA {
+ PVOID InfFile;
+ PCHAR SectionName;
+ ULONG Index;
+ PCHAR Description;
+ PCHAR Identifier;
+} MENU_ITEM_DATA, *PMENU_ITEM_DATA;
+
+typedef enum _OEMFILETYPE {
+ OEMSCSI,
+ OEMHAL,
+ OEMOTHER
+ } OEMFILETYPE, *POEMFILETYPE;
+
+//
+// Define how many lines of SCSI adapters we can list.
+//
+#define MAX_SCSI_MINIPORT_COUNT 4
+
+
+//
+// private function prototypes
+//
+ULONG
+SlpAddSectionToMenu(
+ IN PVOID InfHandle,
+ IN PCHAR SectionName,
+ IN PSL_MENU Menu
+ );
+
+BOOLEAN
+SlpOemDiskette(
+ IN PCHAR ComponentName,
+ IN OEMFILETYPE ComponentType,
+ IN ULONG MenuHeaderId,
+ OUT PDETECTED_DEVICE DetectedDevice,
+ OUT PVOID *ImageBase,
+ OUT OPTIONAL PCHAR *ImageName,
+ OUT OPTIONAL PCHAR *DriverDescription,
+ IN BOOLEAN AllowUserSelection,
+ IN PCHAR PreInstallComponentDescription
+ );
+
+BOOLEAN
+SlpSelectHardware(
+ IN PCHAR ComponentName,
+ IN OEMFILETYPE ComponentType,
+ IN TYPE_OF_MEMORY MemoryType,
+ IN ULONG MenuHeaderId,
+ IN ULONG OemMenuHeaderId,
+ OUT PDETECTED_DEVICE DetectedDevice,
+ OUT PVOID *ImageBase,
+ OUT OPTIONAL PCHAR *ImageName,
+ OUT OPTIONAL PCHAR *DriverDescription,
+ IN BOOLEAN AllowUserSelection,
+ IN PCHAR PreInstallComponentDescription,
+ IN BOOLEAN PreInstallOemComponent
+ );
+
+BOOLEAN
+SlpOemInfSelection(
+ IN PVOID OemInfHandle,
+ IN PCHAR ComponentName,
+ IN PCHAR SelectedId,
+ IN PCHAR ItemDescription,
+ OUT PDETECTED_DEVICE Device
+ );
+
+VOID
+SlpInitDetectedDevice(
+ IN PDETECTED_DEVICE Device,
+ IN PCHAR IdString,
+ IN PCHAR Description,
+ IN BOOLEAN ThirdPartyOptionSelected
+ );
+
+PDETECTED_DEVICE_REGISTRY
+SlpInterpretOemRegistryData(
+ IN PVOID InfHandle,
+ IN PCHAR SectionName,
+ IN ULONG Line,
+ IN HwRegistryType ValueType
+ );
+
+BOOLEAN
+FoundFloppyDiskCallback(
+ IN PCONFIGURATION_COMPONENT_DATA Component
+ );
+
+int
+SlpFindStringInTable(
+ IN PCHAR String,
+ IN PCHAR *StringTable
+ );
+
+//
+// FileTypeNames -- keep in sync with HwFileType enum!
+//
+PCHAR FileTypeNames[HwFileMax] = { "driver", "port" , "class", "inf",
+ "dll" , "detect", "hal"
+ };
+
+//
+// RegistryTypeNames -- keep in sync with HwRegistryType enum!
+//
+PCHAR RegistryTypeNames[HwRegistryMax] = { "REG_DWORD", "REG_BINARY", "REG_SZ",
+ "REG_EXPAND_SZ", "REG_MULTI_SZ"
+ };
+
+ULONG RegistryTypeMap[HwRegistryMax] = { REG_DWORD, REG_BINARY, REG_SZ,
+ REG_EXPAND_SZ, REG_MULTI_SZ
+ };
+
+
+VOID
+SlPromptOemScsi(
+ OUT POEMSCSIINFO *pOemScsiInfo
+ )
+/*++
+
+Routine Description:
+
+ Provides the user interface and logic for allowing the user to manually select
+ SCSI adapters from the main INF file or the INF file on an OEM driver disk.
+
+Arguments:
+
+ pOemScsiInfo - Returns a linked list containing info about any third-party scsi
+ drivers selected.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PVOID OemScsiBase;
+ PCHAR OemScsiName, MessageString, ScsiDescription, MnemonicText;
+ BOOLEAN Success, bFirstTime = TRUE, bRepaint;
+ ULONG x, y1, y2, ScsiDriverCount, NumToSkip;
+ ULONG c;
+ CHAR Mnemonic;
+ POEMSCSIINFO NewOemScsi, CurOemScsi;
+ PDETECTED_DEVICE ScsiDevice;
+ BOOLEAN AllowUserSelection;
+ PPREINSTALL_DRIVER_INFO CurrentDriver;
+
+ AllowUserSelection = ( !PreInstall || (PreinstallDriverList == NULL) )? TRUE : FALSE;
+ CurrentDriver = PreinstallDriverList;
+
+ *pOemScsiInfo = CurOemScsi = NULL;
+
+ MnemonicText = BlFindMessage(SL_SCSI_SELECT_MNEMONIC);
+ Mnemonic = toupper(MnemonicText[0]);
+
+ bRepaint = TRUE;
+ while(1) {
+
+ if( AllowUserSelection ) {
+ if(bRepaint) {
+ SlClearClientArea();
+
+ if(bFirstTime) {
+ MessageString = BlFindMessage(SL_SCSI_SELECT_MESSAGE_1);
+ } else if(Success) {
+ MessageString = BlFindMessage(SL_SCSI_SELECT_MESSAGE_3);
+ } else {
+ MessageString = BlFindMessage(SL_SCSI_SELECT_ERROR);
+ }
+ x = 1;
+ y1 = 4;
+ SlGenericMessageBox(0, NULL, MessageString, &x, &y1, &y2, FALSE);
+ y1 = y2 + 1;
+ x = 4;
+
+ //
+ // Count all currently 'detected' SCSI devices.
+ //
+ for(ScsiDriverCount = 0, ScsiDevice = BlLoaderBlock->SetupLoaderBlock->ScsiDevices;
+ ScsiDevice;
+ ScsiDriverCount++, ScsiDevice = ScsiDevice->Next);
+
+ //
+ // Display each loaded miniport driver description.
+ //
+ if(ScsiDriverCount) {
+
+ if(ScsiDriverCount > MAX_SCSI_MINIPORT_COUNT) {
+ NumToSkip = ScsiDriverCount - MAX_SCSI_MINIPORT_COUNT;
+ //
+ // Display ellipses to indicate that top entries have scrolled out of view
+ //
+ SlGenericMessageBox(0,
+ NULL,
+ "...",
+ &x,
+ &y1,
+ &y2,
+ FALSE
+ );
+
+ y1 = y2 + 1;
+
+ } else {
+ NumToSkip = 0;
+ y1++;
+ }
+
+ ScsiDevice = BlLoaderBlock->SetupLoaderBlock->ScsiDevices;
+ while(NumToSkip && ScsiDevice) {
+ ScsiDevice = ScsiDevice->Next;
+ NumToSkip--;
+ }
+
+ while(ScsiDevice) {
+
+ SlGenericMessageBox(0,
+ NULL,
+ ScsiDevice->Description,
+ &x,
+ &y1,
+ &y2,
+ FALSE
+ );
+
+ y1 = y2 + 1;
+ ScsiDevice = ScsiDevice->Next;
+ }
+ } else {
+
+ y1++;
+ SlGenericMessageBox(0,
+ NULL,
+ BlFindMessage(SL_TEXT_ANGLED_NONE),
+ &x,
+ &y1,
+ &y2,
+ FALSE
+ );
+ y1 = y2 + 1;
+ }
+
+ x = 1;
+ y1++;
+ SlGenericMessageBox(0,
+ NULL,
+ BlFindMessage(SL_SCSI_SELECT_MESSAGE_2),
+ &x,
+ &y1,
+ &y2,
+ FALSE
+ );
+
+ SlWriteStatusText(BlFindMessage(SL_SCSI_SELECT_PROMPT));
+
+ bRepaint = FALSE;
+ }
+ c = SlGetChar();
+ } else {
+ c = ( CurrentDriver != NULL )? Mnemonic : ASCI_CR;
+ }
+ switch (c) {
+ case SL_KEY_F3:
+ SlConfirmExit();
+ bRepaint = TRUE;
+ break;
+
+ case ASCI_CR:
+ return;
+
+ default:
+ if(toupper(c) == Mnemonic) {
+ bFirstTime = FALSE;
+ bRepaint = TRUE;
+ Success = SlpSelectHardware("SCSI",
+ OEMSCSI,
+ LoaderBootDriver,
+ SL_PROMPT_SCSI,
+ SL_PROMPT_OEM_SCSI,
+ NULL,
+ &OemScsiBase,
+ &OemScsiName,
+ &ScsiDescription,
+ AllowUserSelection,
+ (AllowUserSelection)? NULL : CurrentDriver->DriverDescription,
+ (BOOLEAN)((AllowUserSelection)? FALSE : CurrentDriver->OemDriver)
+ );
+
+ if(!AllowUserSelection) {
+ CurrentDriver = CurrentDriver->Next;
+ }
+
+ if(Success) {
+ //
+ // Check to see if the driver loaded was an OEM SCSI driver. If so,
+ // then add an OemScsiInfo entry onto the end of our list.
+ //
+ if(OemScsiBase) {
+
+ NewOemScsi = BlAllocateHeap(sizeof(OEMSCSIINFO));
+ if(!NewOemScsi) {
+ SlNoMemoryError();
+ }
+
+ if(CurOemScsi) {
+ CurOemScsi->Next = NewOemScsi;
+ } else {
+ *pOemScsiInfo = NewOemScsi;
+ }
+ CurOemScsi = NewOemScsi;
+
+ NewOemScsi->ScsiBase = OemScsiBase;
+ NewOemScsi->ScsiName = OemScsiName;
+ NewOemScsi->Next = NULL;
+ }
+ }
+ }
+ }
+ }
+}
+
+
+VOID
+SlPromptOemHal(
+ OUT PVOID *HalBase,
+ OUT PCHAR *HalName
+ )
+
+/*++
+
+Routine Description:
+
+ Provides the user interface and logic for allowing the user to manually select
+ a HAL from the main INF file or the INF file on an OEM driver disk.
+
+Arguments:
+
+ HalBase - Returns the address where the HAL was loaded into memory.
+
+ HalName - Returns the name of the HAL that was loaded.
+
+Return Value:
+
+ ESUCCESS - HAL successfully loaded.
+
+--*/
+
+{
+ BOOLEAN Success;
+ BOOLEAN AllowUserSelection;
+
+ AllowUserSelection = ( !PreInstall || (ComputerType == NULL) )? TRUE : FALSE;
+ do {
+ Success = SlpSelectHardware("Computer",
+ OEMHAL,
+ LoaderHalCode,
+ SL_PROMPT_HAL,
+ SL_PROMPT_OEM_HAL,
+ &BlLoaderBlock->SetupLoaderBlock->ComputerDevice,
+ HalBase,
+ HalName,
+ NULL,
+ AllowUserSelection,
+ ComputerType,
+ OemHal
+ );
+
+ } while ( !Success );
+
+}
+
+
+VOID
+SlPromptOemVideo(
+ OUT PVOID *VideoBase,
+ OUT PCHAR *VideoName
+ )
+
+/*++
+
+Routine Description:
+
+ Provides the user interface and logic for allowing the user to manually select
+ a video adapter from the main INF file or the INF file on an OEM driver disk.
+
+Arguments:
+
+ VideoBase - Returns the address where the video driver was loaded
+
+ VideoName - Returns a pointer to the name of the video driver
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ BOOLEAN Success;
+
+ do {
+ Success = SlpSelectHardware("display",
+ OEMOTHER,
+ LoaderBootDriver,
+ SL_PROMPT_VIDEO,
+ SL_PROMPT_OEM_VIDEO,
+ &BlLoaderBlock->SetupLoaderBlock->VideoDevice,
+ VideoBase,
+ VideoName,
+ NULL,
+ TRUE,
+ NULL,
+ FALSE
+ );
+
+ } while ( !Success );
+
+}
+
+
+BOOLEAN
+SlpSelectHardware(
+ IN PCHAR ComponentName,
+ IN OEMFILETYPE ComponentType,
+ IN TYPE_OF_MEMORY MemoryType,
+ IN ULONG MenuHeaderId,
+ IN ULONG OemMenuHeaderId,
+ OUT OPTIONAL PDETECTED_DEVICE DetectedDevice,
+ OUT PVOID *ImageBase,
+ OUT OPTIONAL PCHAR *ImageName,
+ OUT OPTIONAL PCHAR *DriverDescription,
+ IN BOOLEAN AllowUserSelection,
+ IN PCHAR PreInstallComponentDescription,
+ IN BOOLEAN PreInstallOemComponent
+ )
+
+/*++
+
+Routine Description:
+
+ Present the user with a menu of options for the selected device class.
+ This menu will consist of options listed in the main inf plus a single
+ oem option if one is currently selected, plus additional items in the
+ system partition inf for the component if specified (ARC machines).
+
+ When the user makes a selection, forget any previous OEM option (except
+ for SCSI). If the user selects an option supplied by us, set up the
+ SELECTED_DEVICE structure and return. Otherwise prompt for a manufacturer-
+ supplied diskette.
+
+Arguments:
+
+ ComponentName - Supplies the name of the component to be presented.
+
+ ComponentType - Supplies the type of the component (HAL, SCSI, or Other)
+
+ MemoryType - Supplies the type of memory used to load the image.
+
+ MenuHeaderId - Supplies the ID of the menu header to be displayed
+
+ OemMenuHeaderId - Supplies the ID of the menu header to be displayed
+ when an OEM selection is to be made.
+
+ DetectedDevice - returns the DeviceId of the selected device. If an
+ OEM diskette is required, the necessary OEM structures will
+ be allocated and filled in. (This field is ignored for SCSI
+ components.)
+
+ ImageBase - Returns the base of the image that was loaded.
+
+ ImageName - Returns the filename of the image.
+
+ DriverDescription - If specified, returns the description of the loaded
+ device.
+
+ AllowUserSelection - Indicates whether or not user is allowed to select
+ a driver. This flag is typically set to FALSE when
+ pre-installing components defined in unattend.txt.
+
+ PreInstallComponentDescription - In the pre-install mode, points to the string
+ that identifies the component to pre-install.
+ It is NULL if AllowUserSelction is TRUE.
+
+ PreInstallOemComponent - In the pre-install mode, this flag indicates
+ whether or not the component to pre-install is
+ an OEM or RETAIL component.
+
+
+Return Value:
+
+ TRUE - Success
+
+ FALSE - The user has escaped out of the dialog
+
+--*/
+
+{
+ PSL_MENU Menu;
+ LONG Selection;
+ LONG OtherSelection;
+ CHAR OtherSelectionName[80];
+ PCHAR p;
+ ULONG c, i;
+ PCHAR AdapterName;
+ CHAR Buffer[80];
+ PCHAR FileName;
+ PCHAR FileDescription;
+ ARC_STATUS Status;
+ BOOLEAN b;
+ ULONG Ordinal;
+ SCSI_INSERT_STATUS sis;
+
+ if( AllowUserSelection ) {
+ Menu = SlCreateMenu();
+ if (Menu==NULL) {
+ SlNoMemoryError();
+ return(FALSE);
+ }
+
+ //
+ // Build a list of options containing the drivers we ship and the
+ // currently selected OEM option (if any).
+ //
+
+ c = SlpAddSectionToMenu(InfFile,
+ ComponentName,
+ Menu);
+ //
+ // Add selection for "other"
+ //
+ strncpy(OtherSelectionName,
+ BlFindMessage(SL_TEXT_OTHER_DRIVER),
+ 80
+ );
+ OtherSelectionName[79] = 0;
+ //
+ // Use text up to the first CR or LF.
+ //
+ for(p = OtherSelectionName; *p; p++) {
+ if((*p == '\n') || (*p == '\r')) {
+ *p = '\0';
+ break;
+ }
+ }
+
+ OtherSelection = SlAddMenuItem(Menu,
+ OtherSelectionName,
+ (PVOID)-1,
+ 0);
+
+ //
+ // Default is "other"
+ //
+ Selection = OtherSelection;
+
+ } else {
+ //
+ // This is a pre-install. Find out if the component to pre-install
+ // is RETAIL or OEM.
+ //
+ OtherSelection = SlCountLinesInSection( InfFile,
+ ComponentName );
+ if( PreInstallOemComponent ) {
+ //
+ // Pre-installing an OEM component
+ //
+ Selection = OtherSelection;
+ } else {
+ //
+ // Pre-installing a RETAIL component
+ //
+ PCHAR q;
+ q = SlPreInstallGetComponentName( InfFile,
+ ComponentName,
+ PreInstallComponentDescription );
+ if (q==NULL) {
+ //
+ // we have enumerated the entire section without finding a
+ // match, return failure.
+ //
+ SlFatalError(SL_BAD_UNATTENDED_SCRIPT_FILE,
+ PreInstallComponentDescription,
+ ComponentName,
+ "txtsetup.sif");
+ goto SelectionAbort;
+ }
+
+ Selection = SlGetSectionKeyOrdinal( InfFile,
+ ComponentName,
+ q );
+ }
+ }
+
+ //
+ // Allow the user to interact with the menu
+ //
+ while (1) {
+ if( AllowUserSelection ) {
+ SlClearClientArea();
+ SlWriteStatusText(BlFindMessage(SL_SELECT_DRIVER_PROMPT));
+
+ c = SlDisplayMenu(MenuHeaderId,
+ Menu,
+ &Selection);
+ } else {
+ c = ASCI_CR;
+ }
+ switch (c) {
+ case SL_KEY_F3:
+ SlConfirmExit();
+ break;
+
+ case ASCI_ESC:
+ goto SelectionAbort;
+
+ case ASCI_CR:
+ if (Selection == OtherSelection) {
+
+ //
+ // User selected "other" Prompt for OEM diskette
+ //
+ b = SlpOemDiskette(ComponentName,
+ ComponentType,
+ OemMenuHeaderId,
+ DetectedDevice,
+ ImageBase,
+ ImageName,
+ DriverDescription,
+ AllowUserSelection,
+ PreInstallComponentDescription
+ );
+
+
+ SlClearClientArea();
+ SlWriteStatusText("");
+ return(b);
+
+ } else {
+ //
+ // User selected a built-in. Go ahead and load
+ // it here.
+ //
+
+ if(ComponentType == OEMHAL) {
+ //
+ // then we need to look for [Hal.Load]
+ //
+ strcpy(Buffer, "Hal.Load");
+ } else {
+ sprintf(Buffer, "%s.Load", ComponentName);
+ }
+
+ AdapterName = SlGetKeyName(InfFile,
+ ComponentName,
+ Selection
+ );
+ if(AdapterName==NULL) {
+ SlFatalError(SL_BAD_INF_FILE, "txtsetup.sif");
+ goto SelectionAbort;
+ }
+
+ FileName = SlGetIniValue(InfFile,
+ Buffer,
+ AdapterName,
+ NULL);
+
+ if((FileName==NULL) && (ComponentType == OEMHAL)) {
+ FileName = SlGetIniValue(InfFile,
+ "Hal",
+ AdapterName,
+ NULL);
+ FileDescription = SlCopyString(BlFindMessage(SL_HAL_NAME));
+ } else {
+ FileDescription = SlGetIniValue(InfFile,
+ ComponentName,
+ AdapterName,
+ NULL);
+ }
+
+ if(FileName==NULL) {
+ SlFatalError(SL_BAD_INF_FILE, "txtsetup.sif");
+ goto SelectionAbort;
+ }
+
+ if(ARGUMENT_PRESENT(ImageName)) {
+ *ImageName = FileName;
+ }
+
+ if(ARGUMENT_PRESENT(DriverDescription)) {
+ *DriverDescription = FileDescription;
+ }
+
+ //
+ // If we're doing OEM SCSI, then get a properly-inserted
+ // DETECTED_DEVICE structure
+ //
+ if(ComponentType == OEMSCSI) {
+ //
+ // Find this adapter's ordinal within the Scsi.Load section of txtsetup.sif
+ //
+ Ordinal = SlGetSectionKeyOrdinal(InfFile, Buffer, AdapterName);
+ if(Ordinal == (ULONG)-1) {
+ SlFatalError(SL_BAD_INF_FILE, "txtsetup.sif");
+ goto SelectionAbort;
+ }
+
+ //
+ // Create a new detected device entry.
+ //
+ if((sis = SlInsertScsiDevice(Ordinal, &DetectedDevice)) == ScsiInsertError) {
+ SlFriendlyError(ENOMEM, "SCSI detection", __LINE__, __FILE__);
+ goto SelectionAbort;
+ }
+
+
+ if(sis == ScsiInsertExisting) {
+#if DBG
+ //
+ // Sanity check to make sure we're talking about the same driver
+ //
+ if(_strcmpi(DetectedDevice->BaseDllName, FileName)) {
+ SlError(400);
+ goto SelectionAbort;
+ }
+#endif
+ }
+ }
+
+ DetectedDevice->IdString = AdapterName;
+ DetectedDevice->Description = FileDescription;
+ DetectedDevice->ThirdPartyOptionSelected = FALSE;
+ DetectedDevice->FileTypeBits = 0;
+ DetectedDevice->Files = NULL;
+ DetectedDevice->BaseDllName = FileName;
+
+ //
+ // We only want to load the image if we're not doing SCSI.
+ //
+ if(ComponentType != OEMSCSI) {
+ sprintf(Buffer, "%s%s", BootPath, FileName);
+ SlGetDisk(FileName);
+ BlOutputLoadMessage(FileDescription, FileName);
+ Status = BlLoadImage(BootDeviceId,
+ LoaderHalCode,
+ Buffer,
+ TARGET_IMAGE,
+ ImageBase
+ );
+ } else {
+ *ImageBase = NULL;
+ Status = ESUCCESS;
+ }
+ }
+
+ if (Status != ESUCCESS) {
+ SlMessageBox(SL_FILE_LOAD_FAILED,Buffer,Status);
+ goto SelectionAbort;
+ }
+
+ SlClearClientArea();
+ SlWriteStatusText("");
+ return(TRUE);
+
+ default:
+ break;
+ }
+ }
+
+SelectionAbort:
+ SlClearClientArea();
+ SlWriteStatusText("");
+ return FALSE;
+}
+
+
+BOOLEAN
+SlpOemDiskette(
+ IN PCHAR ComponentName,
+ IN OEMFILETYPE ComponentType,
+ IN ULONG MenuHeaderId,
+ OUT OPTIONAL PDETECTED_DEVICE DetectedDevice,
+ OUT PVOID *ImageBase,
+ OUT OPTIONAL PCHAR *ImageName,
+ OUT OPTIONAL PCHAR *DriverDescription,
+ IN BOOLEAN AllowUserSelection,
+ IN PCHAR PreInstallComponentDescription
+ )
+
+/*++
+
+Routine Description:
+
+ Prompt for an oem driver diskette and read the oem text inf file
+ from it. Present the choices for the device class to the user and
+ allow him to select one.
+
+ Remember information about the selection the user has made.
+
+Arguments:
+
+ ComponentName - Supplies name of component to look for.
+
+ ComponentType - Supplies the type of the component (HAL, SCSI, or Other)
+
+ MenuHeaderId - Supplies ID of menu header to be displayed
+
+ DetectedDevice - Returns information about the device seleceted
+
+ ImageBase - Returns image base of loaded image
+
+ ImageName - Returns filename of loaded image
+
+ DriverDescription - If specified, returns description of loaded driver
+
+ AllowUserSelection - Indicates whether or not user is allowed to select
+ a driver. This flag is typically set to FALSE when
+ pre-installing components defined in unattend.txt.
+
+ PreInstallComponentDescription - In the pre-install mode, points to the string
+ that identifies the component to pre-install.
+ It is NULL if AllowUserSelction is TRUE.
+
+Return Value:
+
+ TRUE if the user made a choice, FALSE if the user cancelled/error occurred.
+
+--*/
+
+{
+
+ CHAR FloppyName[80];
+ ULONG FloppyId;
+ PVOID OemInfHandle;
+ ULONG Error;
+ ARC_STATUS Status;
+ ULONG Count;
+ ULONG DefaultSelection;
+ PCHAR DefaultSelText;
+ PSL_MENU Menu;
+ ULONG c;
+ PMENU_ITEM_DATA Data;
+ PDETECTED_DEVICE_FILE FileStruct;
+ BOOLEAN bDriverLoaded;
+ HwFileType filetype;
+ PDETECTED_DEVICE prev, cur;
+ CHAR FullDriverPath[256];
+ ULONG DirectoryLength;
+ BOOLEAN SeparatorNeeded;
+ CHAR OemTextFilePath[256];
+ PCHAR OemComponentId;
+ PCHAR OemComponentDescription;
+
+ SlClearClientArea();
+
+ if( AllowUserSelection ) {
+ //
+ // Compute the name of the A: drive
+ //
+ if (!SlpFindFloppy(0,FloppyName)) {
+ //
+ // No floppy drive available, bail out.
+ //
+ SlError(0);
+ return(FALSE);
+ }
+
+ //
+ // Prompt for the disk.
+ //
+ while(1) {
+ if (!SlPromptForDisk(BlFindMessage(SL_OEM_DISK_PROMPT), TRUE)) {
+ return(FALSE);
+ }
+
+ Status = ArcOpen(FloppyName, ArcOpenReadOnly, &FloppyId);
+ if(Status == ESUCCESS) {
+ break;
+ }
+ }
+ }
+
+ //
+ // Load the OEM INF file
+ //
+ if( AllowUserSelection ) {
+ strcpy( OemTextFilePath, "" );
+ strcpy( FullDriverPath, "" );
+ } else {
+#ifndef _X86_
+ PCHAR p;
+#endif
+ strcpy( OemTextFilePath, BootPath );
+#ifndef _X86_
+ //
+ // On RISC platforms, remove the platform specific directory
+ // from the path
+ //
+ p = (OemTextFilePath + strlen(OemTextFilePath) - 1);
+ if( *p == '\\' ) {
+ *p = '\0';
+ }
+ p = strrchr( OemTextFilePath, '\\' );
+ *(p+1) = '\0';
+#endif
+ //
+ // Note that on x86 the path to txtsetup.oem is going to be:
+ // $win_nt$.~bt\$OEM$
+ // while on non-x86 platforms, the path is going to be:
+ // $win_nt$.~ls\$OEM$\TEXTMODE
+ //
+ strcat( OemTextFilePath,
+#ifdef _X86_
+ WINNT_OEM_DIR
+#else
+ WINNT_OEM_TEXTMODE_DIR
+#endif
+ );
+ //
+ // Save the path to the directory that contains txtsetup.oem.
+ // It will be used later on, when we load the driver.
+ //
+ strcpy( FullDriverPath, OemTextFilePath );
+ strcat( OemTextFilePath, "\\" );
+ }
+ //
+ // Now form the path to txtsetup.oem
+ //
+ strcat( OemTextFilePath, "txtsetup.oem" );
+ if( AllowUserSelection || (PreInstallOemInfHandle == NULL)) {
+ Status = SlInitIniFile(NULL,
+ ( AllowUserSelection )? FloppyId : BootDeviceId,
+ OemTextFilePath,
+ &OemInfHandle,
+ &Error);
+ if (Status != ESUCCESS) {
+ SlFriendlyError(Status, "txtsetup.oem", __LINE__, __FILE__);
+ goto OemLoadFailed;
+ }
+ if( !AllowUserSelection ) {
+ PreInstallOemInfHandle = OemInfHandle;
+ }
+ } else {
+ OemInfHandle = PreInstallOemInfHandle;
+ }
+
+ Count = SlCountLinesInSection(OemInfHandle, ComponentName);
+ if(Count == (ULONG)(-1)) {
+ SlMessageBox(SL_WARNING_SIF_NO_COMPONENT);
+ goto OemLoadFailed;
+ }
+
+ //
+ // Get the text of the default choice
+ //
+ if( AllowUserSelection ) {
+ if(DefaultSelText = SlGetSectionKeyIndex(OemInfHandle, "Defaults",ComponentName, 0)) {
+ DefaultSelText = SlGetSectionKeyIndex(OemInfHandle,ComponentName,DefaultSelText,0);
+ }
+ } else {
+ DefaultSelText = PreInstallComponentDescription;
+ }
+
+ if( AllowUserSelection ) {
+ //
+ // Build menu
+ //
+ Menu = SlCreateMenu();
+ if (Menu==NULL) {
+ SlNoMemoryError();
+ }
+ SlpAddSectionToMenu(OemInfHandle,ComponentName,Menu);
+
+ //
+ // Find the index of the default choice
+ //
+ if(!DefaultSelText ||
+ !SlGetMenuItemIndex(Menu,DefaultSelText,&DefaultSelection)) {
+ DefaultSelection=0;
+ }
+ }
+
+ //
+ // Allow the user to interact with the menu
+ //
+ while (1) {
+ if( AllowUserSelection ) {
+ SlClearClientArea();
+ SlWriteStatusText(BlFindMessage(SL_SELECT_DRIVER_PROMPT));
+
+ c = SlDisplayMenu(MenuHeaderId,
+ Menu,
+ &DefaultSelection);
+ } else {
+ c = ASCI_CR;
+ }
+ switch (c) {
+
+ case SL_KEY_F3:
+ SlConfirmExit();
+ break;
+
+ case ASCI_ESC:
+ return(FALSE);
+ break;
+
+ case ASCI_CR:
+ //
+ // User selected an option, fill in the detected
+ // device structure with the information from the
+ // INF file.
+ //
+
+ //
+ // If this is for OEM SCSI, then we have to get a new (properly-inserted)
+ // DETECTED_DEVICE structure.
+ //
+ if(ComponentType == OEMSCSI) {
+ if(SlInsertScsiDevice((ULONG)-1, &DetectedDevice) == ScsiInsertError) {
+ SlNoMemoryError();
+ }
+ }
+
+ if( AllowUserSelection ) {
+ Data = SlGetMenuItem(Menu, DefaultSelection);
+ OemComponentId = Data->Identifier;
+ OemComponentDescription = Data->Description;
+ } else {
+ OemComponentId = SlPreInstallGetComponentName( OemInfHandle,
+ ComponentName,
+ PreInstallComponentDescription );
+ if( OemComponentId == NULL ) {
+ SlFatalError(SL_BAD_UNATTENDED_SCRIPT_FILE,
+ PreInstallComponentDescription,
+ ComponentName,
+ "txtsetup.oem");
+
+ }
+ OemComponentDescription = PreInstallComponentDescription;
+ }
+
+ if(SlpOemInfSelection(OemInfHandle,
+ ComponentName,
+ OemComponentId,
+ OemComponentDescription,
+ DetectedDevice))
+ {
+ //
+ // Go load the driver. The correct disk must
+ // already be in the drive, since we just read
+ // the INF file off it.
+ //
+ // We step down the linked list, and load the first driver we find.
+ //
+ for(FileStruct = DetectedDevice->Files, bDriverLoaded = FALSE;
+ (FileStruct && !bDriverLoaded);
+ FileStruct = FileStruct->Next) {
+
+ filetype = FileStruct->FileType;
+
+ if((filetype == HwFilePort) || (filetype == HwFileClass) ||
+ (filetype == HwFileDriver) || (filetype == HwFileHal)) {
+ BlOutputLoadMessage(OemComponentDescription, // Data->Description,
+ FileStruct->Filename);
+ //
+ // Allocate a string buffer large enough to hold the full
+ // path to the file.
+ //
+ DirectoryLength = strlen(FileStruct->Directory);
+ SeparatorNeeded = !(DirectoryLength &&
+ FileStruct->Directory[DirectoryLength - 1] == '\\');
+ //
+ // Note that FullDriverPath is already initialized.
+ // (This was done right before we loaded txtsetup.oem)
+ //
+ strcat(FullDriverPath, FileStruct->Directory);
+ if(SeparatorNeeded) {
+ strcat(FullDriverPath, "\\");
+ }
+ strcat(FullDriverPath, FileStruct->Filename);
+ Status = BlLoadImage(( AllowUserSelection )? FloppyId : BootDeviceId,
+ LoaderHalCode,
+ FullDriverPath,
+ TARGET_IMAGE,
+ ImageBase);
+ if (Status == ESUCCESS) {
+
+ DetectedDevice->BaseDllName = FileStruct->Filename;
+
+ if(ARGUMENT_PRESENT(ImageName)) {
+ *ImageName = FileStruct->Filename;
+ }
+
+ if(ARGUMENT_PRESENT(DriverDescription)) {
+ *DriverDescription = OemComponentDescription; // Data->Description;
+ }
+
+ bDriverLoaded = TRUE;
+
+ } else {
+
+ if( !PreInstall ) {
+ SlFriendlyError(
+ Status,
+ FullDriverPath,
+ __LINE__,
+ __FILE__
+ );
+
+ //
+ // If one of the drivers causes an error, then we abort
+ //
+ if( AllowUserSelection ) {
+ ArcClose(FloppyId);
+ }
+ //
+ // We must take the bad driver entry out of the chain in
+ // the case of SCSI.
+ //
+ if(ComponentType == OEMSCSI) {
+
+ prev = NULL;
+ cur = BlLoaderBlock->SetupLoaderBlock->ScsiDevices;
+
+ while(cur && (cur != DetectedDevice)) {
+ prev = cur;
+ cur = cur->Next;
+ }
+
+ if(cur) { // it better always be non-NULL!
+ if(prev) {
+ prev->Next = cur->Next;
+ } else {
+ BlLoaderBlock->SetupLoaderBlock->ScsiDevices = cur->Next;
+ }
+ }
+ }
+
+ return FALSE;
+ } else {
+ SlFatalError(SL_FILE_LOAD_FAILED, FullDriverPath, Status);
+ }
+ }
+ }
+ }
+ if( AllowUserSelection ) {
+ ArcClose(FloppyId);
+ }
+
+ if(bDriverLoaded) {
+ return TRUE;
+ } else {
+ //
+ // We didn't find any drivers, so inform the user.
+ //
+ SlMessageBox(SL_WARNING_SIF_NO_DRIVERS);
+ break;
+ }
+
+ } else {
+ SlFriendlyError(
+ 0,
+ "",
+ __LINE__,
+ __FILE__
+ );
+ }
+ break;
+ }
+ }
+
+OemLoadFailed:
+ if( AllowUserSelection ) {
+ ArcClose(FloppyId);
+ }
+ return(FALSE);
+}
+
+
+ULONG
+SlpAddSectionToMenu(
+ IN PVOID InfHandle,
+ IN PCHAR SectionName,
+ IN PSL_MENU Menu
+ )
+/*++
+
+Routine Description:
+
+ Adds the entries in an INF section to the given menu
+
+Arguments:
+
+ InfHandle - Supplies a handle to the INF file
+
+ SectionName - Supplies the name of the section.
+
+ Menu - Supplies the menu to add the items in the section to.
+
+Return Value:
+
+ Number of items added to the menu.
+
+--*/
+{
+ ULONG i;
+ ULONG LineCount;
+ PCHAR Description;
+ PMENU_ITEM_DATA Data;
+
+ if (InfHandle==NULL) {
+ //
+ // nothing to add
+ //
+ return(0);
+ }
+
+ LineCount = SlCountLinesInSection(InfHandle,SectionName);
+ if(LineCount == (ULONG)(-1)) {
+ LineCount = 0;
+ }
+ for (i=0;i<LineCount;i++) {
+ Data = BlAllocateHeap(sizeof(MENU_ITEM_DATA));
+ if (Data==NULL) {
+ SlError(0);
+ return(0);
+ }
+
+ Data->InfFile = InfHandle;
+ Data->SectionName = SectionName;
+ Data->Index = i;
+
+ Description = SlGetSectionLineIndex(InfHandle,
+ SectionName,
+ i,
+ 0);
+ if (Description==NULL) {
+ Description="BOGUS!";
+ }
+
+ Data->Description = Description;
+ Data->Identifier = SlGetKeyName(InfHandle,SectionName,i);
+
+ SlAddMenuItem(Menu,
+ Description,
+ Data,
+ 0);
+ }
+
+ return(LineCount);
+}
+
+
+BOOLEAN
+SlpFindFloppy(
+ IN ULONG Number,
+ OUT PCHAR ArcName
+ )
+
+/*++
+
+Routine Description:
+
+ Determines the ARC name for a particular floppy drive.
+
+Arguments:
+
+ Number - Supplies the floppy drive number
+
+ ArcName - Returns the ARC name of the given floppy drive.
+
+Return Value:
+
+ TRUE - Drive was found.
+
+ FALSE - Drive was not found.
+
+--*/
+
+{
+
+ FloppyDiskPath = ArcName;
+
+ BlSearchConfigTree(BlLoaderBlock->ConfigurationRoot,
+ PeripheralClass,
+ FloppyDiskPeripheral,
+ Number,
+ FoundFloppyDiskCallback);
+
+ if (ArcName[0]=='\0') {
+ return(FALSE);
+ } else {
+ return(TRUE);
+ }
+
+}
+
+
+BOOLEAN
+FoundFloppyDiskCallback(
+ IN PCONFIGURATION_COMPONENT_DATA Component
+ )
+
+/*++
+
+Routine Description:
+
+ Callback routine called by SlpFindFloppy to find a given floppy
+ drive in the ARC tree.
+
+ Check to see whether the parent is disk controller 0.
+
+Arguments:
+
+ Component - Supplies the component.
+
+Return Value:
+
+ TRUE if search is to continue.
+ FALSE if search is to stop.
+
+--*/
+
+{
+ PCONFIGURATION_COMPONENT_DATA ParentComponent;
+
+ //
+ // A floppy disk peripheral was found. If the parent was disk(0),
+ // we've got a floppy disk drive.
+ //
+
+ if((ParentComponent = Component->Parent)
+ && (ParentComponent->ComponentEntry.Type == DiskController))
+ {
+
+ //
+ // Store the ARC pathname of the floppy
+ //
+ BlGetPathnameFromComponent(Component,FloppyDiskPath);
+ return(FALSE);
+ }
+
+ return(TRUE); // keep searching
+}
+
+
+BOOLEAN
+SlpOemInfSelection(
+ IN PVOID OemInfHandle,
+ IN PCHAR ComponentName,
+ IN PCHAR SelectedId,
+ IN PCHAR ItemDescription,
+ OUT PDETECTED_DEVICE Device
+ )
+{
+ PCHAR FilesSectionName,ConfigSectionName;
+ ULONG Line,Count,Line2,Count2;
+ BOOLEAN rc = FALSE;
+ PDETECTED_DEVICE_FILE FileList = NULL, FileListTail;
+ PDETECTED_DEVICE_REGISTRY RegList = NULL, RegListTail;
+ ULONG FileTypeBits = 0;
+
+ //
+ // Iterate through the files section, remembering info about the
+ // files to be copied in support of the selection.
+ //
+
+ FilesSectionName = BlAllocateHeap(strlen(ComponentName) + strlen(SelectedId) + sizeof("Files.") + 1);
+ strcpy(FilesSectionName,"Files.");
+ strcat(FilesSectionName,ComponentName);
+ strcat(FilesSectionName,".");
+ strcat(FilesSectionName,SelectedId);
+ Count = SlCountLinesInSection(OemInfHandle,FilesSectionName);
+ if(Count == (ULONG)(-1)) {
+ SlMessageBox(SL_BAD_INF_SECTION,FilesSectionName);
+ goto sod0;
+ }
+
+ for(Line=0; Line<Count; Line++) {
+
+ PCHAR Disk,Filename,Filetype,Tagfile,Description,Directory,ConfigName;
+ HwFileType filetype;
+ PDETECTED_DEVICE_FILE FileStruct;
+
+ //
+ // Get the disk specification, filename, and filetype from the line.
+ //
+
+ Disk = SlGetSectionLineIndex(OemInfHandle,FilesSectionName,Line,OINDEX_DISKSPEC);
+
+ Filename = SlGetSectionLineIndex(OemInfHandle,FilesSectionName,Line,OINDEX_FILENAME);
+ Filetype = SlGetKeyName(OemInfHandle,FilesSectionName,Line);
+
+ if(!Disk || !Filename || !Filetype) {
+ DIAGOUT(("SlpOemDiskette: Disk=%s, Filename=%s, Filetype=%s",Disk ? Disk : "(null)",Filename ? Filename : "(null)",Filetype ? Filetype : "(null)"));
+ SlError(Line);
+// SppOemInfError(ErrorMsg,&SptOemInfErr2,Line+1,FilesSectionName);
+
+ goto sod0;
+ }
+
+ //
+ // Parse the filetype.
+ //
+ filetype = SlpFindStringInTable(Filetype,FileTypeNames);
+ if(filetype == HwFileMax) {
+// SppOemInfError(ErrorMsg,&SptOemInfErr4,Line+1,FilesSectionName);
+ goto sod0;
+ }
+
+ //
+ // Fetch the name of the section containing configuration information.
+ // Required if file is of type port, class, or driver.
+ //
+ if((filetype == HwFilePort) || (filetype == HwFileClass) || (filetype == HwFileDriver)) {
+ ConfigName = SlGetSectionLineIndex(OemInfHandle,FilesSectionName,Line,OINDEX_CONFIGNAME);
+ if(ConfigName == NULL) {
+// SppOemInfError(ErrorMsg,&SptOemInfErr8,Line+1,FilesSectionName);
+ goto sod0;
+ }
+ } else {
+ ConfigName = NULL;
+ }
+
+ //
+ // Using the disk specification, look up the tagfile, description,
+ // and directory for the disk.
+ //
+
+ Tagfile = SlGetSectionKeyIndex(OemInfHandle,"Disks",Disk,OINDEX_TAGFILE);
+ Description = SlGetSectionKeyIndex(OemInfHandle,"Disks",Disk,OINDEX_DISKDESCR);
+ Directory = SlGetSectionKeyIndex(OemInfHandle,"Disks",Disk,OINDEX_DIRECTORY);
+ if((Directory == NULL) || !strcmp(Directory,"\\")) {
+ Directory = SlCopyString("");
+ }
+
+ if(!Tagfile || !Description) {
+ DIAGOUT(("SppOemDiskette: Tagfile=%s, Description=%s",Tagfile ? Tagfile : "(null)",Description ? Description : "(null)"));
+// SppOemInfError(ErrorMsg,&SptOemInfErr5,Line+1,FilesSectionName);
+ goto sod0;
+ }
+
+ FileStruct = BlAllocateHeap(sizeof(DETECTED_DEVICE_FILE));
+
+ FileStruct->Directory = Directory;
+ FileStruct->Filename = Filename;
+ FileStruct->DiskDescription = Description;
+ FileStruct->DiskTagfile = Tagfile;
+ FileStruct->FileType = filetype;
+ //
+ // Insert at tail of list so we preserve the order in the Files section
+ //
+ if(FileList) {
+ FileListTail->Next = FileStruct;
+ FileListTail = FileStruct;
+ } else {
+ FileList = FileListTail = FileStruct;
+ }
+ FileStruct->Next = NULL;
+
+ if(ConfigName) {
+ FileStruct->ConfigName = ConfigName;
+ } else {
+ FileStruct->ConfigName = NULL;
+ }
+ FileStruct->RegistryValueList = NULL;
+
+ if((filetype == HwFilePort) || (filetype == HwFileDriver)) {
+ SET_FILETYPE_PRESENT(FileTypeBits,HwFilePort);
+ SET_FILETYPE_PRESENT(FileTypeBits,HwFileDriver);
+ } else {
+ SET_FILETYPE_PRESENT(FileTypeBits,filetype);
+ }
+
+ //
+ // Now go look in the [Config.<ConfigName>] section for registry
+ // information that is to be set for this driver file.
+ //
+ if(ConfigName) {
+ ConfigSectionName = BlAllocateHeap(strlen(ConfigName) + sizeof("Config."));
+ strcpy(ConfigSectionName,"Config.");
+ strcat(ConfigSectionName,ConfigName);
+ Count2 = SlCountLinesInSection(OemInfHandle,ConfigSectionName);
+ if(Count2 == (ULONG)(-1)) {
+ Count2 = 0;
+ }
+
+ for(Line2=0; Line2<Count2; Line2++) {
+
+ PCHAR KeyName,ValueName,ValueType;
+ PDETECTED_DEVICE_REGISTRY Reg;
+ HwRegistryType valuetype;
+
+ //
+ // Fetch KeyName, ValueName, and ValueType from the line.
+ //
+
+ KeyName = SlGetSectionLineIndex(OemInfHandle,ConfigSectionName,Line2,OINDEX_KEYNAME);
+ ValueName = SlGetSectionLineIndex(OemInfHandle,ConfigSectionName,Line2,OINDEX_VALUENAME);
+ ValueType = SlGetSectionLineIndex(OemInfHandle,ConfigSectionName,Line2,OINDEX_VALUETYPE);
+
+ if(!KeyName || !ValueName || !ValueType) {
+ DIAGOUT(("SlpOemDiskette: KeyName=%s, ValueName=%s, ValueType=%s",KeyName ? KeyName : "(null)",ValueName ? ValueName : "(null)",ValueType ? ValueType : "(null)"));
+// SppOemInfError(ErrorMsg,&SptOemInfErr2,Line2+1,ConfigSectionName);
+ goto sod0;
+ }
+
+ //
+ // Parse the value type and associated values.
+ //
+ valuetype = SlpFindStringInTable(ValueType,RegistryTypeNames);
+ if(valuetype == HwRegistryMax) {
+// SppOemInfError(ErrorMsg,&SptOemInfErr6,Line2+1,ConfigSectionName);
+ goto sod0;
+ }
+
+ Reg = SlpInterpretOemRegistryData(OemInfHandle,ConfigSectionName,Line2,valuetype);
+ if(Reg) {
+
+ Reg->KeyName = KeyName;
+ Reg->ValueName = ValueName;
+ //
+ // Insert at tail of list so as to preserve the order given in the config section
+ //
+ if(RegList) {
+ RegListTail->Next = Reg;
+ RegListTail = Reg;
+ } else {
+ RegList = RegListTail = Reg;
+ }
+ Reg->Next = NULL;
+
+ } else {
+// SppOemInfError(ErrorMsg,&SptOemInfErr7,Line2+1,ConfigSectionName);
+ goto sod0;
+ }
+ }
+
+ FileStruct->RegistryValueList = RegList;
+ RegList = NULL;
+
+ }
+ }
+
+ //
+ // Everything is OK so we can place the information we have gathered
+ // into the main structure for the device class.
+ //
+
+ SlpInitDetectedDevice( Device,
+ SelectedId,
+ ItemDescription,
+ TRUE
+ );
+
+ Device->Files = FileList;
+ Device->FileTypeBits = FileTypeBits;
+ rc = TRUE;
+
+ //
+ // Clean up and exit.
+ //
+
+sod0:
+ return(rc);
+}
+
+int
+SlpFindStringInTable(
+ IN PCHAR String,
+ IN PCHAR *StringTable
+ )
+
+/*++
+
+Routine Description:
+
+ Locate a string in an array of strings, returning its index. The search
+ is not case sensitive.
+
+Arguments:
+
+ String - string to locate in the string table.
+
+ StringTable - array of strings to search in. The final element of the
+ array must be NULL so we can tell where the table ends.
+
+Return Value:
+
+ Index into the table, or some positive index outside the range of valid
+ indices for the table if the string is not found.
+
+--*/
+
+{
+ int i;
+
+ for(i=0; StringTable[i]; i++) {
+ if(_strcmpi(StringTable[i],String) == 0) {
+ return(i);
+ }
+ }
+
+ return(i);
+}
+
+
+VOID
+SlpInitDetectedDevice(
+ IN PDETECTED_DEVICE Device,
+ IN PCHAR IdString,
+ IN PCHAR Description,
+ IN BOOLEAN ThirdPartyOptionSelected
+ )
+{
+ Device->IdString = IdString;
+ Device->Description = Description;
+ Device->ThirdPartyOptionSelected = ThirdPartyOptionSelected;
+ Device->FileTypeBits = 0;
+ Device->Files = NULL;
+}
+
+
+PDETECTED_DEVICE_REGISTRY
+SlpInterpretOemRegistryData(
+ IN PVOID InfHandle,
+ IN PCHAR SectionName,
+ IN ULONG Line,
+ IN HwRegistryType ValueType
+ )
+{
+ PDETECTED_DEVICE_REGISTRY Reg;
+ PCHAR Value;
+ unsigned i,len;
+ ULONG Dword;
+ ULONG BufferSize;
+ PVOID Buffer = NULL;
+ PUCHAR BufferUchar;
+
+ //
+ // Perform appropriate action based on the type
+ //
+
+ switch(ValueType) {
+
+ case HwRegistryDword:
+// case REG_DWORD_LITTLE_ENDIAN:
+// case REG_DWORD_BIG_ENDIAN:
+
+ Value = SlGetSectionLineIndex(InfHandle,SectionName,Line,OINDEX_FIRSTVALUE);
+ if(Value == NULL) {
+ goto x1;
+ }
+
+ //
+ // Make sure it's really a hex number
+ //
+
+ len = strlen(Value);
+ if(len > 8) {
+ goto x1;
+ }
+ for(i=0; i<len; i++) {
+ if(!isxdigit(Value[i])) {
+ goto x1;
+ }
+ }
+
+ //
+ // convert it from ascii to a hex number
+ //
+
+ sscanf(Value,"%lx",&Dword);
+
+ #if 0
+ //
+ // If big endian, perform appropriate conversion
+ //
+
+ if(VaueType == REG_DWORD_BIG_ENDIAN) {
+
+ Dword = ((Dword << 24) & 0xff000000)
+ | ((Dword << 8) & 0x00ff0000)
+ | ((Dword >> 8) & 0x0000ff00)
+ | ((Dword >> 24) & 0x000000ff);
+ }
+ #endif
+
+ //
+ // Allocate a 4-byte buffer and store the dword in it
+ //
+
+ Buffer = BlAllocateHeap(BufferSize = sizeof(ULONG));
+ *(PULONG)Buffer = Dword;
+ break;
+
+ case HwRegistrySz:
+ case HwRegistryExpandSz:
+
+ Value = SlGetSectionLineIndex(InfHandle,SectionName,Line,OINDEX_FIRSTVALUE);
+ if(Value == NULL) {
+ goto x1;
+ }
+
+ //
+ // Allocate a buffer of appropriate size for the string
+ //
+
+ Buffer = BlAllocateHeap(BufferSize = strlen(Value)+1);
+
+ strcpy(Buffer, Value);
+ break;
+
+ case HwRegistryBinary:
+
+ Value = SlGetSectionLineIndex(InfHandle,SectionName,Line,OINDEX_FIRSTVALUE);
+ if(Value == NULL) {
+ goto x1;
+ }
+
+ //
+ // Figure out how many byte values are specified
+ //
+
+ len = strlen(Value);
+ if(len & 1) {
+ goto x1; // odd # of characters
+ }
+
+ //
+ // Allocate a buffer to hold the byte values
+ //
+
+ Buffer = BlAllocateHeap(BufferSize = len / 2);
+ BufferUchar = Buffer;
+
+ //
+ // For each digit pair, convert to a hex number and store in the
+ // buffer
+ //
+
+ for(i=0; i<len; i+=2) {
+
+ UCHAR byte;
+ unsigned j;
+
+ //
+ // Convert the current digit pair to hex
+ //
+
+ for(byte=0,j=i; j<i+2; j++) {
+
+ byte <<= 4;
+
+ if(isdigit(Value[j])) {
+
+ byte |= (UCHAR)Value[j] - (UCHAR)'0';
+
+ } else if((Value[j] >= 'a') && (Value[j] <= 'f')) {
+
+ byte |= (UCHAR)Value[j] - (UCHAR)'a' + (UCHAR)10;
+
+ } else if((Value[j] >= 'A') && (Value[j] <= 'F')) {
+
+ byte |= (UCHAR)Value[j] - (UCHAR)'A' + (UCHAR)10;
+
+ } else {
+
+ goto x1;
+ }
+ }
+
+ BufferUchar[i/2] = byte;
+ }
+
+ break;
+
+ case HwRegistryMultiSz:
+
+ //
+ // Calculate size of the buffer needed to hold all specified strings
+ //
+
+ for(BufferSize=1,i=0;
+ Value = SlGetSectionLineIndex(InfHandle,SectionName,Line,OINDEX_FIRSTVALUE+i);
+ i++)
+ {
+ BufferSize += strlen(Value)+1;
+ }
+
+ //
+ // Allocate a buffer of appropriate size
+ //
+
+ Buffer = BlAllocateHeap(BufferSize);
+ BufferUchar = Buffer;
+
+ //
+ // Store each string in the buffer, converting to wide char format
+ // in the process
+ //
+
+ for(i=0;
+ Value = SlGetSectionLineIndex(InfHandle,SectionName,Line,OINDEX_FIRSTVALUE+i);
+ i++)
+ {
+ strcpy(BufferUchar,Value);
+ BufferUchar += strlen(Value) + 1;
+ }
+
+ //
+ // Place final terminating nul in the buffer
+ //
+
+ *BufferUchar = 0;
+
+ break;
+
+ default:
+ x1:
+
+ //
+ // Error - bad type specified or maybe we detected bad data values
+ // and jumped here
+ //
+
+ return(NULL);
+ }
+
+ Reg = BlAllocateHeap(sizeof(DETECTED_DEVICE_REGISTRY));
+
+ Reg->ValueType = RegistryTypeMap[ValueType];
+ Reg->Buffer = Buffer;
+ Reg->BufferSize = BufferSize;
+
+ return(Reg);
+}
+
+
+PCHAR
+SlPreInstallGetComponentName(
+ IN PVOID Inf,
+ IN PCHAR SectionName,
+ IN PCHAR TargetName
+ )
+
+/*++
+
+Routine Description:
+
+ Determines the canonical short name for a component to be loaded for
+ this machine.
+
+Arguments:
+
+ Inf - Handle to an inf file (retail or OEM).
+
+ SectionName - Supplies the name of the section (eg. [Computer])
+
+ TargetName - Supplies the ARC string to be matched (eg. "Digital DECpc AXP 150")
+
+Return Value:
+
+ NULL - No match was found.
+
+ PCHAR - Pointer to the canonical shortname of the component.
+
+--*/
+
+{
+ ULONG i;
+ PCHAR SearchName;
+
+ //
+ // If this is not an OEM component, then enumerate the entries in the
+ // section in txtsetup.sif
+ //
+ for (i=0;;i++) {
+ SearchName = SlGetSectionLineIndex(Inf,
+ SectionName,
+ i,
+ 0);
+ if (SearchName==NULL) {
+ //
+ // we have enumerated the entire section without finding a
+ // match, return failure.
+ //
+ return(NULL);
+ }
+
+ if (_stricmp(TargetName, SearchName) == 0) {
+ //
+ // we have a match
+ //
+ break;
+ }
+ }
+ //
+ // i is the index into the section of the short machine name
+ //
+ return(SlGetKeyName(Inf,
+ SectionName,
+ i));
+}
diff --git a/private/ntos/boot/setup/parseini.c b/private/ntos/boot/setup/parseini.c
new file mode 100644
index 000000000..8aa3ef7a7
--- /dev/null
+++ b/private/ntos/boot/setup/parseini.c
@@ -0,0 +1,1973 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ parseini.c
+
+Abstract:
+
+ This module implements functions to parse a .INI file
+
+Author:
+
+ John Vert (jvert) 7-Oct-1993
+
+Revision History:
+
+ John Vert (jvert) 7-Oct-1993 - largely lifted from splib\spinf.c
+
+--*/
+
+#include "setupldr.h"
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+#define SpFree(x)
+
+// what follows was alpar.h
+
+//
+// EXPORTED BY THE PARSER AND USED BY BOTH THE PARSER AND
+// THE INF HANDLING COMPONENTS
+//
+
+// typedefs exported
+//
+
+typedef struct _value {
+ struct _value *pNext;
+ PCHAR pName;
+ } VALUE, *PVALUE;
+
+typedef struct _line {
+ struct _line *pNext;
+ PCHAR pName;
+ PVALUE pValue;
+ } LINE, *PLINE;
+
+typedef struct _section {
+ struct _section *pNext;
+ PCHAR pName;
+ PLINE pLine;
+ } SECTION, *PSECTION;
+
+typedef struct _inf {
+ PSECTION pSection;
+ } INF, *PINF;
+
+//
+// Routines exported
+//
+
+PVOID
+ParseInfBuffer(
+ PCHAR Buffer,
+ ULONG Size,
+ PULONG ErrorLine
+ );
+
+//
+// DEFINES USED FOR THE PARSER INTERNALLY
+//
+//
+// typedefs used
+//
+
+typedef enum _tokentype {
+ TOK_EOF,
+ TOK_EOL,
+ TOK_LBRACE,
+ TOK_RBRACE,
+ TOK_STRING,
+ TOK_EQUAL,
+ TOK_COMMA,
+ TOK_ERRPARSE,
+ TOK_ERRNOMEM
+ } TOKENTYPE, *PTOKENTTYPE;
+
+
+typedef struct _token {
+ TOKENTYPE Type;
+ PCHAR pValue;
+ } TOKEN, *PTOKEN;
+
+
+//
+// Routine defines
+//
+
+ARC_STATUS
+SpAppendSection(
+ IN PCHAR pSectionName
+ );
+
+ARC_STATUS
+SpAppendLine(
+ IN PCHAR pLineKey
+ );
+
+ARC_STATUS
+SpAppendValue(
+ IN PCHAR pValueString
+ );
+
+TOKEN
+SpGetToken(
+ IN OUT PCHAR *Stream,
+ IN PCHAR MaxStream
+ );
+
+// Global added to provide INF filename for friendly error messages.
+PCHAR pchINFName = NULL;
+
+// what follows was alinf.c
+
+//
+// Internal Routine Declarations for freeing inf structure members
+//
+
+VOID
+FreeSectionList (
+ IN PSECTION pSection
+ );
+
+VOID
+FreeLineList (
+ IN PLINE pLine
+ );
+
+VOID
+FreeValueList (
+ IN PVALUE pValue
+ );
+
+
+//
+// Internal Routine declarations for searching in the INF structures
+//
+
+
+PVALUE
+SearchValueInLine(
+ IN PLINE pLine,
+ IN ULONG ValueIndex
+ );
+
+PLINE
+SearchLineInSectionByKey(
+ IN PSECTION pSection,
+ IN PCHAR Key,
+ OUT PULONG pOrdinal OPTIONAL
+ );
+
+PLINE
+SearchLineInSectionByIndex(
+ IN PSECTION pSection,
+ IN ULONG LineIndex
+ );
+
+PSECTION
+SearchSectionByName(
+ IN PINF pINF,
+ IN PCHAR SectionName
+ );
+
+PCHAR
+ProcessForStringSubs(
+ IN PINF pInf,
+ IN PCHAR String
+ );
+
+
+//
+// ROUTINE DEFINITIONS
+//
+
+
+PCHAR
+SlGetIniValue(
+ IN PVOID InfHandle,
+ IN PCHAR SectionName,
+ IN PCHAR KeyName,
+ IN PCHAR Default
+ )
+
+/*++
+
+Routine Description:
+
+ Searches an INF handle for a given section/key value.
+
+Arguments:
+
+ InfHandle - Supplies a handle returned by SlInitIniFile.
+
+ SectionName - Supplies the name of the section to search
+
+ KeyName - Supplies the name of the key whose value should be returned.
+
+ Default - Supplies the default setting, returned if the specified key
+ is not found.
+
+Return Value:
+
+ Pointer to the value of the key, if the key is found
+
+ Default, if the key is not found.
+
+--*/
+
+{
+ PCHAR Value;
+
+ Value = SlGetSectionKeyIndex(InfHandle,
+ SectionName,
+ KeyName,
+ 0);
+ if (Value==NULL) {
+ Value = Default;
+ }
+
+ return(Value);
+
+}
+
+//
+// returns a handle to use for further inf parsing
+//
+
+ARC_STATUS
+SlInitIniFile(
+ IN PCHAR DevicePath,
+ IN ULONG DeviceId,
+ IN PCHAR INFFile,
+ OUT PVOID *pINFHandle,
+ OUT PULONG ErrorLine
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ ARC_STATUS Status;
+ ULONG DeviceID,FileID;
+ PCHAR Buffer;
+ ULONG Size, SizeRead;
+ FILE_INFORMATION FileInfo;
+ ULONG PageCount;
+ ULONG ActualBase;
+
+ *ErrorLine = (ULONG)(-1);
+
+ //
+ // If required, open the device
+ //
+
+ if(DevicePath) {
+ Status = ArcOpen(DevicePath,ArcOpenReadOnly,&DeviceID);
+ if (Status != ESUCCESS) {
+ return( Status );
+ }
+ } else {
+ DeviceID = DeviceId;
+ }
+
+ //
+ // Open the file
+ //
+
+ Status = BlOpen(DeviceID,INFFile,ArcOpenReadOnly,&FileID);
+ if (Status != ESUCCESS) {
+ // We report better error messages elsewhere
+ // SlMessageBox(SL_FILE_LOAD_FAILED,INFFile,Status);
+ pchINFName = NULL;
+ goto xx0;
+ } else {
+ pchINFName = INFFile;
+ }
+
+ //
+ // find out size of INF file
+ //
+
+ Status = BlGetFileInformation(FileID, &FileInfo);
+ if (Status != ESUCCESS) {
+ BlClose(FileID);
+ goto xx0;
+ }
+ Size = FileInfo.EndingAddress.LowPart;
+
+ //
+ // allocate a descriptor large enough to hold the entire file.
+ // On x86 this has an unfortunate tendency to slam txtsetup.sif
+ // into a free block at 1MB, which means the kernel can't be
+ // loaded (it's linked for 0x100000 without relocations).
+ //
+#ifdef _X86_
+ {
+ extern ALLOCATION_POLICY BlMemoryAllocationPolicy;
+ ALLOCATION_POLICY policy;
+
+ policy = BlMemoryAllocationPolicy;
+ BlMemoryAllocationPolicy = BlAllocateHighestFit;
+#endif
+
+ PageCount = ROUND_TO_PAGES(Size) >> PAGE_SHIFT;
+
+ Status = BlAllocateDescriptor(LoaderOsloaderHeap,
+ 0,
+ PageCount,
+ &ActualBase);
+#ifdef _X86_
+ BlMemoryAllocationPolicy = policy;
+ }
+#endif
+
+ if (Status != ESUCCESS) {
+ BlClose(FileID);
+ goto xx0;
+ }
+
+ Buffer = (PCHAR)(KSEG0_BASE | (ActualBase << PAGE_SHIFT));
+
+ //
+ // read the file in
+ //
+
+ Status = BlRead(FileID, Buffer, Size, &SizeRead);
+ if (Status != ESUCCESS) {
+ BlClose(FileID);
+ SpFree(Buffer);
+ goto xx0;
+ }
+
+ if (BlLoaderBlock->SetupLoaderBlock->IniFile == NULL) {
+ BlLoaderBlock->SetupLoaderBlock->IniFile = Buffer;
+ BlLoaderBlock->SetupLoaderBlock->IniFileLength = Size;
+ }
+
+ //
+ // parse the file
+ //
+ if((*pINFHandle = ParseInfBuffer(Buffer, SizeRead, ErrorLine)) == (PVOID)NULL) {
+ Status = EBADF;
+ } else {
+ Status = ESUCCESS;
+ }
+
+ //
+ // Clean up and return
+ //
+ SpFree(Buffer);
+ BlClose(FileID);
+
+#if 0
+ if((Status == ESUCCESS)
+ && SlGetSectionKeyIndex(*pINFHandle,"debug","DumpInf",0)
+ && atoi(SlGetSectionKeyIndex(*pINFHandle,"debug","DumpInf",0)))
+ {
+ PINF pInf = *pINFHandle;
+ PSECTION pSection;
+ PLINE pLine;
+ PVALUE pValue;
+
+ for(pSection = pInf->pSection; pSection; pSection = pSection->pNext) {
+
+ SpxClearClientArea();
+ SpxPositionCursor(0,4);
+
+ SpMsg(FALSE,"Section: [%s]\r\n",pSection->pName);
+
+ for(pLine = pSection->pLine; pLine; pLine = pLine->pNext) {
+
+ SpMsg(FALSE," [%s] = ",pLine->pName ? pLine->pName : "(none)");
+
+ for(pValue = pLine->pValue; pValue; pValue = pValue->pNext) {
+
+ SpMsg(FALSE,"[%s]",pValue->pName);
+ }
+ SpMsg(FALSE,"\r\n");
+ }
+ SpMsg(TRUE,"");
+ }
+ }
+#endif
+
+ xx0:
+
+ if(DevicePath) {
+ ArcClose(DeviceID);
+ }
+
+ return( Status );
+
+}
+
+//
+// frees an INF Buffer
+//
+ARC_STATUS
+SpFreeINFBuffer (
+ IN PVOID INFHandle
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ PINF pINF;
+
+ //
+ // Valid INF Handle?
+ //
+
+ if (INFHandle == (PVOID)NULL) {
+ return ESUCCESS;
+ }
+
+ //
+ // cast the buffer into an INF structure
+ //
+
+ pINF = (PINF)INFHandle;
+
+ FreeSectionList(pINF->pSection);
+
+ //
+ // free the inf structure too
+ //
+
+ SpFree(pINF);
+
+ return( ESUCCESS );
+}
+
+
+VOID
+FreeSectionList (
+ IN PSECTION pSection
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ PSECTION Next;
+
+ while(pSection) {
+ Next = pSection->pNext;
+ FreeLineList(pSection->pLine);
+ if(pSection->pName) {
+ SpFree(pSection->pName);
+ }
+ SpFree(pSection);
+ pSection = Next;
+ }
+}
+
+
+VOID
+FreeLineList (
+ IN PLINE pLine
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ PLINE Next;
+
+ while(pLine) {
+ Next = pLine->pNext;
+ FreeValueList(pLine->pValue);
+ if(pLine->pName) {
+ SpFree(pLine->pName);
+ }
+ SpFree(pLine);
+ pLine = Next;
+ }
+}
+
+VOID
+FreeValueList (
+ IN PVALUE pValue
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ PVALUE Next;
+
+ while(pValue) {
+ Next = pValue->pNext;
+ if(pValue->pName) {
+ SpFree(pValue->pName);
+ }
+ SpFree(pValue);
+ pValue = Next;
+ }
+}
+
+
+//
+// searches for the existance of a particular section
+//
+BOOLEAN
+SpSearchINFSection (
+ IN PVOID INFHandle,
+ IN PCHAR SectionName
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ PSECTION pSection;
+
+ //
+ // if search for section fails return false
+ //
+
+ if ((pSection = SearchSectionByName(
+ (PINF)INFHandle,
+ SectionName
+ )) == (PSECTION)NULL) {
+ return( FALSE );
+ }
+
+ //
+ // else return true
+ //
+ return( TRUE );
+
+}
+
+
+
+
+//
+// given section name, line number and index return the value.
+//
+PCHAR
+SlGetSectionLineIndex (
+ IN PVOID INFHandle,
+ IN PCHAR SectionName,
+ IN ULONG LineIndex,
+ IN ULONG ValueIndex
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ PSECTION pSection;
+ PLINE pLine;
+ PVALUE pValue;
+
+ if((pSection = SearchSectionByName(
+ (PINF)INFHandle,
+ SectionName
+ ))
+ == (PSECTION)NULL)
+ return((PCHAR)NULL);
+
+ if((pLine = SearchLineInSectionByIndex(
+ pSection,
+ LineIndex
+ ))
+ == (PLINE)NULL)
+ return((PCHAR)NULL);
+
+ if((pValue = SearchValueInLine(
+ pLine,
+ ValueIndex
+ ))
+ == (PVALUE)NULL)
+ return((PCHAR)NULL);
+
+ return(ProcessForStringSubs(INFHandle,pValue->pName));
+
+}
+
+
+BOOLEAN
+SpGetSectionKeyExists (
+ IN PVOID INFHandle,
+ IN PCHAR SectionName,
+ IN PCHAR Key
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ PSECTION pSection;
+
+ if((pSection = SearchSectionByName(
+ (PINF)INFHandle,
+ SectionName
+ ))
+ == (PSECTION)NULL) {
+ return( FALSE );
+ }
+
+ if (SearchLineInSectionByKey(pSection, Key, NULL) == (PLINE)NULL) {
+ return( FALSE );
+ }
+
+ return( TRUE );
+}
+
+
+PCHAR
+SlGetKeyName(
+ IN PVOID INFHandle,
+ IN PCHAR SectionName,
+ IN ULONG LineIndex
+ )
+{
+ PSECTION pSection;
+ PLINE pLine;
+
+ pSection = SearchSectionByName((PINF)INFHandle,SectionName);
+ if(pSection == NULL) {
+ return(NULL);
+ }
+
+ pLine = SearchLineInSectionByIndex(pSection,LineIndex);
+ if(pLine == NULL) {
+ return(NULL);
+ }
+
+ return(pLine->pName);
+}
+
+
+//
+// given section name and key, return (0-based) ordinal for this entry
+// (returns -1 on error)
+//
+ULONG
+SlGetSectionKeyOrdinal(
+ IN PVOID INFHandle,
+ IN PCHAR SectionName,
+ IN PCHAR Key
+ )
+{
+ PSECTION pSection;
+ PLINE pLine;
+ ULONG Ordinal;
+
+
+ pSection = SearchSectionByName(
+ (PINF)INFHandle,
+ SectionName
+ );
+
+ pLine = SearchLineInSectionByKey(
+ pSection,
+ Key,
+ &Ordinal
+ );
+
+ if(pLine == (PLINE)NULL) {
+ return (ULONG)-1;
+ } else {
+ return Ordinal;
+ }
+}
+
+
+//
+// given section name, key and index return the value
+//
+PCHAR
+SlGetSectionKeyIndex (
+ IN PVOID INFHandle,
+ IN PCHAR SectionName,
+ IN PCHAR Key,
+ IN ULONG ValueIndex
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ PSECTION pSection;
+ PLINE pLine;
+ PVALUE pValue;
+
+ if((pSection = SearchSectionByName(
+ (PINF)INFHandle,
+ SectionName
+ ))
+ == (PSECTION)NULL)
+ return((PCHAR)NULL);
+
+ if((pLine = SearchLineInSectionByKey(
+ pSection,
+ Key,
+ NULL
+ ))
+ == (PLINE)NULL)
+ return((PCHAR)NULL);
+
+ if((pValue = SearchValueInLine(
+ pLine,
+ ValueIndex
+ ))
+ == (PVALUE)NULL)
+ return((PCHAR)NULL);
+
+ return(ProcessForStringSubs(INFHandle,pValue->pName));
+}
+
+
+ULONG
+SlCountLinesInSection(
+ IN PVOID INFHandle,
+ IN PCHAR SectionName
+ )
+{
+ PSECTION pSection;
+ PLINE pLine;
+ ULONG Count;
+
+ if((pSection = SearchSectionByName((PINF)INFHandle,SectionName)) == NULL) {
+ return((ULONG)(-1));
+ }
+
+ for(pLine = pSection->pLine, Count = 0;
+ pLine;
+ pLine = pLine->pNext, Count++
+ );
+
+ return(Count);
+}
+
+
+PVALUE
+SearchValueInLine(
+ IN PLINE pLine,
+ IN ULONG ValueIndex
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ PVALUE pValue;
+ ULONG i;
+
+ if (pLine == (PLINE)NULL)
+ return ((PVALUE)NULL);
+
+ pValue = pLine->pValue;
+ for (i = 0; i < ValueIndex && ((pValue = pValue->pNext) != (PVALUE)NULL); i++)
+ ;
+
+ return pValue;
+
+}
+
+PLINE
+SearchLineInSectionByKey(
+ IN PSECTION pSection,
+ IN PCHAR Key,
+ OUT PULONG pOrdinal OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ PLINE pLine;
+ ULONG LineOrdinal;
+
+ if (pSection == (PSECTION)NULL || Key == (PCHAR)NULL) {
+ return ((PLINE)NULL);
+ }
+
+ pLine = pSection->pLine;
+ LineOrdinal = 0;
+ while ((pLine != (PLINE)NULL) && (pLine->pName == NULL || _strcmpi(pLine->pName, Key))) {
+ pLine = pLine->pNext;
+ LineOrdinal++;
+ }
+
+ if(pLine && pOrdinal) {
+ *pOrdinal = LineOrdinal;
+ }
+
+ return pLine;
+
+}
+
+
+PLINE
+SearchLineInSectionByIndex(
+ IN PSECTION pSection,
+ IN ULONG LineIndex
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ PLINE pLine;
+ ULONG i;
+
+ //
+ // Validate the parameters passed in
+ //
+
+ if (pSection == (PSECTION)NULL) {
+ return ((PLINE)NULL);
+ }
+
+ //
+ // find the start of the line list in the section passed in
+ //
+
+ pLine = pSection->pLine;
+
+ //
+ // traverse down the current line list to the LineIndex th line
+ //
+
+ for (i = 0; i < LineIndex && ((pLine = pLine->pNext) != (PLINE)NULL); i++) {
+ ;
+ }
+
+ //
+ // return the Line found
+ //
+
+ return pLine;
+
+}
+
+
+PSECTION
+SearchSectionByName(
+ IN PINF pINF,
+ IN PCHAR SectionName
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ PSECTION pSection;
+
+ //
+ // validate the parameters passed in
+ //
+
+ if (pINF == (PINF)NULL || SectionName == (PCHAR)NULL) {
+ return ((PSECTION)NULL);
+ }
+
+ //
+ // find the section list
+ //
+ pSection = pINF->pSection;
+
+ //
+ // traverse down the section list searching each section for the section
+ // name mentioned
+ //
+
+ while ((pSection != (PSECTION)NULL) && _strcmpi(pSection->pName, SectionName)) {
+ pSection = pSection->pNext;
+ }
+
+ //
+ // return the section at which we stopped (either NULL or the section
+ // which was found
+ //
+
+ return pSection;
+
+}
+
+
+PCHAR
+ProcessForStringSubs(
+ IN PINF pInf,
+ IN PCHAR String
+ )
+{
+ unsigned Len;
+ PCHAR ReturnString;
+ PSECTION pSection;
+ PLINE pLine;
+
+ //
+ // Assume no substitution necessary.
+ //
+ ReturnString = String;
+
+ //
+ // If it starts and ends with % then look it up in the
+ // strings section. Note the initial check before doing a
+ // strlen, to preserve performance in the 99% case where
+ // there is no substitution.
+ //
+ if((String[0] == '%') && ((Len = strlen(String)) > 2) && (String[Len-1] == '%')) {
+
+ for(pSection = pInf->pSection; pSection; pSection=pSection->pNext) {
+ if(pSection->pName && !_stricmp(pSection->pName,"Strings")) {
+ break;
+ }
+ }
+
+ if(pSection) {
+
+ for(pLine = pSection->pLine; pLine; pLine=pLine->pNext) {
+ if(pLine->pName
+ && !_strnicmp(pLine->pName,String+1,Len-2)
+ && (pLine->pName[Len-2] == 0))
+ {
+ break;
+ }
+ }
+
+ if(pLine && pLine->pValue && pLine->pValue->pName) {
+ ReturnString = pLine->pValue->pName;
+ }
+ }
+ }
+
+ return(ReturnString);
+}
+
+
+
+// what follows was alparse.c
+
+
+//
+// Globals used to make building the lists easier
+//
+
+PINF pINF;
+PSECTION pSectionRecord;
+PLINE pLineRecord;
+PVALUE pValueRecord;
+
+
+//
+// Globals used by the token parser
+//
+
+// string terminators are the whitespace characters (isspace: space, tab,
+// linefeed, formfeed, vertical tab, carriage return) or the chars given below
+
+CHAR StringTerminators[] = "[]=,\t \"\n\f\v\r";
+
+PCHAR QStringTerminators = StringTerminators+6;
+
+
+//
+// Main parser routine
+//
+
+PVOID
+ParseInfBuffer(
+ PCHAR Buffer,
+ ULONG Size,
+ PULONG ErrorLine
+ )
+
+/*++
+
+Routine Description:
+
+ Given a character buffer containing the INF file, this routine parses
+ the INF into an internal form with Section records, Line records and
+ Value records.
+
+Arguments:
+
+ Buffer - contains to ptr to a buffer containing the INF file
+
+ Size - contains the size of the buffer.
+
+ ErrorLine - if a parse error occurs, this variable receives the line
+ number of the line containing the error.
+
+
+Return Value:
+
+ PVOID - INF handle ptr to be used in subsequent INF calls.
+
+--*/
+
+{
+ PCHAR Stream, MaxStream, pchSectionName = NULL, pchValue = NULL;
+ ULONG State, InfLine;
+ TOKEN Token;
+ BOOLEAN Done;
+ BOOLEAN Error;
+ ARC_STATUS ErrorCode;
+
+ //
+ // Initialise the globals
+ //
+ pINF = (PINF)NULL;
+ pSectionRecord = (PSECTION)NULL;
+ pLineRecord = (PLINE)NULL;
+ pValueRecord = (PVALUE)NULL;
+
+ //
+ // Get INF record
+ //
+ if ((pINF = (PINF)BlAllocateHeap(sizeof(INF))) == NULL) {
+ SlNoMemoryError();
+ return NULL;
+ }
+ pINF->pSection = NULL;
+
+ //
+ // Set initial state
+ //
+ State = 1;
+ InfLine = 1;
+ Stream = Buffer;
+ MaxStream = Buffer + Size;
+ Done = FALSE;
+ Error = FALSE;
+
+ //
+ // Enter token processing loop
+ //
+
+ while (!Done) {
+
+ Token = SpGetToken(&Stream, MaxStream);
+
+ switch (State) {
+ //
+ // STATE1: Start of file, this state remains till first
+ // section is found
+ // Valid Tokens: TOK_EOL, TOK_EOF, TOK_LBRACE
+ case 1:
+ switch (Token.Type) {
+ case TOK_EOL:
+ break;
+ case TOK_EOF:
+ Done = TRUE;
+ break;
+ case TOK_LBRACE:
+ State = 2;
+ break;
+ default:
+ Error = Done = TRUE;
+ ErrorCode = EINVAL;
+ SlFatalError(SL_BAD_INF_LINE,InfLine);
+ break;
+ }
+ break;
+
+ //
+ // STATE 2: Section LBRACE has been received, expecting STRING
+ //
+ // Valid Tokens: TOK_STRING
+ //
+ case 2:
+ switch (Token.Type) {
+ case TOK_STRING:
+ State = 3;
+ pchSectionName = Token.pValue;
+ break;
+
+ default:
+ Error = Done = TRUE;
+ ErrorCode = EINVAL;
+ SlFatalError(SL_BAD_INF_LINE,InfLine);
+ break;
+
+ }
+ break;
+
+ //
+ // STATE 3: Section Name received, expecting RBRACE
+ //
+ // Valid Tokens: TOK_RBRACE
+ //
+ case 3:
+ switch (Token.Type) {
+ case TOK_RBRACE:
+ State = 4;
+ break;
+
+ default:
+ Error = Done = TRUE;
+ ErrorCode = EINVAL;
+ SlFatalError(SL_BAD_INF_LINE,InfLine);
+ break;
+ }
+ break;
+ //
+ // STATE 4: Section Definition Complete, expecting EOL
+ //
+ // Valid Tokens: TOK_EOL, TOK_EOF
+ //
+ case 4:
+ switch (Token.Type) {
+ case TOK_EOL:
+ if ((ErrorCode = SpAppendSection(pchSectionName)) != ESUCCESS) {
+
+ Error = Done = TRUE;
+ } else {
+ pchSectionName = NULL;
+ State = 5;
+ }
+ break;
+
+ case TOK_EOF:
+ if ((ErrorCode = SpAppendSection(pchSectionName)) != ESUCCESS)
+ Error = Done = TRUE;
+ else {
+ pchSectionName = NULL;
+ Done = TRUE;
+ }
+ break;
+
+ default:
+ Error = Done = TRUE;
+ ErrorCode = EINVAL;
+ SlFatalError(SL_BAD_INF_LINE,InfLine);
+ break;
+ }
+ break;
+
+ //
+ // STATE 5: Expecting Section Lines
+ //
+ // Valid Tokens: TOK_EOL, TOK_EOF, TOK_STRING, TOK_LBRACE
+ //
+ case 5:
+ switch (Token.Type) {
+ case TOK_EOL:
+ break;
+ case TOK_EOF:
+ Done = TRUE;
+ break;
+ case TOK_STRING:
+ pchValue = Token.pValue;
+ State = 6;
+ break;
+ case TOK_LBRACE:
+ State = 2;
+ break;
+ default:
+ Error = Done = TRUE;
+ ErrorCode = EINVAL;
+ SlFatalError(SL_BAD_INF_LINE, InfLine);
+ break;
+ }
+ break;
+
+ //
+ // STATE 6: String returned, not sure whether it is key or value
+ //
+ // Valid Tokens: TOK_EOL, TOK_EOF, TOK_COMMA, TOK_EQUAL
+ //
+ case 6:
+ switch (Token.Type) {
+ case TOK_EOL:
+ if ( (ErrorCode = SpAppendLine(NULL)) != ESUCCESS ||
+ (ErrorCode = SpAppendValue(pchValue)) !=ESUCCESS )
+ Error = Done = TRUE;
+ else {
+ pchValue = NULL;
+ State = 5;
+ }
+ break;
+
+ case TOK_EOF:
+ if ( (ErrorCode = SpAppendLine(NULL)) != ESUCCESS ||
+ (ErrorCode = SpAppendValue(pchValue)) !=ESUCCESS )
+ Error = Done = TRUE;
+ else {
+ pchValue = NULL;
+ Done = TRUE;
+ }
+ break;
+
+ case TOK_COMMA:
+ if ( (ErrorCode = SpAppendLine(NULL)) != ESUCCESS ||
+ (ErrorCode = SpAppendValue(pchValue)) !=ESUCCESS )
+ Error = Done = TRUE;
+ else {
+ pchValue = NULL;
+ State = 7;
+ }
+ break;
+
+ case TOK_EQUAL:
+ if ( (ErrorCode = SpAppendLine(pchValue)) !=ESUCCESS)
+ Error = Done = TRUE;
+ else {
+ pchValue = NULL;
+ State = 8;
+ }
+ break;
+
+ default:
+ Error = Done = TRUE;
+ ErrorCode = EINVAL;
+ SlFatalError(SL_BAD_INF_LINE,InfLine);
+ break;
+ }
+ break;
+
+ //
+ // STATE 7: Comma received, Expecting another string
+ //
+ // Valid Tokens: TOK_STRING TOK_COMMA
+ // A comma means we have an empty value.
+ //
+ case 7:
+ switch (Token.Type) {
+ case TOK_COMMA:
+ Token.pValue = BlAllocateHeap(1);
+ if(Token.pValue == NULL) {
+ Error = Done = TRUE;
+ ErrorCode = ENOMEM;
+ break;
+ }
+ Token.pValue[0] = 0;
+ if ((ErrorCode = SpAppendValue(Token.pValue)) != ESUCCESS) {
+ Error = Done = TRUE;
+ }
+ //
+ // State stays at 7 because we are expecting a string
+ //
+ break;
+
+ case TOK_STRING:
+ if ((ErrorCode = SpAppendValue(Token.pValue)) != ESUCCESS)
+ Error = Done = TRUE;
+ else
+ State = 9;
+
+ break;
+ default:
+ Error = Done = TRUE;
+ ErrorCode = EINVAL;
+ SlFatalError(SL_BAD_INF_LINE,InfLine);
+ break;
+ }
+ break;
+ //
+ // STATE 8: Equal received, Expecting another string
+ // If none, assume there is a single empty string on the RHS
+ //
+ // Valid Tokens: TOK_STRING, TOK_EOL, TOK_EOF
+ //
+ case 8:
+ switch (Token.Type) {
+ case TOK_EOF:
+ Token.pValue = BlAllocateHeap(1);
+ if(Token.pValue == NULL) {
+ Error = Done = TRUE;
+ ErrorCode = ENOMEM;
+ break;
+ }
+ Token.pValue[0] = 0;
+ if((ErrorCode = SpAppendValue(Token.pValue)) != ESUCCESS) {
+ Error = TRUE;
+ }
+ Done = TRUE;
+ break;
+
+ case TOK_EOL:
+ Token.pValue = BlAllocateHeap(1);
+ if(Token.pValue == NULL) {
+ Error = Done = TRUE;
+ ErrorCode = ENOMEM;
+ break;
+ }
+ Token.pValue[0] = 0;
+ if((ErrorCode = SpAppendValue(Token.pValue)) != ESUCCESS) {
+ Error = TRUE;
+ Done = TRUE;
+ } else {
+ State = 5;
+ }
+ break;
+
+ case TOK_STRING:
+ if ((ErrorCode = SpAppendValue(Token.pValue)) != ESUCCESS)
+ Error = Done = TRUE;
+ else
+ State = 9;
+
+ break;
+
+ default:
+ Error = Done = TRUE;
+ ErrorCode = EINVAL;
+ SlFatalError(SL_BAD_INF_LINE,InfLine);
+ break;
+ }
+ break;
+ //
+ // STATE 9: String received after equal, value string
+ //
+ // Valid Tokens: TOK_EOL, TOK_EOF, TOK_COMMA
+ //
+ case 9:
+ switch (Token.Type) {
+ case TOK_EOL:
+ State = 5;
+ break;
+
+ case TOK_EOF:
+ Done = TRUE;
+ break;
+
+ case TOK_COMMA:
+ State = 7;
+ break;
+
+ default:
+ Error = Done = TRUE;
+ ErrorCode = EINVAL;
+ SlFatalError(SL_BAD_INF_LINE,InfLine);
+ break;
+ }
+ break;
+ //
+ // STATE 10: Value string definitely received
+ //
+ // Valid Tokens: TOK_EOL, TOK_EOF, TOK_COMMA
+ //
+ case 10:
+ switch (Token.Type) {
+ case TOK_EOL:
+ State =5;
+ break;
+
+ case TOK_EOF:
+ Done = TRUE;
+ break;
+
+ case TOK_COMMA:
+ State = 7;
+ break;
+
+ default:
+ Error = Done = TRUE;
+ ErrorCode = EINVAL;
+ SlFatalError(SL_BAD_INF_LINE,InfLine);
+ break;
+ }
+ break;
+
+ default:
+ Error = Done = TRUE;
+ ErrorCode = EINVAL;
+ break;
+
+ } // end switch(State)
+
+
+ if (Error) {
+
+ switch (ErrorCode) {
+ case EINVAL:
+ *ErrorLine = InfLine;
+ break;
+ case ENOMEM:
+ SlFatalError(SL_BAD_INF_LINE,InfLine);
+ break;
+ default:
+ break;
+ }
+
+ ErrorCode = SpFreeINFBuffer((PVOID)pINF);
+ if (pchSectionName != (PCHAR)NULL) {
+ SpFree(pchSectionName);
+ }
+
+ if (pchValue != (PCHAR)NULL) {
+ SpFree(pchValue);
+ }
+
+ pINF = (PINF)NULL;
+ }
+ else {
+
+ //
+ // Keep track of line numbers so that we can display Errors
+ //
+
+ if (Token.Type == TOK_EOL)
+ InfLine++;
+ }
+
+ } // End while
+
+ return((PVOID)pINF);
+}
+
+
+
+ARC_STATUS
+SpAppendSection(
+ IN PCHAR pSectionName
+ )
+
+/*++
+
+Routine Description:
+
+ This appends a new section to the section list in the current INF.
+ All further lines and values pertain to this new section, so it resets
+ the line list and value lists too.
+
+Arguments:
+
+ pSectionName - Name of the new section. ( [SectionName] )
+
+Return Value:
+
+ ESUCCESS - if successful.
+ ENOMEM - if memory allocation failed.
+ EINVAL - if invalid parameters passed in or the INF buffer not
+ initialised
+
+--*/
+
+{
+ PSECTION pNewSection;
+
+ //
+ // Check to see if INF initialised and the parameter passed in is valid
+ //
+
+ if (pINF == (PINF)NULL || pSectionName == (PCHAR)NULL) {
+ if(pchINFName) {
+ SlFriendlyError(
+ EINVAL,
+ pchINFName,
+ __LINE__,
+ __FILE__
+ );
+ } else {
+ SlError(EINVAL);
+ }
+ return EINVAL;
+ }
+
+ //
+ // See if we already have a section by this name. If so we want
+ // to merge sections.
+ //
+ for(pNewSection=pINF->pSection; pNewSection; pNewSection=pNewSection->pNext) {
+ if(pNewSection->pName && !_stricmp(pNewSection->pName,pSectionName)) {
+ break;
+ }
+ }
+ if(pNewSection) {
+ //
+ // Set pLineRecord to point to the list line currently in the section.
+ //
+ for(pLineRecord = pNewSection->pLine;
+ pLineRecord && pLineRecord->pNext;
+ pLineRecord = pLineRecord->pNext)
+ ;
+
+ } else {
+ //
+ // Allocate memory for the new section
+ //
+
+ if ((pNewSection = (PSECTION)BlAllocateHeap(sizeof(SECTION))) == (PSECTION)NULL) {
+ SlNoMemoryError();
+ return ENOMEM;
+ }
+
+ //
+ // initialise the new section
+ //
+ pNewSection->pNext = NULL;
+ pNewSection->pLine = NULL;
+ pNewSection->pName = pSectionName;
+
+ //
+ // link it in
+ //
+ pNewSection->pNext = pINF->pSection;
+ pINF->pSection = pNewSection;
+
+ //
+ // reset the current line record
+ //
+ pLineRecord = NULL;
+ }
+
+ pSectionRecord = pNewSection;
+ pValueRecord = NULL;
+
+ return ESUCCESS;
+}
+
+
+ARC_STATUS
+SpAppendLine(
+ IN PCHAR pLineKey
+ )
+
+/*++
+
+Routine Description:
+
+ This appends a new line to the line list in the current section.
+ All further values pertain to this new line, so it resets
+ the value list too.
+
+Arguments:
+
+ pLineKey - Key to be used for the current line, this could be NULL.
+
+Return Value:
+
+ ESUCCESS - if successful.
+ ENOMEM - if memory allocation failed.
+ EINVAL - if invalid parameters passed in or current section not
+ initialised
+
+
+--*/
+
+
+{
+ PLINE pNewLine;
+
+ //
+ // Check to see if current section initialised
+ //
+
+ if (pSectionRecord == (PSECTION)NULL) {
+ if(pchINFName) {
+ SlFriendlyError(
+ EINVAL,
+ pchINFName,
+ __LINE__,
+ __FILE__
+ );
+ } else {
+ SlError(EINVAL);
+ }
+ return EINVAL;
+ }
+
+ //
+ // Allocate memory for the new Line
+ //
+
+ if ((pNewLine = (PLINE)BlAllocateHeap(sizeof(LINE))) == (PLINE)NULL) {
+ SlNoMemoryError();
+ return ENOMEM;
+ }
+
+ //
+ // Link it in
+ //
+ pNewLine->pNext = (PLINE)NULL;
+ pNewLine->pValue = (PVALUE)NULL;
+ pNewLine->pName = pLineKey;
+
+ if (pLineRecord == (PLINE)NULL) {
+ pSectionRecord->pLine = pNewLine;
+ }
+ else {
+ pLineRecord->pNext = pNewLine;
+ }
+
+ pLineRecord = pNewLine;
+
+ //
+ // Reset the current value record
+ //
+
+ pValueRecord = (PVALUE)NULL;
+
+ return ESUCCESS;
+}
+
+
+
+ARC_STATUS
+SpAppendValue(
+ IN PCHAR pValueString
+ )
+
+/*++
+
+Routine Description:
+
+ This appends a new value to the value list in the current line.
+
+Arguments:
+
+ pValueString - The value string to be added.
+
+Return Value:
+
+ ESUCCESS - if successful.
+ ENOMEM - if memory allocation failed.
+ EINVAL - if invalid parameters passed in or current line not
+ initialised.
+
+--*/
+
+{
+ PVALUE pNewValue;
+
+ //
+ // Check to see if current line record has been initialised and
+ // the parameter passed in is valid
+ //
+
+ if (pLineRecord == (PLINE)NULL || pValueString == (PCHAR)NULL) {
+ if(pchINFName) {
+ SlFriendlyError(
+ EINVAL,
+ pchINFName,
+ __LINE__,
+ __FILE__
+ );
+ } else {
+ SlError(EINVAL);
+ }
+ return EINVAL;
+ }
+
+ //
+ // Allocate memory for the new value record
+ //
+
+ if ((pNewValue = (PVALUE)BlAllocateHeap(sizeof(VALUE))) == (PVALUE)NULL) {
+ SlNoMemoryError();
+ return ENOMEM;
+ }
+
+ //
+ // Link it in.
+ //
+
+ pNewValue->pNext = (PVALUE)NULL;
+ pNewValue->pName = pValueString;
+
+ if (pValueRecord == (PVALUE)NULL)
+ pLineRecord->pValue = pNewValue;
+ else
+ pValueRecord->pNext = pNewValue;
+
+ pValueRecord = pNewValue;
+ return ESUCCESS;
+}
+
+TOKEN
+SpGetToken(
+ IN OUT PCHAR *Stream,
+ IN PCHAR MaxStream
+ )
+
+/*++
+
+Routine Description:
+
+ This function returns the Next token from the configuration stream.
+
+Arguments:
+
+ Stream - Supplies the address of the configuration stream. Returns
+ the address of where to start looking for tokens within the
+ stream.
+
+ MaxStream - Supplies the address of the last character in the stream.
+
+
+Return Value:
+
+ TOKEN - Returns the next token
+
+--*/
+
+{
+
+ PCHAR pch, pchStart, pchNew;
+ ULONG Length;
+ TOKEN Token;
+
+ //
+ // Skip whitespace (except for eol)
+ //
+
+ pch = *Stream;
+ while (pch < MaxStream && *pch != '\n' && isspace(*pch))
+ pch++;
+
+
+ //
+ // Check for comments and remove them
+ //
+
+ if (pch < MaxStream &&
+ ((*pch == '#') ||
+ (*pch == ';') ||
+ (*pch == '/' && pch+1 < MaxStream && *(pch+1) =='/')))
+ while (pch < MaxStream && *pch != '\n')
+ pch++;
+
+ //
+ // Check to see if EOF has been reached, set the token to the right
+ // value
+ //
+
+ if ((pch >= MaxStream) || (*pch == 26)) {
+ *Stream = pch;
+ Token.Type = TOK_EOF;
+ Token.pValue = NULL;
+ return Token;
+ }
+
+
+ switch (*pch) {
+
+ case '[' :
+ pch++;
+ Token.Type = TOK_LBRACE;
+ Token.pValue = NULL;
+ break;
+
+ case ']' :
+ pch++;
+ Token.Type = TOK_RBRACE;
+ Token.pValue = NULL;
+ break;
+
+ case '=' :
+ pch++;
+ Token.Type = TOK_EQUAL;
+ Token.pValue = NULL;
+ break;
+
+ case ',' :
+ pch++;
+ Token.Type = TOK_COMMA;
+ Token.pValue = NULL;
+ break;
+
+ case '\n' :
+ pch++;
+ Token.Type = TOK_EOL;
+ Token.pValue = NULL;
+ break;
+
+ case '\"':
+ pch++;
+ //
+ // determine quoted string
+ //
+ pchStart = pch;
+ while (pch < MaxStream && (strchr(QStringTerminators,*pch) == NULL)) {
+ pch++;
+ }
+
+ if (pch >=MaxStream || *pch != '\"') {
+ Token.Type = TOK_ERRPARSE;
+ Token.pValue = NULL;
+ }
+ else {
+ Length = pch - pchStart;
+ if ((pchNew = BlAllocateHeap(Length + 1)) == NULL) {
+ Token.Type = TOK_ERRNOMEM;
+ Token.pValue = NULL;
+ }
+ else {
+ if (Length != 0) { // Null quoted strings are allowed
+ strncpy(pchNew, pchStart, Length);
+ }
+ pchNew[Length] = 0;
+ Token.Type = TOK_STRING;
+ Token.pValue = pchNew;
+ }
+ pch++; // advance past the quote
+ }
+ break;
+
+ default:
+ //
+ // determine regular string
+ //
+ pchStart = pch;
+ while (pch < MaxStream && (strchr(StringTerminators,*pch) == NULL)) {
+ pch++;
+ }
+
+ if (pch == pchStart) {
+ pch++;
+ Token.Type = TOK_ERRPARSE;
+ Token.pValue = NULL;
+ }
+ else {
+ Length = pch - pchStart;
+ if ((pchNew = BlAllocateHeap(Length + 1)) == NULL) {
+ Token.Type = TOK_ERRNOMEM;
+ Token.pValue = NULL;
+ }
+ else {
+ strncpy(pchNew, pchStart, Length);
+ pchNew[Length] = 0;
+ Token.Type = TOK_STRING;
+ Token.pValue = pchNew;
+ }
+ }
+ break;
+ }
+
+ *Stream = pch;
+ return (Token);
+}
diff --git a/private/ntos/boot/setup/ppc/sources b/private/ntos/boot/setup/ppc/sources
new file mode 100644
index 000000000..1e89c8732
--- /dev/null
+++ b/private/ntos/boot/setup/ppc/sources
@@ -0,0 +1,5 @@
+PPC_SOURCES=arcdtect.c
+
+
+NTTARGETFILES=obj\ppc\setupldr
+
diff --git a/private/ntos/boot/setup/ppcldr.rsp b/private/ntos/boot/setup/ppcldr.rsp
new file mode 100644
index 000000000..0b21d635f
--- /dev/null
+++ b/private/ntos/boot/setup/ppcldr.rsp
@@ -0,0 +1,17 @@
+-machine:ppc
+-force:multiple
+-rom
+-nodefaultlib
+-debug:notmapped
+-debugtype:coff
+-align:0x200
+-base:0x80600000,0x80640000
+-entry:SlInit
+-map:obj\ppc\setupldr.map
+obj\ppc\setupldr.lib
+obj\ppc\setupldr.res
+..\obj\ppc\boot.lib
+..\..\obj\ppc\ke.lib
+..\..\rtl\obj\ppc\bldrrtl.lib
+..\..\..\..\public\sdk\lib\ppc\libcntpr.lib
+..\..\..\..\public\sdk\lib\ppc\int64.lib
diff --git a/private/ntos/boot/setup/setup.c b/private/ntos/boot/setup/setup.c
new file mode 100644
index 000000000..9be879b92
--- /dev/null
+++ b/private/ntos/boot/setup/setup.c
@@ -0,0 +1,2526 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ setup.c
+
+Abstract:
+
+ This module contains the code that implements the NT setup loader
+
+Author:
+
+ John Vert (jvert) 6-Oct-1993
+
+Environment:
+
+ ARC Environment
+
+Revision History:
+
+--*/
+#include <setupbat.h>
+#include "setupldr.h"
+#include "stdio.h"
+#include "string.h"
+#include "stdlib.h"
+
+#define BlDiagLoadMessage(x,y,z)
+
+#define VGA_DRIVER_FILENAME "vga.sys"
+
+#define KERNEL_IMAGE_FILENAME "ntkrnlmp.exe"
+
+//
+// Global string constants.
+//
+PCHAR FilesSectionName = "SourceDisksFiles";
+PCHAR MediaSectionName = "SourceDisksNames";
+
+#if defined(_ALPHA_)
+PCHAR PlatformExtension = ".alpha";
+#elif defined(_MIPS_)
+PCHAR PlatformExtension = ".mips";
+#elif defined(_PPC_)
+PCHAR PlatformExtension = ".ppc";
+#elif defined(_X86_)
+PCHAR PlatformExtension = ".x86";
+#endif
+
+//
+// Global data
+//
+ULONG BlDcacheFillSize = 32;
+
+//
+// Global setupldr control values
+//
+MEDIA_TYPE BootMedia;
+MEDIA_TYPE InstallMedia;
+PCHAR BootDevice;
+ULONG BootDeviceId;
+BOOLEAN BootDeviceIdValid = FALSE;
+PCHAR BootPath;
+ULONG BootDriveNumber;
+ULONG InstallDriveNumber;
+PCHAR HalName;
+PCHAR HalDescription;
+PCHAR AnsiCpName;
+PCHAR OemHalFontName;
+UNICODE_STRING AnsiCodepage;
+UNICODE_STRING OemCodepage;
+UNICODE_STRING UnicodeCaseTable;
+UNICODE_STRING OemHalFont;
+
+BOOLEAN LoadScsiMiniports;
+BOOLEAN LoadDiskClass;
+BOOLEAN LoadCdfs;
+BOOLEAN FixedBootMedia = FALSE;
+
+PVOID InfFile;
+PVOID WinntSifHandle;
+BOOLEAN IgnoreMissingFiles;
+
+//
+// Pre-install stuff
+//
+
+PCHAR OemTag = "OEM";
+BOOLEAN PreInstall = FALSE;
+PCHAR ComputerType = NULL;
+BOOLEAN OemHal = FALSE;
+PPREINSTALL_DRIVER_INFO PreinstallDriverList = NULL;
+
+
+#if defined(ELTORITO)
+extern BOOLEAN ElToritoCDBoot;
+#endif
+
+//
+// Define transfer entry of loaded image.
+//
+
+typedef
+VOID
+(*PTRANSFER_ROUTINE) (
+ PLOADER_PARAMETER_BLOCK LoaderBlock
+ );
+
+//
+// Local function prototypes
+//
+VOID
+SlGetSetupValues(
+ IN PSETUP_LOADER_BLOCK SetupBlock
+ );
+
+ARC_STATUS
+SlLoadDriver(
+ IN PCHAR DeviceName,
+ IN PCHAR DriverName,
+ IN ULONG DriverFlags,
+ IN BOOLEAN InsertIntoDriverList
+ );
+
+ARC_STATUS
+SlLoadOemDriver(
+ IN PCHAR ExportDriver, OPTIONAL
+ IN PCHAR DriverName,
+ IN PVOID BaseAddress,
+ IN PCHAR LoadMessage
+ );
+
+PBOOT_DRIVER_LIST_ENTRY
+SlpCreateDriverEntry(
+ IN PCHAR DriverName
+ );
+
+ARC_STATUS
+SlLoadSection(
+ IN PVOID Inf,
+ IN PCHAR SectionName,
+ IN BOOLEAN IsScsiSection
+ );
+
+BOOLEAN
+SlpIsDiskVacant(
+ IN PARC_DISK_SIGNATURE DiskSignature
+ );
+
+ARC_STATUS
+SlpStampFTSignature(
+ IN PARC_DISK_SIGNATURE DiskSignature
+ );
+
+VOID
+SlpMarkDisks(
+ VOID
+ );
+
+VOID
+SlCheckOemKeypress(
+ VOID
+ );
+
+ARC_STATUS
+SlLoadBusExtender(
+ IN PVOID Inf
+ );
+
+
+ARC_STATUS
+SlInit(
+ IN ULONG Argc,
+ IN PCHAR Argv[],
+ IN PCHAR Envp[]
+ )
+
+/*++
+
+Routine Description:
+
+ The main startup routine for the NT Setup Loader. This is the entrypoint
+ called by the ARC firmware.
+
+ If successful, this routine will never return, it will start NT directly.
+
+Arguments:
+
+ Argc - Supplies the number of arguments that were provided on the
+ command that invoked this program.
+
+ Argv - Supplies a pointer to a vector of pointers to null terminated
+ argument strings.
+
+ Envp - Supplies a pointer to a vector of pointers to null terminated
+ environment variables.
+
+Return Value:
+
+ ARC_STATUS if unsuccessful.
+
+
+--*/
+
+{
+ PCONFIGURATION_COMPONENT_DATA DataCache;
+ ARC_STATUS Status;
+ ULONG LinesPerBlock;
+ ULONG CacheLineSize;
+ CHAR SetupDevice[128];
+ CHAR SetupDirectory[128];
+ CHAR BadFileName[128];
+ CHAR CanonicalName[128];
+ CHAR HalDirectoryPath[256];
+ CHAR KernelDirectoryPath[256];
+ PCHAR p;
+ ULONG ErrorLine=0;
+ ULONG DontCare;
+ PVOID SystemBase;
+ PVOID HalBase;
+ PVOID ScsiBase;
+ PVOID VideoBase;
+ PLDR_DATA_TABLE_ENTRY SystemDataTableEntry;
+ PLDR_DATA_TABLE_ENTRY HalDataTableEntry;
+ PTRANSFER_ROUTINE SystemEntry;
+ PIMAGE_NT_HEADERS NtHeaders;
+ PBOOT_DRIVER_LIST_ENTRY DriverEntry;
+ PSETUP_LOADER_BLOCK SetupBlock;
+ PDETECTED_DEVICE ScsiDevice;
+ PCHAR VideoFileName;
+ PCHAR VideoDescription;
+ PCHAR OemScsiName;
+ POEMSCSIINFO OemScsiInfo;
+ PCHAR OemVideoName;
+ BOOLEAN LoadedAVideoDriver = FALSE;
+
+ //
+ // Initialize the memory descriptor list, the OS loader heap, and the
+ // OS loader parameter block.
+ //
+
+ Status = BlMemoryInitialize();
+ if (Status != ESUCCESS) {
+ BlDiagLoadMessage(LOAD_HW_MEM_CLASS,
+ DIAG_BL_MEMORY_INIT,
+ LOAD_HW_MEM_ACT);
+ goto LoadFailed;
+ }
+
+ SetupBlock = BlAllocateHeap(sizeof(SETUP_LOADER_BLOCK));
+ if (SetupBlock==NULL) {
+ SlNoMemoryError();
+ goto LoadFailed;
+ }
+ BlLoaderBlock->SetupLoaderBlock = SetupBlock;
+ SetupBlock->ScsiDevices = NULL;
+
+ SetupBlock->ScalarValues.SetupFromCdRom = FALSE;
+ SetupBlock->ScalarValues.SetupOperation = SetupOperationSetup;
+ SetupBlock->ScalarValues.LoadedScsi = 0;
+ SetupBlock->ScalarValues.LoadedCdRomDrivers = 0;
+ SetupBlock->ScalarValues.LoadedDiskDrivers = 0;
+ SetupBlock->ScalarValues.LoadedFloppyDrivers = 0;
+
+ //
+ // Initialize the NT configuration tree.
+ //
+
+ BlLoaderBlock->ConfigurationRoot = NULL;
+
+
+ Status = BlConfigurationInitialize(NULL, NULL);
+ if (Status != ESUCCESS) {
+ BlDiagLoadMessage(LOAD_HW_FW_CFG_CLASS,
+ DIAG_BL_CONFIG_INIT,
+ LOAD_HW_FW_CFG_ACT);
+ goto LoadFailed;
+ }
+
+ //
+ // Compute the data cache fill size. This value is used to align
+ // I/O buffers in case the host system does not support coherent
+ // caches.
+ //
+ // If a combined secondary cache is present, then use the fill size
+ // for that cache. Otherwise, if a secondary data cache is present,
+ // then use the fill size for that cache. Otherwise, if a primary
+ // data cache is present, then use the fill size for that cache.
+ // Otherwise, use the default fill size.
+ //
+
+ DataCache = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
+ CacheClass,
+ SecondaryCache,
+ NULL);
+
+ if (DataCache == NULL) {
+ DataCache = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
+ CacheClass,
+ SecondaryDcache,
+ NULL);
+
+ if (DataCache == NULL) {
+ DataCache = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
+ CacheClass,
+ PrimaryDcache,
+ NULL);
+ }
+ }
+
+ if (DataCache != NULL) {
+ LinesPerBlock = DataCache->ComponentEntry.Key >> 24;
+ CacheLineSize = 1 << ((DataCache->ComponentEntry.Key >> 16) & 0xff);
+ BlDcacheFillSize = LinesPerBlock * CacheLineSize;
+ }
+
+ //
+ // Initialize the OS loader I/O system.
+ //
+
+ Status = BlIoInitialize();
+ if (Status != ESUCCESS) {
+ BlDiagLoadMessage(LOAD_HW_DISK_CLASS,
+ DIAG_BL_IO_INIT,
+ LOAD_HW_DISK_ACT);
+ goto LoadFailed;
+ }
+
+ SlPositionCursor(5,3);
+
+ //
+ // Initialize the message resources
+ //
+ Status = BlInitResources(Argv[0]);
+ if (Status != ESUCCESS) {
+ // if this fails, then we can't print out any messages,
+ // so we just exit.
+ return(Status);
+ }
+
+ //
+ // Initialize the display and announce ourselves
+ //
+ SlInitDisplay();
+ SlWriteHeaderText(SL_WELCOME_HEADER);
+ SlClearClientArea();
+
+#if defined(_X86_) && !defined(ALLOW_386)
+ //
+ // Disallow installation on a 386
+ //
+ {
+ extern BOOLEAN SlIs386(VOID);
+
+ if(SlIs386()) {
+ SlFatalError(SL_TEXT_REQUIRES_486);
+ }
+ }
+#endif
+
+ //
+ // If this is a winnt setup, then we want to behave as if
+ // we were started from the location specified by the
+ // OSLOADPARTITION and OSLOADFILENAME nv-ram variables.
+ //
+ p = BlGetArgumentValue(Argc,Argv,"osloadoptions");
+ if(p && !_stricmp(p,"winnt32")) {
+
+ p = BlGetArgumentValue(Argc,Argv,"osloadpartition");
+ if(!p) {
+ SlError(100);
+ goto LoadFailed;
+ }
+
+ Status = BlGenerateDeviceNames(p,SetupDevice,NULL);
+ if (Status != ESUCCESS) {
+ SlError(110);
+ goto LoadFailed;
+ }
+
+ p = BlGetArgumentValue(Argc,Argv,"osloadfilename");
+ if(!p || !(*p)) {
+ SlError(120);
+ goto LoadFailed;
+ }
+
+ strcpy(SetupDirectory,p);
+
+ //
+ // Make sure directory is terminated with a \.
+ //
+ if(SetupDirectory[strlen(SetupDirectory)-1] != '\\') {
+ strcat(SetupDirectory,"\\");
+ }
+
+ } else {
+
+ //
+ // extract device name from our startup path
+ //
+ p=strrchr(Argv[0],')');
+ if (p==NULL) {
+ SlError(0);
+ goto LoadFailed;
+ }
+
+ strncpy(SetupDevice, Argv[0],p-Argv[0]+1);
+ SetupDevice[p-Argv[0]+1] = '\0';
+ Status = BlGenerateDeviceNames(SetupDevice,CanonicalName,NULL);
+ if (Status != ESUCCESS) {
+ SlFriendlyError(
+ Status,
+ SetupDevice,
+ __LINE__,
+ __FILE__
+ );
+ goto LoadFailed;
+ }
+ strcpy(SetupDevice,CanonicalName);
+
+ //
+ // extract directory from our startup path.
+ //
+ if(*(p+1) != '\\') {
+ //
+ // directory must begin at root
+ //
+ strcpy(SetupDirectory, "\\");
+ } else {
+ *SetupDirectory = '\0';
+ }
+ strcat(SetupDirectory, p+1);
+ p=strrchr(SetupDirectory, '\\');
+ *(p+1) = '\0';
+ }
+
+#if defined(ELTORITO)
+ if (ElToritoCDBoot) {
+ //
+ // Use the i386 directory for setup files when we boot from an El Torito CD
+ //
+ strcat(SetupDirectory, "i386\\");
+ }
+#endif
+
+ //
+ // We need to check to see if the user pressed any keys to force OEM HAL,
+ // OEM SCSI, or both. Do this before getting the settings in the sif file,
+ // so that we won't try to detect the machine if OEM HAL is needed.
+ //
+ SlCheckOemKeypress();
+
+ strcpy(KernelDirectoryPath, SetupDirectory);
+ strcat(KernelDirectoryPath, "txtsetup.sif");
+
+ BlLoaderBlock->SetupLoaderBlock->IniFile = NULL;
+
+ Status = SlInitIniFile(SetupDevice,
+ 0,
+ KernelDirectoryPath,
+ &InfFile,
+ &ErrorLine);
+ if (Status != ESUCCESS) {
+ SlFatalError(SL_BAD_INF_FILE,"txtsetup.sif");
+ goto LoadFailed;
+ }
+
+ SlGetSetupValues(SetupBlock);
+
+ //
+ // Now we know everything we should load, compute the ARC name to load
+ // from and start loading things.
+ //
+ if (BootDevice==NULL) {
+ //
+ // No device was explicitly specified, so use whatever device
+ // setupldr was started from.
+ //
+
+ BootDevice = SlCopyString(SetupDevice);
+ }
+
+ Status = ArcOpen(BootDevice, ArcOpenReadOnly, &BootDeviceId);
+ if (Status != ESUCCESS) {
+ SlFatalError(SL_IO_ERROR,BootDevice);
+ goto LoadFailed;
+ } else {
+ BootDeviceIdValid = TRUE;
+ }
+
+ _strlwr(BootDevice);
+ FixedBootMedia = (strstr(BootDevice,")rdisk(") != NULL);
+
+ //
+ // If we are booting from fixed media, we better load disk class drivers.
+ //
+ if(FixedBootMedia) {
+ LoadDiskClass = TRUE;
+ }
+
+ if(!BlGetPathMnemonicKey(BootDevice,"disk",&DontCare)
+ && !BlGetPathMnemonicKey(BootDevice,"fdisk",&BootDriveNumber))
+ {
+ //
+ // boot was from floppy, canonicalize the ARC name.
+ //
+ BlLoaderBlock->ArcBootDeviceName = BlAllocateHeap(80);
+ sprintf(BlLoaderBlock->ArcBootDeviceName, "multi(0)disk(0)fdisk(%d)",BootDriveNumber);
+ } else {
+ BlLoaderBlock->ArcBootDeviceName = BootDevice;
+ }
+ if (BootPath==NULL) {
+ //
+ // No explicit boot path given, default to the directory setupldr was started
+ // from.
+ //
+#ifdef _X86_
+ //
+ // Increadibly nauseating hack:
+ //
+ // If we are booting from hard drive on x86, we will assume this is
+ // the 'floppyless' winnt/winnt32 scenario, in which case the actual
+ // boot path is \$win_nt$.~bt.
+ //
+ // This lets us avoid having winnt and winnt32 attempt to modify
+ // the BootPath value in the [SetupData] section of txtsetup.sif.
+ //
+ if(FixedBootMedia) {
+ BootPath = SlCopyString("\\$WIN_NT$.~BT\\");
+ } else
+#endif
+ BootPath = SlCopyString(SetupDirectory);
+ }
+ BlLoaderBlock->NtBootPathName = BootPath;
+
+ //
+ // Attempt to load winnt.sif from the path where we are
+ // loading setup files. Borrow the BadFileName buffer
+ // for temporary use.
+ //
+ strcpy(BadFileName,BootPath);
+ strcat(BadFileName,WINNT_SIF_FILE);
+ Status = SlInitIniFile(NULL,BootDeviceId,BadFileName,&WinntSifHandle,&DontCare);
+ if(Status == ESUCCESS) {
+ //
+ // Find out if this is a pre-install, by looking at OemPreinstall key
+ // in [unattended] section of winnt.sif
+ //
+ p = SlGetSectionKeyIndex(WinntSifHandle,WINNT_UNATTENDED,WINNT_U_OEMPREINSTALL,0);
+ if(p && !_stricmp(p,"yes")) {
+ PreInstall = TRUE;
+ }
+
+ //
+ // If this is a pre-install, find out which hal to load, by looking
+ // at ComputerType key in [unattended] section of winnt.sif.
+ //
+ if( PreInstall ) {
+ ComputerType = SlGetSectionKeyIndex(WinntSifHandle,WINNT_UNATTENDED,WINNT_U_COMPUTERTYPE,0);
+ if(ComputerType) {
+ //
+ // If the hal to load is an OEM one, then set OemHal to TRUE
+ //
+ p = SlGetSectionKeyIndex(WinntSifHandle,WINNT_UNATTENDED,WINNT_U_COMPUTERTYPE,1);
+ if(p && !_stricmp(p, OemTag)) {
+ OemHal = TRUE;
+ } else {
+ OemHal = FALSE;
+ }
+ //
+ // In the pre-install mode, don't let the user specify
+ // an OEM hal, if one was specified in unattend.txt
+ //
+ PromptOemHal = FALSE;
+ }
+
+ //
+ // Find out which SCSI drivers to load, by looking at
+ // [MassStorageDrivers] in winnt.sif
+ //
+ if( SpSearchINFSection( WinntSifHandle, WINNT_OEMSCSIDRIVERS ) ) {
+ ULONG i;
+ PPREINSTALL_DRIVER_INFO TempDriverInfo;
+
+ PreinstallDriverList = NULL;
+ for( i = 0;
+ ((p = SlGetKeyName( WinntSifHandle, WINNT_OEMSCSIDRIVERS, i )) != NULL);
+ i++ ) {
+ TempDriverInfo = BlAllocateHeap(sizeof(PREINSTALL_DRIVER_INFO));
+ if (TempDriverInfo==NULL) {
+ SlNoMemoryError();
+ goto LoadFailed;
+ }
+ TempDriverInfo->DriverDescription = p;
+ p = SlGetIniValue( WinntSifHandle,
+ WINNT_OEMSCSIDRIVERS,
+ TempDriverInfo->DriverDescription,
+ NULL );
+ TempDriverInfo->OemDriver = (p && !_stricmp(p, OemTag))? TRUE : FALSE;
+ TempDriverInfo->Next = PreinstallDriverList;
+ PreinstallDriverList = TempDriverInfo;
+ }
+ if( PreinstallDriverList != NULL ) {
+ //
+ // In the pre-install mode, don't let the user specify
+ // an OEM scsi, if at least one was specified in unattend.txt
+ //
+ PromptOemScsi = FALSE;
+ }
+ }
+ }
+
+ p = SlGetSectionKeyIndex(WinntSifHandle,WINNT_SETUPPARAMS,WINNT_S_SKIPMISSING,0);
+ if(p && (*p != '0')) {
+ IgnoreMissingFiles = TRUE;
+ }
+ } else {
+ WinntSifHandle = NULL;
+ }
+
+ //
+ // Initialize the debugging system.
+ //
+
+ BlLogInitialize(BootDeviceId);
+
+ //
+ // Do PPC-specific initialization.
+ //
+
+#if defined(_PPC_)
+
+ Status = BlPpcInitialize();
+ if (Status != ESUCCESS) {
+ goto LoadFailed;
+ }
+
+#endif // defined(_PPC_)
+
+ SlGetDisk(KERNEL_IMAGE_FILENAME);
+
+ strcpy(KernelDirectoryPath, BootPath);
+ strcat(KernelDirectoryPath,KERNEL_IMAGE_FILENAME);
+ BlOutputLoadMessage(BlFindMessage(SL_KERNEL_NAME), KernelDirectoryPath);
+ Status = BlLoadImage(BootDeviceId,
+ LoaderSystemCode,
+ KernelDirectoryPath,
+ TARGET_IMAGE,
+ &SystemBase);
+ if (Status != ESUCCESS) {
+ SlFatalError(SL_FILE_LOAD_FAILED,KernelDirectoryPath,Status);
+ goto LoadFailed;
+ }
+
+ strcpy(HalDirectoryPath, BootPath);
+
+ if (PromptOemHal || (PreInstall && (ComputerType != NULL))) {
+ if(PreInstall && OemHal) {
+ //
+ // This is a pre-install and an OEM hal was specified
+ //
+ strcat( HalDirectoryPath,
+#ifdef _X86_
+ WINNT_OEM_DIR
+#else
+ WINNT_OEM_TEXTMODE_DIR
+#endif
+ );
+ strcat( HalDirectoryPath, "\\" );
+ }
+ SlPromptOemHal(&HalBase, &HalName);
+ strcat(HalDirectoryPath,HalName);
+
+
+ } else {
+
+ strcat(HalDirectoryPath,HalName);
+ SlGetDisk(HalName);
+ BlOutputLoadMessage(BlFindMessage(SL_HAL_NAME), HalDirectoryPath);
+ Status = BlLoadImage(BootDeviceId,
+ LoaderHalCode,
+ HalDirectoryPath,
+ TARGET_IMAGE,
+ &HalBase);
+ if (Status != ESUCCESS) {
+ SlFatalError(SL_FILE_LOAD_FAILED,HalDirectoryPath,Status);
+ goto LoadFailed;
+ }
+ }
+
+ //
+ // Generate a loader data entry for the system image.
+ //
+
+ Status = BlAllocateDataTableEntry("ntoskrnl.exe",
+ KernelDirectoryPath,
+ SystemBase,
+ &SystemDataTableEntry);
+
+ if (Status != ESUCCESS) {
+ SlFatalError(SL_FILE_LOAD_FAILED,KernelDirectoryPath,Status);
+ goto LoadFailed;
+ }
+
+ //
+ // Generate a loader data entry for the HAL DLL.
+ //
+
+ Status = BlAllocateDataTableEntry("hal.dll",
+ HalDirectoryPath,
+ HalBase,
+ &HalDataTableEntry);
+
+ if (Status != ESUCCESS) {
+ SlFatalError(SL_FILE_LOAD_FAILED,HalDirectoryPath,Status);
+ goto LoadFailed;
+ }
+
+#if defined(_ALPHA_)
+ {
+ CHAR PalFileName[32];
+ CHAR FloppyName[80];
+ PCHAR DiskDescription;
+ ULONG FloppyId;
+ PDETECTED_DEVICE OemPal;
+ PDETECTED_DEVICE_FILE OemPalFile;
+
+ //
+ // Get the name of the pal file we are suppose to load.
+ //
+
+ Status = BlGeneratePalName(PalFileName);
+
+ //
+ // If we get an error from BlGenereatePalName, something is
+ // really wrong with the firmware or the ARC tree. Abort and
+ // bail out.
+ //
+
+ if (Status != ESUCCESS) {
+ SlFatalError(SL_FILE_LOAD_FAILED,PalFileName,Status);
+ goto LoadFailed;
+ }
+
+ //
+ // Try loading the pal file from the boot device.
+ //
+
+ //
+ // NOTE John Vert (jvert) 4-Feb-1994
+ // Below call assumes all the PALs are on
+ // the same floppy. We really should check the SIF
+ // file and go immediately to the diskette prompt
+ // if it's not in the SIF file, otherwise get
+ // the appropriate disk.
+ //
+ SetupBlock->OemPal = NULL;
+ SlGetDisk("A321064.PAL");
+
+ Status = BlLoadPal(BootDeviceId,
+ LoaderSystemCode,
+ BootPath,
+ TARGET_IMAGE,
+ &BlLoaderBlock->u.Alpha.PalBaseAddress,
+ BlFindMessage(SL_PAL_NAME));
+
+ //
+ // If we have failed, prompt the user for a floppy that contains
+ // the pal code and load it from floppy. We keep looping until
+ // either we get the right disk, or we get an error other than
+ // 'file not found'.
+ //
+
+ if(Status == ENOENT) {
+ DiskDescription = BlFindMessage(SL_OEM_DISK_PROMPT);
+ }
+
+ while (Status == ENOENT) {
+
+ SlClearClientArea();
+
+ //
+ // Compute the name of the A: drive.
+ //
+
+ if (!SlpFindFloppy(0,FloppyName)) {
+
+ //
+ // No floppy drive available, bail out.
+ //
+
+ SlFatalError(SL_FILE_LOAD_FAILED,PalFileName,Status);
+ goto LoadFailed;
+ }
+
+ //
+ // Prompt for the disk.
+ //
+ SlPromptForDisk(DiskDescription, FALSE);
+
+ //
+ // Open the floppy.
+ //
+
+ Status = ArcOpen(FloppyName, ArcOpenReadOnly, &FloppyId);
+ if (Status != ESUCCESS) {
+
+ //
+ // We want to give the user another chance if they didn't
+ // have a floppy inserted.
+ //
+ if(Status != ENOENT) {
+ Status = (Status == EIO) ? ENOENT : Status;
+ }
+ continue;
+ }
+
+ //
+ // Load the pal file from the root of the floppy.
+ //
+
+ Status = BlLoadPal(FloppyId,
+ LoaderSystemCode,
+ "\\",
+ TARGET_IMAGE,
+ &BlLoaderBlock->u.Alpha.PalBaseAddress,
+ BlFindMessage(SL_PAL_NAME));
+
+ ArcClose(FloppyId);
+
+ //
+ // if we found the PAL, then record DETECTED_DEVICE info
+ //
+ if(Status == ESUCCESS) {
+ OemPal = BlAllocateHeap(sizeof(DETECTED_DEVICE));
+ if(!OemPal) {
+ SlNoMemoryError();
+ }
+ SetupBlock->OemPal = OemPal;
+
+ OemPal->Next = NULL;
+ OemPal->IdString = NULL;
+ OemPal->Description = NULL;
+ OemPal->ThirdPartyOptionSelected = TRUE;
+ OemPal->FileTypeBits = 0;
+
+ OemPalFile = BlAllocateHeap(sizeof(DETECTED_DEVICE_FILE));
+ if(!OemPalFile) {
+ SlNoMemoryError();
+ }
+ OemPal->Files = OemPalFile;
+
+ OemPalFile->Next = NULL;
+ OemPalFile->Filename = SlCopyString(PalFileName);
+ OemPalFile->FileType = HwFileMax;
+ OemPalFile->ConfigName = NULL;
+ OemPalFile->RegistryValueList = NULL;
+ OemPalFile->DiskDescription = SlCopyString(DiskDescription);
+ OemPalFile->DiskTagfile = NULL;
+ OemPalFile->Directory = SlCopyString("");
+ }
+ }
+
+ if(Status != ESUCCESS) {
+ SlFriendlyError(
+ Status,
+ PalFileName,
+ __LINE__,
+ __FILE__
+ );
+ goto LoadFailed;
+ }
+
+ }
+
+#endif // ifdef _ALPHA_
+
+ Status = BlScanImportDescriptorTable(BootDeviceId,
+ BootDevice,
+ BootPath,
+ SystemDataTableEntry);
+
+ if (Status != ESUCCESS) {
+ SlFatalError(SL_FILE_LOAD_FAILED,KERNEL_IMAGE_FILENAME,Status);
+ }
+
+ //
+ // Scan the import table for the HAL DLL and load all referenced DLLs.
+ //
+
+ Status = BlScanImportDescriptorTable(BootDeviceId,
+ BootDevice,
+ BootPath,
+ HalDataTableEntry);
+
+ if (Status != ESUCCESS) {
+ SlFatalError(SL_FILE_LOAD_FAILED,"hal.dll",Status);
+ goto LoadFailed;
+ }
+
+ //
+ // Relocate the system entry point and set system specific information.
+ //
+
+ NtHeaders = RtlImageNtHeader(SystemBase);
+ SystemEntry = (PTRANSFER_ROUTINE)((ULONG)SystemBase +
+ NtHeaders->OptionalHeader.AddressOfEntryPoint);
+
+#if defined(_MIPS_)
+
+ BlLoaderBlock->u.Mips.GpBase = (ULONG)SystemBase +
+ NtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_GLOBALPTR].VirtualAddress;
+
+#endif
+
+#if defined(_ALPHA_)
+
+ BlLoaderBlock->u.Alpha.GpBase = (ULONG)SystemBase +
+ NtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_GLOBALPTR].VirtualAddress;
+
+#endif
+
+ //
+ // Load registry's SYSTEM hive
+ //
+ SlGetDisk("SETUPREG.HIV");
+ Status = BlLoadSystemHive(BootDeviceId,
+ BlFindMessage(SL_HIVE_NAME),
+ BootPath,
+ "SETUPREG.HIV");
+ if (Status != ESUCCESS) {
+ SlFatalError(SL_FILE_LOAD_FAILED,"SETUPREG.HIV",Status);
+ goto LoadFailed;
+ }
+
+
+ //
+ // Allocate structure for NLS data.
+ //
+
+ BlLoaderBlock->NlsData = BlAllocateHeap(sizeof(NLS_DATA_BLOCK));
+ if (BlLoaderBlock->NlsData == NULL) {
+ Status = ENOMEM;
+ SlNoMemoryError();
+ goto LoadFailed;
+ }
+
+ //
+ // Load the OEM font
+ //
+ SlGetDisk(OemHalFontName);
+ Status = BlLoadOemHalFont(BootDeviceId,
+ BlFindMessage(SL_OEM_FONT_NAME),
+ BootPath,
+ &OemHalFont,
+ BadFileName);
+
+ if(Status != ESUCCESS) {
+ SlFatalError(SL_FILE_LOAD_FAILED, OemHalFontName, Status);
+ goto LoadFailed;
+ }
+
+ //
+ // Load the NLS data.
+ //
+ // For now, we ensure that the disk containing the ansi
+ // codepage file is in the drive and hope that the rest of the
+ // nls files (oem codepage, unicode table) are on the same disk.
+ //
+ SlGetDisk(AnsiCpName);
+ Status = BlLoadNLSData(BootDeviceId,
+ BlFindMessage(SL_NLS_NAME),
+ BootPath,
+ &AnsiCodepage,
+ &OemCodepage,
+ &UnicodeCaseTable,
+ BadFileName);
+
+ if(Status != ESUCCESS) {
+ SlFatalError(SL_FILE_LOAD_FAILED, AnsiCpName, Status);
+ goto LoadFailed;
+ }
+
+ //
+ // Load the system drivers we will need here
+ //
+
+ InitializeListHead(&BlLoaderBlock->BootDriverListHead);
+
+ //
+ // Always load setupdd.sys first, it will need to prep the rest of the
+ // system.
+ //
+ Status = SlLoadDriver(BlFindMessage(SL_SETUP_NAME),
+ "setupdd.sys",
+ 0,
+ TRUE
+ );
+ if (Status != ESUCCESS) {
+ SlFatalError(SL_FILE_LOAD_FAILED,"setupdd.sys",Status);
+ goto LoadFailed;
+ }
+
+ //
+ // Fill in its registry key.
+ //
+ DriverEntry = (PBOOT_DRIVER_LIST_ENTRY)(BlLoaderBlock->BootDriverListHead.Flink);
+ DriverEntry->RegistryPath.Buffer = BlAllocateHeap(256);
+ if (DriverEntry->RegistryPath.Buffer == NULL) {
+ SlNoMemoryError();
+ goto LoadFailed;
+ }
+ DriverEntry->RegistryPath.Length = 0;
+ DriverEntry->RegistryPath.MaximumLength = 256;
+ RtlAppendUnicodeToString(&DriverEntry->RegistryPath,
+ L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\setupdd");
+
+ //
+ // Load the Winnt.SIF file *here*
+ //
+
+ //
+ // Load bus extenders.
+ // It has to be done before scsiport.sys
+ //
+
+ Status = SlLoadBusExtender( InfFile );
+
+ //
+ // Load scsiport.sys next, so it'll always be around for any scsi miniports we may load
+ //
+ Status = SlLoadDriver(BlFindMessage(SL_SCSIPORT_NAME),
+ "SCSIPORT.SYS",
+ 0,
+ FALSE
+ );
+
+ //
+ // Detect scsi, video
+ //
+ // (If the user wants to select their own SCSI devices, we won't
+ // do any detection)
+ //
+ if(!PromptOemScsi && (PreinstallDriverList == NULL) ) {
+ SlDetectScsi(SetupBlock);
+ }
+ SlDetectVideo(SetupBlock);
+
+#if defined(ELTORITO)
+ //
+ // If this is an El Torito CD-ROM install, then we want to load all SCSI miniports
+ // and disk class drivers.
+ //
+ if(ElToritoCDBoot) {
+ LoadScsiMiniports = TRUE;
+ }
+#endif
+
+ //
+ // If the LoadScsi flag is set, enumerate all the known SCSI miniports and load each
+ // one.
+ //
+ if(LoadScsiMiniports) {
+ Status = SlLoadSection(InfFile,"Scsi",TRUE);
+ if (Status!=ESUCCESS) {
+ goto LoadFailed;
+ }
+ SetupBlock->ScalarValues.LoadedScsi = 1;
+ }
+
+ //
+ // Allow the user to pick an OEM SCSI driver here
+ //
+ if (PromptOemScsi || (PreinstallDriverList != NULL) ) {
+ SlPromptOemScsi(&OemScsiInfo);
+ }
+
+ //
+ // Walk the list of detected SCSI miniports and load each one.
+ //
+ ScsiDevice = SetupBlock->ScsiDevices;
+ while (ScsiDevice != NULL) {
+
+ if(ScsiDevice->ThirdPartyOptionSelected) {
+
+ if(!OemScsiInfo) {
+ SlError(500);
+ goto LoadFailed;
+ }
+
+ Status = SlLoadOemDriver(
+ NULL,
+ OemScsiInfo->ScsiName,
+ OemScsiInfo->ScsiBase,
+ BlFindMessage(SL_SCSIPORT_NAME)
+ );
+ OemScsiInfo = OemScsiInfo->Next;
+
+ } else {
+ Status = SlLoadDriver(ScsiDevice->Description,
+ ScsiDevice->BaseDllName,
+ 0,
+ TRUE
+ );
+ }
+
+ if((Status == ESUCCESS)
+ || ((Status == ENOENT) && IgnoreMissingFiles && !ScsiDevice->ThirdPartyOptionSelected)) {
+
+ SetupBlock->ScalarValues.LoadedScsi = 1;
+
+ } else {
+ SlFriendlyError(
+ Status,
+ ScsiDevice->BaseDllName,
+ __LINE__,
+ __FILE__
+ );
+ goto LoadFailed;
+ }
+
+ ScsiDevice = ScsiDevice->Next;
+ }
+
+ //
+ // If the LoadDiskClass flag is set, enumerate all the monolithic disk class drivers
+ // and load each one. Note that we also do this if we've "detected" any scsi drivers,
+ // so that we preserve the drive order.
+ //
+ if((LoadDiskClass) || (SetupBlock->ScalarValues.LoadedScsi == 1)) {
+ Status = SlLoadSection(InfFile, "DiskDrivers", FALSE);
+ if (Status == ESUCCESS) {
+ SetupBlock->ScalarValues.LoadedDiskDrivers = 1;
+ } else {
+ goto LoadFailed;
+ }
+ }
+
+ //
+ // On x86, the video type is always set to VGA in i386\x86dtect.c.
+ // On non-x86, the video type is either recognized, in which case
+ // we don't unconditionally need vga.sys (the Display.Load section
+ // tells us what to load), or it's not recognized,
+ // in which case we will prompt the user for an oem disk.
+ // If there is no display controller node at all, then PromptOemDisk
+ // will be false and there will be no video device. In this case
+ // we load vga.sys.
+ //
+
+ if (SetupBlock->VideoDevice.IdString != NULL) {
+ VideoFileName = SlGetSectionKeyIndex(InfFile,
+ "Display.Load",
+ SetupBlock->VideoDevice.IdString,
+ SIF_FILENAME_INDEX);
+ if (VideoFileName != NULL) {
+#if 0
+ VideoDescription = SlGetIniValue(InfFile,
+ "Display",
+ SetupBlock->VideoDevice.IdString,
+ BlFindMessage(SL_VIDEO_NAME));
+#else
+ //
+ // With the new video detection mechanism, the description
+ // for the video driver is likely to be something like
+ // "Windows NT Compatible" which looks funny when displayed
+ // in the status bar.
+ //
+ VideoDescription = BlFindMessage(SL_VIDEO_NAME);
+#endif
+ Status = SlLoadDriver(VideoDescription,
+ VideoFileName,
+ 0,
+ TRUE
+ );
+ if (Status == ESUCCESS) {
+ SetupBlock->VideoDevice.BaseDllName = SlCopyString(VideoFileName);
+ } else {
+ SlFriendlyError(
+ Status,
+ VideoFileName,
+ __LINE__,
+ __FILE__
+ );
+ goto LoadFailed;
+ }
+
+ LoadedAVideoDriver = TRUE;
+ }
+ } else if (PromptOemVideo) {
+
+ SlPromptOemVideo(&VideoBase, &OemVideoName);
+
+ Status = SlLoadOemDriver(
+ "VIDEOPRT.SYS",
+ OemVideoName,
+ VideoBase,
+ BlFindMessage(SL_VIDEO_NAME)
+ );
+
+ if(Status==ESUCCESS) {
+
+ LoadedAVideoDriver = TRUE;
+ SetupBlock->VideoDevice.BaseDllName = SlCopyString(OemVideoName);
+ }
+ }
+
+ if(!LoadedAVideoDriver) {
+ Status = SlLoadDriver(BlFindMessage(SL_VIDEO_NAME),
+ VGA_DRIVER_FILENAME,
+ 0,
+ TRUE
+ );
+ if(Status == ESUCCESS) {
+ SetupBlock->VideoDevice.BaseDllName = SlCopyString(VGA_DRIVER_FILENAME);
+ } else {
+ SlFriendlyError(
+ Status,
+ VGA_DRIVER_FILENAME,
+ __LINE__,
+ __FILE__
+ );
+ goto LoadFailed;
+ }
+ }
+
+ if(SetupBlock->VideoDevice.IdString == NULL) {
+ SetupBlock->VideoDevice.IdString = SlCopyString("VGA");
+ }
+
+ //
+ // Load the floppy driver
+ //
+ Status = SlLoadDriver(BlFindMessage(SL_FLOPPY_NAME),
+ "floppy.sys",
+ 0,
+ TRUE
+ );
+ if (Status == ESUCCESS) {
+ SetupBlock->ScalarValues.LoadedFloppyDrivers = 1;
+ }
+#ifdef i386
+ else {
+ SlFriendlyError(
+ Status,
+ "floppy.sys",
+ __LINE__,
+ __FILE__
+ );
+ goto LoadFailed;
+ }
+#endif
+
+ if(SetupBlock->ScalarValues.LoadedScsi == 1) {
+ //
+ // Enumerate the entries in the scsi class section and load each one.
+ //
+ Status = SlLoadSection(InfFile, "ScsiClass",FALSE);
+ if (Status != ESUCCESS) {
+ goto LoadFailed;
+ }
+ }
+
+ //
+ // Load the keyboard driver
+ //
+ SetupBlock->KeyboardDevice.Next = NULL;
+ SetupBlock->KeyboardDevice.IdString = SlCopyString("Keyboard");
+ SetupBlock->KeyboardDevice.ThirdPartyOptionSelected = FALSE;
+ SetupBlock->KeyboardDevice.FileTypeBits = 0;
+ SetupBlock->KeyboardDevice.BaseDllName = SlCopyString("i8042prt.sys");
+
+ Status = SlLoadDriver(BlFindMessage(SL_KBD_NAME),
+ "i8042prt.sys",
+ 0,
+ TRUE
+ );
+ if(Status != ESUCCESS) {
+ SlFriendlyError(
+ Status,
+ "i8042prt.sys",
+ __LINE__,
+ __FILE__
+ );
+ goto LoadFailed;
+ }
+
+ Status = SlLoadDriver(BlFindMessage(SL_KBD_NAME),
+ "kbdclass.sys",
+ 0,
+ TRUE
+ );
+ if(Status != ESUCCESS) {
+ SlFriendlyError(
+ Status,
+ "kbdclass.sys",
+ __LINE__,
+ __FILE__
+ );
+ goto LoadFailed;
+ }
+
+ //
+ // Load FAT
+ //
+ Status = SlLoadDriver(BlFindMessage(SL_FAT_NAME),
+ "fastfat.sys",
+ 0,
+ TRUE
+ );
+#ifdef i386
+ if(Status != ESUCCESS) {
+ SlFriendlyError(
+ Status,
+ "fastfat.sys",
+ __LINE__,
+ __FILE__
+ );
+ goto LoadFailed;
+ }
+#endif
+
+ //
+ // Load CDFS if setupldr was started from a cdrom, or if ForceLoadCdfs is set.
+ //
+ if (LoadCdfs || (!BlGetPathMnemonicKey(SetupDevice,
+ "cdrom",
+ &BootDriveNumber))) {
+ Status = SlLoadSection(InfFile, "CdRomDrivers",FALSE);
+ if (Status == ESUCCESS) {
+ SetupBlock->ScalarValues.LoadedCdRomDrivers = 1;
+ } else {
+ goto LoadFailed;
+ }
+ }
+
+ //
+ // Finally, make sure the appropriate disk containing NTDLL.DLL is in
+ // the drive.
+ //
+ SlGetDisk("ntdll.dll");
+
+ //
+ // Fill in the SETUPLDR block with relevant information
+ //
+ SetupBlock->ArcSetupDeviceName = BlLoaderBlock->ArcBootDeviceName;
+
+ SetupBlock->ScalarValues.SetupFromCdRom = FALSE;
+ SetupBlock->ScalarValues.SetupOperation = SetupOperationSetup;
+
+ //
+ // Get the NTFT drive signatures to allow the kernel to create the
+ // correct ARC name <=> NT name mappings.
+ //
+ BlGetArcDiskInformation();
+ SlpMarkDisks();
+
+ //
+ // If setup was started from a CD-ROM, generate an entry in the ARC disk
+ // information list describing the cd-rom.
+ //
+ if (!BlGetPathMnemonicKey(SetupDevice,
+ "cdrom",
+ &BootDriveNumber)) {
+ BlReadSignature(SetupDevice,TRUE);
+ }
+
+
+ //
+ //
+ // Execute the architecture specific setup code.
+ //
+
+ Status = BlSetupForNt(BlLoaderBlock);
+ if (Status != ESUCCESS) {
+ SlFriendlyError(
+ Status,
+ "\"Windows NT Executive\"",
+ __LINE__,
+ __FILE__
+ );
+ goto LoadFailed;
+ }
+
+ //
+ // Turn off the debugging system.
+ //
+
+ BlLogTerminate();
+
+ //
+ // Transfer control to loaded image.
+ //
+
+ (SystemEntry)(BlLoaderBlock);
+
+ Status = EBADF;
+ SlFriendlyError(
+ Status,
+ "\"Windows NT Executive\"",
+ __LINE__,
+ __FILE__
+ );
+
+LoadFailed:
+ SlWriteStatusText(BlFindMessage(SL_TOTAL_SETUP_DEATH));
+ SlFlushConsoleBuffer();
+ SlGetChar();
+ ArcRestart();
+ return(Status);
+}
+
+
+
+VOID
+SlGetSetupValues(
+ IN PSETUP_LOADER_BLOCK SetupBlock
+ )
+
+/*++
+
+Routine Description:
+
+ Reads the setup control values out of the given .INI file. Also supplies
+ reasonable defaults for values that don't exist.
+
+Arguments:
+
+ SetupBlock - Supplies a pointer to the Setup loader block
+
+Return Value:
+
+ None. Global variables are initialized to reflect the contents of the INI file
+
+--*/
+
+{
+ PCHAR MachineName = NULL;
+ PCHAR NlsName;
+ ANSI_STRING NlsString;
+
+ BlLoaderBlock->LoadOptions = SlGetIniValue(InfFile,
+ "setupdata",
+ "osloadoptions",
+ "");
+
+ //
+ // Determine which HAL to load. If the appropriate HAL cannot be
+ // determined, or if we are to prompt for an OEM HAL, then set the
+ // 'PromptOemHal' flag (may have already been set by the user's
+ // keypress).
+ //
+ if(!PromptOemHal) {
+ PromptOemHal = (atoi(SlGetIniValue(InfFile,
+ "setupdata",
+ "ForceOemHal",
+ "0")) == 1);
+ }
+
+ if(!PromptOemHal) {
+ MachineName = SlDetectHal(SetupBlock);
+ }
+ SetupBlock->ComputerDevice.Files = 0;
+ SetupBlock->ComputerDevice.Next = NULL;
+ SetupBlock->ComputerDevice.Description = NULL;
+ SetupBlock->ComputerDevice.ThirdPartyOptionSelected = FALSE;
+ SetupBlock->ComputerDevice.FileTypeBits = 0;
+ SetupBlock->ComputerDevice.Files = 0;
+ SetupBlock->ComputerDevice.BaseDllName = SlCopyString("");
+
+ if(MachineName!=NULL) {
+ SetupBlock->ComputerDevice.IdString = SlCopyString(MachineName);
+ HalName = SlGetIniValue(InfFile,
+ "Hal.Load",
+ MachineName,
+ NULL);
+ HalDescription = SlGetIniValue(InfFile,
+ "Computer",
+ MachineName,
+ NULL);
+ }
+
+ if(!(MachineName && HalName && HalDescription)) {
+ PromptOemHal = TRUE;
+ }
+
+
+ AnsiCpName = SlGetIniValue(InfFile,
+ "nls",
+ "AnsiCodepage",
+ "c_1252.nls");
+ NlsString.Buffer = AnsiCpName;
+ NlsString.Length = strlen(AnsiCpName);
+ AnsiCodepage.MaximumLength = strlen(AnsiCpName)*sizeof(WCHAR)+sizeof(UNICODE_NULL);
+ AnsiCodepage.Buffer = BlAllocateHeap(AnsiCodepage.MaximumLength);
+ RtlAnsiStringToUnicodeString(&AnsiCodepage, &NlsString, FALSE);
+
+ NlsName = SlGetIniValue(InfFile,
+ "nls",
+ "OemCodepage",
+ "c_437.nls");
+ NlsString.Buffer = NlsName;
+ NlsString.Length = strlen(NlsName);
+ OemCodepage.MaximumLength = strlen(NlsName)*sizeof(WCHAR)+sizeof(UNICODE_NULL);
+ OemCodepage.Buffer = BlAllocateHeap(OemCodepage.MaximumLength);
+ RtlAnsiStringToUnicodeString(&OemCodepage, &NlsString, FALSE);
+
+ NlsName = SlGetIniValue(InfFile,
+ "nls",
+ "UnicodeCasetable",
+ "l_intl.nls");
+ NlsString.Buffer = NlsName;
+ NlsString.Length = strlen(NlsName);
+ UnicodeCaseTable.MaximumLength = strlen(NlsName)*sizeof(WCHAR)+sizeof(UNICODE_NULL);
+ UnicodeCaseTable.Buffer = BlAllocateHeap(UnicodeCaseTable.MaximumLength);
+ RtlAnsiStringToUnicodeString(&UnicodeCaseTable, &NlsString, FALSE);
+
+ OemHalFontName = SlGetIniValue(InfFile,
+ "nls",
+ "OemHalFont",
+ "vgaoem.fon");
+ NlsString.Buffer = OemHalFontName;
+ NlsString.Length = strlen(OemHalFontName);
+ OemHalFont.MaximumLength = strlen(OemHalFontName)*sizeof(WCHAR)+sizeof(UNICODE_NULL);
+ OemHalFont.Buffer = BlAllocateHeap(OemHalFont.MaximumLength);
+ RtlAnsiStringToUnicodeString(&OemHalFont, &NlsString, FALSE);
+
+ LoadScsiMiniports = (atoi(SlGetIniValue(InfFile,
+ "SetupData",
+ "ForceScsi",
+ "0")) == 1);
+ LoadDiskClass = (atoi(SlGetIniValue(InfFile,
+ "setupdata",
+ "ForceDiskClass",
+ "0")) == 1);
+
+ LoadCdfs = (atoi(SlGetIniValue(InfFile,
+ "setupdata",
+ "ForceCdRom",
+ "0")) == 1);
+
+ //
+ // If we haven't already been instructed to prompt for an OEM SCSI disk (by
+ // the user's keypress), then get this value from the inf file.
+ //
+ if(!PromptOemScsi) {
+ PromptOemScsi = (atoi(SlGetIniValue(InfFile,
+ "setupdata",
+ "ForceOemScsi",
+ "0")) == 1);
+ }
+
+ BootPath = SlGetIniValue(InfFile,
+ "setupdata",
+ "BootPath",
+ NULL);
+ BootDevice = SlGetIniValue(InfFile,
+ "setupdata",
+ "BootDevice",
+ NULL);
+
+ return;
+}
+
+
+VOID
+BlOutputLoadMessage (
+ IN PCHAR DeviceName,
+ IN PCHAR FileName
+ )
+
+/*++
+
+Routine Description:
+
+ This routine outputs a loading message on the status line
+
+Arguments:
+
+ DeviceName - Supplies a pointer to a zero terminated device name.
+
+ FileName - Supplies a pointer to a zero terminated file name.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ CHAR OutputBuffer[256];
+ PCHAR FormatString;
+
+ //
+ // Construct and output loading file message.
+ //
+ FormatString = BlFindMessage(SL_FILE_LOAD_MESSAGE);
+ sprintf(OutputBuffer,FormatString,DeviceName);
+
+ SlWriteStatusText(OutputBuffer);
+
+ return;
+}
+
+
+
+ARC_STATUS
+SlLoadDriver(
+ IN PCHAR DeviceName,
+ IN PCHAR DriverName,
+ IN ULONG DriverFlags,
+ IN BOOLEAN InsertIntoDriverList
+ )
+
+/*++
+
+Routine Description:
+
+ Attempts to load a driver from the device identified by the global
+ variable BootDeviceId.
+
+Arguments:
+
+ DeviceName - Supplies the name of the device.
+
+ DriverName - Supplies the name of the driver.
+
+ DriverFlags - Flags to set in the LDR_DATA_TABLE_ENTRY.
+
+ InsertIntoDriverList - Flag specifying whether this 'driver' should be
+ placed into the BootDriveListHead list (eg, scsiport.sys
+ is not a true driver, and should not be placed in this list)
+
+Return Value:
+
+ ESUCCESS - Driver successfully loaded
+
+--*/
+
+{
+ PBOOT_DRIVER_LIST_ENTRY DriverEntry;
+ NTSTATUS Status;
+ CHAR DriverPath[128];
+ PLDR_DATA_TABLE_ENTRY DataTableEntry;
+
+ if(BlCheckForLoadedDll(DriverName,&DataTableEntry)) {
+ return(ESUCCESS);
+ }
+
+ DriverEntry = SlpCreateDriverEntry(DriverName);
+ if(DriverEntry == NULL) {
+ SlNoMemoryError();
+ return(ENOMEM);
+ }
+
+ SlGetDisk(DriverName);
+
+ strcpy(DriverPath,BootPath);
+
+ Status = BlLoadDeviceDriver(
+ BootDeviceId,
+ DeviceName,
+ DriverPath,
+ DriverName,
+ DriverFlags,
+ &DriverEntry->LdrEntry
+ );
+
+ if((Status == ESUCCESS) && InsertIntoDriverList) {
+ InsertTailList(&BlLoaderBlock->BootDriverListHead,&DriverEntry->Link);
+ }
+
+ return(Status);
+}
+
+
+
+ARC_STATUS
+SlLoadOemDriver(
+ IN PCHAR ExportDriver, OPTIONAL
+ IN PCHAR DriverName,
+ IN PVOID BaseAddress,
+ IN PCHAR LoadMessage
+ )
+{
+ PBOOT_DRIVER_LIST_ENTRY DriverEntry;
+ ARC_STATUS Status;
+ PLDR_DATA_TABLE_ENTRY DataTableEntry;
+
+ if(BlCheckForLoadedDll(DriverName,&DataTableEntry)) {
+ return(ESUCCESS);
+ }
+
+ if(ExportDriver) {
+ SlGetDisk(ExportDriver);
+ }
+
+ DriverEntry = SlpCreateDriverEntry(DriverName);
+ if (DriverEntry==NULL) {
+ return(ENOMEM);
+ }
+
+ Status = BlAllocateDataTableEntry(
+ DriverName,
+ DriverName,
+ BaseAddress,
+ &DriverEntry->LdrEntry
+ );
+
+ if (Status == ESUCCESS) {
+
+ Status = BlScanImportDescriptorTable(
+ BootDeviceId,
+ LoadMessage,
+ BootPath,
+ DriverEntry->LdrEntry
+ );
+
+ if(Status == ESUCCESS) {
+
+ InsertTailList(&BlLoaderBlock->BootDriverListHead,&DriverEntry->Link);
+ }
+ }
+
+ return(Status);
+}
+
+
+
+
+PBOOT_DRIVER_LIST_ENTRY
+SlpCreateDriverEntry(
+ IN PCHAR DriverName
+ )
+
+/*++
+
+Routine Description:
+
+ Allocates and initializes a boot driver list entry structure.
+
+Arguments:
+
+ DriverName - Supplies the name of the driver.
+
+Return Value:
+
+ Pointer to the initialized structure.
+
+--*/
+
+{
+ PBOOT_DRIVER_LIST_ENTRY DriverEntry;
+ ANSI_STRING String;
+
+ DriverEntry = BlAllocateHeap(sizeof(BOOT_DRIVER_LIST_ENTRY));
+ if (DriverEntry==NULL) {
+ SlNoMemoryError();
+ return(NULL);
+ }
+ DriverEntry->FilePath.MaximumLength = strlen(DriverName)*sizeof(WCHAR)+1;
+ DriverEntry->FilePath.Buffer = BlAllocateHeap(DriverEntry->FilePath.MaximumLength);
+ if (DriverEntry->FilePath.Buffer==NULL) {
+ SlNoMemoryError();
+ return(NULL);
+ }
+ String.Length = strlen(DriverName);
+ String.Buffer = DriverName;
+ RtlAnsiStringToUnicodeString(&DriverEntry->FilePath, &String, FALSE);
+
+ return(DriverEntry);
+}
+
+
+BOOLEAN
+SlGetDisk(
+ IN PCHAR Filename
+ )
+
+/*++
+
+Routine Description:
+
+ Given a filename, this routine ensures that the correct disk is
+ in the drive identified by the global variables BootDevice and
+ BootDeviceId. The user may be prompted to change disks.
+
+Arguments:
+
+ Filename - Supplies the name of the file to be loaded.
+
+Return Value:
+
+ TRUE - Disk was successfully loaded.
+
+ FALSE - User has cancelled out of Setup.
+
+--*/
+
+{
+ PCHAR DiskNumber;
+ PCHAR DiskName;
+ PCHAR DiskTag;
+ ULONG FileId;
+ CHAR PlatformSpecificSection[128];
+
+ //
+ // If the media is fixed, the user can't change disks.
+ // Just return TRUE indicating that the disk is in the drive.
+ //
+ if(FixedBootMedia) {
+ return(TRUE);
+ }
+
+ //
+ // Look up filename to get the disk number. Look in the platform-specific
+ // directory first.
+ //
+ strcpy(PlatformSpecificSection,FilesSectionName);
+ strcat(PlatformSpecificSection,PlatformExtension);
+
+#if defined(ELTORITO)
+ if (ElToritoCDBoot) {
+ // for Cd boot we use the setup media path instead of a boot-media-specific path
+ DiskNumber = SlGetSectionKeyIndex(InfFile,PlatformSpecificSection,Filename,0);
+ } else {
+#endif
+
+ DiskNumber = SlGetSectionKeyIndex(InfFile,PlatformSpecificSection,Filename,6);
+
+#if defined(ELTORITO)
+ }
+#endif
+
+ if(DiskNumber == NULL) {
+
+#if defined(ELTORITO)
+ if (ElToritoCDBoot) {
+ // for Cd boot we use the setup media path instead of a boot-media-specific path
+ DiskNumber = SlGetSectionKeyIndex(InfFile,FilesSectionName,Filename,0);
+ } else {
+#endif
+
+ DiskNumber = SlGetSectionKeyIndex(InfFile,FilesSectionName,Filename,6);
+
+#if defined(ELTORITO)
+ }
+#endif
+
+ }
+
+ if((DiskNumber==NULL) || !(*DiskNumber)) {
+ SlFatalError(SL_INF_ENTRY_MISSING,Filename,FilesSectionName);
+ return(FALSE);
+ }
+
+ //
+ // Look up disk number to get the diskname and tag.
+ // Look in platform-specific directory first.
+ //
+ strcpy(PlatformSpecificSection,MediaSectionName);
+ strcat(PlatformSpecificSection,PlatformExtension);
+
+ if(DiskName = SlGetSectionKeyIndex(InfFile,PlatformSpecificSection,DiskNumber,0)) {
+ DiskTag = SlGetSectionKeyIndex(InfFile,PlatformSpecificSection,DiskNumber,1);
+ } else {
+ if(DiskName = SlGetSectionKeyIndex(InfFile,MediaSectionName,DiskNumber,0)) {
+ DiskTag = SlGetSectionKeyIndex(InfFile,MediaSectionName,DiskNumber,1);
+ } else {
+ SlFatalError(SL_INF_ENTRY_MISSING,DiskNumber,MediaSectionName);
+ return(FALSE);
+ }
+ }
+
+ while(1) {
+
+ //
+ // Open a new device id onto the disk.
+ //
+ if(BootDeviceIdValid) {
+ ArcClose(BootDeviceId);
+ BootDeviceIdValid = FALSE;
+ }
+
+ if(ArcOpen(BootDevice,ArcOpenReadOnly,&BootDeviceId) == ESUCCESS) {
+
+ BootDeviceIdValid = TRUE;
+ //
+ // Check for existence of the disk tag.
+ //
+ if(BlOpen(BootDeviceId,DiskTag,ArcOpenReadOnly,&FileId) == ESUCCESS) {
+
+ //
+ // Disk is in the drive. Return success.
+ // Leave BootDeviceId open onto the device.
+ //
+ BlClose(FileId);
+ return(TRUE);
+
+ } else {
+
+ //
+ // Prompt for the user to change disks.
+ //
+ ArcClose(BootDeviceId);
+ BootDeviceIdValid = FALSE;
+
+ SlPromptForDisk(DiskName, FALSE);
+ }
+ } else {
+ //
+ // Can't open device. Prompt for the disk.
+ //
+ SlPromptForDisk(DiskName, FALSE);
+ }
+ }
+}
+
+
+PCHAR
+SlCopyString(
+ IN PCHAR String
+ )
+
+/*++
+
+Routine Description:
+
+ Copies a string into the loader heap so it can be passed to the
+ kernel.
+
+Arguments:
+
+ String - Supplies the string to be copied.
+
+Return Value:
+
+ PCHAR - pointer into the loader heap where the string was copied to.
+
+--*/
+
+{
+ PCHAR Buffer;
+
+ if (String==NULL) {
+ SlNoMemoryError();
+ }
+ Buffer = BlAllocateHeap(strlen(String)+1);
+ if (Buffer==NULL) {
+ SlNoMemoryError();
+ } else {
+ strcpy(Buffer, String);
+ }
+
+ return(Buffer);
+}
+
+
+ARC_STATUS
+SlLoadSection(
+ IN PVOID Inf,
+ IN PCHAR SectionName,
+ IN BOOLEAN IsScsiSection
+ )
+
+/*++
+
+Routine Description:
+
+ Enumerates all the drivers in a section and loads them.
+
+Arguments:
+
+ Inf - Supplies a handle to the INF file.
+
+ SectionName - Supplies the name of the section.
+
+ IsScsiSection - Flag specifying whether this is the Scsi.Load section.
+ If so, we create the DETECTED_DEVICE linked list, but
+ don't actually load the drivers.
+
+Return Value:
+
+ ESUCCESS if all drivers were loaded successfully/no errors encountered
+
+--*/
+
+{
+ ULONG i;
+ CHAR LoadSectionName[100];
+ PCHAR DriverFilename;
+ PCHAR DriverId;
+ PCHAR DriverDescription;
+ PCHAR NoLoadSpec;
+ PCHAR p;
+ ARC_STATUS Status;
+ PDETECTED_DEVICE ScsiDevice;
+ SCSI_INSERT_STATUS sis;
+
+ sprintf(LoadSectionName, "%s.Load",SectionName);
+
+ i=0;
+ do {
+ DriverFilename = SlGetSectionLineIndex(Inf,LoadSectionName,i,SIF_FILENAME_INDEX);
+ NoLoadSpec = SlGetSectionLineIndex(Inf,LoadSectionName,i,2);
+
+ if(DriverFilename && ((NoLoadSpec == NULL) || _stricmp(NoLoadSpec,"noload"))) {
+
+ if(!IsScsiSection) {
+ //
+ // We only want to load the drivers if they aren't scsi miniports
+ //
+ DriverId = SlGetKeyName(Inf,LoadSectionName,i);
+ DriverDescription = SlGetIniValue(Inf,SectionName,DriverId,"noname");
+ Status = SlLoadDriver(DriverDescription,
+ DriverFilename,
+ 0,
+ TRUE
+ );
+
+ if((Status == ENOENT) && IgnoreMissingFiles) {
+ Status = ESUCCESS;
+ }
+ } else {
+ Status = ESUCCESS;
+ }
+
+ if (Status == ESUCCESS) {
+
+ if(IsScsiSection) {
+
+ //
+ // Create a new detected device entry.
+ //
+ if((sis = SlInsertScsiDevice(i, &ScsiDevice)) == ScsiInsertError) {
+ return(ENOMEM);
+ }
+
+ if(sis == ScsiInsertExisting) {
+#if DBG
+ //
+ // Sanity check to make sure we're talking about the same driver
+ //
+ if(_strcmpi(ScsiDevice->BaseDllName, DriverFilename)) {
+ SlError(400);
+ return EINVAL;
+ }
+#endif
+ } else {
+ p = SlGetKeyName(Inf,LoadSectionName,i);
+
+ //
+ // Find the driver description
+ //
+ if(p) {
+ DriverDescription = SlGetIniValue(Inf,
+ SectionName,
+ p,
+ p);
+ } else {
+ DriverDescription = SlCopyString(BlFindMessage(SL_TEXT_SCSI_UNNAMED));
+ }
+
+ ScsiDevice->IdString = p ? p : SlCopyString("");
+ ScsiDevice->Description = DriverDescription;
+ ScsiDevice->ThirdPartyOptionSelected = FALSE;
+ ScsiDevice->FileTypeBits = 0;
+ ScsiDevice->Files = NULL;
+ ScsiDevice->BaseDllName = DriverFilename;
+ }
+ }
+ } else {
+ SlFriendlyError(
+ Status,
+ DriverFilename,
+ __LINE__,
+ __FILE__
+ );
+ return(Status);
+ }
+ }
+
+ i++;
+
+ } while ( DriverFilename != NULL );
+
+ return(ESUCCESS);
+
+}
+
+
+VOID
+SlpMarkDisks(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine ensures that there is not more than one disk with the
+ same checksum, a signature of zero, and a valid partition table.
+
+ If it finds a disk with a signature of zero, it searches the rest
+ of the list for any other disks with a zero signature and the same
+ checksum. If it finds one, it stamps a unique signature on the
+ first disk.
+
+ We also use a heuristic to determine if the disk is 'vacant', and if
+ so, we stamp a unique signature on it (unless it's the first one we
+ found).
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PARC_DISK_INFORMATION DiskInfo;
+ PLIST_ENTRY Entry;
+ PLIST_ENTRY CheckEntry;
+ PARC_DISK_SIGNATURE DiskSignature;
+ PARC_DISK_SIGNATURE CheckSignature;
+ ARC_STATUS Status;
+ BOOLEAN VacantDiskFound = FALSE;
+
+ DiskInfo = BlLoaderBlock->ArcDiskInformation;
+ Entry = DiskInfo->DiskSignatures.Flink;
+ while (Entry != &DiskInfo->DiskSignatures) {
+ DiskSignature = CONTAINING_RECORD(Entry,ARC_DISK_SIGNATURE,ListEntry);
+
+ if (DiskSignature->ValidPartitionTable) {
+
+ if (DiskSignature->Signature==0) {
+ //
+ // Check the rest of the list to see if there is another
+ // disk with the same checksum and an signature of zero.
+ //
+ CheckEntry = Entry->Flink;
+ while (CheckEntry != &DiskInfo->DiskSignatures) {
+ CheckSignature = CONTAINING_RECORD(CheckEntry,ARC_DISK_SIGNATURE,ListEntry);
+ if ((CheckSignature->Signature==0) &&
+ (CheckSignature->ValidPartitionTable) &&
+ (CheckSignature->CheckSum == DiskSignature->CheckSum)) {
+
+ //
+ // We have two disks that are indistinguishable, both do
+ // not have signatures. Mark the first one with a signature
+ // so that they can be differentiated by textmode setup.
+ //
+ Status = SlpStampFTSignature(DiskSignature);
+ if (Status != ESUCCESS) {
+ SlError(Status);
+ }
+ break;
+ } else {
+ CheckEntry = CheckEntry->Flink;
+ }
+ }
+ }
+ } else {
+ //
+ // See if the disk is vacant, to find out whether we can mess with it.
+ //
+ if (SlpIsDiskVacant(DiskSignature)) {
+ //
+ // stamp all but the first one.
+ //
+ if (VacantDiskFound) {
+
+ Status = SlpStampFTSignature(DiskSignature);
+ if (Status != ESUCCESS) {
+ SlError(Status);
+ }
+
+ } else {
+ VacantDiskFound = TRUE;
+ }
+ }
+ }
+
+ Entry = Entry->Flink;
+ }
+
+}
+
+
+BOOLEAN
+SlpIsDiskVacant(
+ IN PARC_DISK_SIGNATURE DiskSignature
+ )
+
+/*++
+
+Routine Description:
+
+ This routine attempts to determine if a disk is 'vacant' by
+ checking to see if the first half of its MBR has all bytes set
+ to the same value.
+
+Arguments:
+
+ DiskSignature - Supplies a pointer to the existing disk
+ signature structure.
+
+Return Value:
+
+ TRUE - The disk is vacant.
+ FALSE - The disk is not vacant (ie, we can't determine if it
+ is vacant using our heuristic)
+
+--*/
+{
+ UCHAR Partition[100];
+ ULONG DiskId;
+ ARC_STATUS Status;
+ UCHAR SectorBuffer[512+256];
+ PUCHAR Sector;
+ LARGE_INTEGER SeekValue;
+ ULONG Count, i;
+ BOOLEAN IsVacant;
+
+ //
+ // Open partition0.
+ //
+ strcpy(Partition, DiskSignature->ArcName);
+ strcat(Partition, "partition(0)");
+ Status = ArcOpen(Partition, ArcOpenReadOnly, &DiskId);
+ if (Status != ESUCCESS) {
+ return(FALSE);
+ }
+
+ //
+ // Read in the first sector
+ //
+ Sector = ALIGN_BUFFER(SectorBuffer);
+ SeekValue.QuadPart = 0;
+ Status = ArcSeek(DiskId, &SeekValue, SeekAbsolute);
+ if (Status == ESUCCESS) {
+ Status = ArcRead(DiskId, Sector, 512, &Count);
+ }
+ if (Status != ESUCCESS) {
+ ArcClose(DiskId);
+ return(FALSE);
+ }
+
+ //
+ // See if 1st 256 bytes are identical
+ //
+ for(i = 1, IsVacant = TRUE; i<256; i++) {
+ if(Sector[i] - *Sector) {
+ IsVacant = FALSE;
+ break;
+ }
+ }
+
+ ArcClose(DiskId);
+
+ return(IsVacant);
+}
+
+
+
+ARC_STATUS
+SlpStampFTSignature(
+ IN PARC_DISK_SIGNATURE DiskSignature
+ )
+
+/*++
+
+Routine Description:
+
+ This routine stamps a given drive with a unique signature.
+ It traverses the list of disk signatures to ensure that it
+ stamps a signature that is not already present in the
+ disk list. Then it writes the new disk signature to the
+ disk and recomputes the checksum.
+
+Arguments:
+
+ DiskSignature - Supplies a pointer to the existing disk
+ signature structure.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ULONG NewSignature;
+ PLIST_ENTRY ListEntry;
+ UCHAR SectorBuffer[512+256];
+ PUCHAR Sector;
+ LARGE_INTEGER SeekValue;
+ UCHAR Partition[100];
+ PARC_DISK_SIGNATURE Signature;
+ ULONG DiskId;
+ ARC_STATUS Status;
+ ULONG i;
+ ULONG Sum;
+ ULONG Count;
+
+ //
+ // Get a reasonably unique seed to start with.
+ //
+ NewSignature = ArcGetRelativeTime();
+
+ //
+ // Scan through the list to make sure it's unique.
+ //
+ReScan:
+ ListEntry = BlLoaderBlock->ArcDiskInformation->DiskSignatures.Flink;
+ while (ListEntry != &BlLoaderBlock->ArcDiskInformation->DiskSignatures) {
+ Signature = CONTAINING_RECORD(ListEntry,ARC_DISK_SIGNATURE,ListEntry);
+ if (Signature->Signature == NewSignature) {
+ //
+ // Found a duplicate, pick a new number and
+ // try again.
+ //
+ if (++NewSignature == 0) {
+ //
+ // zero signatures are what we're trying to avoid
+ // (like this will ever happen)
+ //
+ NewSignature = 1;
+ }
+ goto ReScan;
+ }
+ ListEntry = ListEntry->Flink;
+ }
+
+ //
+ // Now we have a valid new signature to put on the disk.
+ // Read the sector off disk, put the new signature in,
+ // write the sector back, and recompute the checksum.
+ //
+ strcpy(Partition,DiskSignature->ArcName);
+ strcat(Partition,"partition(0)");
+ Status = ArcOpen(Partition, ArcOpenReadWrite, &DiskId);
+ if (Status != ESUCCESS) {
+ return(Status);
+ }
+
+ //
+ // Read in the first sector
+ //
+ Sector = ALIGN_BUFFER(SectorBuffer);
+ SeekValue.QuadPart = 0;
+ Status = ArcSeek(DiskId, &SeekValue, SeekAbsolute);
+ if (Status == ESUCCESS) {
+ Status = ArcRead(DiskId,Sector,512,&Count);
+ }
+ if (Status != ESUCCESS) {
+ ArcClose(DiskId);
+ return(Status);
+ }
+ ((PULONG)Sector)[PARTITION_TABLE_OFFSET/2-1] = NewSignature;
+
+ Status = ArcSeek(DiskId, &SeekValue, SeekAbsolute);
+ if (Status == ESUCCESS) {
+ Status = ArcWrite(DiskId,Sector,512,&Count);
+ }
+ ArcClose(DiskId);
+ if (Status != ESUCCESS) {
+ return(Status);
+ }
+
+ //
+ // We have successfully written back out the new signature,
+ // recompute the checksum.
+ //
+ DiskSignature->Signature = NewSignature;
+ Sum = 0;
+ for (i=0;i<128;i++) {
+ Sum += ((PULONG)Sector)[i];
+ }
+ DiskSignature->CheckSum = 0-Sum;
+
+ return(ESUCCESS);
+
+}
+
+
+VOID
+SlCheckOemKeypress(
+ VOID
+ )
+{
+
+ ULONG StartTime;
+ ULONG EndTime;
+ ULONG c;
+
+ StartTime = ArcGetRelativeTime();
+ EndTime = StartTime + 3;
+ do {
+ if(ArcGetReadStatus(ARC_CONSOLE_INPUT) == ESUCCESS) {
+ //
+ // There is a key pending, so see what it is.
+ //
+ c = SlGetChar();
+
+ switch(c) {
+
+ case SL_KEY_F5: // Force OEM HAL prompt
+ PromptOemHal = TRUE;
+ break;
+
+ case SL_KEY_F6: // Force OEM SCSI prompt
+ PromptOemScsi = TRUE;
+ }
+ }
+
+ } while (EndTime > ArcGetRelativeTime());
+}
+
+
+SCSI_INSERT_STATUS
+SlInsertScsiDevice(
+ IN ULONG Ordinal,
+ OUT PDETECTED_DEVICE *pScsiDevice
+ )
+/*++
+
+Routine Description:
+
+ This routine
+
+Arguments:
+
+ Ordinal - Supplies the 0-based ordinal of the Scsi device
+ to insert (based on order listed in [Scsi.Load]
+ section of txtsetup.sif). If the Scsi device is a third party
+ driver, then Ordinal is -1.
+
+ pScsiDevice - Receives a pointer to the inserted DETECTED_DEVICE structure,
+ the existing structure, or NULL.
+Return Value:
+
+ ScsiInsertError - Not enough memory to allocate a new DETECTED_DEVICE.
+ ScsiInsertNewEntry - A new entry was inserted into the DETECTED_DEVICE list.
+ ScsiInsertExisting - An existing entry was found that matched the specified
+ ordinal, so we returned this entry.
+
+--*/
+{
+ PDETECTED_DEVICE prev, cur;
+
+ if(Ordinal == (ULONG)-1) {
+ //
+ // This is a third-party driver, so find the end of the linked list
+ // (we want to preserve the order in which the user specifies the drivers).
+ //
+ for(prev=BlLoaderBlock->SetupLoaderBlock->ScsiDevices, cur = NULL;
+ prev && prev->Next;
+ prev=prev->Next);
+
+ } else {
+ //
+ // Find the insertion point in the linked list for this driver,
+ // based on its ordinal. (Note that we will insert all supported drivers
+ // before any third-party ones, since (ULONG)-1 = maximum unsigned long value)
+ //
+ for(prev = NULL, cur = BlLoaderBlock->SetupLoaderBlock->ScsiDevices;
+ cur && (Ordinal > cur->Ordinal);
+ prev = cur, cur = cur->Next);
+ }
+
+ if(cur && (cur->Ordinal == Ordinal)) {
+ //
+ // We found an existing entry for this driver
+ //
+ *pScsiDevice = cur;
+ return ScsiInsertExisting;
+ }
+
+ if(!(*pScsiDevice = BlAllocateHeap(sizeof(DETECTED_DEVICE)))) {
+ return ScsiInsertError;
+ }
+
+ (*pScsiDevice)->Next = cur;
+ if(prev) {
+ prev->Next = *pScsiDevice;
+ } else {
+ BlLoaderBlock->SetupLoaderBlock->ScsiDevices = *pScsiDevice;
+ }
+
+ (*pScsiDevice)->Ordinal = Ordinal;
+
+ return ScsiInsertNewEntry;
+}
+
+
+ARC_STATUS
+SlLoadBusExtender(
+ IN PVOID Inf
+ )
+
+/*++
+
+Routine Description:
+
+ Loads all known extender drivers.
+
+Arguments:
+
+ Inf - Supplies a handle to the INF file.
+
+
+Return Value:
+
+ ESUCCESS if all drivers were loaded successfully/no errors encountered
+
+--*/
+
+{
+ return( SlLoadSection(Inf,"Extenders",FALSE) );
+}
+
diff --git a/private/ntos/boot/setup/setupldr.h b/private/ntos/boot/setup/setupldr.h
new file mode 100644
index 000000000..42b920a27
--- /dev/null
+++ b/private/ntos/boot/setup/setupldr.h
@@ -0,0 +1,550 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ setupldr.h
+
+Abstract:
+
+ Common header file for the setupldr module
+
+Author:
+
+ John Vert (jvert) 6-Oct-1993
+
+Environment:
+
+ ARC environment
+
+Revision History:
+
+--*/
+#include "bldr.h"
+#include "setupblk.h"
+#include "msgs.h"
+#include "stdio.h"
+#include "stdarg.h"
+
+//
+//
+// Functions for managing the display
+//
+//
+
+VOID
+SlSetCurrentAttribute(
+ IN UCHAR Attribute
+ );
+
+ARC_STATUS
+SlWriteString(
+ IN PUCHAR s
+ );
+
+ARC_STATUS
+SlPositionCursor(
+ IN unsigned x,
+ IN unsigned y
+ );
+
+VOID
+SlGetCursorPosition(
+ OUT unsigned *x,
+ OUT unsigned *y
+ );
+
+ARC_STATUS
+SlClearClientArea(
+ VOID
+ );
+
+ARC_STATUS
+SlClearToEol(
+ VOID
+ );
+
+VOID
+SlInitDisplay(
+ VOID
+ );
+
+VOID
+SlWriteHeaderText(
+ IN ULONG MsgId
+ );
+
+VOID
+SlSetStatusAttribute(
+ IN UCHAR Attribute
+ );
+
+VOID
+SlWriteStatusText(
+ IN PCHAR Text
+ );
+
+VOID
+SlGetStatusText(
+ OUT PCHAR Text
+ );
+
+VOID
+SlSetCopyingStatus(
+ IN PCHAR Filename,
+ IN PCHAR StatusVerb
+ );
+
+VOID
+SlClearDisplay(
+ VOID
+ );
+
+VOID
+SlPrint(
+ IN PCHAR FormatString,
+ ...
+ );
+
+VOID
+SlConfirmExit(
+ VOID
+ );
+
+
+BOOLEAN
+SlPromptForDisk(
+ IN PCHAR DiskName,
+ IN BOOLEAN IsCancellable
+ );
+
+BOOLEAN
+SlGetDisk(
+ IN PCHAR Filename
+ );
+
+//
+// Menuing support
+//
+typedef struct _SL_MENU {
+ ULONG ItemCount;
+ ULONG Width;
+ LIST_ENTRY ItemListHead;
+} SL_MENU, *PSL_MENU;
+
+typedef struct _SL_MENUITEM {
+ LIST_ENTRY ListEntry;
+ PCHAR Text;
+ PVOID Data;
+ ULONG Attributes;
+} SL_MENUITEM, *PSL_MENUITEM;
+
+PSL_MENU
+SlCreateMenu(
+ VOID
+ );
+
+ULONG
+SlAddMenuItem(
+ PSL_MENU Menu,
+ PCHAR Text,
+ PVOID Data,
+ ULONG Attributes
+ );
+
+PVOID
+SlGetMenuItem(
+ IN PSL_MENU Menu,
+ IN ULONG Item
+ );
+
+ULONG
+SlDisplayMenu(
+ IN ULONG HeaderId,
+ IN PSL_MENU Menu,
+ IN OUT PULONG Selection
+ );
+
+BOOLEAN
+SlGetMenuItemIndex(
+ IN PSL_MENU Menu,
+ IN PCHAR Text,
+ OUT PULONG Index
+ );
+
+//
+// Bullet character and macro to make a beep at the console
+//
+#define BULLET "*"
+#define BEEP { ULONG c; ArcWrite(ARC_CONSOLE_OUTPUT,"",1,&c); }
+
+#if 0
+#define BULLET ""
+#define BEEP HWCURSOR(0x80000000,0xe07); // int 10 func e, char 7
+#endif
+
+
+//
+// Character attributes used for various purposes.
+//
+
+#define ATT_FG_BLACK 0
+#define ATT_FG_RED 1
+#define ATT_FG_GREEN 2
+#define ATT_FG_YELLOW 3
+#define ATT_FG_BLUE 4
+#define ATT_FG_MAGENTA 5
+#define ATT_FG_CYAN 6
+#define ATT_FG_WHITE 7
+
+#define ATT_BG_BLACK (ATT_FG_BLACK << 4)
+#define ATT_BG_BLUE (ATT_FG_BLUE << 4)
+#define ATT_BG_GREEN (ATT_FG_GREEN << 4)
+#define ATT_BG_CYAN (ATT_FG_CYAN << 4)
+#define ATT_BG_RED (ATT_FG_RED << 4)
+#define ATT_BG_MAGENTA (ATT_FG_MAGENTA << 4)
+#define ATT_BG_YELLOW (ATT_FG_YELLOW << 4)
+#define ATT_BG_WHITE (ATT_FG_WHITE << 4)
+
+#define ATT_FG_INTENSE 8
+#define ATT_BG_INTENSE (ATT_FG_INTENSE << 4)
+#define DEFATT (ATT_FG_WHITE | ATT_BG_BLUE)
+#define INVATT (ATT_FG_BLUE | ATT_BG_WHITE)
+#define DEFIATT (ATT_FG_WHITE | ATT_BG_BLUE | ATT_FG_INTENSE)
+// intense red on blue doesn't show up on all monitors.
+//#define DEFERRATT (ATT_FG_RED | ATT_BG_BLUE | ATT_FG_INTENSE)
+#define DEFERRATT DEFATT
+#define DEFSTATTR (ATT_FG_BLACK | ATT_BG_WHITE)
+#define DEFDLGATT (ATT_FG_RED | ATT_BG_WHITE)
+
+
+//
+// Function to flush keyboard buffer
+//
+
+VOID
+SlFlushConsoleBuffer(
+ VOID
+ );
+
+
+//
+// Function to retrieve a keystroke
+//
+
+ULONG
+SlGetChar(
+ VOID
+ );
+
+
+//
+// Virtualized contants for various keystrokes
+//
+#define ASCI_BS 8
+#define ASCI_CR 13
+#define ASCI_LF 10
+#define ASCI_ESC 27
+#define SL_KEY_UP 0x00010000
+#define SL_KEY_DOWN 0x00020000
+#define SL_KEY_HOME 0x00030000
+#define SL_KEY_END 0x00040000
+#define SL_KEY_PAGEUP 0x00050000
+#define SL_KEY_PAGEDOWN 0x00060000
+#define SL_KEY_F1 0x01000000
+#define SL_KEY_F3 0x03000000
+#define SL_KEY_F5 0x05000000
+#define SL_KEY_F6 0x06000000
+
+
+//
+// Standard error handling functions
+//
+#if DEVL
+
+#define SlError(x) SlMessageBox(SL_WARNING_ERROR, x , __LINE__, __FILE__ )
+#define SlNoMemoryError() SlFatalError(SL_NO_MEMORY, __LINE__,__FILE__)
+
+#else
+
+#define SlError(x)
+
+#endif
+
+extern CHAR MessageBuffer[1024];
+
+VOID
+SlFriendlyError(
+ IN ULONG uStatus,
+ IN PCHAR pchBadFile,
+ IN ULONG uLine,
+ IN PCHAR pchCodeFile
+ );
+
+ULONG
+SlDisplayMessageBox(
+ IN ULONG MessageId,
+ ...
+ );
+
+VOID
+SlGenericMessageBox(
+ IN ULONG MessageId, OPTIONAL
+ IN va_list *args, OPTIONAL
+ IN PCHAR Message, OPTIONAL
+ IN OUT PULONG xLeft, OPTIONAL
+ IN OUT PULONG yTop, OPTIONAL
+ OUT PULONG yBottom, OPTIONAL
+ IN BOOLEAN bCenterMsg
+ );
+
+VOID
+SlMessageBox(
+ IN ULONG MessageId,
+ ...
+ );
+
+VOID
+SlFatalError(
+ IN ULONG MessageId,
+ ...
+ );
+
+//
+// Routines for parsing the setupldr.ini file
+//
+
+#define SIF_FILENAME_INDEX 0
+
+extern PVOID InfFile;
+extern PVOID WinntSifHandle;
+
+ARC_STATUS
+SlInitIniFile(
+ IN PCHAR DevicePath,
+ IN ULONG DeviceId,
+ IN PCHAR INFFile,
+ OUT PVOID *pINFHandle,
+ OUT PULONG ErrorLine
+ );
+
+PCHAR
+SlGetIniValue(
+ IN PVOID InfHandle,
+ IN PCHAR SectionName,
+ IN PCHAR KeyName,
+ IN PCHAR Default
+ );
+
+PCHAR
+SlGetKeyName(
+ IN PVOID INFHandle,
+ IN PCHAR SectionName,
+ IN ULONG LineIndex
+ );
+
+ULONG
+SlGetSectionKeyOrdinal(
+ IN PVOID INFHandle,
+ IN PCHAR SectionName,
+ IN PCHAR Key
+ );
+
+PCHAR
+SlGetSectionKeyIndex (
+ IN PVOID INFHandle,
+ IN PCHAR SectionName,
+ IN PCHAR Key,
+ IN ULONG ValueIndex
+ );
+
+PCHAR
+SlCopyString(
+ IN PCHAR String
+ );
+
+PCHAR
+SlGetSectionLineIndex (
+ IN PVOID INFHandle,
+ IN PCHAR SectionName,
+ IN ULONG LineIndex,
+ IN ULONG ValueIndex
+ );
+
+ULONG
+SlCountLinesInSection(
+ IN PVOID INFHandle,
+ IN PCHAR SectionName
+ );
+
+BOOLEAN
+SpSearchINFSection (
+ IN PVOID INFHandle,
+ IN PCHAR SectionName
+ );
+
+//
+// functions for querying the ARC configuration tree
+//
+typedef
+BOOLEAN
+(*PNODE_CALLBACK)(
+ IN PCONFIGURATION_COMPONENT_DATA FoundComponent
+ );
+
+BOOLEAN
+SlSearchConfigTree(
+ IN PCONFIGURATION_COMPONENT_DATA Node,
+ IN CONFIGURATION_CLASS Class,
+ IN CONFIGURATION_TYPE Type,
+ IN ULONG Key,
+ IN PNODE_CALLBACK CallbackRoutine
+ );
+
+BOOLEAN
+SlFindFloppy(
+ IN ULONG FloppyNumber,
+ OUT PCHAR ArcName
+ );
+
+//
+// Routines for detecting various hardware
+//
+PCHAR
+SlDetectHal(
+ IN PSETUP_LOADER_BLOCK SetupBlock
+ );
+
+VOID
+SlDetectScsi(
+ IN PSETUP_LOADER_BLOCK SetupBlock
+ );
+
+VOID
+SlDetectVideo(
+ IN PSETUP_LOADER_BLOCK SetupBlock
+ );
+
+//
+// Routines for dealing with OEM disks.
+//
+extern BOOLEAN PromptOemHal;
+extern BOOLEAN PromptOemScsi;
+extern BOOLEAN PromptOemVideo;
+
+typedef struct _OEMSCSIINFO {
+
+ struct _OEMSCSIINFO *Next;
+
+ //
+ // Address where the SCSI driver was loaded
+ //
+ PVOID ScsiBase;
+
+ //
+ // Name of the SCSI driver
+ //
+ PCHAR ScsiName;
+
+} OEMSCSIINFO, *POEMSCSIINFO;
+
+VOID
+SlPromptOemVideo(
+ OUT PVOID *VideoBase,
+ OUT PCHAR *VideoName
+ );
+
+VOID
+SlPromptOemHal(
+ OUT PVOID *HalBase,
+ OUT PCHAR *ImageName
+ );
+
+
+VOID
+SlPromptOemScsi(
+ OUT POEMSCSIINFO *pOemScsiInfo
+ );
+
+//
+// Routine to find the ARC name of a floppy
+//
+BOOLEAN
+SlpFindFloppy(
+ IN ULONG Number,
+ OUT PCHAR ArcName
+ );
+
+
+//
+// Enums for controlling setupldr process
+//
+typedef enum _SETUP_TYPE {
+ SetupInteractive,
+ SetupRepair,
+ SetupCustom,
+ SetupUpgrade,
+ SetupExpress
+} SETUP_TYPE;
+
+typedef enum _MEDIA_TYPE {
+ MediaInteractive,
+ MediaFloppy,
+ MediaCdRom,
+ MediaDisk
+} MEDIA_TYPE;
+
+//
+// Enum for status of inserting a new SCSI device
+//
+typedef enum _SCSI_INSERT_STATUS {
+ ScsiInsertError,
+ ScsiInsertNewEntry,
+ ScsiInsertExisting
+} SCSI_INSERT_STATUS;
+
+//
+// Routine to insert a DETECTED_DEVICE into its
+// correct position in the ScsiDevices linked list.
+//
+SCSI_INSERT_STATUS
+SlInsertScsiDevice(
+ IN ULONG Ordinal,
+ OUT PDETECTED_DEVICE *pScsiDevice
+ );
+
+//
+// Variables dealing with pre-installation.
+//
+
+typedef struct _PREINSTALL_DRIVER_INFO {
+
+ struct _PREINSTALL_DRIVER_INFO *Next;
+
+ //
+ // String that describes the driver to preinstall
+ //
+ PCHAR DriverDescription;
+
+ //
+ // Name of the SCSI driver
+ //
+ BOOLEAN OemDriver;
+
+} PREINSTALL_DRIVER_INFO, *PPREINSTALL_DRIVER_INFO;
+
+
+
+extern BOOLEAN PreInstall;
+extern PCHAR ComputerType;
+extern BOOLEAN OemHal;
+// extern PCHAR OemBootPath;
+extern PPREINSTALL_DRIVER_INFO PreinstallDriverList;
+
+PCHAR
+SlPreInstallGetComponentName(
+ IN PVOID Inf,
+ IN PCHAR SectionName,
+ IN PCHAR TargetName
+ );
diff --git a/private/ntos/boot/setup/setupldr.rc b/private/ntos/boot/setup/setupldr.rc
new file mode 100644
index 000000000..39d3683a7
--- /dev/null
+++ b/private/ntos/boot/setup/setupldr.rc
@@ -0,0 +1,16 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Setup Loader"
+#define VER_INTERNALNAME_STR "setupldr.exe"
+
+#include "common.ver"
+
+//
+// message text
+//
+#include "msgs.rc"
+
diff --git a/private/ntos/boot/setup/sources b/private/ntos/boot/setup/sources
new file mode 100644
index 000000000..77a25bf54
--- /dev/null
+++ b/private/ntos/boot/setup/sources
@@ -0,0 +1,47 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=setupldr
+
+TARGETNAME=setupldr
+TARGETPATH=obj
+TARGETTYPE=LIBRARY
+
+INCLUDES=\nt\public\sdk\inc;..\inc;..\..\inc;..\..\config;..\..\nthals
+
+C_DEFINES=$(C_DEFINES) -D_NTSYSTEM_
+
+SOURCES=arcdisp.c \
+ config.c \
+ oemdisk.c \
+ setup.c \
+ parseini.c \
+ setupldr.rc
+
+NTTARGETFILE0=msgs.h msgs.rc
+
+UMLIBS=..\obj\*\boot.lib
+UMRES=obj\*\setupldr.res
+
diff --git a/private/ntos/boot/startup/16bitbld.cmd b/private/ntos/boot/startup/16bitbld.cmd
new file mode 100644
index 000000000..49124f449
--- /dev/null
+++ b/private/ntos/boot/startup/16bitbld.cmd
@@ -0,0 +1,9 @@
+setlocal
+cd obj\i386
+out startup.com
+del startup.com
+cd ..\..
+path %SystemRoot%\mstools;\\kernel\razzle3\os2sup\oak\bin;\\kernel\razzle3\os2sup\sdk\bin;%path%
+set NTVERSION=
+nmake
+endlocal
diff --git a/private/ntos/boot/startup/i386/a20.asm b/private/ntos/boot/startup/i386/a20.asm
new file mode 100644
index 000000000..343588d1e
--- /dev/null
+++ b/private/ntos/boot/startup/i386/a20.asm
@@ -0,0 +1,359 @@
+; NOTICE
+; This was taken from the os2 bios sources and was slightly modified to
+; enable the a20 line. There's still some work to do and much clean-up to
+; bring the file upto coding standards. I'll do this when time permits.
+; TomP
+
+
+;* _EnableA20
+;* Description: *
+;* This routine enables and disables the A20 address line, depending on *
+;* the value in ax *
+;* *
+;* In general when in real mode we want the A20 line disabled, *
+;* when in protected mode enabled. However if there is no high *
+;* memory installed we can optimise out unnecessary switching *
+;* of the A20 line. Unfortunately the PC/AT ROM does not allow *
+;* us to completely decouple mode switching the 286 from gating *
+;* the A20 line. *
+;* *
+;* In real mode we would want A20 enabled if we need to access *
+;* high memory, for example in a device driver. We want it *
+;* disabled while running arbitrary applications because they *
+;* may rely on the 1 meg address wrap feature which having the *
+;* A20 line off provides. *
+;* *
+;* This code is largely duplicated from the PC/AT ROM BIOS. *
+;* See Module "BIOS1" on page 5-155 of the PC/AT tech ref. *
+;* *
+;* WARNING: *
+;* *
+;* The performance characteristics of these routines *
+;* are not well understood. There may be worst case *
+;* scenarios where the routine could take a relatively *
+;* long time to complete. *
+;* *
+;* Linkage: *
+;* far call *
+;* *
+;* Input: *
+;* *
+;* Exit: *
+;* A20 line enabled/disabled *
+;* *
+;* Uses: *
+;* ax *
+;* *
+;* Internal References: *
+;* empty_8042 -- waits for 8042 input buffer to drain *
+
+.386p
+include su.inc
+
+IODelay macro
+ jmp $+2
+ endm
+
+extrn _puts:near
+
+
+; Equates for cmos
+
+CMOS_DATA equ 71h ; I/O word for cmos chip
+SHUT_ADDR equ 8fh ; shutdown byte address in cmos
+SHUT_CODE equ 9 ; block copy return code we use
+
+
+; equates for 8042
+STATUS_PORT equ 64h ; 8042 com port
+PORT_A equ 60h ; 8042 data port
+BUF_FULL equ 2 ; 8042 busy bit
+
+
+SHUT_CMD equ 0feh ; RESET 286 command
+
+MSW_VIRTUAL equ 1 ; protected mode bit of MSW
+
+MASTER_IMR equ 21h ; mask port for master 8259
+
+
+_DATA SEGMENT PARA USE16 PUBLIC 'DATA'
+err_empty8042 db 'Internal Error in empty_8042: 8042 input buffer full', 10, 0ah
+
+_DATA ENDS
+;CONST SEGMENT WORD USE16 PUBLIC 'CONST'
+;CONST ENDS
+
+;_BSS SEGMENT WORD USE16 PUBLIC 'BSS'
+;_BSS ENDS
+
+;DGROUP GROUP CONST, _BSS, _DATA
+; ASSUME CS: _TEXT, DS: DGROUP, SS: DGROUP
+
+_TEXT segment para use16 public 'CODE'
+ ASSUME CS: _TEXT, DS: DGROUP, SS: DGROUP
+
+;++
+;
+;VOID
+;EnableMcaA20(
+; VOID
+; )
+;
+;Routine Description:
+;
+; Enables the A20 line for a Microchannel machine
+;
+;Arguments:
+;
+; None
+;
+;Return Value:
+;
+; None.
+;
+; The A20 line is enabled.
+;
+;--
+ public _EnableMcaA20
+
+_EnableMcaA20 proc near
+
+ in al, 92h
+ jmp $+2
+ or al, 02h
+
+ out 92h, al
+ jmp $+2
+
+ ret
+
+_EnableMcaA20 endp
+
+
+;++
+;
+;VOID
+;EnableA20(
+; VOID
+; )
+;
+;Routine Description:
+;
+; Enables the A20 line for any machine. If the MachineType global variable
+; is set to MCA, then it will call the EnableMcaA20 routine. If not, it
+; will execute the ISA code for enabling the A20 line.
+;
+;Arguments:
+;
+; None
+;
+;Return Value:
+;
+; None.
+;
+; The A20 line is enabled.
+;
+;--
+ public _EnableA20
+
+_EnableA20 proc near
+
+extrn _MachineType:dword
+
+ test dword ptr _MachineType,MACHINE_TYPE_MCA
+ jz EA0
+
+;
+; This is an MCA machine, so we use the special MCA routine
+;
+ call _EnableMcaA20
+ ret
+
+EA0:
+ mov ah,0dfh ; (AH) = Code for enable
+ call empty_8042 ; ensure 8042 input buffer empty
+ jnz EA2 ; 8042 error return
+
+
+; Enable or disable the A20 line
+
+ mov al,0d1h ; 8042 cmd to write output port
+ out STATUS_PORT,al ; send cmd to 8042
+ call empty_8042 ; wait for 8042 to accept cmd
+ jnz EA2 ; 8042 error return
+ mov al,ah ; 8042 port data
+ out PORT_A,al ; output port data to 8042
+ call empty_8042
+
+; We must wait for the a20 line to settle down, which (on an AT)
+; may not happen until up to 20 usec after the 8042 has accepted
+; the command. We make use of the fact that the 8042 will not
+; accept another command until it is finished with the last one.
+; The 0FFh command does a NULL 'Pulse Output Port'. Total execution
+; time is on the order of 30 usec, easily satisfying the IBM 8042
+; settling requirement. (Thanks, CW!)
+
+ mov al,0FFh ;* Pulse Output Port (pulse no lines)
+ out STATUS_PORT,al ;* send cmd to 8042
+ call empty_8042 ;* wait for 8042 to accept cmd
+
+EA2:
+ ret
+
+_EnableA20 endp
+
+
+;++
+;
+;VOID
+;DisableMcaA20(
+; VOID
+; )
+;
+;Routine Description:
+;
+; Disables the A20 line for a Microchannel machine
+;
+;Arguments:
+;
+; None
+;
+;Return Value:
+;
+; None.
+;
+; The A20 line is disabled.
+;
+;--
+ public _DisableMcaA20
+
+_DisableMcaA20 proc near
+
+ in al, 92h
+ jmp $+2
+ and al, not 02h
+
+ out 92h, al
+ jmp $+2
+
+ ret
+
+_DisableMcaA20 endp
+
+
+;++
+;
+;VOID
+;DisableA20(
+; VOID
+; )
+;
+;Routine Description:
+;
+; Disables the A20 line for any machine. If the MachineType global variable
+; is set to MCA, then it will call the DisableMcaA20 routine. If not, it
+; will execute the ISA code for disabling the A20 line.
+;
+;Arguments:
+;
+; None
+;
+;Return Value:
+;
+; None.
+;
+; The A20 line is disabled.
+;
+;--
+ public _DisableA20
+
+_DisableA20 proc near
+
+extrn _MachineType:dword
+
+ test dword ptr _MachineType,MACHINE_TYPE_MCA
+ jz DA0
+
+;
+; This is an MCA machine, so we use the special MCA routine
+;
+ call _DisableMcaA20
+ ret
+
+DA0:
+ mov ah,0ddh ; (AH) = Code for disable
+
+DA1:
+ call empty_8042 ; ensure 8042 input buffer empty
+ jnz DA2 ; 8042 error return
+
+
+; Disable the A20 line
+
+ mov al,0d1h ; 8042 cmd to write output port
+ out STATUS_PORT,al ; send cmd to 8042
+ call empty_8042 ; wait for 8042 to accept cmd
+ jnz DA2 ; 8042 error return
+ mov al,ah ; 8042 port data
+ out PORT_A,al ; output port data to 8042
+ call empty_8042
+
+; We must wait for the a20 line to settle down, which (on an AT)
+; may not happen until up to 20 usec after the 8042 has accepted
+; the command. We make use of the fact that the 8042 will not
+; accept another command until it is finished with the last one.
+; The 0FFh command does a NULL 'Pulse Output Port'. Total execution
+; time is on the order of 30 usec, easily satisfying the IBM 8042
+; settling requirement. (Thanks, CW!)
+
+ mov al,0FFh ;* Pulse Output Port (pulse no lines)
+ out STATUS_PORT,al ;* send cmd to 8042
+ call empty_8042 ;* wait for 8042 to accept cmd
+
+DA2:
+ ret
+
+_DisableA20 endp
+;**
+; empty_8042 -- wait for 8042 input buffer to drain
+;
+; Input:
+; interrupts disabled
+;
+; Exit:
+; al=0, z=0 => 8042 input buffer empty
+;
+; Uses:
+; ax, flags
+
+ public Empty8042
+Empty8042 proc near
+empty_8042:
+ sub cx,cx ; cx = 0, timeout loop counter
+
+emp1: in al,STATUS_PORT ; read 8042 status port
+ IODelay
+ IODelay
+ IODelay
+ IODelay
+ and al,BUF_FULL ; test buffer full bit
+ loopnz emp1
+ jnz emp2
+
+ ret
+
+emp2:
+emp3:
+ push offset err_empty8042
+ call _puts
+ add sp,2
+ ret
+
+
+Empty8042 endp
+
+_TEXT ends
+
+ end
+ \ No newline at end of file
diff --git a/private/ntos/boot/startup/i386/abios.inc b/private/ntos/boot/startup/i386/abios.inc
new file mode 100644
index 000000000..9f61e7773
--- /dev/null
+++ b/private/ntos/boot/startup/i386/abios.inc
@@ -0,0 +1,112 @@
+;++
+;
+; Copyright (c) 1989 Microsoft Corporation
+;
+; Module Name:
+;
+; abios.inc
+;
+; Abstract:
+;
+; This module contains the assembly structures and definitions
+; for ABIOS support code.
+;
+; Author:
+;
+; Shie-Lin (shielint) 23-May-1991
+;
+; Revision History:
+;
+;--
+
+;
+; ABIOS System Parameter Table definition
+;
+
+ABIOS_SYSTEM_PARAMETER_TABLE struc
+
+SP_CommonStartRoutine dd 0
+SP_CommonInterruptRoutine dd 0
+SP_CommonTimeoutroutine dd 0
+SP_StackSize dw 0
+SP_Reserved1 dd 0
+SP_Reserved2 dd 0
+SP_Reserved3 dd 0
+SP_Reserved4 dd 0
+SP_NumberOfEntries dw 0
+
+ABIOS_SYSTEM_PARAMETER_TABLE ends
+
+ABIOS_SPT_SIZE equ size ABIOS_SYSTEM_PARAMETER_TABLE
+ABIOS_BUILD_SPT equ 04
+ABIOS_BUILD_IT equ 05
+RETURN_SYSTEM_CONFIG equ 0C0h
+
+;
+; CBIOS machine configuration structure
+;
+
+MACHINE_CONFIGURATION struc
+
+MC_Length dw 0
+MC_Model db 0
+MC_Submodel db 0
+MC_BiosRevision db 0
+
+MACHINE_CONFIGURATION ends
+
+;
+; ABIOS Initialization Table definitions
+;
+
+INITIALIZATION_TABLE_ENTRY_SIZE equ 18H
+
+ABIOS_IT_ENTRY struc
+
+IT_DeviceId dw 0
+IT_NumberLid dw 0
+IT_DeviceBlockLength dw 0
+IT_InitializeRoutine dd 0
+IT_RequestBlockLength dw 0
+IT_FttLength dw 0
+IT_DataPointerLength dw 0
+IT_SecondDeviceId db 0
+IT_Revision db 0
+IT_Reserved1 dw 0, 0, 0
+
+ABIOS_IT_ENTRY ends
+
+;
+; machine Configuration definition
+;
+
+MACHINE_INFORMATION struc
+
+Model db 0
+SubModel db 0
+BiosRevision db 0
+Valid db 0
+
+MACHINE_INFORMATION ends
+
+MEMORY_MAP_TABLE struc
+ ReturnedLength dw 0
+ Local1to16M dd 0
+ Local16to4G dd 0
+ System1to16M dd 0
+ System16to4G dd 0
+ Cached1to16M dd 0
+ Cached1to4G dd 0
+ NonSystemStart1 dd 0
+ NonSystemStart16 dd 0
+ DataReserved dd 0
+MEMORY_MAP_TABLE ends
+
+
+;
+; Misc. definitions
+;
+
+TRUE equ 1
+FALSE equ 0
+ \ No newline at end of file
diff --git a/private/ntos/boot/startup/i386/abiosa.asm b/private/ntos/boot/startup/i386/abiosa.asm
new file mode 100644
index 000000000..9c42389c1
--- /dev/null
+++ b/private/ntos/boot/startup/i386/abiosa.asm
@@ -0,0 +1,556 @@
+ title "Abios Support Assembley Code"
+;++
+;
+; Copyright (c) 1989 Microsoft Corporation
+;
+; Module Name:
+;
+; abiosa.asm
+;
+; Abstract:
+;
+; This module implements the assembley code necessary to initialize
+; ABIOS on PS/2 machines.
+;
+; Author:
+;
+; Shie-Lin Tzong (shielint) 7-May-1991
+;
+; Environment:
+;
+; Real Mode 16-bit code.
+;
+; Revision History:
+;
+;
+;--
+
+
+.386p
+ .xlist
+include su.inc
+include abios.inc
+ .list
+
+_TEXT SEGMENT PARA USE16 PUBLIC 'CODE'
+ ASSUME CS: _TEXT, DS: DGROUP, SS: DGROUP
+
+;++
+;
+; BOOLEAN
+; IsAbiosPresent (
+; VOID
+; )
+;
+; Routine Description:
+;
+; This function determines whether ABIOS is present in the machine or
+; not. This function calls BIOS int 15h to build System Parameter
+; Table. If the call fails, there is no ABIOS in the system.
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; TRUE - if ABIOS is present. Otherwise a value of FALSE is returned.
+;
+;--
+
+ public IsAbiosPresent
+IsAbiosPresent proc near
+
+;
+; Save registers which will be destroyed.
+;
+
+ push ds
+ push es
+ push di
+
+ push ss
+ pop es
+ assume es:DGROUP
+
+ sub sp, ABIOS_SPT_SIZE
+ mov di, sp ; (es:di) = SystemParamTable
+ xor ax, ax
+ mov ds, ax ; (ds) = 0 = No Ram extension
+ mov ah, ABIOS_BUILD_SPT
+ int 15h ; return Carry flag
+ jc short Iap00 ; if c, Abios is not present
+ mov eax, 1 ; else (ax)=true and exit
+ jnc Iap99
+
+Iap00:
+ mov eax, 0
+Iap99:
+
+;
+; Restore registers
+;
+
+ add sp, ABIOS_SPT_SIZE
+
+ pop di
+ pop es
+ pop ds
+ ret
+
+IsAbiosPresent endp
+
+;++
+;
+; MACHINE_INFORMATION
+; AbiosGetMachineConfig (
+; VOID
+; )
+;
+; Routine Description:
+;
+; This function performs real mode int 15h call to retrieve machine
+; model byte, submodel byte and ROM revision level.
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; TRUE - if operation is successful. Otherwise, a value FALSE is returned.
+;
+;--
+
+ public AbiosGetMachineConfig
+AbiosGetMachineConfig proc
+
+ push es
+ push bx
+
+ mov ah, RETURN_SYSTEM_CONFIG
+ int 15h
+ mov ah, FALSE
+ jc short AgmcExit
+
+ mov ah, TRUE
+ mov al, es:[bx].MC_BiosRevision
+ shl eax, 8
+ mov al, es:[bx].MC_Submodel
+ shl eax, 8
+ mov al, es:[bx].MC_Model
+AgmcExit:
+
+ pop bx
+ pop es
+ ret
+
+AbiosGetMachineConfig endp
+
+;++
+;
+; USHORT
+; AbiosInitializeSpt (
+; IN PRAM_EXTENSION RamExtension
+; )
+;
+; Routine Description:
+;
+; This function performs real mode int 15 call to build Abios System
+; Parameter Table.
+;
+; N.B. the caller needs to switch processor to real mode before calling
+; this routine. This routine does not perform any CPU mode switching.
+;
+; Arguments:
+;
+; (bp)-> AbiosServiceStackFrame:
+; RamExtension - Physical address of RAM extension area.
+;
+; Return Value:
+;
+; NumberInitTableEntries - returnthe number of Initialization Table
+; Entries.
+; if NumberInitTableEntries = 0, an error occurred.
+;
+;--
+
+ public AbiosInitializeSpt
+
+AbiosInitializeSpt proc
+
+ push bx
+ push di
+ push si
+ push ds
+ push es
+
+;
+; Allocate AbiosSystemParameterTable on stack
+;
+
+ mov ax, ds
+ mov es, ax
+ sub sp, ABIOS_SPT_SIZE
+ mov di, sp ; (es:di)-> ABIOS SPT
+ mov eax, [bp].RamExtension
+ shr eax, 4 ; RAM extension MUST on para.
+ ; boundary and low memory.
+ mov ds, ax ; (ds) = segment of Ram Patch
+ mov ah, ABIOS_BUILD_SPT
+ int 15h
+ jc short ArmiError ; if c, fail, jmp to error exit
+ or ah, ah
+ jne short ArmiError ; if (ah)!=0, fail
+
+ movzx eax, es:[di].SP_NumberOfEntries
+ jmp short ArmiExit
+
+ArmiError:
+ mov eax, 0
+ArmiExit:
+ add sp, ABIOS_SPT_SIZE
+ pop es
+ pop ds
+ pop si
+ pop di
+ pop bx
+ ret
+
+AbiosInitializeSpt endp
+
+;++
+;
+; BOOLEAN
+; AbiosBuildInitTable (
+; IN PCHAR InitializationTable,
+; IN PRAM_EXTENSION RamExtension
+; )
+;
+; Routine Description:
+;
+; This function calls BIOS to build the initialization Table. When
+; the initialization process is complete the memory allocated for the
+; initialization table can be deallocated and reused by the operating
+; system.
+;
+; N.B. The caller needs to allocate the memory for the Initialization
+; Table. It is the responsibility of caller to deallocate the memory
+; after the Initialization Table is no longer needed.
+;
+; Arguments:
+;
+; (bp)-> Abios Services Stack frame:
+; InitializationTable - FLAT and identity mapped address of the
+; Initialization Table.
+; RamExtension - Physical address of RAM extension area.
+;
+; Return Value:
+;
+; TRUE - if operation is successful. Otherwise, a value FALSE is returned.
+;
+;--
+
+ public AbiosBuildInitTable
+AbiosBuildInitTable proc
+
+ push edi ; Save registers
+ push es
+ push ds
+
+ mov eax, [bp].InitTable ; (eax)-> InitTable Phys addr
+ mov edi, eax
+ and edi, 0FH
+ shr eax, 4
+ mov es, ax ; (es:di)-> InitTable
+ mov eax, [bp].RamExtension
+ shr eax, 4 ; RAM extension MUST on para.
+ ; boundary and low memory.
+ mov ds, ax ; (ds) = segment of Ram Patch
+ mov ah, ABIOS_BUILD_IT
+ int 15h
+ jc short AbitError ; if c or (ah) != 0, fail
+ or ah, ah
+ jnz short AbitError
+
+ mov eax, TRUE
+ jmp short AbitExit
+
+AbitError:
+ mov eax, FALSE
+AbitExit:
+ pop ds ; Restore registers
+ pop es
+ pop edi
+ ret
+
+AbiosBuildInitTable endp
+
+;++
+;
+; BOOLEAN
+; AbiosInitializeDbsFtt (
+; IN ULONG CdaPhysicalAddress
+; IN PVOID InitializationRoutine,
+; IN USHORT StartingLid,
+; IN USHORT NumberLids
+; )
+;
+; Routine Description:
+;
+; This function calls ABIOS Device Block and Function Transfer Table
+; initialization routine for the passed in Initialization table
+; entry. ABIOS will fill in the FTT, Device Blocks and Data pointers
+; in Common Data Area.
+;
+; Arguments:
+;
+; (bp)-> Abios Services Stack Frame:
+; InitTableEntry - Supplies a pointer the the entry of
+; Initialization table to be initialized.
+;
+; NumberLids - Number of Lids to initialize.
+;
+; StartingLid - Starting Logical Id.
+;
+; CdaPhysicalAddress - the physical address of Commom Data Area.
+;
+; RamExtension - Physical Address of Ram Extension.
+;
+; Return Value:
+;
+; TRUE - if operation is successful. Otherwise, a value FALSE is returned.
+;
+;--
+
+ public AbiosInitializeDbsFtt
+AbiosInitializeDbsFtt proc
+
+ push ds
+ mov cx, word ptr [bp].NumberLids
+ mov dx, word ptr [bp].LogicalId
+ mov eax, [bp].CommonDataArea
+ shr eax, 4
+ mov ds, ax ; (ds)= Anchor pointer to CDA
+ call dword ptr [bp].AbiosRoutine
+ or al, al
+ je Aidf00
+ mov eax, 0
+ jmp short Aidf10
+
+Aidf00:
+ mov eax, 1
+Aidf10:
+ pop ds
+ ret ; (ax) = Return value
+
+AbiosInitializeDbsFtt endp
+
+;++
+;
+; BOOLEAN
+; BtIsMcaSystem (
+; VOID
+; )
+;
+; Routine Description:
+;
+; This function determines if the target machines is MCA based machines.
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; TRUE - if this is MCA machine. Otherwise, a value of FALSE is returned.
+;--
+
+ public _BtIsMcaSystem
+_BtIsMcaSystem proc
+
+ push es
+ push bx
+ mov ax, 0c000h
+ int 15h
+ mov ax, 0 ; assume NOT mca system
+ test byte ptr es:[bx+5], 2 ; check Mca bit in misc.config byte
+ jz bims00
+ mov ax, 1
+bims00:
+ pop bx
+ pop es
+ ret
+
+_BtIsMcaSystem endp
+
+;++
+;
+; USHORT
+; McaConstructMemoryDescriptors(
+; VOID
+; )
+;
+; Routine Description:
+;
+; This function determines the amount of memory present in the system
+; by using INT 15h, function C7. It is only used on Microchannel systems.
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; USHORT - Size of usable memory (in pages)
+;
+; The memory descriptor list is updated to reflect the memory present in
+; the system.
+;
+;--
+extrn _MemoryDescriptorList:near
+extrn _InsertDescriptor:near
+extrn _IsaConstructMemoryDescriptors:near
+extrn _McaMemoryData:near
+
+ public _McaConstructMemoryDescriptors
+MemTotal equ [bp-4]
+Func88Result equ word ptr [bp-6]
+_McaConstructMemoryDescriptors proc near
+
+ push bp
+ mov bp, sp
+ sub sp, 6
+
+;
+; Initialize the MemoryList to start with a zero entry (end-of-list)
+;
+ les si, dword ptr _MemoryDescriptorList
+ xor eax, eax
+ mov es:[si].BlockSize,eax
+ mov es:[si].BlockBase,eax
+;
+; Get conventional (below one meg) memory size
+;
+ push es
+ push si
+ int 12h
+ movzx eax,ax
+;
+; EAX is the number of 1k blocks, which we need to convert to the
+; number of bytes.
+;
+ shl eax,10
+ push eax
+ shr eax,12
+ mov MemTotal,eax
+ xor eax,eax
+ push eax
+ call _InsertDescriptor
+ add sp,8
+
+;
+; We'd like to just use 15/C7 and believe it if it works. Unfortunately,
+; some 3rd party memory boards do not seem to support this at all. So if
+; you have 8Mb on the system board and 8Mb on an add-in card, INT 15/C7
+; will only report 8Mb, even though INT 15/88 reports 16. So we have to
+; try them both and pick one we like.
+;
+ mov ah,88h
+ int 15h
+ mov Func88Result,ax
+
+;
+; Call BIOS to fill in memory map information
+;
+ mov si, offset DGROUP:_McaMemoryData
+ mov ax, 0C700h
+ int 15h
+
+;
+; make sure all the return codes indicate this is supported
+;
+ jc mca20
+ cmp ah, 080h
+ je mca20
+ cmp ah, 086h
+ je mca20
+
+;
+; function is supported
+;
+ mov eax, [si].System1to16M
+;
+; if it returned 15Mb between 1 and 16M, then we will always believe it
+; since the machine has >= 16M.
+;
+
+ cmp eax,15*1024
+ je mca10
+;
+; if it returned less than INT15/88 did, ignore it and use INT15/88. This
+; can happen with third-party addin memory cards.
+;
+ cmp ax,Func88Result
+ jb mca20
+
+;
+; convert 1k blocks to number of bytes
+;
+mca10:
+ shl eax,10
+ push eax
+ shr eax,12
+ add MemTotal,ax
+ mov eax,0100000h ; this memory starts at 1Mb
+ push eax
+ call _InsertDescriptor
+ add sp,8
+
+ mov eax, [si].System16to4G
+ or eax,eax
+ jz short mcadone
+ shl eax, 10
+ push eax
+ shr eax, 12
+ add MemTotal,ax
+ mov eax,01000000h ; this memory starts at 16Mb
+ push eax
+ call _InsertDescriptor
+ add sp,8
+
+ mov eax, MemTotal
+ jmp short mcadone
+mca20:
+;
+; function is not supported on this machine. Use the result from INT15/88.
+;
+ mov ax,Func88Result
+ and eax,0ffffh
+;
+; EAX is the number of 1k blocks, which we need to convert to the
+; number of bytes.
+;
+ shl eax,10
+ push eax
+ shr eax,12
+ add MemTotal, ax
+ mov eax,0100000h
+ push eax
+ call _InsertDescriptor
+ add sp,8
+
+
+mcadone:
+ pop si
+ pop es
+ mov sp, bp
+ pop bp
+ ret
+
+_McaConstructMemoryDescriptors endp
+
+_TEXT ENDS
+ END
+
+ \ No newline at end of file
diff --git a/private/ntos/boot/startup/i386/backend.asm b/private/ntos/boot/startup/i386/backend.asm
new file mode 100644
index 000000000..ea1fa61b0
--- /dev/null
+++ b/private/ntos/boot/startup/i386/backend.asm
@@ -0,0 +1,28 @@
+;++
+;
+; Module Name:
+;
+; backend.asm
+;
+; Module Description:
+;
+; This module is needed only to get around a linker quirk we
+; run into because we're linking an app compiled as a "small"
+; model app as a "tiny" model app.
+;
+; BUGBUG
+; This is how we find the end of the com file and the beginning of the
+; OS loader coff header. This could probably be moved into the last file
+; on the link line. I will do that when time permits.
+;--
+
+
+.386p
+
+_DATA segment para use16 public 'DATA'
+
+public _BackEnd
+_BackEnd equ $
+
+_DATA ends
+ end
diff --git a/private/ntos/boot/startup/i386/constant.h b/private/ntos/boot/startup/i386/constant.h
new file mode 100644
index 000000000..3aaf258ce
--- /dev/null
+++ b/private/ntos/boot/startup/i386/constant.h
@@ -0,0 +1,91 @@
+/*--
+
+ Module Name
+
+ constant.h
+
+ Author
+
+ Thomas Parslow (tomp)
+
+--*/
+
+//
+// Debugging Level defines
+//
+
+#ifdef DEBUG0
+#define DBG0(x) x
+#define DBG1(x)
+#elif defined DEBUG1
+#define DBG0(x) x
+#define DBG1(x) x
+#else
+#define DBG0(x)
+#define DBG1(x)
+#endif
+
+#define WAITFOREVER while(1);
+#define BUGCHECK while(1);
+
+
+#define ENTRIES_PER_PAGETABLE 1024
+#define PAGE_SIZE 0x1000
+#define ENABLING 0
+#define RE_ENABLING 1
+
+
+
+//
+// Define page-table-entry bit definitions
+//
+// Dir Table
+// ----------==========
+// 00000000000000000000xxxxxxxxxxxx
+// ::::::+--- Present = 1 - Not Present = 0
+// :::::+---- ReadWrite = 1 - Read only = 0
+// ::::+----- UserAccess = 1 - Supervisor = 0
+// :::+------ Reserved
+// ::+------- Reserved
+// :+-------- Dirty = 1 - Not written = 0
+// +--------- Accessed = 1 - No accessed = 0
+
+#define PAGE_SUPERVISOR 0x0000
+#define PAGE_READ_ONLY 0x0000
+#define PAGE_PRESENT 0x0001
+#define PAGE_NOT_PRESENT 0x0000
+#define PAGE_READ_WRITE 0x0002
+#define PAGE_USER_ACCESS 0x0004
+#define PAGE_PERSIST 0x0200 // Tells kernel maintain
+//
+// Define RWSP (Read, Write, Supervisor, Present)
+//
+
+#define PAGE_RWSP 0L | PAGE_READ_WRITE | PAGE_SUPERVISOR | PAGE_PRESENT
+#define PAGE_ROSP 0L | PAGE_READ_ONLY | PAGE_SUPERVISOR | PAGE_PRESENT
+// Since the entire boot process occurs at ring 0, the only way we can
+// protext areas that we don't want trashed is too mark them not present
+#define PAGE_NO_ACCESS 0L | PAGE_READ_ONLY | PAGE_SUPERVISOR | PAGE_NOT_PRESENT
+
+
+//
+// Page-entry macros
+//
+
+#define PD_Entry(x) (USHORT)((x)>>22) & 0x3ff
+#define PT_Entry(x) (USHORT)((x)>>12) & 0x3ff
+#define PAGE_Count(x) (USHORT)((x)/PAGE_SIZE) + (((x) % PAGE_SIZE) ? 1 : 0)
+#define PhysToSeg(x) (USHORT)((x) >> 4) & 0xffff
+#define PhysToOff(x) (USHORT)((x) & 0x0f)
+#define MAKE_FP(p,a) FP_SEG(p) = (USHORT)((a) >> 4) & 0xffff; FP_OFF(p) = (USHORT)((a) & 0x0f)
+#define MAKE_FLAT_ADDRESS(fp) ( ((ULONG)FP_SEG(fp) * 16 ) + (ULONG)FP_OFF(fp) )
+
+//
+// Machine type definitions.
+// N.B. All the constants defined here
+// must match the ones defined in ntos\inc\i386.h
+//
+
+#define MACHINE_TYPE_ISA 0
+#define MACHINE_TYPE_EISA 1
+#define MACHINE_TYPE_MCA 2
diff --git a/private/ntos/boot/startup/i386/display.c b/private/ntos/boot/startup/i386/display.c
new file mode 100644
index 000000000..ad0116a7f
--- /dev/null
+++ b/private/ntos/boot/startup/i386/display.c
@@ -0,0 +1,632 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ display.c
+
+Author:
+
+ Thomas Parslow (tomp) Mar-01-90
+
+Abstract:
+
+ Video support routines.
+
+ The SU module only need to be able to write to the video display
+ in order to report errors, traps, etc.
+
+ The routines in this file all write to a video buffer assumed to be
+ at realmode address b800:0000, and 4k bytes in length. The segment
+ portion of the far pointers used to access the video buffer are stamped
+ with a protmode selector value when we switch to protect mode. This is
+ done in the routine "ProtMode" in "misc386.asm".
+
+
+--*/
+
+#include "su.h"
+
+
+#define ZLEN_SHORT(x) ((x < 0x10) + (x < 0x100) + (x < 0x1000))
+#define ZLEN_LONG(x) ((x < 0x10) + (x < 0x100) + (x < 0x1000) + (x < 0x10000) + (x < 0x100000)+(x < 0x1000000)+(x < 0x10000000))
+
+#ifdef DEBUG1
+#define ROWS 43
+#else
+#define ROWS 25
+#endif
+#define COLUMNS 80
+#define SCREEN_WIDTH COLUMNS
+#define SCREEN_SIZE ROWS * COLUMNS
+#define NORMAL_ATTRIB 0x07
+#define REVERSE_ATTRIB 0x70
+#define SCREEN_START 0xb8000000
+
+#define VIDEO_BIOS 0x10
+#define LINES_400_CONFIGURATION 0x1202
+#define SELECT_SCAN_LINE 0x301
+#define SET_80X25_16_COLOR_MODE 0x3
+#define LOAD_8X8_CHARACTER_SET 0x1112
+
+//
+// Internal routines
+//
+
+static
+VOID
+tab(
+ VOID
+ );
+
+static
+VOID
+newline(
+ VOID
+ );
+
+static
+VOID
+putzeros(
+ USHORT,
+ USHORT
+ );
+
+
+USHORT
+Redirect = 0;
+
+
+VOID
+InitializeVideoSubSystem(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Initializes the video mode to 80x50 alphanumeric mode with 400 lines
+ vertical resolution.
+
+Arguments:
+
+ None
+
+Returns:
+
+ Nothing
+
+
+--*/
+
+{
+ BIOSREGS ps;
+ UCHAR _far *BiosArea;
+
+ //
+ // Set 40:10 to indicate color is the default display
+ // *(40:10) &= ~0x30;
+ // *(40:10) |= 0x20;
+ //
+ // Fixes obscure situation where both monochrome and VGA adapters
+ // are installed and the monochrome is the default display.
+ //
+ BiosArea = (UCHAR _far *)(0x410L);
+
+ *BiosArea &= ~0x30;
+ *BiosArea |= 0x20;
+
+
+ //
+ // Establish 80x25 alphanumeric mode with 400-lines vertical resolution
+ //
+ ps.fn = VIDEO_BIOS;
+ ps.ax = LINES_400_CONFIGURATION;
+ ps.bx = SELECT_SCAN_LINE;
+ biosint(&ps);
+
+ ps.fn = VIDEO_BIOS;
+ ps.ax = SET_80X25_16_COLOR_MODE;
+ biosint(&ps);
+
+ DBG1(
+ ps.ax = LOAD_8X8_CHARACTER_SET;
+ ps.bx = 0;
+ biosint(&ps);
+ )
+
+ //
+ // HACK-O-RAMA - Make some random video BIOS calls here to make sure the
+ // BIOS is initialized and warmed up and ready to go. Otherwise,
+ // some Number 9 S3 cards don't quite work right later in the game.
+ // John Vert (jvert) 9-Jun-1993
+ //
+
+ //
+ // set cursor position to 0,0
+ //
+ ps.fn = VIDEO_BIOS;
+ ps.ax = 0x2000;
+ ps.bx = 0;
+ ps.dx = 0;
+ biosint(&ps);
+
+ //
+ // write character (' ' in this case)
+ //
+ ps.fn = VIDEO_BIOS;
+ ps.ax = 0x0a00 | (USHORT)' ';
+ ps.bx = 0;
+ ps.cx = 1;
+ biosint(&ps);
+
+ clrscrn();
+ return ;
+}
+
+
+//
+// Used by all BlPrint subordinate routines for padding computations.
+//
+
+CHAR sc=0;
+ULONG fw=0;
+
+
+
+VOID
+BlPrint(
+ PCHAR cp,
+ ...
+ )
+
+/*++
+
+Routine Description:
+
+ Standard printf function with a subset of formating features supported.
+
+ Currently handles
+
+ %d, %ld - signed short, signed long
+ %u, %lu - unsigned short, unsigned long
+ %c, %s - character, string
+ %x, %lx - unsigned print in hex, unsigned long print in hex
+
+ Does not do:
+
+ - field width specification
+ - floating point.
+
+Arguments:
+
+ cp - pointer to the format string, text string.
+
+
+Returns:
+
+ Nothing
+
+
+--*/
+
+{
+ USHORT b,c,w,len;
+ PUCHAR ap;
+ ULONG l;
+
+ //
+ // Cast a pointer to the first word on the stack
+ //
+
+ ap = (PUCHAR)&cp + sizeof(PCHAR);
+ sc = ' '; // default padding char is space
+
+ //
+ // Process the arguments using the descriptor string
+ //
+
+
+ while (b = *cp++)
+ {
+ if (b == '%')
+ {
+ c = *cp++;
+
+ switch (c)
+ {
+ case 'd':
+ puti((long)*((int *)ap));
+ ap += sizeof(int);
+ break;
+
+ case 's':
+ puts(*((PCHAR *)ap));
+ ap += sizeof (char *);
+ break;
+
+ case 'c':
+ putc(*((char *)ap));
+ ap += sizeof(int);
+ break;
+
+ case 'x':
+ w = *((USHORT *)ap);
+ len = ZLEN_SHORT(w);
+ while(len--) putc('0');
+ putx((ULONG)*((USHORT *)ap));
+ ap += sizeof(int);
+ break;
+
+ case 'u':
+ putu((ULONG)*((USHORT *)ap));
+ ap += sizeof(int);
+ break;
+
+ case 'l':
+ c = *cp++;
+
+ switch(c) {
+
+ case 'u':
+ putu(*((ULONG *)ap));
+ ap += sizeof(long);
+ break;
+
+ case 'x':
+ l = *((ULONG *)ap);
+ len = ZLEN_LONG(l);
+ while(len--) putc('0');
+ putx(*((ULONG *)ap));
+ ap += sizeof(long);
+ break;
+
+ case 'd':
+ puti(*((ULONG *)ap));
+ ap += sizeof(long);
+ break;
+
+ }
+ break;
+
+ default :
+ putc((char)b);
+ putc((char)c);
+ }
+ }
+ else
+ putc((char)b);
+ }
+
+}
+
+FPUCHAR vp = (FPUCHAR)SCREEN_START;
+FPUCHAR ScreenStart = (FPUCHAR)SCREEN_START;
+
+static int lcnt = 0;
+static int row = 0;
+
+
+VOID puts(
+ PCHAR cp
+ )
+/*++
+
+Routine Description:
+
+ Writes a string on the display at the current cursor position
+
+Arguments:
+
+ cp - pointer to ASCIIZ string to display.
+
+
+Returns:
+
+ Nothing
+
+
+
+--*/
+
+
+{
+ char c;
+
+ while(c = *cp++)
+ putc(c);
+}
+
+
+//
+// Write a hex short to display
+//
+
+
+VOID putx(
+ ULONG x
+ )
+/*++
+
+Routine Description:
+
+ Writes hex long to the display at the current cursor position.
+
+Arguments:
+
+ x - ulong to write.
+
+Returns:
+
+ Nothing
+
+
+--*/
+
+{
+ ULONG j;
+
+ if (x/16)
+ putx(x/16);
+
+ if((j=x%16) > 9) {
+ putc((char)(j+'A'- 10));
+ } else {
+ putc((char)(j+'0'));
+ }
+}
+
+
+VOID puti(
+ LONG i
+ )
+/*++
+
+Routine Description:
+
+ Writes a long integer on the display at the current cursor position.
+
+Arguments:
+
+ i - the integer to write to the display.
+
+Returns:
+
+ Nothing
+
+
+--*/
+
+
+{
+ if (i<0)
+ {
+ i = -i;
+ putc((char)'-');
+ }
+
+ if (i/10)
+ puti(i/10);
+
+ putc((char)((i%10)+'0'));
+}
+
+
+
+VOID putu(
+ ULONG u
+ )
+/*++
+
+Routine Description:
+
+ Write an unsigned long to display
+
+Arguments:
+
+ u - unsigned
+
+
+--*/
+
+{
+ if (u/10)
+ putu(u/10);
+
+ putc((char)((u%10)+'0'));
+
+}
+
+
+VOID putc(
+ CHAR c
+ )
+/*++
+
+Routine Description:
+
+ Writes a character on the display at the current position.
+
+Arguments:
+
+ c - character to write
+
+
+Returns:
+
+ Nothing
+
+
+--*/
+
+{
+ switch (c)
+ {
+ case '\n':
+ newline();
+ break;
+
+ case '\t':
+ tab();
+ break;
+
+ default :
+ if (FP_OFF(vp) >= (SCREEN_SIZE * 2)) {
+ vp = (FPUCHAR)((ScreenStart + (2*SCREEN_WIDTH*(ROWS-1))));
+ scroll();
+ }
+ *vp = c;
+ vp += 2;
+ ++lcnt;
+ }
+}
+
+
+VOID newline(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Moves the cursor to the beginning of the next line. If the bottom
+ of the display has been reached, the screen is scrolled one line up.
+
+Arguments:
+
+ None
+
+
+Returns:
+
+ Nothing
+
+
+--*/
+
+{
+ vp += (SCREEN_WIDTH - lcnt)<<1;
+
+ if (++row > ROWS-1) {
+
+ vp = (FPUCHAR)((ScreenStart + (2*SCREEN_WIDTH*(ROWS-1))));
+ scroll();
+
+ }
+
+ lcnt = 0;
+
+}
+
+
+VOID scroll(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Scrolls the display UP one line.
+
+Arguments:
+
+ None
+
+Returns:
+
+ Nothing
+
+Notes:
+
+ Currently we scroll the display by reading and writing directly from
+ and to the video display buffer. We optionally switch to real mode
+ and to int 10s
+
+--*/
+
+{
+ USHORT i,j;
+ USHORT far *p1 = (USHORT far *)ScreenStart;
+ USHORT far *p2 = (USHORT far *)(ScreenStart + 2*SCREEN_WIDTH) ;
+
+ for (i=0; i < ROWS - 1; i++)
+ for (j=0; j < SCREEN_WIDTH; j++)
+ *p1++ = *p2++;
+
+ for (i=0; i < SCREEN_WIDTH; i++)
+ *p1++ = REVERSE_ATTRIB*256 + ' ';
+
+}
+
+
+static
+VOID tab(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+
+ Computes the next tab stop and moves the cursor to that location.
+
+
+Arguments:
+
+
+ None
+
+
+Returns:
+
+ Nothing
+
+--*/
+
+{
+ int inc;
+
+ inc = 8 - (lcnt % 8);
+ vp += inc<<1;
+ lcnt += inc;
+}
+
+
+VOID clrscrn(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Clears the video display by writing blanks with the current
+ video attribute over the entire display.
+
+
+Arguments:
+
+ None
+
+Returns:
+
+ Nothing
+
+
+--*/
+
+{
+ int i,a;
+ unsigned far *vwp = (unsigned far *)SCREEN_START;
+ a = NORMAL_ATTRIB*256 + ' ';
+
+ for (i = SCREEN_SIZE ; i ; i--)
+ *vwp++ = a;
+
+ row = 0;
+ lcnt = 0;
+ vp = (FPUCHAR)ScreenStart;
+
+}
+
+// END OF FILE
diff --git a/private/ntos/boot/startup/i386/eisa.h b/private/ntos/boot/startup/i386/eisa.h
new file mode 100644
index 000000000..d7766f117
--- /dev/null
+++ b/private/ntos/boot/startup/i386/eisa.h
@@ -0,0 +1,102 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ eisa.h
+
+Abstract:
+
+ This module contains the i386 EISA bus specific header file.
+
+Author:
+
+ Shie-Lin Tzong (shielint) 6-June-1991
+
+Revision History:
+
+--*/
+
+//
+// SU module's version of the memory descriptor
+//
+typedef struct _MEMORY_LIST_ENTRY {
+ ULONG BlockBase;
+ ULONG BlockSize;
+} MEMORY_LIST_ENTRY, *PMEMORY_LIST_ENTRY;
+
+
+//
+// SU module's version of the address space parameters for int-15 E820 calls
+//
+
+typedef struct {
+ ULONG ErrorFlag;
+ ULONG Key;
+ ULONG Size;
+ struct {
+ ULONG BaseAddrLow;
+ ULONG BaseAddrHigh;
+ ULONG SizeLow;
+ ULONG SizeHigh;
+ ULONG MemoryType;
+ } Descriptor;
+} E820Frame;
+
+
+//
+// Misc. definitions
+//
+
+#define _16MEGB ((ULONG)16 * 1024 * 1024)
+#define _64MEGB ((ULONG)64 * 1024 * 1024)
+
+typedef CM_EISA_SLOT_INFORMATION BTEISA_SLOT_INFORMATION;
+typedef CM_EISA_SLOT_INFORMATION *PBTEISA_SLOT_INFORMATION;
+typedef CM_EISA_FUNCTION_INFORMATION BTEISA_FUNCTION_INFORMATION;
+typedef CM_EISA_FUNCTION_INFORMATION *PBTEISA_FUNCTION_INFORMATION;
+typedef EISA_MEMORY_CONFIGURATION BTEISA_MEMORY_CONFIGURATION;
+typedef EISA_MEMORY_CONFIGURATION *PBTEISA_MEMORY_CONFIGURATION;
+
+BOOLEAN
+FindFunctionInformation (
+ IN UCHAR SlotFlags,
+ IN UCHAR FunctionFlags,
+ OUT PBTEISA_FUNCTION_INFORMATION Buffer,
+ IN BOOLEAN FromBeginning
+ );
+
+USHORT
+CountMemoryBlocks (
+ VOID
+ );
+
+ULONG
+EisaConstructMemoryDescriptors (
+ VOID
+ );
+
+UCHAR
+BtGetEisaSlotInformation (
+ PBTEISA_SLOT_INFORMATION SlotInformation,
+ UCHAR Slot
+ );
+
+UCHAR
+BtGetEisaFunctionInformation (
+ PBTEISA_FUNCTION_INFORMATION FunctionInformation,
+ UCHAR Slot,
+ UCHAR Function
+ );
+
+BOOLEAN
+BtIsEisaSystem (
+ VOID
+ );
+
+//
+// External References
+//
+
+extern MEMORY_LIST_ENTRY _far *MemoryDescriptorList;
diff --git a/private/ntos/boot/startup/i386/eisa.inc b/private/ntos/boot/startup/i386/eisa.inc
new file mode 100644
index 000000000..05aa94ade
--- /dev/null
+++ b/private/ntos/boot/startup/i386/eisa.inc
@@ -0,0 +1,61 @@
+;++
+;
+; Copyright (c) 1989 Microsoft Corporation
+;
+; Module Name:
+;
+; eisa.inc
+;
+; Abstract:
+;
+; This module contains the assembly structures and definitions
+; for making 16-bit real mode EISA BIOS calls.
+;
+; Author:
+;
+; Shie-Lin (shielint) 7-June-1991
+;
+; Revision History:
+;
+;--
+
+;
+; EISA BIOS call function number.
+;
+
+GET_EISA_SLOT_INFORMATION equ 0D800h
+GET_EISA_FUNCTION_INFORMATION equ 0D801h
+
+;
+; Length of EISA information block
+;
+
+EISA_INFORMATION_BLOCK_LENGTH equ 320
+
+;
+; Structure for EISA slot information block
+;
+
+EISA_SLOT_INFORMATION struc
+
+ SlotReturn db 0
+ SlotFlags db 0
+ SlotMajorRevision db 0
+ SlotMinorRevision db 0
+ SlotChecksum dw 0
+ SlotNumberFunctions db 0
+ SlotFunctionInformation db 0
+ SlotCompressedId dd 0
+
+EISA_SLOT_INFORMATION ends
+
+;
+; Structure for EISA function information block
+;
+
+EISA_FUNCTION_INFORMATION struc
+
+ FunctionReturn db 0
+ FunctionInformation db EISA_INFORMATION_BLOCK_LENGTH dup (0)
+
+EISA_FUNCTION_INFORMATION ends
diff --git a/private/ntos/boot/startup/i386/eisaa.asm b/private/ntos/boot/startup/i386/eisaa.asm
new file mode 100644
index 000000000..17f1eb32a
--- /dev/null
+++ b/private/ntos/boot/startup/i386/eisaa.asm
@@ -0,0 +1,216 @@
+ title "EISA bus Support Assembley Code"
+;++
+;
+; Copyright (c) 1989 Microsoft Corporation
+;
+; Module Name:
+;
+; eisaa.asm
+;
+; Abstract:
+;
+; This module implements the assembley code necessary to get configuration
+; information on EISA machines.
+;
+; Author:
+;
+; Shie-Lin Tzong (shielint) 7-June-1991
+;
+; Environment:
+;
+; Real Mode 16-bit code.
+;
+; Revision History:
+;
+;
+;--
+
+
+.386p
+ .xlist
+include eisa.inc
+ .list
+
+_DATA SEGMENT PARA USE16 PUBLIC 'DATA'
+
+ public _FunctionInformation
+_FunctionInformation db 0
+ db EISA_INFORMATION_BLOCK_LENGTH dup (0)
+
+_DATA ends
+
+_TEXT SEGMENT PARA USE16 PUBLIC 'CODE'
+ ASSUME CS: _TEXT
+
+;++
+;
+; VOID
+; BtGetEisaSlotInformation (
+; PBTEISA_SLOT_INFORMATION SlotInformation,
+; UCHAR Slot
+; )
+;
+; Routine Description:
+;
+; This function retrieves the slot information for the specified slot.
+;
+; Arguments:
+;
+; SlotInformation - Supplies a pointer to the structure which will
+; receive the slot information.
+;
+; Slot - Specifies the slot to retrieve the information.
+;
+; Return Value:
+;
+; None.
+;
+;--
+
+BgesSlotInformation equ [bp + 4]
+BgesSlot equ [bp + 6]
+
+ public _BtGetEisaSlotInformation
+_BtGetEisaSlotInformation proc
+
+ push bp ; The following INT 15H destroies
+ mov bp, sp ; ALL the general registers.
+ push si
+ push di
+ push bx
+
+ mov cl, BgesSlot
+ mov ax, GET_EISA_SLOT_INFORMATION
+ int 15h
+
+ push bx ; Save revision level
+ mov bx, BgesSlotInformation
+
+ ;
+ ; fill values into eisa slot info structure.
+ ;
+
+ mov [bx].SlotReturn, ah
+ mov [bx].SlotFlags, al
+ pop ax ; [ax] = revision level
+ mov [bx].SlotMajorRevision, ah
+ mov [bx].SlotMinorRevision, al
+ mov [bx].SlotChecksum, cx
+ mov [bx].SlotNumberFunctions, dh
+ mov [bx].SlotFunctionInformation, dl
+ mov word ptr [bx].SlotCompressedId, di
+ mov word ptr [bx+2].SlotCompressedId, si
+
+ pop bx
+ pop di
+ pop si
+ pop bp
+ ret
+
+_BtGetEisaSlotInformation endp
+
+;++
+;
+; UCHAR
+; BtGetEisaFunctionInformation (
+; PBTEISA_FUNCTION_INFORMATION FunctionInformation,
+; UCHAR Slot,
+; UCHAR Function
+; )
+;
+; Routine Description:
+;
+; This function retrieves function information for the specified slot
+; and function.
+;
+; Arguments:
+;
+; FunctionInformation - Supplies a pointer to the structure which will
+; receive the slot information.
+;
+; Slot - Specifies the slot to retrieve the information.
+;
+; Function - Supplies the function number of the desired slot.
+;
+; Return Value:
+;
+; Return code of the EISA function call.
+;
+;--
+
+BgefFunctionInformation equ [bp + 4]
+BgefSlot equ [bp + 6]
+BgefFunction equ [bp + 8]
+
+ public _BtGetEisaFunctionInformation
+_BtGetEisaFunctionInformation proc
+
+ push bp
+ mov bp, sp
+ push si
+
+ mov ax, GET_EISA_FUNCTION_INFORMATION
+ mov cl, BgefSlot ; [cl] = slot, [ch]=function
+ mov ch, BgefFunction
+ mov si, BgefFunctionInformation
+ ; (ds:si)->Function information
+ int 15h
+
+ mov al, ah ; move the return code to AL
+
+ pop si
+ pop bp
+ ret
+_BtGetEisaFunctionInformation endp
+
+;++
+;
+; BOOLEAN
+; BtIsEisaSystem (
+; VOID
+; )
+;
+; Routine Description:
+;
+; This function determines if the target machines is EISA based machines.
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; TRUE - if this is EISA machine. Otherwise, a value of FALSE is returned.
+;--
+
+ public _BtIsEisaSystem
+_BtIsEisaSystem proc
+
+ push es
+ push bx
+
+;
+; Check for an EISA system. If "EISA" is at F000:FFD9h then it
+; is an EISA system.
+;
+
+ mov ax,0f000h ; segment
+ mov es,ax
+ mov bx,0ffd9h ; offset in the ROM
+ mov eax, "ASIE"
+ cmp eax, es:[bx]
+ jne short bies00 ; if ne, Not EISA system, go bies00
+
+ mov ax, 1 ; set return value to TRUE
+ jmp short bies10
+
+bies00:
+ mov ax, 0
+bies10:
+ pop bx
+ pop es
+ ret
+_BtIsEisaSystem endp
+
+_TEXT ends
+ end
diff --git a/private/ntos/boot/startup/i386/eisac.c b/private/ntos/boot/startup/i386/eisac.c
new file mode 100644
index 000000000..3143f4cc8
--- /dev/null
+++ b/private/ntos/boot/startup/i386/eisac.c
@@ -0,0 +1,538 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ eisac.c
+
+Abstract:
+
+ This module implements routines to get EISA configuration information.
+
+Author:
+
+ Shie-Lin Tzong (shielint) 10-June-1991
+
+Environment:
+
+ 16-bit real mode.
+
+
+Revision History:
+
+ John Vert (jvert) 5-Sep-1991
+ Moved into the SU module of portable bootloader
+
+--*/
+#include "su.h"
+#include "eisa.h"
+
+//
+// HACKHACK - John Vert (jvert) 12-Sep-1991
+// We have to initialize this or else it gets stuck in our BSS section
+// which is right in the middle of the osloader.exe header
+//
+extern BTEISA_FUNCTION_INFORMATION FunctionInformation;
+
+
+BOOLEAN
+FindFunctionInformation (
+ IN UCHAR SlotFlags,
+ IN UCHAR FunctionFlags,
+ OUT PBTEISA_FUNCTION_INFORMATION Buffer,
+ IN BOOLEAN FromBeginning
+ )
+
+/*++
+
+Routine Description:
+
+ This routine finds function information that matches the specified
+ flags. It starts, either where it left off last time, or at the
+ beginning (slot 0, function 0)
+
+Arguments:
+
+ Flags - Flags to check against EISA function and slot information.
+
+ Buffer - pointer to buffer to store EISA information in.
+
+ FromBeginning - if TRUE, search starts at slot 0, function 0.
+ else continue from where it left off last time.
+
+Return Value:
+
+ TRUE - If the operation is success (Buffer is filled in.)
+ FALSE - Request fails.
+
+ Notes: The buffer is always changed, reguardless of the success
+ of the function. When failure is returned, the info is invalid.
+
+--*/
+
+{
+ static UCHAR Slot=0;
+ static UCHAR Function=0;
+ BTEISA_SLOT_INFORMATION SlotInformation;
+ UCHAR Flags;
+ UCHAR ReturnCode;
+
+ if (FromBeginning) {
+ Slot = 0;
+ Function = 0;
+ }
+ BtGetEisaSlotInformation(&SlotInformation, Slot);
+ while (SlotInformation.ReturnCode != EISA_INVALID_SLOT) {
+
+ //
+ // insure that the slot is not empty, and all of the flags are set.
+ // the flags are tested by performing the following logic:
+ //
+ // -- (RequestSlotFlags XOR (SlotFlags AND RequestSlotFlags)) --
+ //
+ // if all the requested flags are set, the result will be zero
+ //
+
+ if ((SlotInformation.ReturnCode != EISA_EMPTY_SLOT) &&
+ (!(SlotFlags ^ (SlotInformation.FunctionInformation & SlotFlags)))) {
+
+ while (SlotInformation.NumberFunctions > Function) {
+ ReturnCode = BtGetEisaFunctionInformation(Buffer, Slot, Function);
+ Function++;
+
+ //
+ // if function call succeeded
+ //
+
+ if (!ReturnCode){
+
+ Flags = Buffer->FunctionFlags;
+
+ //
+ // Function Enable/Disable bit reversed.
+ //
+
+ Flags |= (~Flags & EISA_FUNCTION_ENABLED);
+
+ //
+ // insure that all the function flags are set.
+ // the flags are tested by performing the following logic:
+ //
+ // -- (ReqFuncFlags XOR (FuncFlags AND ReqFuncFlags)) --
+ //
+ // if all the requested flags are set, the result will
+ // be zero
+ //
+
+ if (!(FunctionFlags ^ (Flags & FunctionFlags))) {
+ return TRUE;
+ }
+ }
+
+ }
+ }
+ Slot++;
+ Function = 0;
+ BtGetEisaSlotInformation(&SlotInformation, Slot);
+ }
+
+ Slot = 0;
+ Function = 0;
+ return FALSE;
+}
+
+VOID
+InsertDescriptor (
+ ULONG Address,
+ ULONG Size
+ )
+
+/*++
+
+Routine Description:
+
+ This routine inserts a descriptor into the correct place in the
+ memory descriptor list.
+
+Arguments:
+
+ Address - Starting address of the memory block.
+
+ Size - Size of the memory block to be inserted.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ MEMORY_LIST_ENTRY _far *CurrentEntry;
+
+#ifdef DEBUG1
+ BlPrint("Inserting descriptor %lx at %lx\n",Size,Address);
+ _asm {
+ push ax
+ mov ax, 0
+ int 16h
+ pop ax
+ }
+#endif
+ //
+ // Search the spot to insert the new descriptor.
+ //
+
+ CurrentEntry = MemoryDescriptorList;
+
+ while (CurrentEntry->BlockSize > 0) {
+ //
+ // Check to see if this memory descriptor is contiguous with
+ // the current one. If so, coalesce them. (yes, some machines
+ // will return memory descriptors that look like this. Compaq
+ // Prosignia machines)
+ //
+ if (Address+Size == CurrentEntry->BlockBase) {
+#ifdef DEBUG1
+ BlPrint(" coalescing with descriptor at %lx (%lx)\n",
+ CurrentEntry->BlockBase,
+ CurrentEntry->BlockSize);
+#endif
+ CurrentEntry->BlockBase = Address;
+ CurrentEntry->BlockSize += Size;
+#ifdef DEBUG1
+ BlPrint(" new descriptor at %lx (%lx)\n",
+ CurrentEntry->BlockBase,
+ CurrentEntry->BlockSize);
+#endif
+ break;
+ }
+ if (Address == (CurrentEntry->BlockBase + CurrentEntry->BlockSize)) {
+#ifdef DEBUG1
+ BlPrint(" coalescing with descriptor at %lx (%lx)\n",
+ CurrentEntry->BlockBase,
+ CurrentEntry->BlockSize);
+#endif
+ CurrentEntry->BlockSize += Size;
+#ifdef DEBUG1
+ BlPrint(" new descriptor at %lx (%lx)\n",
+ CurrentEntry->BlockBase,
+ CurrentEntry->BlockSize);
+#endif
+ break;
+ }
+
+ CurrentEntry++;
+ }
+
+ if (CurrentEntry->BlockSize == 0) {
+ //
+ // If CurrentEntry->BlockSize == 0, we have reached the end of the list
+ // So, insert the new descriptor here, and create a new end-of-list entry
+ //
+ CurrentEntry->BlockBase = Address;
+ CurrentEntry->BlockSize = Size;
+
+ ++CurrentEntry;
+ //
+ // Create a new end-of-list marker
+ //
+ CurrentEntry->BlockBase = 0L;
+ CurrentEntry->BlockSize = 0L;
+ }
+#ifdef DEBUG1
+ //
+ // Wait for a keypress
+ //
+ _asm {
+ push ax
+ mov ax, 0
+ int 16h
+ pop ax
+ }
+#endif
+
+}
+
+ULONG
+EisaConstructMemoryDescriptors (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine gets the information EISA memory function above 16M
+ and creates entries in the memory Descriptor array for them.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Number of pages of usable memory.
+
+--*/
+
+{
+ BOOLEAN Success;
+ PBTEISA_MEMORY_CONFIGURATION MemoryConfiguration;
+ ULONG Address;
+ ULONG EndAddress;
+ ULONG Size;
+ ULONG MemorySize=0;
+ ULONG IsaMemUnder1Mb=0xffffffff;
+ MEMORY_LIST_ENTRY _far *CurrentEntry;
+
+ //
+ // HACKHACK John Vert (jvert) 5-Mar-1993
+ //
+ // See if there is already a memory descriptor for the 640k under
+ // 1Mb. If so, we will believe it instead of the EISA routine. This
+ // is because many EISA routines will always return 640k, even if
+ // the disk parameter table is in the last 1k. The ISA routines will
+ // always account for the disk parameter tables. If we believe the
+ // EISA routines, we can overwrite the disk parameter tables, causing
+ // much grief.
+ //
+ CurrentEntry = MemoryDescriptorList;
+ while (CurrentEntry->BlockSize > 0) {
+ if (CurrentEntry->BlockBase == 0) {
+ //
+ // found a descriptor starting at zero with a size > 0, so
+ // this is the one we want to override the EISA information.
+ //
+ IsaMemUnder1Mb = CurrentEntry->BlockSize;
+ break;
+ }
+ ++CurrentEntry;
+ }
+
+ //
+ // Initialize the first entry in the list to zero (end-of-list)
+ //
+
+ MemoryDescriptorList->BlockSize = 0;
+ MemoryDescriptorList->BlockBase = 0;
+
+ Success = FindFunctionInformation(
+ EISA_HAS_MEMORY_ENTRY,
+ EISA_FUNCTION_ENABLED | EISA_HAS_MEMORY_ENTRY,
+ &FunctionInformation,
+ TRUE
+ );
+
+ //
+ // while there are more memory functions, and more free descriptors
+ //
+
+ while (Success) {
+
+ MemoryConfiguration = &FunctionInformation.EisaMemory[0];
+
+ do {
+
+ //
+ // Get physical address of the memory.
+ // Note: physical address is stored divided by 100h
+ //
+
+ Address = (((ULONG)MemoryConfiguration->AddressHighByte << 16)
+ + MemoryConfiguration->AddressLowWord) * 0x100;
+
+ //
+ // Get the size of the memory block.
+ // Note: Size is stored divided by 400h with the value of 0
+ // meaning a size of 64M
+ //
+
+ if (MemoryConfiguration->MemorySize) {
+ Size = ((ULONG)MemoryConfiguration->MemorySize) * 0x400;
+ } else {
+ Size = (_64MEGB);
+ }
+
+#ifdef DEBUG1
+ BlPrint("EISA memory at %lx Size=%lx Type=%x ",
+ Address,
+ Size,
+ MemoryConfiguration->ConfigurationByte);
+
+ if ((MemoryConfiguration->ConfigurationByte.Type == EISA_SYSTEM_MEMORY) &&
+ (MemoryConfiguration->ConfigurationByte.ReadWrite == EISA_MEMORY_TYPE_RAM) ) {
+
+ BlPrint(" (USED BY NT)\n");
+ } else {
+ BlPrint(" (not used)\n");
+ }
+#endif
+
+ //
+ // Compute end address to determine if any part of the block
+ // is above 16M
+ //
+
+ EndAddress = Address + Size;
+
+ //
+ // If it is SYSTEM memory and RAM, add the descriptor to the list.
+ //
+
+ if ((MemoryConfiguration->ConfigurationByte.Type == EISA_SYSTEM_MEMORY) &&
+ (MemoryConfiguration->ConfigurationByte.ReadWrite == EISA_MEMORY_TYPE_RAM) ) {
+
+ if (Address==0) {
+ //
+ // This is the descriptor for the memory under 1Mb.
+ // Compare it with the ISA routine's result, and see
+ // if the ISA one is smaller. If it is, use the ISA
+ // answer.
+ //
+ if (Size > IsaMemUnder1Mb) {
+ Size = IsaMemUnder1Mb;
+ }
+ }
+ InsertDescriptor(Address, Size);
+ MemorySize += (Size >> 12);
+ }
+
+ } while (MemoryConfiguration++->ConfigurationByte.MoreEntries);
+
+ Success = FindFunctionInformation(
+ EISA_HAS_MEMORY_ENTRY,
+ EISA_FUNCTION_ENABLED | EISA_HAS_MEMORY_ENTRY,
+ &FunctionInformation,
+ FALSE
+ );
+ }
+#ifdef DEBUG1
+ //
+ // Wait for a keypress
+ //
+ _asm {
+ push ax
+ mov ax, 0
+ int 16h
+ pop ax
+ }
+#endif
+ return(MemorySize);
+}
+
+BOOLEAN
+Int15E820 (
+ E820Frame *Frame
+ );
+
+
+BOOLEAN
+ConstructMemoryDescriptors (
+ VOID
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ ULONG BAddr, EAddr, round;
+ E820Frame Frame;
+
+ //
+ // Initialize the first entry in the list to zero (end-of-list)
+ //
+
+ MemoryDescriptorList->BlockSize = 0;
+ MemoryDescriptorList->BlockBase = 0;
+
+ //
+ // Any entries returned for E820?
+ //
+
+ Frame.Key = 0;
+ Frame.Size = sizeof (Frame.Descriptor);
+ Int15E820 (&Frame);
+ if (Frame.ErrorFlag || Frame.Size < sizeof (Frame.Descriptor)) {
+ return FALSE;
+ }
+
+ //
+ // Found memory in table, use the reported memory
+ //
+
+ Frame.Key = 0;
+ do {
+ Frame.Size = sizeof (Frame.Descriptor);
+ Int15E820 (&Frame);
+ if (Frame.ErrorFlag || Frame.Size < sizeof (Frame.Descriptor)) {
+ break ;
+ }
+
+#ifdef DEBUG1
+ BlPrint("E820: %lx %lx:%lx %lx:%lx %lx %lx\n",
+ Frame.Size,
+ Frame.Descriptor.BaseAddrHigh, Frame.Descriptor.BaseAddrLow,
+ Frame.Descriptor.SizeHigh, Frame.Descriptor.SizeLow,
+ Frame.Descriptor.MemoryType,
+ Frame.Key
+ );
+
+ _asm {
+ push ax
+ mov ax, 0
+ int 16h
+ pop ax
+ }
+#endif
+
+ BAddr = Frame.Descriptor.BaseAddrLow;
+ EAddr = Frame.Descriptor.BaseAddrLow + Frame.Descriptor.SizeLow - 1;
+
+ //
+ // All the processors we have right now only support 32 bits
+ // If the upper 32 bits of the Base Address is non-zero, then
+ // this range is entirely above the 4g mark and can be ignored
+ //
+
+ if (Frame.Descriptor.BaseAddrHigh == 0) {
+
+ if (EAddr < BAddr) {
+ //
+ // address wrapped - truncate the Ending address to
+ // 32 bits of address space
+ //
+
+ EAddr = 0xFFFFFFFF;
+ }
+
+ //
+ // Based upon the address range descriptor type, find the
+ // available memory and add it to the descriptor list
+ //
+
+ switch (Frame.Descriptor.MemoryType) {
+ case 1:
+ //
+ // This is a memory descriptor
+ //
+
+ InsertDescriptor (BAddr, EAddr - BAddr + 1);
+ break;
+ }
+ }
+
+ } while (Frame.Key) ;
+
+ return TRUE;
+}
+
+
+
diff --git a/private/ntos/boot/startup/i386/exp.asm b/private/ntos/boot/startup/i386/exp.asm
new file mode 100644
index 000000000..76357d773
--- /dev/null
+++ b/private/ntos/boot/startup/i386/exp.asm
@@ -0,0 +1,1610 @@
+;++
+;
+; Module name
+;
+; exp.asm
+;
+; Author
+;
+; Thomas Parslow (tomp) Feb-26-91
+;
+; Description
+;
+; Entry points exported to OS loader by SU module. Exported
+; routines provide basic machine dependent i/o funtions needed
+; by the OS loader. Providing these routines decouples the
+; OS loader from the h/w. Note that the OS loader will
+; refer to these exported routines as the "external services".
+;
+;
+; Exported Procedures
+;
+; RebootProcessor - Reboots the machine
+; GetSector - Read one or more sectors from the boot device.
+; PutChar - Puts a character on the video display.
+; GetKey - Gets a key from the keyboard
+; GetCounter - Reads the Tick Counter
+; Reboot - Transfers control to a loaded boot sector.
+; HardwareCursor - set position of hardware cursor
+; GetDateTime - gets date and time
+; ComPort - int14 functions
+; IsMcaMachine - determine whether machine is MCA machine
+; GetStallCount - calculates processor stall count
+;
+;
+; Notes
+;
+; When adding a new exported routine note that you must manually add the
+; entry's name to the BootRecord in "sudata.asm".
+;
+;--
+
+include su.inc
+include macro.inc
+
+DISK_TABLE_VECTOR equ 01Eh * 4
+
+_TEXT segment para use16 public 'CODE'
+ ASSUME CS: _TEXT, DS: DGROUP, SS: DGROUP
+.386p
+
+ extrn _DiskBaseTable:near
+ extrn _RomDiskBasePointer:near
+ extrn _EddsAddressPacket:near
+
+
+;++
+;
+; Exported Name:
+;
+; RebootProcessor
+;
+; Arguments:
+;
+; None
+;
+; Description:
+;
+; Reboot the processor using INT 19h
+;
+;
+;
+;--
+;
+; ExportEntry takes us from a 32bit cs to a 16bit cs, inits 16bit stack
+; and ds segments and saves the callers esp and ebp.
+;
+;--
+
+EXPORT_ENTRY_MACRO RebootProcessor
+;
+; Switch to real mode so we can take interrupts
+;
+
+ ENTER_REALMODE_MACRO
+
+ int 19h
+;
+; Loop forever and wait to ctrl-alt-del (should never get here)
+;
+
+ WAIT_FOREVER_MACRO
+
+;EXPORT_EXIT_MACRO
+
+
+;++
+;
+; Name:
+;
+; GetSector
+;
+; Description:
+;
+; Reads the requested number of sectors from the specified drive into
+; the specified buffer.
+;
+; Arguments:
+;
+; ULONG Virtual address into which to read data
+; ULONG Number of sectors to read
+; ULONG Physical sector number
+; ULONG Drive Number
+; ULONG Function Number
+; TOS -> ULONG Flat return address (must be used with KeCodeSelector)
+;
+;--
+
+EXPORT_ENTRY_MACRO GetSector
+;
+; Move the arguments from the caller's 32bit stack to the SU module's
+; 16bit stack.
+;
+
+ MAKE_STACK_FRAME_MACRO <GetSectorFrame>, ebx
+
+;
+; Go into real mode. We still have the same stack and sp
+; but we'll be executing in realmode.
+;
+
+ ENTER_REALMODE_MACRO
+
+;
+; Get the requested sectors. Arguments on realmode stack
+; Make (bp) point to the bottom of the argument frame.
+;
+ push bp
+ mov bp,sp
+ add bp,2
+
+;
+; Put the buffer pointer into es:bx. Note that and buffer
+; addresses passed to this routine MUST be in the lower one
+; megabyte of memory to be addressable in real mode.
+;
+
+ mov eax,[bp].BufferPointer
+ mov bx,ax
+ and bx,0fh
+ shr eax,4
+ mov es,ax
+;
+; Place the upper 2 bits of the 10bit track/cylinder number
+; into the uppper 2 bits of the SectorNumber as reguired by
+; the bios.
+;
+ mov cx,word ptr [bp].TrackNumber
+ xchg ch,cl
+ shl cl,6
+ add cl,byte ptr [bp].SectorNumber
+
+;
+; Get the rest of the arguments
+;
+ mov ah,byte ptr [bp].FunctionNumber
+ mov al,byte ptr [bp].NumberOfSectors
+ mov dh,byte ptr [bp].HeadNumber
+ mov dl,byte ptr [bp].DriveNumber
+
+;
+; Check to see if we are trying to reset/read/write/verify off the second
+; floppy drive. If so, we need to go change the disk-base vector.
+;
+ cmp dl,1
+ jne gs3
+ cmp ah,4
+ jg gs3
+ cmp ah,0
+ je gs1
+ cmp ah,2
+ jl gs3
+
+gs1:
+;
+; We need to point the BIOS disk-table vector to our own table for this
+; drive.
+;
+ push es
+ push bx
+ push di
+
+ push 0
+ pop es
+
+ mov di, offset DGROUP:_RomDiskBasePointer
+
+ mov bx,es:[DISK_TABLE_VECTOR]
+ mov [di],bx
+ mov bx,es:[DISK_TABLE_VECTOR+2]
+ mov [di+2],bx
+
+ mov bx,offset DGROUP:_DiskBaseTable
+ mov es:[DISK_TABLE_VECTOR],bx
+ mov bx,ds
+ mov es:[DISK_TABLE_VECTOR+2],bx
+
+ pop di
+ pop bx
+ pop es
+
+ int BIOS_DISK_INTERRUPT
+
+ push es
+ push bx
+ push di
+
+ push 0
+ pop es
+
+ mov di, offset DGROUP:_RomDiskBasePointer
+
+ mov bx, [di]
+ mov es:[DISK_TABLE_VECTOR],bx
+ mov bx, [di+2]
+ mov es:[DISK_TABLE_VECTOR+2],bx
+
+ pop di
+ pop bx
+ pop es
+
+ jc gs5
+ xor eax,eax
+ jmp short gs5
+
+gs3:
+
+;
+; Call the bios to read the sector now
+;
+if 0
+ push ax
+ push dx
+ push cx
+ push bx
+ push es
+extrn _DisplayArgs:near
+ call _DisplayArgs
+ pop es
+ pop bx
+ pop cx
+ pop dx
+ pop ax
+endif
+
+ int BIOS_DISK_INTERRUPT
+ jc gs5
+
+;
+; Carry wasn't set so we have no error and need to "clean" eax of
+; any garbage that may have been left in it.
+;
+ xor eax,eax
+gs5:
+if 0
+ push ax
+ push dx
+ push cx
+ push bx
+ push es
+extrn _DisplayArgs:near
+ call _DisplayArgs
+ pop es
+ pop bx
+ pop cx
+ pop dx
+ pop ax
+endif
+
+;
+; Mask-off any garbage that my have been left in the upper
+; 16bits of eax.
+;
+ and eax,0000ffffh
+
+;
+; Restore bp and remove stack-frame from stack
+;
+ pop bp
+
+ REMOVE_STACK_FRAME_MACRO <GetSectorFrame>
+
+;
+; Save return code on 16bit stack
+; Re-enable protect-mode and paging.
+;
+
+; move cx into high 16-bits of ecx, and dx into cx. This is so the loader
+; can get at interesting values in dx, even though edx gets munged by the
+; random real-mode macros.
+
+ shl ecx, 16
+ mov cx,dx
+ push eax
+ RE_ENABLE_PAGING_MACRO
+ pop eax
+;
+; Return to caller and the 32bit universe.
+;
+EXPORT_EXIT_MACRO
+
+;++
+;
+; Name:
+;
+; GetEddsSector
+;
+; Description:
+;
+; Reads the requested number of sectors from the specified drive into
+; the specified buffer based on the Phoenix Enhanced Disk Drive Spec.
+;
+; Arguments:
+;
+; ULONG Virtual address into which to read data
+; ULONG Number of logical blocks to read
+; ULONG Logical block number (High word)
+; ULONG Logical block number (Low word)
+; ULONG Drive Number
+; TOS -> ULONG Flat return address (must be used with KeCodeSelector)
+;
+;--
+
+EXPORT_ENTRY_MACRO GetEddsSector
+;
+; Move the arguments from the caller's 32bit stack to the SU module's
+; 16bit stack.
+;
+
+ MAKE_STACK_FRAME_MACRO <GetEddsSectorFrame>, ebx
+
+;
+; Go into real mode. We still have the same stack and sp
+; but we'll be executing in realmode.
+;
+
+ ENTER_REALMODE_MACRO
+
+;
+; Get the requested sectors. Arguments on realmode stack
+; Make (bp) point to the bottom of the argument frame.
+;
+ push bp
+ mov bp,sp
+ add bp,2
+
+ push ds
+ push si
+ push bx
+
+;
+; Set up DS:SI -> Disk Address Packet
+;
+ push 0
+ pop ds
+ mov si, offset DGROUP:_EddsAddressPacket
+ mov ds:[si],byte ptr 10h ; Packet size = 10h
+ mov ds:[si][1],byte ptr 0 ; Reserved = 0
+ mov al,byte ptr [bp].NumberOfBlocks
+ mov ds:[si][2],al ; Num blocks to transfer
+ mov ds:[si][3],byte ptr 0 ; Reserved = 0
+ mov eax,[bp].BufPointer
+ mov bx,ax
+ and bx,0fh
+ mov ds:[si][4],bx ; Transfer buffer address (low word=offset)
+ shr eax,4
+ mov ds:[si][6],ax ; Transfer buffer address (high word=segment)
+ mov eax,[bp].LBNLow
+ mov ds:[si][8],eax ; Starting logical block number (low dword)
+ mov eax,[bp].LBNHigh
+ mov ds:[si][12],eax ; Starting logical block number (high dword)
+
+;
+; Call the bios to read the sector now (DS:SI -> Disk address packet)
+;
+ mov ah,42h ; function = Extended Read
+ mov dl,byte ptr [bp].DriveNum ; DL = drive number
+ int BIOS_DISK_INTERRUPT
+ jc geserror1
+
+;
+; Carry wasn't set so we have no error and need to "clean" eax of
+; any garbage that may have been left in it.
+;
+ xor eax,eax
+geserror1:
+
+;
+; Mask-off any garbage that my have been left in the upper
+; 16bits of eax.
+;
+ and eax,0000ffffh
+
+ pop bx
+ pop si
+ pop ds
+
+;
+; Restore bp and remove stack-frame from stack
+;
+ pop bp
+
+ REMOVE_STACK_FRAME_MACRO <GetEddsSectorFrame>
+
+;
+; Save return code on 16bit stack
+; Re-enable protect-mode and paging.
+;
+
+; move cx into high 16-bits of ecx, and dx into cx. This is so the loader
+; can get at interesting values in dx, even though edx gets munged by the
+; random real-mode macros.
+
+ shl ecx, 16
+ mov cx,dx
+ push eax
+ RE_ENABLE_PAGING_MACRO
+ pop eax
+;
+; Return to caller and the 32bit universe.
+;
+EXPORT_EXIT_MACRO
+
+;++
+;
+; Routine Name:
+;
+; GetKey
+;
+; Description:
+;
+; Checks the keyboard to see if a key is available.
+;
+; Arguments:
+;
+; None.
+;
+; Returns:
+;
+; If no key is available, returns 0
+;
+; If ASCII character is available, LSB 0 is ASCII code
+; LSB 1 is keyboard scan code
+; If extended character is available, LSB 0 is extended ASCII code
+; LSB 1 is keyboard scan code
+;
+;--
+
+EXPORT_ENTRY_MACRO GetKey
+;
+; Go into real mode. We still have the same stack and sp
+; but we'll be executing in real mode.
+;
+
+ ENTER_REALMODE_MACRO
+
+;
+; Set up registers to call BIOS and check to see if a key is available
+;
+
+ mov ax,0100h
+ int BIOS_KEYBOARD_INTERRUPT
+
+ jnz GkKeyAvail
+ mov eax, 0
+ jmp GkDone
+
+GkKeyAvail:
+;
+; Now we call BIOS again, this time to get the key from the keyboard buffer
+;
+ mov ax,0
+ int BIOS_KEYBOARD_INTERRUPT
+ and eax,0000ffffh
+
+;
+; Save return code on 16bit stack
+; Re-enable protect mode and paging
+;
+GkDone:
+ push eax
+ RE_ENABLE_PAGING_MACRO
+ pop eax
+;
+; Return to caller and the 32-bit universe
+;
+EXPORT_EXIT_MACRO
+
+;++
+;
+; Routine Name:
+;
+; GetCounter
+;
+; Description:
+;
+; Reads the tick counter (incremented 18.2 times per second)
+;
+; Arguments:
+;
+; None
+;
+; Returns:
+;
+; The current value of the tick counter
+;
+;--
+
+EXPORT_ENTRY_MACRO GetCounter
+;
+; Go into real mode.
+;
+
+ ENTER_REALMODE_MACRO
+
+ mov ah,0
+ int 01ah
+ mov ax,cx ; high word of count
+ shl eax,16
+ mov ax,dx ; low word of count
+
+ push eax
+ RE_ENABLE_PAGING_MACRO
+ pop eax
+
+EXPORT_EXIT_MACRO
+
+
+;++
+;
+; Routine Name:
+;
+; Reboot
+;
+; Description:
+;
+; Switches to real-mode and transfers control to a loaded boot sector
+;
+; Arguments:
+;
+; unsigned BootType
+; 0 = FAT. Just jump to 0:7c00.
+; 1 = HPFS. Assumes boot code and super+spare areas (20 sectors)
+; are already loaded at 0xd000; jumps to d00:200.
+; 2 = NTFS. Assumes boot code is loaded (16 sectors) at 0xd000.
+; Jumps to d00:256.
+;
+; Returns:
+; Does not return
+;
+; Environment:
+;
+; Boot sector has been loaded at 7C00
+;--
+
+EXPORT_ENTRY_MACRO Reboot
+;
+; Move the arguments from the caller's 32bit stack to the SU module's
+; 16bit stack.
+;
+
+ MAKE_STACK_FRAME_MACRO <RebootFrame>, ebx
+;
+; Go into real mode.
+;
+
+ ENTER_REALMODE_MACRO
+
+;
+; Get the BootType argument. Arguments on realmode stack
+; Make (bp) point to the bottom of the argument frame.
+;
+
+ push bp
+ mov bp,sp
+ add bp,2
+ mov edx, [bp].BootType
+
+;
+; Zero out the firmware heaps, 3000:0000 - 4000:ffff.
+;
+
+ xor eax,eax ; prepare for stosd
+ mov bx,3000h
+ mov es,bx
+ mov di,ax ; es:di = physical address 30000
+ mov cx,4000h ; cx = rep count, # dwords in 64K
+ cld
+ rep stosd
+ mov cx,4000h ; rep count
+ mov es,cx ; es:di = physical address 40000
+ rep stosd
+
+;
+; Disable the A20 line. Some things (like EMM386 and OS/2 on PS/2 machines)
+; hiccup or die if we don't do this.
+;
+
+extrn _DisableA20:near
+ call _DisableA20
+
+;
+; Put the video adapter back in 80x25 mode
+;
+ push dx
+ mov ax, 0003h
+ int 010h
+ pop dx
+
+;
+; Reset all the segment registers and setup the original stack
+;
+ mov ax,0
+ mov ds,ax
+ mov es,ax
+ mov fs,ax
+ mov gs,ax
+
+ mov ax,30
+ mov ss,ax
+ mov esp,0100h
+ mov ebp,0
+ mov esi,0
+ mov edi,0
+
+ test dx,-1
+ jz FatBoot
+
+;
+; Setup the registers the way the second sector of the OS/2 HPFS boot code
+; expects them. We skip the first sector entirely, as that just loads in
+; the rest of the sectors. Since the rest of the sectors are ours and not
+; OS/2's, this would cause great distress.
+;
+ mov ax,07c0h
+ mov ds, ax
+ mov ax, 0d00h
+ mov es, ax
+
+ cli
+ xor ax,ax
+ mov ss,ax
+ mov sp, 07c00h
+ sti
+
+ cmp dx,4 ; ofs?
+ jne OfsBoot
+ push 1000h
+ push 020ch
+ jmp RebootDoit
+
+OfsBoot:
+ push 0d00h
+ cmp dx,1 ; hpfs?
+ je HpfsBoot
+ push 0256h
+ jmp RebootDoit
+HpfsBoot:
+ push 0200h
+ jmp RebootDoit
+
+FatBoot:
+ push 0 ; set up for branch to boot sector
+ push 07c00h
+ mov dx,080h
+
+;
+; And away we go!
+;
+RebootDoit:
+ retf
+
+ RE_ENABLE_PAGING_MACRO
+
+ REMOVE_STACK_FRAME_MACRO <RebootFrame>
+
+EXPORT_EXIT_MACRO
+
+;++
+;
+; Name:
+;
+; HardwareCursor
+;
+; Description:
+;
+; Positions the hardware cursor and performs other display stuff.
+;
+; Arguments:
+;
+; ULONG Y coord (0 based)
+; ULONG X coord (0 based)
+; TOS -> ULONG Flat return address (must be used with KeCodeSelector)
+;
+; If X = 0x80000000, then Y contains values that get placed into
+; ax (low word of Y) and bx (hi word of y).
+; Otherwise X,Y = coors for cursor
+;
+;
+;--
+
+EXPORT_ENTRY_MACRO HardwareCursor
+;
+; Move the arguments from the caller's 32bit stack to the SU module's
+; 16bit stack.
+;
+
+ MAKE_STACK_FRAME_MACRO <HardwareCursorFrame>, ebx
+
+;
+; Go into real mode. We still have the same stack and sp
+; but we'll be executing in realmode.
+;
+
+ ENTER_REALMODE_MACRO
+
+;
+; Get the requested sectors. Arguments on realmode stack
+; Make (bp) point to the bottom of the argument frame.
+;
+ push bp
+ mov bp,sp
+ add bp,2
+
+;
+; Put the row (y coord) in dh and the column (x coord) in dl.
+;
+
+ mov eax,[bp].YCoord
+ mov edx,[bp].XCoord
+ cmp edx,80000000h
+ jne gotxy
+
+ mov ebx,eax
+ shr ebx,16
+ jmp doint10
+
+ gotxy:
+ mov dh,al
+ mov ah,2
+ mov bh,0
+
+ doint10:
+ int 10h
+
+;
+; Restore bp and remove stack-frame from stack
+;
+ pop bp
+
+ REMOVE_STACK_FRAME_MACRO <HardwareCursorFrame>
+
+;
+; Re-enable protect-mode and paging.
+;
+
+ RE_ENABLE_PAGING_MACRO
+
+;
+; Return to caller and the 32bit universe.
+;
+EXPORT_EXIT_MACRO
+
+
+;++
+;
+; Name:
+;
+; GetDateTime
+;
+; Description:
+;
+; Gets date and time
+;
+; Arguments:
+;
+; ULONG Virtual address of a dword in which to place time.
+; ULONG Virtual address of a dword in which to place date.
+; TOS -> ULONG Flat return address (must be used with KeCodeSelector)
+;
+;--
+
+BCD_TO_BIN macro
+ xor ah,ah
+ rol ax,4
+ ror al,4
+ aad
+endm
+
+EXPORT_ENTRY_MACRO GetDateTime
+;
+; Move the arguments from the caller's 32bit stack to the SU module's
+; 16bit stack.
+;
+
+ MAKE_STACK_FRAME_MACRO <GetDateTimeFrame>, ebx
+
+;
+; Go into real mode. We still have the same stack and sp
+; but we'll be executing in realmode.
+;
+
+ ENTER_REALMODE_MACRO
+
+;
+; Make (bp) point to the bottom of the argument frame.
+;
+ push bp
+ mov bp,sp
+ add bp,2
+
+;
+; Get the time
+;
+
+ mov ah,2
+ int 1ah
+
+;
+; Convert BIOS time format into our format and place in caller's dword
+; bits 0-5 are the second
+; bits 6-11 are the minute
+; bits 12-16 are the hour
+;
+ xor eax,eax
+ mov al,dh ; BCD seconds
+ BCD_TO_BIN
+ movzx edx,ax
+ mov al,cl ; BCD minutes
+ BCD_TO_BIN
+ shl ax,6
+ or dx,ax
+ mov al,ch ; BCD hours
+ BCD_TO_BIN
+ shl eax,12
+ or edx,eax
+
+ mov eax,[bp].TimeDword
+ mov bx,ax
+ and bx,0fh
+ shr eax,4
+ mov es,ax
+
+ mov es:[bx],edx
+
+;
+; Get the date
+;
+
+ mov ah,4
+ int 1ah
+
+;
+; Convert BIOS date format into our format and place in caller's dword
+; bits 0-4 are the day
+; bits 5-8 are the month
+; bits 9-31 are the year
+;
+
+ xor eax,eax
+ mov al,dl ; BCD day
+ BCD_TO_BIN
+ mov bl,dh
+ movzx edx,ax
+ mov al,bl ; BCD month
+ BCD_TO_BIN
+ shl ax,5
+ or dx,ax
+ mov al,cl ; BCD year
+ BCD_TO_BIN
+ mov cl,al
+ mov al,ch ; BCD century
+ BCD_TO_BIN
+ mov ah,100
+ mul ah
+ xor ch,ch
+ add ax,cx
+ shl eax,9
+ or edx,eax
+
+ mov eax,[bp].DateDword
+ mov bx,ax
+ and bx,0fh
+ shr eax,4
+ mov es,ax
+
+ mov es:[bx],edx
+
+;
+; Restore bp and remove stack-frame from stack
+;
+ pop bp
+
+ REMOVE_STACK_FRAME_MACRO <GetDateTimeFrame>
+
+;
+; Re-enable protect-mode and paging.
+;
+
+ RE_ENABLE_PAGING_MACRO
+
+;
+; Return to caller and the 32bit universe.
+;
+EXPORT_EXIT_MACRO
+
+extrn AbiosServicesTable:WORD
+
+;--
+;++
+;
+; BOOLEAN
+; AbiosServices (
+; VOID
+; )
+;
+; Routine Description:
+;
+; This routine performs certain ABIOS initialization function according
+; to the function number specified in ABIOS Service Stack Frame.
+;
+; Arguments:
+;
+; AbiosServiceFrame on stack. (see su.inc)
+;
+; Return Value:
+;
+; TRUE - if the required function is success. Otherwise a value of
+; FALSE is returned in eax.
+;
+;--
+
+
+EXPORT_ENTRY_MACRO AbiosServices
+
+;
+; Move the arguments from the caller's 32bit stack to the SU module's
+; 16bit stack.
+;
+
+ MAKE_STACK_FRAME_MACRO <AbiosServicesFrame>, ebx
+
+;
+; Go into real mode. We still have the same stack and sp
+; but we'll be executing in realmode.
+;
+
+ ENTER_REALMODE_MACRO
+
+;
+; Get the requested Arguments on realmode stack.
+; Make (bp) point to the bottom of the argument frame.
+;
+
+ push bp
+ mov bp,sp
+ add bp,2
+
+;
+; Call the appropriate abios service routine and pass
+; bp as the pointer to the arguments.
+;
+
+ push bx
+ mov bx, word ptr [bp].AbiosFunction
+ shl bx, 1
+ call AbiosServicesTable[bx]
+ pop bx
+
+;
+; Restore bp and remove stack-frame from stack
+;
+
+ pop bp
+
+ REMOVE_STACK_FRAME_MACRO <AbiosServicesFrame>
+
+;
+; Save return code on 16bit stack
+; Re-enable protect-mode and paging.
+;
+
+ push eax
+ RE_ENABLE_PAGING_MACRO
+ pop eax
+
+;
+; Return to caller and the 32bit universe.
+;
+
+EXPORT_EXIT_MACRO
+
+;++
+;
+; VOID
+; DetectHardware (
+; IN PDETECTION_RECORD DetectionRecord
+; )
+;
+; Routine Description:
+;
+; This routine invokes x86 16 bit real mode detection code from
+; osloader 32 bit flat mode.
+;
+; Arguments:
+;
+; DetectionRecord - Supplies a pointer to a detection record structure.
+;
+; Return Value:
+;
+; None.
+;
+;--
+
+
+EXPORT_ENTRY_MACRO DetectHardware
+
+;
+; Move the arguments from the caller's 32bit stack to the SU module's
+; 16bit stack.
+;
+
+ MAKE_STACK_FRAME_MACRO <DetectionFrame>, ebx
+
+;
+; Go into real mode. We still have the same stack and sp
+; but we'll be executing in realmode.
+;
+
+ ENTER_REALMODE_MACRO
+
+;
+; Call the Hardware Detection code
+;
+
+ push cs
+ push offset _TEXT:DetectionDone ; push far return addr
+
+ push DETECTION_ADDRESS_SEG
+ push DETECTION_ADDRESS_OFFSET
+ retf
+
+DetectionDone:
+
+;
+; Restore bp and remove stack-frame from stack
+;
+
+ REMOVE_STACK_FRAME_MACRO <DetectionFrame>
+
+;
+; No return code, so we don't save return code around page enabling code
+; Re-enable protect-mode and paging.
+;
+
+ RE_ENABLE_PAGING_MACRO
+
+;
+; Return to caller and the 32bit universe.
+;
+
+EXPORT_EXIT_MACRO
+
+;++
+;
+; VOID
+; ComPort (
+; IN LONG Port,
+; IN ULONG Function,
+; IN UCHAR Arg
+; )
+;
+; Routine Description:
+;
+; Invoke int14 on com1.
+;
+; Arguments:
+;
+; Port - port # (0 = com1, etc).
+;
+; Function - int 14 function (for ah)
+;
+; Arg - arg for function (for al)
+;
+; Return Value:
+;
+; None.
+;
+;--
+
+
+EXPORT_ENTRY_MACRO ComPort
+
+;
+; Move the arguments from the caller's 32bit stack to the SU module's
+; 16bit stack.
+;
+
+ MAKE_STACK_FRAME_MACRO <ComPortFrame>, ebx
+
+;
+; Go into real mode. We still have the same stack and sp
+; but we'll be executing in realmode.
+;
+
+ ENTER_REALMODE_MACRO
+
+;
+; Make (bp) point to the bottom of the argument frame.
+;
+ push bp
+ mov bp,sp
+ add bp,2
+
+;
+; Get args and call int14
+;
+
+ mov ah,byte ptr [bp].ComPortFunction
+ mov al,byte ptr [bp].ComPortArg
+ mov dx,word ptr [bp].ComPortPort
+ int 14h
+
+;
+; Restore bp and remove stack-frame from stack
+;
+
+ pop bp
+
+ REMOVE_STACK_FRAME_MACRO <ComPortFrame>
+
+;
+; No return code, so we don't save return code around page enabling code
+; Re-enable protect-mode and paging.
+;
+
+ RE_ENABLE_PAGING_MACRO
+
+;
+; Return to caller and the 32bit universe.
+;
+
+EXPORT_EXIT_MACRO
+
+;++
+;
+; VOID
+; IsMcaMachine (
+; VOID
+; )
+;
+; Routine Description:
+;
+; Determine whether machine is Mca machine
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; 0 - not MCA machine
+; 1 - MCA machine
+;
+;--
+
+extrn _BtIsMcaSystem:near
+
+EXPORT_ENTRY_MACRO IsMcaMachine
+
+;
+; Move the arguments from the caller's 32bit stack to the SU module's
+; 16bit stack.
+;
+
+ MAKE_STACK_FRAME_MACRO <IsMcaMachineFrame>, ebx
+
+;
+; Go into real mode. We still have the same stack and sp
+; but we'll be executing in realmode.
+;
+
+ ENTER_REALMODE_MACRO
+
+;
+; Make (bp) point to the bottom of the argument frame.
+;
+ push bp
+ mov bp,sp
+ add bp,2
+
+;
+; Make the determination
+;
+
+ call _BtIsMcaSystem
+ movzx eax,ax
+
+;
+; Restore bp and remove stack-frame from stack
+;
+
+ pop bp
+
+ REMOVE_STACK_FRAME_MACRO <IsMcaMachineFrame>
+
+;
+; No return code, so we don't save return code around page enabling code
+; Re-enable protect-mode and paging.
+;
+
+ push eax
+ RE_ENABLE_PAGING_MACRO
+ pop eax
+
+;
+; Return to caller and the 32bit universe.
+;
+
+EXPORT_EXIT_MACRO
+
+;++
+;
+; ULONG
+; GetStallCount (
+; VOID
+; )
+;
+; Routine Description:
+;
+; Calculates how many increments are required to stall for one microsecond
+;
+; The way this routine works is to set up an ISR on the BIOS vector 1C.
+; This routine will get called 18.2 times a second. The location where
+; IP will be stored when the interrupt occurs is computed and stashed in
+; the code segment. When the ISR fires, the IP on the stack is changed
+; to point to the next chunk of code to execute. So we can spin in a
+; very tight loop and automatically get blown out of the loop when the
+; interrupt occurs.
+;
+; This is all pretty sleazy, but it allows us to calibrate accurately
+; without relying on the 8259 or 8254 (just BIOS). It also does not
+; depend on whether the ISR can affect the CPU registers or not. (some
+; BIOSes, notably Olivetti, will preserve the registers for you)
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; Number of increments required to stall for one microsecond
+;
+;--
+
+EXPORT_ENTRY_MACRO GetStallCount
+;
+; Go into real mode.
+;
+
+
+ ENTER_REALMODE_MACRO
+
+ cli
+
+ push di
+ push si
+ push ds
+ mov ax,0
+ mov ds,ax
+
+;
+; save previous vector
+;
+ mov di, 01ch*4
+ mov cx, [di]
+ mov dx, [di+2]
+
+;
+; insert our vector
+;
+ mov ax, offset GscISR
+ mov [di], ax
+ push cs
+ pop ax
+ mov [di+2], ax
+
+ mov eax,0
+ mov ebx,0
+ mov si,sp
+ sub si,6
+ mov cs:savesp,si
+ mov cs:newip,offset GscLoop2
+ sti
+
+;
+; wait for first tick.
+;
+GscLoop1:
+ cmp ebx,0
+ je GscLoop1
+
+;
+; start counting
+;
+;
+; We spin in this loop until the ISR fires. The ISR will munge the return
+; address on the stack to blow us out of the loop and into GscLoop3
+;
+GscLoop2:
+ mov cs:newip,offset GscLoop4
+
+GscLoop3:
+
+ add eax,1
+ jnz short GscLoop3
+
+;
+GscLoop4:
+;
+; stop counting
+;
+
+;
+; replace old vector
+;
+ cli
+ mov [di],cx
+ mov [di+2],dx
+ sti
+
+ pop ds
+ pop si
+ pop di
+ jmp GscDone
+
+newip dw ?
+savesp dw ?
+
+GscISR:
+;
+; blow out of loop
+;
+ push bp
+ push ax
+ mov bp,cs:savesp
+ mov ax,cs:newip
+ mov ss:[bp],ax
+ pop ax
+ pop bp
+
+GscISRdone:
+ iret
+
+
+GscDone:
+ mov edx, eax
+ mov ecx,16
+ shr edx,cl ; (dx:ax) = dividend
+ mov cx,0D6A6h ; (cx) = divisor
+
+ div cx
+
+ and eax,0ffffh
+ inc eax ; round loopcount up (prevent 0)
+
+;
+; Re-enable protect-mode and paging.
+;
+ push eax
+ RE_ENABLE_PAGING_MACRO
+ pop eax
+
+;
+; Return to caller and the 32bit universe.
+;
+
+EXPORT_EXIT_MACRO
+
+
+;++
+;
+; Routine Name:
+;
+; InitializeDisplayForNt
+;
+; Description:
+;
+; Puts the display into 50 line mode
+;
+; Arguments:
+;
+; None
+;
+; Returns:
+;
+; None
+;
+;--
+
+EXPORT_ENTRY_MACRO InitializeDisplayForNt
+;
+; Go into real mode.
+;
+
+ ENTER_REALMODE_MACRO
+
+ mov ax, 1112h ; Load 8x8 font
+ mov bx, 0
+ int 10h
+
+ RE_ENABLE_PAGING_MACRO
+
+EXPORT_EXIT_MACRO
+
+;++
+;
+; Routine Name:
+;
+; GetMemoryDescriptor
+;
+; Description:
+;
+; Returns a memory descriptor
+;
+; Arguments:
+;
+; pointer to MemoryDescriptorFrame
+;
+; Returns:
+;
+; None
+;
+;--
+
+EXPORT_ENTRY_MACRO GetMemoryDescriptor
+
+;
+; Move the arguments from the caller's 32bit stack to the SU module's
+; 16bit stack.
+;
+
+ MAKE_STACK_FRAME_MACRO <MemoryDescriptorFramePointer>, ebx
+
+;
+; Go into real mode. We still have the same stack and sp
+; but we'll be executing in realmode.
+;
+
+ ENTER_REALMODE_MACRO
+
+;
+; Make (bp) point to the bottom of the argument frame.
+;
+ push bp
+ mov bp,sp
+ add bp,2
+
+
+ mov eax,[bp].E820FramePointer
+ mov bp,ax
+ and bp,0fh
+ shr eax,4
+ mov es,ax ; (es:bp) = E820 Frame
+
+ mov ebx, es:[bp].Key
+ mov ecx, es:[bp].DescSize
+ lea di, [bp].BaseAddrLow
+ mov eax, 0E820h
+ mov edx, 'SMAP' ; (edx) = signature
+
+ INT 15h
+ mov es:[bp].Key, ebx ; update callers ebx
+ mov es:[bp].DescSize, ecx ; update callers size
+
+ sbb ecx, ecx ; ecx = -1 if carry, else 0
+ sub eax, 'SMAP' ; eax = 0 if signature matched
+ or ecx, eax
+ mov es:[bp].ErrorFlag, ecx ; return 0 or non-zero
+
+;
+; Restore bp and remove stack-frame from stack
+;
+
+ pop bp
+ REMOVE_STACK_FRAME_MACRO <MemoryDescriptorFramePointer>
+ RE_ENABLE_PAGING_MACRO
+
+EXPORT_EXIT_MACRO
+
+;++
+;
+; Routine Name:
+;
+; GetElToritoStatus
+;
+; Description:
+;
+; Get El Torito Disk Emulation Status
+;
+; Arguments:
+;
+; None
+;
+; Returns:
+;
+; None
+;
+;--
+
+EXPORT_ENTRY_MACRO GetElToritoStatus
+;
+; Move the arguments from the caller's 32bit stack to the SU module's
+; 16bit stack.
+;
+
+ MAKE_STACK_FRAME_MACRO <GetElToritoStatusFrame>, ebx
+
+;
+; Go into real mode. We still have the same stack and sp
+; but we'll be executing in realmode.
+;
+
+ ENTER_REALMODE_MACRO
+
+;
+; Make (bp) point to the bottom of the argument frame.
+;
+ push bp
+ mov bp,sp
+ add bp,2
+
+ push dx
+ push bx
+ push ds
+ push si
+
+;
+; Put the Specification Packet pointer into DS:SI, and the Drive
+; Number on DL. Note that and buffer
+; addresses passed to this routine MUST be in the lower one
+; megabyte of memory to be addressable in real mode.
+;
+
+ mov eax,[bp].SpecPacketPointer
+ mov bx,ax
+ and bx,0fh
+ mov si,bx
+ shr eax,4
+ mov ds,ax
+
+ mov dl,byte ptr [bp].ETDriveNum
+
+ mov ax,04B01h ; Function = Return Disk Emulation status
+ int BIOS_DISK_INTERRUPT
+
+ jc etstatuserr
+
+;
+; Carry wasn't set so we have no error and need to "clean" eax of
+; any garbage that may have been left in it.
+;
+ xor eax,eax
+
+etstatuserr:
+;
+; Mask-off any garbage that my have been left in the upper
+; 16bits of eax.
+;
+ and eax,0000ffffh
+
+ pop si
+ pop ds
+ pop bx
+ pop dx
+
+;
+; Restore bp and remove stack-frame from stack
+;
+ pop bp
+
+ REMOVE_STACK_FRAME_MACRO <GetElToritoStatusFrame>
+
+;
+; Save return code on 16bit stack
+; Re-enable protect-mode and paging.
+;
+
+ push eax
+ RE_ENABLE_PAGING_MACRO
+ pop eax
+
+;
+; Return to caller and the 32bit universe.
+;
+EXPORT_EXIT_MACRO
+
+_TEXT ends
+
+ end
+
diff --git a/private/ntos/boot/startup/i386/global.h b/private/ntos/boot/startup/i386/global.h
new file mode 100644
index 000000000..b572dc93a
--- /dev/null
+++ b/private/ntos/boot/startup/i386/global.h
@@ -0,0 +1,190 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+
+File Name:
+
+ global.h
+
+
+Abstract:
+
+ Prototypes for all global functions defined for the 386 NT bootloader
+
+
+Author
+
+ Thomas Parslow (TomP) 2-Jan-90
+
+
+
+--*/
+VOID
+SuMain(
+ IN FPVOID BtRootDir,
+ IN FPDISKBPB BtBiosBlock,
+ IN SHORT BtBootDrive
+ );
+
+
+
+extern
+USHORT
+Debugger;
+
+
+/////
+///// IN sumain.c
+/////
+
+
+VOID
+SetupPageTables(
+ VOID
+ );
+
+
+//
+// in Supage.c
+//
+
+extern
+VOID
+InitializePageTables(
+ VOID
+ );
+
+VOID
+ZeroMemory(
+ ULONG,
+ ULONG
+);
+
+
+
+USHORT DebuggerPresent;
+
+VOID
+PrintBootMessage(
+ VOID
+ );
+
+/*
+VOID
+DoGlobalInitialization(
+ IN FPVOID,
+ IN FPDISKBPB,
+ IN USHORT
+ );
+
+
+VOID
+MoveMemory(
+ IN ULONG,
+ IN PUCHAR,
+ IN USHORT
+ );
+
+
+/////
+///// IN disk.c
+/////
+
+VOID
+InitializeDiskSubSystem(
+ IN FPDISKBPB,
+ IN USHORT
+ );
+
+/*
+
+VOID
+InitializePageSets(
+ IN PIMAGE_FILE_HEADER
+ );
+
+VOID
+EnableA20(
+ VOID
+ );
+
+
+extern IDT IDT_Table;
+
+*/
+
+/////
+///// IN su.asm
+/////
+
+
+VOID
+EnableProtectPaging(
+ USHORT
+ );
+
+
+SHORT
+biosint(
+ IN BIOSREGS far *
+ );
+
+extern
+VOID
+TransferToLoader(
+ ULONG
+ );
+
+
+/////
+///// IN video.c
+/////
+
+VOID
+InitializeVideoSubSystem(
+ VOID
+ );
+
+VOID
+putc(
+ IN CHAR
+ );
+VOID
+putu(
+ IN ULONG
+ );
+
+VOID
+puts(
+ IN PCHAR
+ );
+
+VOID
+puti(
+ IN LONG
+ );
+
+VOID
+putx(
+ IN ULONG
+ );
+
+VOID
+scroll(
+ VOID
+ );
+
+VOID
+clrscrn(
+ VOID
+ );
+
+VOID
+BlPrint(
+ IN PCHAR,
+ ...
+ );
+
+
+// END OF FILE //
diff --git a/private/ntos/boot/startup/i386/macro.inc b/private/ntos/boot/startup/i386/macro.inc
new file mode 100644
index 000000000..1327ef34d
--- /dev/null
+++ b/private/ntos/boot/startup/i386/macro.inc
@@ -0,0 +1,239 @@
+;++
+;
+; File Name:
+;
+; macro.inc
+;
+; Author:
+;
+; Thomas Parslow [tomp]
+;
+; Created:
+;
+; 27-Feb-91
+;
+; Abstract:
+;
+; The macros used for creating the exported entry points the
+; OS loader will use for basic h/w dependent services. These
+; services are:
+;
+; o Disk I/O
+; o Character I/O
+;
+;
+;--
+
+
+;++
+;
+; EXPORT_ENTRY_MACRO
+; We arrive here from the OS loader with a 32bit CS. That is, we're
+; executing the code with cs:eip where cs contains a selector for a
+; 32bit flat segment. We want to get to a 16bit cs. That is, cs:ip.
+; The entry points are exported as 32bit near pointers to the OS loader.
+; All code in the SU module is identity mapped so the flat 32bit offset
+; is equal to the physical address.
+;
+; Therefore, we export the 32bit physical address as the
+; entry point and the code may be executed with either the 32bit
+; flat cs or the SU module's 16bit based cs. Before we can switch
+; modes we must load all of the segment registers with selectors for
+; 16bit segments. We start by pushing a far pointer to a label in
+; the macro and then doing a retf. This allows us to fall through
+; to the next instruction, but we're now executing through cs:ip
+; with a 16bit CS.
+;
+; Output:
+;
+; (ebx) = pointer to stack frame (and top of 32bit stack).
+;
+
+EXPORT_ENTRY_MACRO macro entryname
+ LOCAL exp1
+_TEXT32 segment para use32 public 'CODE'
+ ASSUME CS:_TEXT32
+ALIGN 4
+Public EntryName
+EntryName LABEL near
+;
+; We've go a 32bit CS:EIP - go to a 16bit CS:IP
+
+ push dword ptr SuCodeSelector
+ push dword ptr (offset exp1)
+
+ retf
+_TEXT32 ends
+ ASSUME CS:_TEXT
+ALIGN 4
+exp1:
+;
+; Save caller's EBP register and stack pointer (ESP)
+;
+
+ push ebp
+ push ebx
+ push esi
+ push edi
+ mov ebx,esp
+;
+; Load all the segment registers with 16bit segment selectors
+;
+ mov ax,SuDataSelector
+ mov ds,ax
+ mov ss,ax
+;
+; Set the stack to the top of the segment. We can do this now since
+; all of the OS loader's code has already be relocated. Also, we need
+; plenty of stack since we'll be calling BIOS routines.
+;
+ mov sp,EXPORT_STACK
+ push ebx ; save the caller's esp
+ endm
+;
+; EXPORT_ENTRY_MACRO end
+;
+
+
+
+;++
+;
+; Name:
+;
+; ExportExit
+;
+; Arguments:
+;
+;
+; Notes:
+;
+; EAX = return code and MUST be preserved by this macro.
+;
+;--
+
+EXPORT_EXIT_MACRO macro
+;
+; Next get caller's esp that we saved upon entry on the 16bit stack
+;
+ pop ebx ; get caller's esp
+;
+; Restore flat selectors in segment registers.
+;
+ mov dx,KeDataSelector
+ mov ds,dx
+ mov ss,dx
+ mov es,dx
+ mov esp,ebx
+
+
+;
+; Restore callers' ebp that we saved on the 32bit stack
+;
+ pop edi
+ pop esi
+ pop ebx
+ pop ebp ; (ebp) = caller's ebp
+
+;
+; Pull callers flat return address off stack and push the
+; flat code selector followed by the return offset, then
+; execute a far return and we'll be back in the OS loaders code space.
+;
+ pop edx ; (edx) = caller's return address
+ push dword ptr KeCodeSelector
+ push edx
+ db OVERRIDE
+ retf
+ endm
+
+;++
+;
+;
+;
+;--
+
+RE_ENABLE_PAGING_MACRO macro
+extrn _EnableProtectPaging:near
+ push RE_ENABLING
+ call _EnableProtectPaging
+ add sp,2
+ endm
+
+ENTER_REALMODE_MACRO macro
+extrn _RealMode:near
+ call _RealMode
+ endm
+
+
+
+WAIT_FOREVER_MACRO macro
+ LOCAL wf1
+wf1: jmp wf1
+ endm
+
+;++
+;
+; MAKE_STACK_FRAME_MACRO
+;
+; Arguments:
+;
+; _FrameName_ - is the name of the structure defining the
+; stack frame layout.
+;
+; _PointerRegister_ - is the register containing the linear pointer to
+; the top of the stack frame.
+; ProtectMode ONLY
+;
+;--
+
+MAKE_STACK_FRAME_MACRO macro _FrameName_ , _PointerRegister_
+Local msf1
+ mov ecx, (size _FrameName_)/2
+ mov esi,_PointerRegister_ ; (esi) = offset of argument frame
+ add esi,20 ; account for ebp, ebx, esi, edi and
+ ; return address
+ push KeDataSelector ; (ax) = Flat 32bit segment selector
+ pop ds ; (ds:esi) points to argument frame
+ push ss ;
+ pop es ; (es) = 16bit stack selector
+ sub sp, size _FrameName_ ; make room for the arguments
+ xor edi,edi ; clear out upper 16bits of edi
+ mov di,sp ; (es:edi) points to top of stack
+msf1:
+ mov ax,[esi]
+ mov es:[edi],ax
+ add esi,2
+ add edi,2
+ loop msf1
+ push es ;
+ pop ds ; put 16bit selector back into ds
+ endm
+
+
+REMOVE_STACK_FRAME_MACRO macro _FrameName_
+
+ add sp, size _FrameName_
+ endm
+
+
+;BuildDescriptor macro Base,Limit,Access,Dpl,Stype
+; dw (Limit AND 0ffffh)
+; dw (Base AND 0ffffh)
+; db ((Base SHR 16) AND 0ffh)
+; db (Gran + Dpl + Stype)
+; db ((Limit SHR 16) AND 0ffh)
+; db ((Base SHR 24) AND 0ffh)
+; endm
+
+
+
+;
+;
+;
+RETURNCODE_IN_EAX_MACRO macro
+
+ shl edx,16
+ mov dx,ax
+ mov eax,edx
+ endm
+ \ No newline at end of file
diff --git a/private/ntos/boot/startup/i386/main.c b/private/ntos/boot/startup/i386/main.c
new file mode 100644
index 000000000..8b507197d
--- /dev/null
+++ b/private/ntos/boot/startup/i386/main.c
@@ -0,0 +1,642 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+
+Module Name:
+
+ main.c
+
+Abstract:
+
+ Main for the SU (startup) module for the OS loader. The SU module
+ must take the x86 from a real-mode 16bit state to a FLAT model,
+ 32bit protect/paging enabled state.
+
+Author:
+
+ Thomas Parslow (tomp) Created 20-Dec-90
+
+
+Revision History:
+
+--*/
+
+
+int _acrtused = 0;
+
+#define NTAPI
+
+#include "su.h"
+#include "eisa.h"
+#include "ntimage.h"
+#include "strings.h"
+
+extern VOID RealMode(VOID);
+extern USHORT IDTregisterZero;
+extern USHORT edata;
+extern VOID MoveMemory(ULONG,ULONG,ULONG);
+extern USHORT SuStackBegin;
+extern UCHAR Beginx86Relocation;
+extern UCHAR Endx86Relocation;
+extern USHORT BackEnd;
+extern ULONG FileStart;
+extern BOOLEAN BtIsMcaSystem(VOID);
+extern BOOLEAN IsNpxPresent(VOID);
+extern USHORT HwGetProcessorType(VOID);
+extern USHORT HwGetCpuStepping(USHORT);
+extern ULONG MachineType;
+extern ULONG OsLoaderStart;
+extern ULONG OsLoaderEnd;
+extern ULONG ResourceDirectory;
+extern ULONG ResourceOffset;
+extern ULONG OsLoaderBase;
+extern ULONG OsLoaderExports;
+
+VOID
+PatchDiskBaseTable(
+ VOID
+ );
+
+extern
+TurnMotorOff(
+ VOID
+ );
+
+extern
+EnableA20(
+ VOID
+ );
+
+extern
+EnableMcaA20(
+ VOID
+ );
+
+extern
+BOOLEAN
+ConstructMemoryDescriptors(
+ VOID
+ );
+
+extern
+USHORT
+IsaConstructMemoryDescriptors(
+ VOID
+ );
+
+extern
+USHORT
+McaConstructMemoryDescriptors(
+ VOID
+ );
+
+VOID
+Relocatex86Structures(
+ VOID
+ );
+
+ULONG
+RelocateLoaderSections(
+ OUT PULONG Start,
+ OUT PULONG End
+ );
+
+extern
+FSCONTEXT_RECORD
+FsContext;
+
+#define REVISION_NUMBER "1.1"
+#define DISK_TABLE_VECTOR (0x1e*4)
+
+VOID
+SuMain(
+ IN FPVOID BtRootDir,
+ IN FPDISKBPB BtBiosBlock,
+ IN SHORT BtBootDrive
+)
+/*++
+
+Routine Description:
+
+ Main entrypoint of the SU module. Control is passed from the boot
+ sector to startup.asm which does some run-time fixups on the stack
+ and data segments and then passes control here.
+
+Arguments:
+
+ BtRootDir - Address of root directory left in memory by boot sector
+
+ BtBiosBlock - Address of bios parameter block.
+
+ BtBootDrive - Drive that we booted from.
+
+Returns:
+
+ Does not return. Passes control to the OS loader
+
+
+--*/
+{
+ ULONG LoaderEntryPoint;
+ ULONG EisaNumPages;
+ USHORT IsaNumPages;
+ MEMORY_LIST_ENTRY _far *CurrentEntry;
+ PIMAGE_OPTIONAL_HEADER OptionalHeader;
+ ULONG BlockEnd;
+ ULONG ImageSize;
+ ULONG ImageBase;
+
+ //
+ // Save fs context info
+ //
+
+ FsContext.BootDrive = (ULONG)BtBootDrive;
+ FsContext.PointerToBPB = MAKE_FLAT_ADDRESS(BtBiosBlock);
+
+ //
+ // Initialize the video subsystem first so that
+ // errors end exceptions can be displayed.
+ //
+
+ InitializeVideoSubSystem();
+
+ //
+ // In case we booted from a floppy, turn the drive motor off.
+ //
+
+ TurnMotorOff();
+
+ //
+ // Copy floppy disk-base table and patch it so we can talk to both
+ // 5.25 and 3.5 floppies
+ //
+ PatchDiskBaseTable();
+
+ //
+ // Set up machine type based on its Bus type.
+ //
+
+ if (BtIsEisaSystem()) {
+ MachineType = MACHINE_TYPE_EISA;
+ } else {
+ if (BtIsMcaSystem()) {
+ MachineType = MACHINE_TYPE_MCA;
+ } else {
+ MachineType = MACHINE_TYPE_ISA;
+ }
+ }
+
+ if (!ConstructMemoryDescriptors()) {
+ //
+ // If INT 15 E802h fails...
+ //
+
+ if (MachineType == MACHINE_TYPE_EISA) {
+
+ //
+ // HACKHACK John Vert (jvert)
+ // This is completely bogus. Since there are a number of EISA
+ // machines which do not let you correctly configure the EISA
+ // NVRAM, and even MORE machines which are improperly configured,
+ // we first check to see how much memory the ISA routines say
+ // exists. Then we check what the EISA routines tell us, and
+ // compare the two. If the EISA number is much lower (where "much"
+ // is a completely random fudge factor) than the ISA number, we
+ // assume the machine is improperly configured and we throw away
+ // the EISA numbers and use the ISA ones. If not, we assume that
+ // the machine is actually configured properly and we trust the
+ // EISA numbers..
+ //
+
+ IsaNumPages = IsaConstructMemoryDescriptors();
+ EisaNumPages = EisaConstructMemoryDescriptors();
+ if (EisaNumPages + 0x80 < IsaNumPages) {
+ IsaConstructMemoryDescriptors();
+ }
+ } else {
+ if (MachineType == MACHINE_TYPE_MCA) {
+ McaConstructMemoryDescriptors();
+ } else {
+ IsaConstructMemoryDescriptors();
+ }
+ }
+ }
+
+ //
+ // Search for memory descriptor describing low memory
+ //
+ CurrentEntry = MemoryDescriptorList;
+ while ((CurrentEntry->BlockBase != 0) &&
+ (CurrentEntry->BlockSize != 0)) {
+ CurrentEntry++;
+ }
+
+ if ((CurrentEntry->BlockBase == 0) &&
+ (CurrentEntry->BlockSize < (ULONG)512 * (ULONG)1024)) {
+
+ BlPrint(SU_NO_LOW_MEMORY,CurrentEntry->BlockSize/1024);
+ while (1) {
+ }
+ }
+
+ //
+ // Ensure there is a memory descriptor to contain osloader image
+ //
+ OptionalHeader = (PIMAGE_OPTIONAL_HEADER)((PUCHAR)&edata + sizeof(IMAGE_FILE_HEADER));
+ ImageBase = OptionalHeader->ImageBase;
+ ImageSize = OptionalHeader->SizeOfImage;
+ OsLoaderBase = ImageBase;
+ OsLoaderExports = ImageBase + OptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
+ CurrentEntry = MemoryDescriptorList;
+ while (ImageSize > 0) {
+ while (CurrentEntry->BlockSize != 0) {
+ BlockEnd = CurrentEntry->BlockBase + CurrentEntry->BlockSize;
+
+ if ((CurrentEntry->BlockBase <= ImageBase) &&
+ (BlockEnd > ImageBase)) {
+
+ //
+ // this descriptor at least partially contains a chunk
+ // of the osloader.
+ //
+ if (BlockEnd-ImageBase > ImageSize) {
+ ImageSize = 0;
+ } else {
+ ImageSize -= (BlockEnd-ImageBase);
+ ImageBase = BlockEnd;
+ }
+
+ //
+ // look for remaining part (if any) of osloader
+ //
+ CurrentEntry = MemoryDescriptorList;
+ break;
+ }
+ CurrentEntry++;
+ }
+ if (CurrentEntry->BlockSize == 0) {
+ break;
+ }
+ }
+
+ if (ImageSize > 0) {
+ //
+ // We could not relocate the osloader to high memory. Error out
+ // and display the memory map.
+ //
+ BlPrint(SU_NO_EXTENDED_MEMORY);
+
+ CurrentEntry = MemoryDescriptorList;
+ while (CurrentEntry->BlockSize != 0) {
+ BlPrint(" %lx - %lx\n",
+ CurrentEntry->BlockBase,
+ CurrentEntry->BlockBase + CurrentEntry->BlockSize);
+
+ CurrentEntry++;
+ }
+ while (1) {
+ }
+
+ }
+
+ //
+ // Enable the A20 line for protect mode
+ //
+
+ EnableA20();
+
+ //
+ // Relocate x86 structures. This includes the GDT, IDT,
+ // page directory, and first level page table.
+ //
+
+ Relocatex86Structures();
+
+ //
+ // Enable protect and paging modes for the first time
+ //
+
+
+ EnableProtectPaging(ENABLING);
+
+ //
+ // Go relocate loader sections and build page table entries
+ //
+
+ LoaderEntryPoint = RelocateLoaderSections(&OsLoaderStart, &OsLoaderEnd);
+
+ //
+ // Search for memory descriptor containing the osloader and
+ // change it.
+ //
+
+ //
+ // Transfer control to the OS loader
+ //
+
+ TransferToLoader(LoaderEntryPoint);
+
+}
+
+ULONG
+RelocateLoaderSections(
+ OUT PULONG Start,
+ OUT PULONG End
+ )
+/*++
+
+Routine Description:
+
+ The SU module is prepended to the OS loader file. The OS loader file
+ is a coff++ file. This routine computes the beginning of the OS loader
+ file, then relocates the OS loader's sections as if it were just
+ loading the file from disk file.
+
+Arguments:
+
+ Start - Returns the address of the start of the image
+ End - Returns the address of the end of the image
+
+Returns:
+
+ Entry point of loader
+
+
+--*/
+{
+ USHORT Section;
+ ULONG Source,Destination;
+ ULONG VirtualSize;
+ ULONG SizeOfRawData;
+ PIMAGE_FILE_HEADER FileHeader;
+ PIMAGE_OPTIONAL_HEADER OptionalHeader;
+ PIMAGE_SECTION_HEADER SectionHeader;
+
+ //
+ // Make a pointer to the beginning of the loader's coff header
+ //
+
+ FileHeader = (PIMAGE_FILE_HEADER) &edata;
+
+ //
+ // Validate the appended loader image by checking signatures.
+ // 1st - is it an executable image?
+ // 2nd - is the target environment the 386?
+ //
+
+ if ((FileHeader->Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE) == 0) {
+ puts(SU_NTLDR_CORRUPT);
+ WAITFOREVER;
+ }
+
+ if (FileHeader->Machine != IMAGE_FILE_MACHINE_I386) {
+ puts(SU_NTLDR_CORRUPT);
+ WAITFOREVER;
+ }
+
+ //
+ // Make a pointer to the optional header in the header-buffer
+ //
+
+ OptionalHeader = (PIMAGE_OPTIONAL_HEADER)((PUCHAR)FileHeader +
+ sizeof(IMAGE_FILE_HEADER));
+
+ //
+ // Make a pointer to the first section in the header buffer
+ //
+
+ SectionHeader = (PIMAGE_SECTION_HEADER)((PUCHAR)OptionalHeader +
+ FileHeader->SizeOfOptionalHeader);
+
+ *Start = OptionalHeader->ImageBase+SectionHeader->VirtualAddress;
+ *End = *Start + SectionHeader->SizeOfRawData;
+
+ //
+ // Display some debug stuff for now
+ //
+
+ DBG1(
+ BlPrint("Machine = %x\n",FileHeader->Machine);
+ BlPrint("NumberOfSections = %x\n",FileHeader->NumberOfSections);
+ BlPrint("TimeDateStamp %lx\n",FileHeader->TimeDateStamp);
+ BlPrint("PointerToSymbolTable = %lx\n",FileHeader->PointerToSymbolTable);
+ BlPrint("NumberOfSymbols %lx\n",FileHeader->NumberOfSymbols);
+ BlPrint("SizeOfOptionalHeader = %x\n",FileHeader->SizeOfOptionalHeader);
+ BlPrint("Characteristics = %x\n",FileHeader->Characteristics);
+ )
+
+ //
+ // Loop and relocate each section with a non-zero RawData size
+ //
+
+ for (Section=FileHeader->NumberOfSections ; Section-- ; SectionHeader++) {
+
+ //
+ // Compute source, destination, and count arguments
+ //
+
+ Source = FileStart + SectionHeader->PointerToRawData;
+ Destination = OptionalHeader->ImageBase + SectionHeader->VirtualAddress;
+
+ VirtualSize = SectionHeader->Misc.VirtualSize;
+ SizeOfRawData = SectionHeader->SizeOfRawData;
+
+ if (VirtualSize == 0) {
+ VirtualSize = SizeOfRawData;
+ }
+
+ if (SectionHeader->PointerToRawData == 0) {
+ //
+ // SizeOfRawData can be non-zero even if PointerToRawData is zero
+ //
+
+ SizeOfRawData = 0;
+ } else if (SizeOfRawData > VirtualSize) {
+ //
+ // Don't load more from image than is expected in memory
+ //
+
+ SizeOfRawData = VirtualSize;
+ }
+
+ if (Destination < *Start) {
+ *Start = Destination;
+ }
+
+ if (Destination+VirtualSize > *End) {
+ *End = Destination+VirtualSize;
+ }
+
+ DBG1(BlPrint("src=%lx dest=%lx raw=%lx\n",Source,Destination,SizeOfRawData);)
+
+ if (SizeOfRawData != 0) {
+ //
+ // This section is either a code (.TEXT) section or an
+ // initialized data (.DATA) section.
+ // Relocate the section to memory at the virtual/physical
+ // addresses specified in the section header.
+ //
+ MoveMemory(Source,Destination,SizeOfRawData);
+ }
+
+ if (SizeOfRawData < VirtualSize) {
+ //
+ // Zero the portion not loaded from the image
+ //
+
+ DBG1( BlPrint("Zeroing destination %lx\n",Destination+SizeOfRawData); )
+ ZeroMemory(Destination+SizeOfRawData,VirtualSize - SizeOfRawData);
+ }
+ //
+ // Check if this is the resource section. If so, we need
+ // to pass its location to the osloader.
+ //
+ if ((SectionHeader->Name[0] == '.') &&
+ (SectionHeader->Name[1] == 'r') &&
+ (SectionHeader->Name[2] == 's') &&
+ (SectionHeader->Name[3] == 'r') &&
+ (SectionHeader->Name[4] == 'c')) {
+ ResourceDirectory = Destination;
+ ResourceOffset = SectionHeader->VirtualAddress;
+ }
+ }
+
+ DBG1( BlPrint("RelocateLoaderSections done - EntryPoint == %lx\n",
+ OptionalHeader->AddressOfEntryPoint + OptionalHeader->ImageBase);)
+ return(OptionalHeader->AddressOfEntryPoint + OptionalHeader->ImageBase);
+
+}
+
+VOID
+Relocatex86Structures(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ The gdt and idt are statically defined and imbedded in the SU modules
+ data segment. This routine moves then out of the data segment and into
+ a page mapped at a defined location.
+
+Arguments:
+
+ None
+
+Returns:
+
+ Nothing
+
+
+--*/
+{
+ FPUCHAR Fpsrc, Fpdst;
+ USHORT Count;
+
+ //
+ // Make pointers to the data and compute the size
+ // of the block to use.
+ //
+
+ Fpsrc = (FPUCHAR)&Beginx86Relocation;
+ MAKE_FP(Fpdst,SYSTEM_STRUCTS_BASE_PA);
+ Count = (&Endx86Relocation - &Beginx86Relocation);
+
+ //
+ // Move the data to its new location
+ //
+
+ while (Count--) {
+ *Fpdst++ = *Fpsrc++;
+
+ }
+
+}
+
+VOID
+DisplayArgs(
+ USHORT es,
+ USHORT bx,
+ USHORT cx,
+ USHORT dx,
+ USHORT ax
+ )
+/*++
+
+Routine Description:
+
+ Just a debugging routine to dump some registers.
+
+Arguments:
+
+ The x86 registers es, bx, cx, dx, and ax are pushed on the stack
+ before this routine is called.
+
+
+Returns:
+
+ Nothing
+
+
+Environment:
+
+ Real Mode ONLY
+
+
+--*/
+{
+ BlPrint("ax:%x dx:%x cx:%x bx:%x es:%x\n",
+ (USHORT) ax,
+ (USHORT) dx,
+ (USHORT) cx,
+ (USHORT) bx,
+ (USHORT) es);
+
+ return;
+}
+
+
+VOID
+PatchDiskBaseTable(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine copies the floppy disk-base table from the ROM into our
+ data segment, then patches the last sector value to 63. This enables
+ us to read from 3.5 B: drives when the A: drive is 5.25.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ FPUCHAR Fpsrc, Fpdst;
+ USHORT Count;
+ extern DISK_BASE_TABLE DiskBaseTable;
+ DISK_BASE_TABLE _far *RomTable;
+
+ RomTable = (DISK_BASE_TABLE _far *)(*(ULONG _far *)DISK_TABLE_VECTOR);
+
+ Fpsrc = (FPUCHAR)RomTable;
+ Fpdst = (FPUCHAR)&DiskBaseTable;
+ Count = sizeof(DISK_BASE_TABLE);
+ while (Count--) {
+ *Fpdst++ = *Fpsrc++;
+ }
+
+ DiskBaseTable.LastSector = 63;
+
+}
+
+// END OF FILE //
diff --git a/private/ntos/boot/startup/i386/memmap.h b/private/ntos/boot/startup/i386/memmap.h
new file mode 100644
index 000000000..d619a8a9c
--- /dev/null
+++ b/private/ntos/boot/startup/i386/memmap.h
@@ -0,0 +1,83 @@
+//
+// The following memory address definitions apply to
+// indentity mapped objects for the x86 environment.
+//
+
+#define RM_PROTECT_BASE_VA 0x000000
+#define RM_PROTECT_BASE_PA 0x000000
+#define RM_PROTECT_SIZE 0x001000
+#define RM_PROTECT_ATTRIBUTES PAGE_ROSP
+
+#define BPB_BASE_VA 0x007000
+#define BPB_BASE_PA 0x007000
+#define BPB_SIZE 0x001000
+#define BPB_ATTRIBUTES PAGE_ROSP
+
+#define SU_MODULE_BASE_VA 0x020000
+#define SU_MODULE_BASE_PA 0x020000
+#define SU_MODULE_SIZE 0x020000
+#define SU_MODULE_ATTRIBUTES PAGE_RWSP
+
+#define LOADER_BASE_VA 0x040000
+#define LOADER_BASE_PA 0x040000
+#define LOADER_SIZE 0x020000
+#define LOADER_ATTRIBUTES PAGE_RWSP
+
+#define SYSTEM_STRUCTS_BASE_VA 0x80420000
+#define SYSTEM_STRUCTS_BASE_PA 0x00017000
+#define SYSTEM_STRUCTS_SIZE 0x002000
+#define SYSTEM_STRUCTS_ATTRIBUTES PAGE_RWSP + PAGE_PERSIST
+
+#define PAGE_TABLE_AREA_BASE_VA 0x00099000
+#define PAGE_TABLE_AREA_BASE_PA 0x00099000
+#define PAGE_TABLE_AREA_SIZE 0x002000
+#define PAGE_TABLE_AREA_ATTRIBUTES PAGE_RWSP + PAGE_PERSIST
+
+#define LDR_STACK_BASE_VA 0x09b000
+#define LDR_STACK_BASE_PA 0x09b000
+#define LDR_STACK_SIZE 0x001000
+#define LDR_STACK_ATTRIBUTES PAGE_RWSP
+#define LDR_STACK_POINTER 0x09bffe // in su.inc also
+
+#define VIDEO_BUFFER_BASE_VA 0x0B8000
+#define VIDEO_BUFFER_BASE_PA 0x0B8000
+#define VIDEO_BUFFER_SIZE 0x004000
+#define VIDEO_BUFFER_ATTRIBUTES PAGE_RWSP
+
+
+#define HYPER_PAGE_DIRECTORY 0xC0300C00
+#define HYPER_SPACE_BEGIN 0xC0000000 // points to 1st page table
+#define HYPER_SPACE_SIZE 0x8000L
+#define HYPER_SPACE_ENTRY 768
+#define PAGE_TABLE1_ADDRESS 0xC0000000L
+#define PD_PHYSICAL_ADDRESS PAGE_TABLE_AREA_BASE_PA // in su.inc also.
+#define PT_PHYSICAL_ADDRESS PAGE_TABLE_AREA_BASE_PA + PAGE_SIZE
+#define VIDEO_ENTRY 0xB8
+
+
+/*
+
+
+
+Switching to Realmode
+~~~~~~~~~~~~~~~~~~~~~
+
+When switching to realmode "sp" will be initialized to
+0xfffe and (ss) will be set to the base of the SU module's
+data segment. This has several effects.
+
+ 1) The stack will remain withing the 0x20000 - 0x3ffff range
+ reserved for the original SU module and loader image prior to
+ relocation, and since the loader will already have been relocated
+ it is no longer necessary to preserve this area.
+
+ 2) This will preserve the SU module's small model character which
+ requires that offsets can be used interchangably through (ss) or (ds).
+
+ 3) This allows for the maximum stack size for small model apps (which is
+ what the SU module is). Bios calls should not be tromping on any
+ data or code while in realmode.
+
+*/
+
+
diff --git a/private/ntos/boot/startup/i386/memmap.inc b/private/ntos/boot/startup/i386/memmap.inc
new file mode 100644
index 000000000..cba60188d
--- /dev/null
+++ b/private/ntos/boot/startup/i386/memmap.inc
@@ -0,0 +1,24 @@
+
+
+
+PAGE_DIR_ADDRESS equ 99000h
+PAGE_TABLE_ADDRESS equ 9A000h
+
+;;
+;; Address Mappings
+;;
+
+
+PhysAddressVideo equ 0b8000h
+PhysSizeVideo equ 2000h
+
+SYSTEM_PAGE_PA equ 17000h
+SYSTEM_PAGE_VA equ 80420000h
+GDT_LOC equ 0
+IDT_LOC equ 400h
+TSS_LOC equ 0C00h
+
+
+
+
+ \ No newline at end of file
diff --git a/private/ntos/boot/startup/i386/ntmisc.h b/private/ntos/boot/startup/i386/ntmisc.h
new file mode 100644
index 000000000..4d0a7306c
--- /dev/null
+++ b/private/ntos/boot/startup/i386/ntmisc.h
@@ -0,0 +1,60 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ ntmisc.h
+
+Abstract:
+
+ This module contains the misc. definitions in \nt\public\sdk\inc
+ directory. Note, we created this file because ntdetect uses 16 bit
+ compiler and various new C compiler switches/pragamas are not recognized
+ by the 16 bit C compiler.
+
+Author:
+
+ Shie-Lin Tzong (shielint) 11-Nov-1992
+
+
+Revision History:
+
+
+--*/
+//
+// PHYSICAL_ADDRESS
+//
+
+typedef LARGE_INTEGER PHYSICAL_ADDRESS, *PPHYSICAL_ADDRESS;
+
+//
+// Note all the definitions defined below are used to make compiler shut up.
+// Ntdetect.com does not rely on the correctness of the structures.
+//
+
+//
+// Define the I/O bus interface types.
+//
+
+typedef enum _INTERFACE_TYPE {
+ Internal,
+ Isa,
+ Eisa,
+ MicroChannel,
+ TurboChannel,
+ MaximumInterfaceType
+}INTERFACE_TYPE, *PINTERFACE_TYPE;
+
+//
+// Doubly linked list structure. Can be used as either a list head, or
+// as link words.
+//
+
+typedef struct _LIST_ENTRY {
+ struct _LIST_ENTRY far *Flink;
+ struct _LIST_ENTRY far *Blink;
+} LIST_ENTRY, far *PLIST_ENTRY;
+
+#define PTIME_FIELDS PVOID
+
diff --git a/private/ntos/boot/startup/i386/su.asm b/private/ntos/boot/startup/i386/su.asm
new file mode 100644
index 000000000..9a55ce54b
--- /dev/null
+++ b/private/ntos/boot/startup/i386/su.asm
@@ -0,0 +1,1458 @@
+;++
+;
+; Module name
+;
+; su.asm
+;
+; Author
+;
+; Thomas Parslow (tomp) Jan-15-91
+;
+; Description
+;
+; Startup module for the 386 NT OS loader.
+;
+; Exported Procedures
+;
+; EnableProtectPaging
+;
+; Notes
+; NT386 Boot Loader program. This assembly file is required in
+; order to link C modules into a "/TINY" (single segment) memory
+; model.
+;
+;
+; ** WHAT'S MISSING **
+; Still need to add:
+; o a20 enable code
+; o compaq speed code (??)
+; o low/high memory size determination
+;
+;
+;
+; This file does the following:
+; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+; 1) Defines the entry point for the boot loader's startup program
+; 2) Computes what values should actually be in the DS and SS registers.
+; 3) Provides the int bios functionality
+; 4) Provides 386/486 mode (protect/paging) switching code.
+;
+; The OS/2 bootstrap routine (boot sector) loads the boot loader program at
+; real-mode address 2000:0000 with the following register values:
+;
+; CS = 2000
+; IP = 0000
+; DS = 07C0
+; ES = 1000
+; SS = 0000
+; SP = 7C00
+;
+; Build Notes:
+; ~~~~~~~~~~~~
+; The microsoft C compiler will not produce "tiny" model programs. In the
+; tiny model, the entire program consists of only one segment. The small
+; model produced by our compilers consists of two segments: DGROUP and _TEXT.
+; If you convert a small model program into a tiny model program, DS (which
+; should point to DGROUP (bss,const,data) will always be wrong. For this reason
+; we need an assembly module to do a simple run-time fixup on SS and DS. To
+; guarantee that DS will point to DGROUP no matter where os2ldr is loaded,
+; the paragraph (shifted right four bits) offset of DGROUP from _TEXT must
+; be added to the value in CS to compute DS and SS.
+;
+; We get the linker to fixup the offset of the beginning of the dgroup segment
+; relative to the beginning of the code segment and it's this value added
+; to the value in CS that allows us to build a "tiny" model program in C
+; without a lot of munging around in order to get the data reference offsets
+; in the code correct.
+;
+; If the _TEXT:DGROUP fixup appears in other files (which it does), the linker
+; will not compute the correct value unless the accumulated data pointer is
+; zero when it gets there. Therefore, no data should be placed in the data segment
+; until after all instances of _TEXT:DGROUP have been encountered by the linker.
+; The linker processes files from right to left on the command line.
+;
+; A Note About Stacks
+; Initially we run on our internal stack (SuStack) which is only 160 bytes deep
+; but seems to do the trick. Then we have to have a separate double fault stack.
+; This stack can be in the middle of the stack/data segment. It will step on
+; the loader image, but that's ok since the fault was either caused by 16bit
+; code (which won't be in the loader image) or, it was caused by the 32bit
+; loader (which has already been relocated) so we won't be stepping on code
+; that may have caused the fault. And finally, we have the "call back" stack
+; which starts at the top of the stack/data segment. We use this during
+; all call backs since the original loader source is no longer needed and
+; this'll give us plenty of stack for bios calls etc.
+;
+;--
+
+DoubleWord struc
+lsw dw ?
+msw dw ?
+DoubleWord ends
+
+;
+; This is the structure used to pass all shared data between the boot sector
+; and NTLDR.
+;
+
+SHARED struc
+ ReadClusters dd ? ; function pointer
+ ReadSectors dd ? ; function pointer
+
+ SectorBase dd ? ; starting sector
+ ; for ReadSectors
+ ; callback
+SHARED ends
+
+
+BPB struc
+ BytesPerSector dw ?
+ SectorsPerCluster db ?
+ ReservedSectors dw ?
+ Fats db ?
+ DirectoryEntries dw ?
+ Sectors dw ?
+ Media db ?
+ FatSectors dw ?
+ SectorsPerTrack dw ?
+ Heads dw ?
+ HiddenSectors dd ?
+ SectorsLong dd ?
+;
+; The following byte is NOT part of the BPB but is set by SYS and format
+;
+
+ BootDriveNumber db ?
+BPB ends
+
+SU_CODEMODULE equ 1 ; Identifies this module to "su.inc"
+include su.inc
+include macro.inc
+
+extrn _BootRecord:word
+extrn _puts:near
+extrn _MemoryDescriptorList:near
+extrn _InsertDescriptor:near
+
+MAXREAD EQU 10000h
+MAXSECTORS EQU MAXREAD/0200h
+
+_TEXT segment para use16 public 'CODE'
+ ASSUME CS: _TEXT, DS: DGROUP, SS: DGROUP
+.386p
+
+;
+; Run-time fixups for stack and data segment
+;
+
+public Start
+Start:
+;
+; The FAT boot sector only reads in the first 512 bytes of NTLDR. This is
+; the module that contains those 512 bytes, so we are now responsible for
+; loading the rest of the file. Other filesystems (i.e. HPFS, NTFS, RIPL)
+; will load the whole file, so the default entrypoint branches around the
+; FAT-specific code.
+;
+ jmp RealStart
+
+FatBegin:
+.386
+;
+; If we're here, we've booted off a FAT system and we must load the rest
+; of NTLDR at 2000:0200 (right behind this sector) NTLDR passes us the
+; following:
+; BX = Starting Cluster Number of NTLDR
+; DL = INT 13h drive number we've booted from
+; DS:SI -> boot media's BPB
+; DS:DI -> argument structure (see above struc definition)
+;
+
+;
+; Save away the boot drive and the starting cluster number
+;
+ push dx
+ push bx
+
+;
+; Blast the FAT into memory at 6000:0000 - 8000:0000
+;
+
+.386
+ push 06000h
+.8086
+ pop es
+ xor bx,bx ; (es:bx) = 6000:0000
+ mov cx,ds:[si].ReservedSectors
+ mov ds:[di].SectorBase.msw,0
+ mov ds:[di].SectorBase.lsw,cx ; set up Sector Base
+
+ mov ax,ds:[si].FatSectors ; (al) = # Sectors to read
+ cmp ax,080h
+ jbe FatLt64k
+
+; The FAT is > 64k, so we read the first 64k chunk, then the rest.
+; (A 16-bit FAT can't be bigger than 128k)
+
+ push cx
+ mov ax,080h ; (al) = # of sectors to read
+ call ds:[di].ReadSectors
+ pop cx ; (cx) = previous SectorBase
+.386
+ push 07000h
+.8086
+ pop es
+ xor bx,bx ; (es:bx) = 7000:0000
+ mov ax,ds:[si].FatSectors
+ sub ax,080h ; (ax) = # Sectors left to read
+ add cx,080h ; (cx) = SectorBase for next read
+ mov ds:[di].SectorBase.lsw,cx
+ adc ds:[di].SectorBase.msw,0 ; set up SectorBase
+
+;
+; (al) = # of sectors to read
+;
+FatLt64k:
+ call ds:[di].ReadSectors
+
+;
+; FAT is in memory, now we restore our starting cluster number
+;
+ pop dx ; (dx) = starting cluster number
+ xor bx,bx
+
+;
+; set up FS and GS for reading the FAT
+;
+.386
+ mov ax,6000h
+ mov fs,ax
+ mov ax,7000h
+ mov gs,ax
+.8086
+
+;
+; set up ES for reading in the rest of us
+;
+ push cs
+ pop es
+
+ mov ah,MAXSECTORS ; (ah) = number of sectors we can read
+ ; until boundary
+
+FatLoop:
+;
+; (dx) = next cluster to load
+;
+ push dx
+ mov al,ds:[si].SectorsPerCluster ; (al) = number of contiguous sectors
+ ; found
+ sub ah,ds:[si].SectorsPerCluster ; can read before 64k
+
+;
+; Check to see if we've reached the end of the file
+;
+ cmp dx,0ffffh
+ jne Fat10
+
+;
+; The entire file has been loaded. Throw away the saved next cluster,
+; restore the boot drive, and let NTLDR do its thing.
+;
+ pop dx
+ pop dx
+ jmp RealStart
+
+Fat10:
+ mov cx,dx
+;
+; (dx) = (cx) = last contiguous cluster
+; (al) = # of contiguous clusters found
+;
+
+ call NextFatEntry
+;
+; (dx) = cluster following last contiguous cluster
+
+;
+; Check to see if the next cluster is contiguous. If not, go load the
+; contiguous block we've found.
+;
+ inc cx
+ cmp dx,cx
+
+ jne LncLoad
+
+;
+; Check to see if we've reached the 64k boundary. If so, go load the
+; contiguous block so far. If not, increment the number of contiguous
+; sectors and loop again.
+;
+ cmp ah,0
+ jne Lnc20
+ mov ah,MAXSECTORS ; (ah) = number of sectors until
+ ; boundary reached again
+ jmp short LncLoad
+
+Lnc20:
+ add al,ds:[si].SectorsPerCluster
+ sub ah,ds:[si].SectorsPerCluster
+ jmp short Fat10
+
+
+LncLoad:
+;
+; (TOS) = first cluster to load
+; (dx) = first cluster of next group to load
+; (al) = number of contiguous sectors
+;
+ pop cx
+ push dx
+ mov dx,cx
+ mov cx,10 ; (cx) = retry count
+
+;
+; N.B.
+; This assumes that we will never have more than 255 contiguous clusters.
+; Since that would get broken up into chunks that don't cross the 64k
+; boundary, this is ok.
+;
+; (dx) = first cluster to load
+; (al) = number of contiguous sectors
+; (TOS) = first cluster of next group to load
+; (es:bx) = address where clusters should be loaded
+;
+FatRetry:
+ push bx
+ push ax
+ push dx
+ push cx
+
+if 0
+ push dx
+ call PrintDbg
+ mov dx,ax
+ call PrintDbg
+ pop dx
+endif
+
+ call [di].ReadClusters
+ jnc ReadOk
+;
+; error in the read, reset the drive and try again
+;
+if 0
+ mov dx, ax
+ call PrintDbg
+endif
+ mov ax,01h
+ mov al,ds:[si].BootDriveNumber
+ int 13h
+if 0
+ mov dx,ax
+ call PrintDbg
+endif
+ xor ax,ax
+ mov al,ds:[si].BootDriveNumber
+ int 13h
+
+;
+; pause for a while
+;
+ xor ax,ax
+FatPause:
+ dec ax
+ jnz FatPause
+
+ pop cx
+ pop dx
+ pop ax
+ pop bx
+
+ dec cx
+ jnz FatRetry
+
+;
+; we have re-tried ten times, it still doesn't work, so punt.
+;
+ push cs
+ pop ds
+ mov si,offset FAT_ERROR
+FatErrPrint:
+ lodsb
+ or al,al
+ jz FatErrDone
+ mov ah,14 ; write teletype
+ mov bx,7 ; attribute
+ int 10h ; print it
+ jmp FatErrPrint
+
+FatErrDone:
+ jmp $
+FAT_ERROR db "NTLDR: I/O error reading disk",0dh,0ah
+ db " Please insert another disk",0dh,0ah,0
+
+
+ReadOk:
+ pop cx
+ pop dx
+ pop ax
+ pop bx
+ pop dx ; (dx) = first cluster of next group
+ ; to load.
+
+.386
+;
+; Convert # of sectors into # of bytes.
+;
+ mov cl,al
+ xor ch,ch
+ shl cx,9
+.8086
+ add bx,cx
+ jz FatLoopDone
+ jmp FatLoop
+
+FatLoopDone:
+;
+; (bx) = 0
+; This means we've just ended on a 64k boundary, so we have to
+; increment ES to continue reading the file. We are guaranteed to
+; always end on a 64k boundary and never cross it, because we
+; will reduce the number of contiguous clusters to read
+; to ensure that the last cluster read will end on the 64k boundary.
+; Since we start reading at 0, and ClusterSize will always be a power
+; of two, a cluster will never cross a 64k boundary.
+;
+ mov ax,es
+ add ax,01000h
+ mov es,ax
+ mov ah,MAXSECTORS
+ jmp FatLoop
+
+;++
+;
+; NextFatEntry - This procedure returns the next cluster in the FAT chain.
+; It will deal with both 12-bit and 16-bit FATs. It assumes
+; that the entire FAT has been loaded into memory.
+;
+; Arguments:
+; (dx) = current cluster number
+; (fs:0) = start of FAT in memory
+; (gs:0) = start of second 64k of FAT in memory
+;
+; Returns:
+; (dx) = next cluster number in FAT chain
+; (dx) = 0ffffh if there are no more clusters in the chain
+;
+;--
+NextFatEntry proc near
+ push bx
+
+;
+; Check to see if this is a 12-bit or 16-bit FAT. The biggest FAT we can
+; have for a 12-bit FAT is 4080 clusters. This is 6120 bytes, or just under
+; 12 sectors.
+;
+; A 16-bit FAT that's 12 sectors long would only hold 3072 clusters. Thus,
+; we compare the number of FAT sectors to 12. If it's greater than 12, we
+; have a 16-bit FAT. If it's less than or equal to 12, we have a 12-bit FAT.
+;
+ call IsFat12
+ jnc Next16Fat
+
+Next12Fat:
+ mov bx,dx ; (fs:bx) => temporary index
+ shr dx,1 ; (dx) = offset/2
+ ; (CY) = 1 need to shift
+ pushf ; = 0 don't need to shift
+ add bx,dx ; (fs:bx) => next cluster number
+.386
+ mov dx,fs:[bx] ; (dx) = next cluster number
+.8086
+ popf
+ jc shift ; carry flag tells us whether to
+ and dx,0fffh ; mask
+ jmp short N12Tail
+shift:
+.386
+ shr dx,4 ; or shift
+.8086
+
+N12Tail:
+;
+; Check for end of file
+;
+ cmp dx,0ff8h ; If we're at the end of the file,
+ jb NfeDone ; convert to canonical EOF.
+ mov dx,0ffffh
+ jmp short NfeDone
+
+Next16Fat:
+ add dx,dx ; (dx) = offset
+ jc N16high
+
+ mov bx,dx ; (fs:bx) => next cluster number
+.386
+ mov dx,fs:[bx] ; (dx) = next cluster number
+.8086
+ jmp short N16Tail
+
+N16high:
+ mov bx,dx
+.386
+ mov dx,gs:[bx]
+.8086
+
+N16Tail:
+ cmp dx,0fff8h
+ jb NfeDone
+ mov dx,0ffffh ; If we're at the end of the file
+ ; convert to canonical EOF.
+
+NfeDone:
+ pop bx
+ ret
+NextFatEntry endp
+
+;++
+;
+; IsFat12 - This function determines whether the BPB describes a 12-bit
+; or 16-bit FAT.
+;
+; Arguments - ds:si supplies pointer to BPB
+;
+; Returns
+; CY set - 12-bit FAT
+; CY clear - 16-bit FAT
+;
+;--
+IsFat12 proc near
+
+.386
+ push eax
+ push ebx
+ push ecx
+ push edx
+
+ movzx ecx, ds:[si].Sectors
+ or cx,cx
+ jnz if10
+ mov ecx, ds:[si].SectorsLong
+if10:
+;
+; (ecx) = number of sectors
+;
+ movzx ebx, byte ptr ds:[si].Fats
+ movzx eax, word ptr ds:[si].FatSectors
+ mul ebx
+ sub ecx,eax
+
+;
+; (ecx) = (#sectors)-(sectors in FATs)
+;
+ movzx eax, word ptr ds:[si].DirectoryEntries
+ shl eax, 5
+;
+; (eax) = #bytes in root dir
+;
+ mov edx,eax
+ and edx,0ffff0000h
+ div word ptr ds:[si].BytesPerSector
+ sub ecx,eax
+
+;
+; (ecx) = (#sectors) - (sectors in fat) - (sectors in root dir)
+;
+ movzx eax, word ptr ds:[si].ReservedSectors
+ sub ecx, eax
+ mov eax, ecx
+ movzx ecx, byte ptr ds:[si].SectorsPerCluster
+ xor edx,edx
+ div ecx
+
+ cmp eax, 4087
+ jae if20
+ stc
+ jmp short if30
+if20:
+ clc
+if30:
+ pop edx
+ pop ecx
+ pop ebx
+ pop eax
+ ret
+.8086
+IsFat12 endp
+
+
+
+
+PrintDbg proc near
+ push ax
+ push bx
+ push cx
+
+ mov cx,4
+pd10:
+.386
+ rol dx,4
+.8086
+ mov ah,0eh
+ mov bx,7
+ mov al,dl
+ and al,0fh
+ add al,'0'
+ cmp al,'9'
+ jbe pd15
+ add al,'A'-('9'+1)
+
+pd15:
+ int 010h
+ loop pd10
+
+ mov ah,0eh
+ mov al,' '
+ mov bx,7
+ int 010h
+ pop cx
+ pop bx
+ pop ax
+
+ ret
+
+PrintDbg endp
+
+
+
+
+Free EQU 512-($-Start)
+if Free lt 0
+ %out FATAL PROBLEM: FAT-specific startup code is greater than
+ %out 512 bytes. Fix it!
+ .err
+endif
+
+RealStart:
+.386p
+;
+; Compute the paragraph needed for DS
+;
+if 0
+ mov ax,0
+ int 16h
+endif
+
+ mov bx,offset _TEXT:DGROUP ; first calculate offset to data
+ shr bx,4 ; must be para aligned
+
+ mov ax,cs ; get base of code
+ add ax,bx ; add paragraph offset to data
+
+ mov ss,ax ; ints disabled for next instruct
+ mov sp,offset DGROUP:SuStack ; (sp) = top of internal stack
+;
+; Build C stack frame for _SuMain
+;
+ xor dh,dh
+ push dx ; pass bootdisk (dl) to main.
+ push ds ; segment of bios parameter block
+ push si ; offset to bios parameter block
+ push es ; segment of root directory
+ push di ; offset to root directory
+;
+; Make DS point to the paragraph address of DGROUP
+;
+ mov ds,ax ; ds now points to beginning of DGROUP
+;
+; Compute the physical address of the end of the data segment (which
+; will be the beginning of the prepended loader file).
+;
+
+ movzx edx,ax
+ shl edx,4
+ add edx,offset DGROUP:_edata
+ mov dword ptr _FileStart,edx
+
+;
+; Force the upper parts of
+; of EBP and ESP to be zero in real mode.
+;
+
+ xor bp,bp
+ movzx ebp,bp
+ movzx esp,sp
+ mov [saveDS],ds
+
+ call _SuMain ; go to C code to do everything else.
+
+
+;++
+; _EnableProtectPaging
+;
+; Loads 386 protect mode registers.
+; Enables 386 protection h/w
+; Loads pagings registers
+; Enables 386 paging h/w
+;
+;--
+
+public _EnableProtectPaging
+_EnableProtectPaging proc near
+;
+; Sanitize ES and GS and clean out any junk in the upper 16bits
+; of the flags that may have been left by the bios, before we go protected
+;
+ push dword ptr 0
+ popfd
+ mov bx,sp
+ mov dx,[bx+2] ; are we enabling prot/paging for the first time?
+ xor ax,ax
+ mov gs,ax
+ mov es,ax
+
+
+;
+; FS must contain the selector of the PCR when we call the kernel
+;
+ push PCR_Selector
+ pop fs
+;
+; Load the gdtr and idtr.
+; We disable interrupts here since we can't handle interrups with the
+; idt loaded while were in real mode and before we switch to protmode.
+
+ cli
+ lgdt fword ptr [_GDTregister]
+ lidt fword ptr [_IDTregister]
+
+
+;
+; We have to stamp the segment portion of any real-mode far pointer with
+; the corresponding selector values before we go protected.
+;
+ mov si,offset _ScreenStart
+ mov word ptr [si+2],VideoSelector
+ mov si,offset _vp
+ mov word ptr [si+2],VideoSelector
+
+;
+; Enable protect and paging mode
+;
+ mov eax,cr0
+
+; If we're enabling protect mode for the first time, don't turn on paging
+; because the osloader does all that. However, if we're returning to
+; protected mode, the page tables are already setup, therefore we do want
+; to turn paging on.
+ or dx,dx
+ jz only_prot
+ or eax,PROT_MODE + ENABLE_PAGING
+ mov cr0,eax
+
+;
+; The following JMP must be DWORD-aligned in order to avoid an obscure i386
+; hardware bug. If not, it is possible (albeit unlikely) that the prefetch
+; queue can get trashed.
+;
+
+ALIGN 4
+ jmp flush
+
+
+only_prot:
+ or eax,PROT_MODE
+ mov cr0,eax
+;
+; Flush the prefetch queue
+;
+
+ALIGN 4
+ jmp flush
+flush:
+
+
+;
+; Load CS with the SU module's code selector
+;
+ push SuCodeSelector
+ push offset cs:restart
+ retf
+;
+; Now load DS and SS with the SU module's protect mode data selector.
+;
+
+restart:
+ mov ax,SuDataSelector
+ mov ds,ax
+ mov ss,ax
+
+;
+; Load LDT with zero since it will never be used.
+;
+ xor bx,bx
+ lldt bx
+
+;
+; Load the Task Register and return to the boot SU module.
+;
+ or dx,dx
+ jnz epp10
+
+
+ mov bx,TSS_Selector
+ ltr bx
+
+
+epp10:
+ ret
+
+_EnableProtectPaging endp
+
+.286p
+;** _biosint
+;
+; Rom bios interrupt dispatcher
+;
+
+public _biosint
+_biosint proc near
+
+ enter 0,0
+ push di
+ push si
+ push ds
+ push es
+
+; Get pointer to register parameter frame
+
+ les di,[bp+4]
+
+; Get requested interrupt number
+
+ mov ax,es:[di].intnum
+
+; Check that requested bios interrupt is supported
+
+ sub ax,10h ; sub lowest int number supported
+ jnc short bios1
+ mov es:[di].intnum,FUNCTION_ERROR
+ jmp short biosx
+bios1:
+ shl ax,1 ; shift if to make it a word offset
+ cmp ax,bios_cnt ; offset beyond end of table?
+ jb short bios2
+
+; Error: requested interrupt not supported
+
+ mov es:[di].sax,FUNCTION_ERROR
+ jmp short biosx
+
+bios2: mov bx,ax
+ mov ax,word ptr cs:bios_table[bx]
+ push es ; save seg of address frame
+ push di ; save stack register frame pointer
+ push ax ; address of bios int
+
+ mov ax,es:[di].sax
+ mov bx,es:[di].sbx
+ mov cx,es:[di].scx
+ mov dx,es:[di].sdx
+ mov si,es:[di].ssi
+ mov es,es:[di].ses
+ ret ; this sends us to the "int #" instruction
+
+; We return here from the jmp instruction following the int
+
+bios_ret:
+
+ pop di ; get address of register parameter frame
+ pop es ; restore segment of parameter frame
+
+
+bios5: pushf
+ pop es:[di].sfg
+ mov es:[di].sax,ax
+ mov es:[di].sbx,bx
+ mov es:[di].scx,cx
+ mov es:[di].sdx,dx
+ mov es:[di].ssi,si
+ mov es:[di].ses,es
+
+; Restore original registers and return to caller
+
+biosx:
+ pop es
+ pop ds
+ pop si
+ pop di
+ leave
+ ret
+
+_biosint endp
+
+;** Bios Interrupt Table
+;
+
+
+bios10: int 10h
+ jmp short bios_ret
+bios11: int 11h
+ jmp short bios_ret
+bios12: int 12h
+ jmp short bios_ret
+bios13: int 13h
+ jmp short bios_ret
+bios14: int 14h
+ jmp short bios_ret
+bios15: int 15h
+ jmp short bios_ret
+bios16: int 16h
+ jmp short bios_ret
+bios17: int 17h
+ jmp short bios_ret
+bios18: int 18h
+ jmp short bios_ret
+bios19: int 19h
+ jmp short bios_ret
+
+bios_table dw bios10,bios11,bios12,bios13,bios14,bios15,bios16,bios17,bios18,bios19
+
+bios_cnt equ $ - bios_table
+
+.386p
+
+;++
+;
+; _MoveMemory
+;
+; Routine Description
+;
+; Moves dwords in memory from source to destination.
+;
+; Arguments
+;
+; (TOS+4) = number of bytes to move
+; (TOS+8) = linear address of destination
+; (TOS+12) = linear address of source
+;
+; Notes
+;
+; 1) Valid page table entries must already exist for the
+; source and destination memory.
+;
+; 2) ALL memory in the lower one megabyte is assumed to
+; be identity mapped if used.
+;
+; USES ESI, EDI, ECX, FLAGS
+;
+;
+;--
+
+
+public _MoveMemory
+_MoveMemory proc near
+
+ enter 0,0
+ push ds
+ push es
+;
+; Get source, destination, and count arguments from the stack
+; Make "count" the number of dwords to move.
+;
+
+ mov esi,dword ptr [bp+4]
+ mov edi,dword ptr [bp+8]
+ mov ecx,dword ptr [bp+12]
+ shr ecx,2
+
+;
+; Load FLAT selectors into DS and ES
+;
+
+ mov ax,KeDataSelector
+ mov ds,ax
+ mov es,ax
+
+;
+; Move the block of data.
+;
+assume es:FLAT, ds:FLAT
+
+;
+; move the dwords
+;
+ cld
+ rep movs dword ptr [edi],dword ptr [esi]
+
+;
+; move the remaining tail
+;
+ mov ecx, dword ptr [bp+12]
+ and ecx, 3
+ rep movs byte ptr [edi],byte ptr [esi]
+
+
+assume es:nothing, ds:DGROUP
+
+ pop es
+ pop ds
+ leave
+ ret
+
+_MoveMemory endp
+
+
+
+;++
+;
+; _ZeroMemory
+;
+; Routine Description
+;
+; Writes zeros into memory at the target address.
+;
+; Arguments
+;
+; (TOS+4) = linear address of target
+; (TOS+8) = number of bytes to zero
+;
+; Notes
+;
+; 1) Valid page table entries must already exist for the
+; source and destination memory.
+;
+; 2) ALL memory in the lower one megabyte is assumed to
+; be identity mapped if used.
+;
+; USES ESI, EDI, ECX, FLAGS
+;
+;
+;--
+
+public _ZeroMemory
+_ZeroMemory proc near
+
+
+ enter 0,0
+ push es
+;
+; Get source, destination, and count arguments from the stack
+; Make "count" the number of dwords to move.
+;
+
+ mov edi,dword ptr [bp+4]
+ mov ecx,dword ptr [bp+8]
+ shr ecx,2
+
+;
+; Load FLAT selectors into DS and ES
+;
+
+ mov ax,KeDataSelector
+ mov es,ax
+ xor eax,eax
+
+;
+; Zero the the block of data.
+;
+assume es:FLAT
+
+;
+; Zero the dwords
+;
+ cld
+ rep stos dword ptr [edi]
+
+;
+; Zero the remaining bytes
+;
+ mov ecx, dword ptr [bp+8]
+ and ecx, 3
+ rep stos byte ptr [edi]
+
+assume es:nothing, ds:DGROUP
+
+ pop es
+ leave
+ ret
+
+
+_ZeroMemory endp
+
+
+
+
+;++
+;
+; Turn Floppy Drive Motor Off
+;
+;--
+
+public _TurnMotorOff
+DriveControlRegister equ 3f2h ; Floppy control register
+
+_TurnMotorOff proc near
+
+ mov dx,DriveControlRegister
+ mov ax,0CH
+ out dx,al
+ ret
+
+_TurnMotorOff endp
+
+
+;
+; Note: we do not save and restore the gdt and idt values because they
+; cannot change while external services are being used by the OS loader.
+; This is because they MUST remain identity mapped until all mode
+; switching has ceased.
+;
+
+public _RealMode
+_RealMode proc near
+
+;
+; Switch to real-mode
+;
+
+ sgdt fword ptr [_GDTregister]
+ sidt fword ptr [_IDTregister]
+ push [saveDS] ; push this so we can get to it later
+ mov ax,SuDataSelector
+ mov es,ax
+ mov fs,ax
+ mov gs,ax
+
+ mov eax,cr0
+ and eax, not (ENABLE_PAGING + PROT_MODE)
+ mov cr0,eax
+
+;
+; flush the pipeline
+;
+ jmp far ptr here
+here:
+
+;
+; Flush TLB
+;
+
+; HACKHACK - We don't know where the page directory is, since it was
+; allocated in the osloader. So we don't want to clear out cr3,
+; but we DO want to flush the TLB....
+;
+ mov eax,cr3
+
+ nop ; Fill - Ensure 13 non-page split
+ nop ; accesses before CR3 load
+ nop ; (P6 errata #11 stepping B0)
+ nop
+
+ mov cr3,eax
+;
+; switch to real mode addressing
+;
+; N. B. We need to do a far jump rather than a retf, because a retf will not
+; reset the access rights to CS properly.
+;
+ db 0EAh ; JMP FAR PTR
+ dw offset _TEXT:rmode ; 2000:rmode
+ dw 02000h
+rmode:
+ pop ax
+ mov ds,ax
+ mov ss,ax
+;
+; Stamp video pointers for real-mode use
+;
+ mov si,offset _ScreenStart
+ mov word ptr [si+2],0b800h
+ mov si,offset _vp
+ mov word ptr [si+2],0b800h
+;
+; re-enable interrups
+;
+ lidt fword ptr [_IDTregisterZero]
+
+;
+; Re-enable interrupts
+;
+
+ sti
+ ret
+
+_RealMode endp
+
+
+
+
+
+
+
+
+;** _TransferToLoader - transfer control the the OS loader
+;
+;
+; Arguments:
+;
+; None
+;
+; Returns:
+;
+; Does not return
+;
+;**
+
+public _TransferToLoader
+_TransferToLoader proc near
+
+; generates a double fault for debug purposes
+; mov sp,0
+; push 0
+
+ mov ebx,dword ptr [esp+2] ; get entrypoint arg
+ xor eax,eax
+ mov ax,[saveDS]
+
+;
+; Setup OS loader's stack. Compute FLAT model esp to id map to
+; original stack.
+;
+ mov cx,KeDataSelector
+ mov ss,cx
+ mov esp,LOADER_STACK ;** TMP HACK *** BUGBUG BUGBUG
+;
+; Load ds and es with kernel's data selectors
+;
+
+ mov ds,cx
+ mov es,cx
+
+;
+; Setup pointer to file system and boot context records
+;
+; Make a linear pointer to the Boot Context Record
+
+ shl eax,4
+ xor ecx,ecx
+ mov cx,offset _BootRecord
+ add eax,ecx
+ push eax
+
+ push 1010h ; dummy return address.
+ push 1010h ; dummy return address.
+
+;
+; Push 48bit address of loader entry-point
+;
+ db OVERRIDE
+ push KeCodeSelector
+ push ebx
+
+;
+; Pass control to the OS loader
+;
+ db OVERRIDE
+ retf
+
+_TransferToLoader endp
+
+
+
+
+;++
+; Description:
+;
+; Gets memory block sizes for memory from zero to one meg and
+; from one meg to 64 meg. We do this by calling int 12h
+; (get conventional memory size) and int 15h function 88h (get
+; extended memory size).
+;
+; Arguments:
+;
+; None
+;
+; Returns:
+;
+; USHORT - Size of usable memory (in pages)
+;
+;--
+
+public _IsaConstructMemoryDescriptors
+BmlTotal equ [bp-4]
+Func88Result equ [bp-6]
+_IsaConstructMemoryDescriptors proc near
+ push bp ; save ebp
+ mov bp, sp
+ sub sp, 6
+;
+; Initialize the MemoryList to start with a zero entry. (end-of-list)
+;
+ les si, dword ptr _MemoryDescriptorList
+ xor eax,eax
+ mov es:[si].BlockSize,eax
+ mov es:[si].BlockBase,eax
+
+;
+; Get conventional (below one meg) memory size
+;
+ push es
+ push si
+ int 12h
+ movzx eax,ax
+;
+; EAX is the number of 1k blocks, which we need to convert to the
+; number of bytes.
+;
+ shl eax,10
+
+ push eax
+ shr eax, 12
+ mov BmlTotal, eax
+ xor eax,eax
+ push eax
+ call _InsertDescriptor
+ add sp,8
+
+;
+; Get extended memory size and fill-in the second descriptor
+;
+
+ mov ah,88h
+
+ int 15h
+
+ mov Func88Result,ax
+ and eax,0ffffh
+
+;
+; EAX is the number of 1k blocks, which we need to convert to the
+; number of bytes.
+;
+ shl eax,10
+ push eax
+ shr eax,12
+ add BmlTotal, ax
+ mov eax,0100000h
+ push eax
+ call _InsertDescriptor
+ add sp,8
+
+;
+; Try function E801, see if that is supported on this machine
+;
+ mov ax,0E801h
+ int 15h
+ jc short Isa50
+
+ cmp ax,Func88Result ; Is extended memory same as 88?
+ je short Isa40 ; Yes, go add the rest
+
+ cmp ax, (16-1) * 1024 ; Is extended memory exactly 16MB?
+ jne short Isa50 ; No, conflict between 88 & E801
+
+Isa40:
+;
+; Function looks like it worked
+;
+; AX = extended memory < 16M in 1k blocks
+; BX = extended memory > 16M in 64k blocks
+;
+ and ebx,0ffffh
+ jz short Isa50
+
+ shl ebx,16 ; ebx = memory > 16M in bytes (via E801)
+ add ebx, 16*1024*1024 ; ebx = end of memory in bytes (via E801)
+
+ mov ax, Func88Result
+ and eax,0ffffh
+ shl eax, 10 ; eax = memory > 1M in bytes (via 88)
+ add eax, 1*1024*1024 ; eax = end of memory in bytes (via 88)
+
+ sub ebx, eax ; ebx = memory above eax
+ jbe short Isa50 ; if ebx <= eax, done
+
+ push ebx
+ shr ebx,12
+ add BmlTotal, bx
+ push eax
+ call _InsertDescriptor
+ add sp,8
+ and eax,0ffffh
+
+Isa50:
+ pop si
+ pop es
+ mov eax, BmlTotal
+ mov sp, bp
+ pop bp
+ ret
+
+_IsaConstructMemoryDescriptors endp
+
+;++
+;
+; BOOLEAN
+; Int15E820 (
+; E820Frame *Frame
+; );
+;
+;
+; Description:
+;
+; Gets address range descriptor by calling int 15 function E820h.
+;
+; Arguments:
+;
+; Returns:
+;
+; BOOLEAN - failed or succeed.
+;
+;--
+
+cmdpFrame equ [bp + 6]
+public _Int15E820
+_Int15E820 proc near
+
+ push ebp
+ mov bp, sp
+ mov bp, cmdpFrame ; (bp) = Frame
+ push es
+ push edi
+ push esi
+ push ebx
+
+ push ss
+ pop es
+
+ mov ebx, [bp].Key
+ mov ecx, [bp].DescSize
+ lea di, [bp].BaseAddrLow
+ mov eax, 0E820h
+ mov edx, 'SMAP' ; (edx) = signature
+
+ INT 15h
+
+ mov [bp].Key, ebx ; update callers ebx
+ mov [bp].DescSize, ecx ; update callers size
+
+ sbb ecx, ecx ; ecx = -1 if carry, else 0
+ sub eax, 'SMAP' ; eax = 0 if signature matched
+ or ecx, eax
+ mov [bp].ErrorFlag, ecx ; return 0 or non-zero
+
+ pop ebx
+ pop esi
+ pop edi
+ pop es
+ pop ebp
+ ret
+
+_Int15E820 endp
+
+_TEXT ends
+
+ end Start
+
diff --git a/private/ntos/boot/startup/i386/su.h b/private/ntos/boot/startup/i386/su.h
new file mode 100644
index 000000000..797e7835d
--- /dev/null
+++ b/private/ntos/boot/startup/i386/su.h
@@ -0,0 +1,14 @@
+//
+// Master include file for StartUp Module
+//
+
+#define i386
+#define __stdcall
+#define __cdecl
+#define UNALIGNED
+#include "types.h"
+#include "ntmisc.h"
+#include "ntconfig.h"
+#include "global.h"
+#include "constant.h"
+#include "memmap.h"
diff --git a/private/ntos/boot/startup/i386/su.inc b/private/ntos/boot/startup/i386/su.inc
new file mode 100644
index 000000000..34f25cf40
--- /dev/null
+++ b/private/ntos/boot/startup/i386/su.inc
@@ -0,0 +1,466 @@
+;++
+;
+; Module name
+;
+; su.inc
+;
+; Author
+;
+; Thomas Parslow (tomp) Mar-1-90
+;
+; Description
+;
+; Include file for SU.ASM.
+;
+;
+;--
+
+.386
+
+PAGE_SIZE equ 1000h
+MACHINE_TYPE_ISA equ 0
+MACHINE_TYPE_EISA equ 1
+MACHINE_TYPE_MCA equ 2
+
+;
+; Define the segment:offset address pair of the location to
+; load detection module.
+; N.B. This definition *MUST* be the same as the ones defined
+; in ..\constant.h
+;
+
+DETECTION_ADDRESS_SEG equ 1000h
+DETECTION_ADDRESS_OFFSET equ 0
+
+;
+; Structure definitions and equates for INT 15 function E820
+;
+
+E820Frame struc
+ ErrorFlag dd ?
+ Key dd ?
+ DescSize dd ?
+
+ BaseAddrLow dd ?
+ BaseAddrHigh dd ?
+ SizeLow dd ?
+ SizeHigh dd ?
+ MemoryType dd ?
+E820Frame ends
+
+MemoryDescriptorFramePointer struc
+ E820FramePointer dd ?
+MemoryDescriptorFramePointer ends
+
+
+
+;
+
+BIOS_DISK_INTERRUPT equ 13h
+BIOS_READ_SECTOR equ 2
+IDT_ENTRIES equ 100h
+
+BIOS_KEYBOARD_INTERRUPT equ 16h
+
+EXPORT_STACK equ 07ffeh
+RE_ENABLING equ 1
+LOADER_STACK equ 061ffch
+
+CR0_ET equ 10h
+
+;
+; Trap Number macro save eax on the stack and then pushes the
+; number of the trap that's in progress.
+;
+
+TRAP_NUMBER macro num,addr
+ IF num EQ 9
+ push eax ; push place holder for error code
+ ENDIF
+ IF num LE 7
+ push eax ; push place holder for error code
+ ENDIF
+ push eax ; save eax on stack first
+ mov eax,num
+ push eax
+ jmp addr
+ endm
+
+;;
+;
+; GetSector Stack Frame Structure
+;
+; Stack frame definition for GetSector call from OS loader
+; to 16bit routines.
+;
+;;
+
+GetSectorFrame struc
+ FunctionNumber dd ?
+ DriveNumber dd ?
+ HeadNumber dd ?
+ TrackNumber dd ?
+ SectorNumber dd ?
+ NumberOfSectors dd ?
+ BufferPointer dd ?
+GetSectorFrame ends
+
+;;
+;
+; GetEddsSector Stack Frame Structure
+;
+; Stack frame definition for GetEddsSector call from OS loader
+; to 16bit routines.
+;
+;;
+
+GetEddsSectorFrame struc
+ DriveNum dd ?
+ LBNLow dd ?
+ LBNHigh dd ?
+ NumberOfBlocks dd ?
+ BufPointer dd ?
+GetEddsSectorFrame ends
+
+RebootFrame struc
+ BootType dd ?
+RebootFrame ends
+
+;
+; ABIOS services Stack Frame Structure
+;
+; Stack frame definition for ABIOS services call from OS loader
+; to 16 bit routine.
+;
+
+AbiosServicesFrame struc
+ AbiosFunction dd ?
+ CommonDataArea dd ?
+ InitTable dd ?
+ RamExtension dd ?
+ AbiosRoutine dd ?
+ LogicalId dd ?
+ NumberLids dd ?
+AbiosServicesFrame ends
+
+;
+; Hardware detection frame structure
+;
+; Stack frame definition for DetectHardware call from OS loader
+; to 16 bit routine.
+;
+
+DetectionFrame struc
+ HeapStart dd ?
+ HeapSize dd ?
+ ConfigTree dd ?
+ HeapUsed dd ?
+ LoadOptions dd ?
+ OptionsLength dd ?
+DetectionFrame ends
+
+;
+; HardwareCursor Stack Frame Structure
+;
+; Stack frame definition for HardwareCursor call from OS loader
+; to 16 bit routine.
+;
+
+HardwareCursorFrame struc
+ XCoord dd ?
+ YCoord dd ?
+HardwareCursorFrame ends
+
+;
+; GetDateTime Stack Frame Structure
+;
+; Stack frame definition for GetDateTime call from OS loader
+; to 16 bit routine.
+;
+
+GetDateTimeFrame struc
+ DateDword dd ?
+ TimeDword dd ?
+GetDateTimeFrame ends
+
+
+;
+; ComPort Stack Frame Structure
+;
+; Stack frame definition for ComPort call from OS loader
+; to 16 bit routine.
+;
+
+ComPortFrame struc
+ ComPortPort dd ?
+ ComPortFunction dd ?
+ ComPortArg dd ?
+ComPortFrame ends
+
+;
+; IsMcaMachine Stack Frame Structure
+;
+; Stack frame definition for IsMcaMachine call from OS loader
+; to 16 bit routine.
+;
+
+IsMcaMachineFrame struc
+ Dummy dd ?
+IsMcaMachineFrame ends
+
+;;
+;
+; GetElToritoStatus Stack Frame Structure
+;
+; Stack frame definition for GetElToritoStatus call from OS loader
+; to 16bit routines.
+;
+;;
+
+GetElToritoStatusFrame struc
+ SpecPacketPointer dd ?
+ ETDriveNum dd ?
+GetElToritoStatusFrame ends
+
+;;
+;
+; Memory Descriptor Structure.
+;
+; Passed to OS loader as part of the boot context record
+;
+;;
+
+MemoryDescriptor struc
+ BlockBase dd ?
+ BlockSize dd ?
+MemoryDescriptor ends
+
+;;
+;
+; File System Context Record Structure
+;
+;;
+
+FsContextRecord struc
+ BootDrive dd ?
+ PointerToBpb dd ?
+ Reserved dd ?
+FsContextRecord ends
+
+;;
+;
+; IDT Descriptor Structure
+;
+;;
+
+TrapDesc struc
+ IDT_offset dw ?
+ IDT_selector dw ?
+ IDT_attribute dw ?
+ IDT_reserved dw ?
+TrapDesc ends
+
+;;
+;
+; GDT Descriptor Structure ;;
+;
+;;
+
+GDTDesc struc
+ GDT_limit dw 0
+ GDT_base1 dw 0
+ GDT_base2 db 0
+ GDT_access db 0
+ GDT_limacc db 0
+ GDT_base3 db 0
+GDTDesc ends
+
+
+;;
+;
+; GDT Selector Definitions
+;
+;;
+
+NULL_Selector equ 0h
+KeCodeSelector equ 8h
+KeDataSelector equ 10h
+UsCodeSelector equ 18h
+UsDataSelector equ 20h
+TSS_Selector equ 28h
+PCR_Selector equ 30h
+TEP_Selector equ 38h
+BDA_Selector equ 40h
+KeLdtSelector equ 48h
+DblFltTskSelector equ 50h
+SuCodeSelector equ 58h
+SuDataSelector equ 60h
+VideoSelector equ 68h
+GDT_AliasSelector equ 70h
+DbCodeSelector equ 78h
+DbDataSelector equ 80h
+DebugUseSelector equ 88h
+ReservedSelector equ 90h
+
+;;
+;
+; Exception Frame Structure
+; Note, this absolutely must match the corresponding structure
+; defined in "types.h"
+;
+;;
+
+ExceptionFrame struc
+ Ftr dw 0
+ Fdr6 dd 0
+ Fcr0 dd 0
+ Fcr2 dd 0
+ Fcr3 dd 0
+ Fss dw 0
+ Fgs dw 0
+ Ffs dw 0
+ Fes dw 0
+ Fds dw 0
+ Fedi dd 0
+ Fesi dd 0
+ Febp dd 0
+ Fesp dd 0
+ Febx dd 0
+ Fedx dd 0
+ Fecx dd 0
+ TrapNum dd 0
+ Feax dd 0
+ Error dd 0
+ Feip dd 0
+ Fcs dd 0
+ Feflags dd 0
+ExceptionFrame ends
+
+
+tFsContext struc
+ dw 0
+tFsContext ends
+
+
+
+tBootContext struc
+ dd 0
+ dd 0
+tBootContext ends
+
+
+
+
+FUNCTION_ERROR equ -1
+
+;;
+;
+; Register Frame Structure
+;
+; For bios int calls
+;
+;;
+
+reg_frame struc
+ intnum dw ?
+ sfg dw ?
+ sax dw ?
+ sbx dw ?
+ scx dw ?
+ sdx dw ?
+ ssi dw ?
+ ses dw ?
+reg_frame ends
+
+
+;;
+;; Processor Flags
+;;
+
+PROT_MODE equ 000000001 ; Enable protect mode operation
+ENABLE_PAGING equ 80000000h ; Enable paging hardware
+PD_PHYSICAL_ADDRESS equ 99000h
+TSS_SIZE equ 80h
+OVERRIDE equ 66h
+
+;
+; Operand and Address size overrides
+;
+
+OPSIZE macro
+ db 66h
+ endm
+ADSIZE macro
+ db 67h
+ endm
+
+
+;
+; External Procedures for SUDATA.ASM
+;
+
+IFDEF SU_CODEMODULE
+extrn _SuMain:near
+extrn _ScreenStart:near
+extrn _vp:near
+extrn _putx:near
+extrn _TrapHandler:near
+extrn _GDTregister:fword
+extrn _IDTregister:fword
+extrn _IDTregisterZero:fword
+extrn saveDS:word
+extrn SuStack:word
+extrn _edata:word
+extrn _FileStart:dword
+ENDIF
+
+
+
+;
+; External Procedures for SUDATA.ASM
+;
+
+IFDEF SU_DATAMODULE
+extrn Trap0:far
+extrn Trap1:far
+extrn Trap2:far
+extrn Trap3:far
+extrn Trap4:far
+extrn Trap5:far
+extrn Trap6:far
+extrn Trap7:far
+extrn Trap8:far
+extrn Trap9:far
+extrn TrapA:far
+extrn TrapB:far
+extrn TrapC:far
+extrn TrapD:far
+extrn TrapE:far
+extrn TrapF:far
+extrn _edata:near
+ENDIF
+
+
+
+;
+; Segment declarations for "Small Model" 16 bit Su Module.
+;
+
+_TEXT segment para use16 public 'CODE'
+_TEXT ends
+
+_DATA segment para use16 public 'DATA'
+_DATA ends
+
+CONST segment para use16 public 'CONST'
+CONST ends
+
+_BSS segment para use16 public 'BSS'
+_BSS ends
+
+DGROUP group const, _BSS, _DATA
+
+
+;;; END OF FILE ;;;
+
+ \ No newline at end of file
diff --git a/private/ntos/boot/startup/i386/sudata.asm b/private/ntos/boot/startup/i386/sudata.asm
new file mode 100644
index 000000000..08bc15147
--- /dev/null
+++ b/private/ntos/boot/startup/i386/sudata.asm
@@ -0,0 +1,522 @@
+;++
+;
+; Module name
+;
+; su.asm
+;
+; Author
+;
+; Thomas Parslow (tomp) Mar-1-90
+;
+; Description
+;
+; Static data for Startup module for the 386 NT OS loader. The gdt
+; idt, and double fault tss are statically defined here. Also most
+; of the zero init static data is defined here because the SU module
+; must have a zero length .bss section.
+;
+;
+;--
+
+.386p
+
+SU_DATAMODULE equ 1
+
+
+include su.inc
+include memmap.inc
+
+
+
+_DATA SEGMENT PARA USE16 PUBLIC 'DATA'
+
+;
+; Global Descriptor Table
+;
+; Note, the SuCode and SuData segments must have limits of 64k in
+; order for the mode switch code to work.
+;
+
+public _Beginx86Relocation
+public _GDT
+
+_Beginx86Relocation equ $
+_GDT equ $
+;;;
+;;; Lim 0-15, Base0-15,Base 16-23, LimAcc,
+;;;
+
+;
+; Selector 00h - Null selector - unsused
+;
+
+GDTDesc <00000h, 00000h, 000h, 000h, 000h, 000h>
+
+;
+; Selector 08h KeCodeSelector - kernel code segment : FLAT 4gig limit
+;
+
+GDTDesc <0ffffh, 00000h, 000h, 09ah, 0cfh, 000h>
+
+;
+; Selector 10h - KeDataSelector - kernel data segment : FLAT 4gig limit
+;
+
+GDTDesc <0ffffh, 00000h, 000h, 092h, 0cfh, 000h>
+
+;
+; Selector 18h - UsCodeSelector - User code segment : FLAT 2gig limit
+;
+
+GDTDesc <0ffffh, 00000h, 000h, 0fah, 0cfh, 000h>
+
+;
+; Selector 20h - UsDataSelector - User data segment : FLAT 2gig limit
+;
+GDTDesc <0ffffh, 00000h, 000h, 0f2h, 0cfh, 000h>
+
+;
+; Selector 28h - TSS_Selector - Kernels TSS
+;
+
+GDTDesc <EndTssKernel - _TssKernel - 1, offset _TEXT:_TssKernel, \
+002h, 089h, 000h, 000h> ; TSS
+
+;
+; Selector 30h - PCR_Selector - Master Boot Processor's PCR segment
+; This is actually edited later in BlSetupForNt in order to
+; point to a page located at a high virtual address.
+;
+
+GDTDesc <01h, 00000h, 000h, 092h, 0c0h, 000h>
+
+;
+; Selector 38h - TEP_Selector - Thread Environment
+;
+
+GDTDesc <0fffh, 00000h, 000h, 0f3h, 040h, 000h>
+
+;
+; Selector 40 - BDA_SAelector - Bios Data Area near-clone
+;
+
+GDTDesc <0ffffh, 00400h, 000h, 0f2h, 000h, 000h>
+
+;
+; Selector 48h - LdtDescriptor - used to load an ldt
+; (Gets set at Ldt set and process switch by the kernel)
+;
+
+GDTDesc <00000h, 00000h, 000h, 000h, 000h, 000h>
+
+;
+; Selector 50h - DblFltTskSelector - Double Fault TSS
+;
+
+GDTDesc <EndTssDblFault32 - _TssDblFault32 - 1, offset _TEXT:_TssDblFault32, \
+002h, 089h, 000h, 000h> ;
+
+;
+; Selector 58h - SuCodeSelector - Startup module's code segment
+;
+
+GDTDesc <0ffffh, 00000h, 002h, 09ah, 000h, 000h>
+
+;
+; Selector 60h - SuDataSelector - Startup module's data segment
+;
+
+GDTDesc <0ffffh, offset _TEXT:DGROUP, 002h, 092h, 000h, 000h>
+
+;
+; Selector 68h - VideoSelector - Video display buffer
+;
+
+GDTDesc <03fffh, 08000h, 00bh, 092h, 000h, 000h>
+
+;
+; Selector 70h - GDT_AliasSelector - GDT Alias Selector
+;
+
+GDTDesc <EndGDT - _GDT - 1, 7000h, 0ffh, 092h, 000h,0ffh>
+
+
+; Debug selectors : CURRENTLY NOT USED
+
+GDTDesc <0ffffh, 00000h, 040h, 09ah, 000h, 080h> ; 70 Debug Code
+GDTDesc <0ffffh, 00000h, 040h, 092h, 000h, 080h> ; 78 Debug Data
+GDTDesc <00000h, 00000h, 000h, 092h, 000h, 000h> ; 80 Debug Use
+GDTDesc <00000h, 00000h, 000h, 000h, 000h, 000h> ; 88 Spare
+DEFINED_GDT_ENTRIES equ ($ - _GDT) / size GDTDesc
+ dq ((1024 / size GDTDesc) - DEFINED_GDT_ENTRIES) DUP(0)
+EndGDT equ $
+GDT_SIZE equ (EndGDT - _GDT)
+
+
+;;
+;; Interrupt Descriptor Table
+;;
+
+
+public _IDT
+align 16
+_IDT equ $
+TrapDesc <offset Trap0, KeCodeSelector, 8f00h, 0>
+TrapDesc <offset Trap1, SuCodeSelector, 8f00h, 0>
+TrapDesc <offset Trap2, SuCodeSelector, 8f00h, 0>
+TrapDesc <offset Trap3, SuCodeSelector, 8f00h, 0>
+TrapDesc <offset Trap4, SuCodeSelector, 8f00h, 0>
+TrapDesc <offset Trap5, SuCodeSelector, 8f00h, 0>
+TrapDesc <offset Trap6, SuCodeSelector, 8f00h, 0>
+TrapDesc <offset Trap7, SuCodeSelector, 8f00h, 0>
+TrapDesc <offset Trap8, SuCodeSelector, 8f00h, 0>
+;TrapDesc <offset Trap8, DblFltTskSelector,8500h, 0>
+TrapDesc <offset Trap9, SuCodeSelector, 8f00h, 0>
+TrapDesc <offset TrapA, SuCodeSelector, 8f00h, 0>
+TrapDesc <offset TrapB, SuCodeSelector, 8f00h, 0>
+TrapDesc <offset TrapC, SuCodeSelector, 8f00h, 0>
+TrapDesc <offset TrapD, SuCodeSelector, 8f00h, 0>
+TrapDesc <offset TrapE, SuCodeSelector, 8f00h, 0>
+TrapDesc <offset TrapF, SuCodeSelector, 8f00h, 0>
+DEFINED_IDT_ENTRIES equ ($ - _IDT) / size TrapDesc
+ dq (IDT_ENTRIES - DEFINED_IDT_ENTRIES) DUP(0)
+
+
+
+EndIDT equ $
+public _Endx86Relocation
+_Endx86Relocation equ $
+
+;
+; disk-base table. We copy it from the ROM to here so we can patch the
+; last sector number. This lets us access both 5.25" and 3.5" drives.
+;
+Public _DiskBaseTable
+_DiskBaseTable equ $
+ SpecifyBytes dw 0
+ WaitTime db 0
+ SectorLength db 0
+ LastSector db 0
+ SecGapLength db 0
+ DataTransfer db 0
+ TrackGapLength db 0
+ DataValue db 0
+ HeadSettle db 0
+ StartupTime db 0
+
+Public _RomDiskBasePointer
+_RomDiskBasePointer dd 0
+
+;
+; Enhanced Disk Drive Spec. Disk Address Packet
+;
+Public _EddsAddressPacket
+_EddsAddressPacket equ $
+ PacketSize db 10h
+ Reserved1 db 0
+ Blocks2Xfer db 0
+ Reserved2 db 0
+ XferBuf dd 0
+ LBALow dd 0
+ LBAHigh dd 0
+
+;
+; Task State Segment for Double Fault Handler
+;
+Public _TssDblFault
+align 16
+_TssDblFault equ $
+ dw 0 ;link
+ dw offset _DATA:DblFaultStack
+ dw SuDataSelector
+ dd 0 ; ring1 ss:sp
+ dd 0 ; ring2 ss:sp
+ dw offset _TEXT:Trap8
+ dw 0 ; flags
+ dw 0 ; ax
+ dw 0 ; cx
+ dw 0 ; dx
+ dw 0 ; bx
+ dw offset _DATA:DblFaultStack ; sp
+ dw 0 ; bp
+ dw 0 ; si
+ dw 0 ; di
+ dw SuDataSelector ; es
+ dw SuCodeSelector ; cs
+ dw SuDataSelector ; ss
+ dw SuDataSelector ; ds
+ dw 0 ; ldt selector
+ dw 0
+EndTssDblFault equ $
+
+
+_TssDblFault32 equ $
+ dd 0 ;link
+ dd offset _DATA:DblFaultStack
+ dd SuDataSelector
+ dd 0 ; ring1 esp
+ dd 0 ; ring1 ss
+ dd 0 ; ring2 esp
+ dd 0 ; ring2 ss
+ dd PD_PHYSICAL_ADDRESS
+ dd offset _TEXT:Trap8
+ dd 0 ; eflags
+ dd 0 ; eax
+ dd 0 ; ecx
+ dd 0 ; edx
+ dd 0 ; ebx
+ dd offset _DATA:DblFaultStack ; sp
+ dd 0 ; bp
+ dd 0 ; si
+ dd 0 ; di
+ dd SuDataSelector ; es
+ dd SuCodeSelector ; cs
+ dd SuDataSelector ; ss
+ dd SuDataSelector ; ds
+ dd 0 ;fs
+ dd 0 ;gs
+ dd 0 ; ldt selector
+ dd 0 ; i/o map
+ dd 0 ;
+ dd 0 ;
+EndTssDblFault32 equ $
+
+
+
+;
+; Stack for Double Fault Handler Task
+;
+
+public _FileStart
+_FileStart dd 0
+
+align 4
+public DblFaultStack
+ dw 50 DUP(0)
+DblFaultStack equ $
+
+;
+; Note that we need at least 2k of real-mode stack because some EISA BIOS
+; routines require it.
+;
+align 4
+public SuStack
+public _SuStackBegin
+_SuStackBegin equ $
+ db 2048 DUP (0)
+SuStack equ $
+
+align 16
+public _TssKernel
+_TssKernel dw 60 DUP(0)
+EndTssKernel equ $
+
+align 4
+public _GDTregister
+_GDTregister dw EndGDT - _GDT - 1
+ dw (SYSTEM_PAGE_PA and 0ffffh) + offset DGROUP:_GDT
+ dw (SYSTEM_PAGE_PA SHR 16) and 0ffh
+
+align 4
+public _IDTregister
+_IDTregister dw EndIDT - _IDT - 1
+ dw (SYSTEM_PAGE_PA and 0ffffh) + offset DGROUP:_IDT
+ dw (SYSTEM_PAGE_PA SHR 16) and 0ffh
+
+;
+; We load the idtr from the this fword .
+;
+public _IDTregisterZero
+_IDTregisterZero dw 0ffffh
+ dd 0
+
+;
+; We save the base of the real mode data segment here so we
+; can use it later in calculations of the linear address of
+; the start of DGROUP.
+;
+public saveDS
+saveDS dw 0
+;
+; When ever we enter the debugger we set this variable to
+; on so we can tell if we've faulted in the debugger when
+; we get an exception.
+;
+public _InDebugger
+_InDebugger dw 0
+
+; We save SP here when we get an exception in the debugging
+; version of the SU module. If we get an exception in the
+; debugger, we use this value to reset the stack to point to
+; the base of the original exception/break-point stack frame.
+;
+public SaveSP
+SaveSP dw 0
+
+;
+; BOOT CONTEXT RECORD
+;
+
+;
+; Export Entry Table
+;
+
+extrn RebootProcessor:near
+extrn GetSector:near
+extrn GetEddsSector:near
+extrn GetKey:near
+extrn GetCounter:near
+extrn Reboot:near
+extrn AbiosServices:near
+extrn DetectHardware:near
+extrn HardwareCursor:near
+extrn GetDateTime:near
+extrn ComPort:near
+extrn IsMcaMachine:near
+extrn GetStallCount:near
+extrn InitializeDisplayForNt:near
+extrn GetMemoryDescriptor:near
+extrn GetElToritoStatus:near
+
+SU_LOAD_ADDRESS equ 20000h
+
+
+
+; FsContext
+;
+;
+public _FsContext
+align 4
+_FsContext FsContextRecord <0,0,0>
+
+;
+; Memory Descriptor Table
+; The Memory Descriptor Table begins at 7000:0000 and grows upward.
+; Note that this is 64k above the start of the OS Loader Heap and
+; 64k below the start of the OS Loader Stack. This is ok, since the
+; x86 Arc Emulation will have converted all of this information into
+; Arc Memory Descriptors before the OS Loader is initialized.
+;
+
+align 4
+public _MemoryDescriptorList
+_MemoryDescriptorList dw 0
+ dw 7000h
+
+;
+; This is for getting the memory information from a MCA machine. Not
+; sure why we need 66 bytes, since the actual structure isn't that big,
+; but that's what the spec. says...
+;
+align 4
+public _McaMemoryData
+_McaMemoryData db 66 dup(0)
+
+;
+; This is called the External Services Table by the OS loader
+;
+
+align 4
+public _ExportEntryTable
+_ExportEntryTable equ $
+ dw offset _TEXT:RebootProcessor
+ dw SU_LOAD_ADDRESS SHR 16
+ dw offset _TEXT:GetSector
+ dw SU_LOAD_ADDRESS SHR 16
+ dw offset _TEXT:GetKey
+ dw SU_LOAD_ADDRESS SHR 16
+ dw offset _TEXT:GetCounter
+ dw SU_LOAD_ADDRESS SHR 16
+ dw offset _TEXT:Reboot
+ dw SU_LOAD_ADDRESS SHR 16
+ dw offset _TEXT:AbiosServices
+ dw SU_LOAD_ADDRESS SHR 16
+ dw offset _TEXT:DetectHardware
+ dw SU_LOAD_ADDRESS SHR 16
+ dw offset _TEXT:HardwareCursor
+ dw SU_LOAD_ADDRESS SHR 16
+ dw offset _TEXT:GetDateTime
+ dw SU_LOAD_ADDRESS SHR 16
+ dw offset _TEXT:ComPort
+ dw SU_LOAD_ADDRESS SHR 16
+ dw offset _TEXT:IsMcaMachine
+ dw SU_LOAD_ADDRESS SHR 16
+ dw offset _TEXT:GetStallCount
+ dw SU_LOAD_ADDRESS SHR 16
+ dw offset _TEXT:InitializeDisplayForNt
+ dw SU_LOAD_ADDRESS SHR 16
+ dw offset _TEXT:GetMemoryDescriptor
+ dw SU_LOAD_ADDRESS SHR 16
+ dw offset _TEXT:GetEddsSector
+ dw SU_LOAD_ADDRESS SHR 16
+ dw offset _TEXT:GetElToritoStatus
+ dw SU_LOAD_ADDRESS SHR 16
+ dd 0
+
+align 4
+Public _BootRecord
+_BootRecord dw offset _TEXT:_FsContext
+ dw SU_LOAD_ADDRESS SHR 16
+
+ dw offset _TEXT:_ExportEntryTable
+ dw SU_LOAD_ADDRESS SHR 16
+
+;
+; The memory descriptor table begins at 0x70000
+;
+ dw 0
+ dw 7
+
+public _MachineType
+_MachineType dd 0 ; Machine type infor.
+
+;
+; pointer to where osloader.exe is in memory
+;
+public _OsLoaderStart
+_OsLoaderStart dd 0
+public _OsLoaderEnd
+_OsLoaderEnd dd 0
+public _ResourceDirectory
+_ResourceDirectory dd 0
+public _ResourceOffset
+_ResourceOffset dd 0
+public _OsLoaderBase
+_OsLoaderBase dd 0
+public _OsLoaderExports
+_OsLoaderExports dd 0
+
+
+;
+; ABIOS related definitions
+;
+
+extrn IsAbiosPresent:near
+extrn AbiosGetMachineConfig:near
+extrn AbiosInitializeSpt:near
+extrn AbiosBuildInitTable:near
+extrn AbiosInitializeDbsFtt:near
+
+;
+; Define ABIOS specific variables
+;
+
+;
+; Defines the machine variables, we can use them to check the validity of
+; loaded Ram Extension later.
+;
+
+ public MachineModel, MachineSubmodel, BiosRevision
+MachineModel db 0
+MachineSubmodel db 0
+BiosRevision db 0
+
+ public AbiosServicesTable
+AbiosServicesTable dw offset _TEXT:IsAbiosPresent
+ dw offset _TEXT:AbiosGetMachineConfig
+ dw offset _TEXT:AbiosInitializeSpt
+ dw offset _TEXT:AbiosBuildInitTable
+ dw offset _TEXT:AbiosInitializeDbsFtt
+
+_DATA ends
+ end
diff --git a/private/ntos/boot/startup/i386/trap.asm b/private/ntos/boot/startup/i386/trap.asm
new file mode 100644
index 000000000..7534803ee
--- /dev/null
+++ b/private/ntos/boot/startup/i386/trap.asm
@@ -0,0 +1,388 @@
+;++
+;
+; Module Name:
+;
+; trap.asm
+;
+; Author:
+;
+; Thomas Parslow [tomp]
+;
+; Created:
+;
+; 15-Jan-91
+;
+;
+; Description:
+;
+; x86 exception code
+;
+;
+
+include su.inc
+
+;
+; Exception Routing Table:
+; ~~~~~~~~~~~~~~~~~~~~~~~~
+; When an exception occurs in the SU module or before the OS loader
+; is able to setup its own IDT, control is vectored to one of the
+; Trap0 though TrapF labels. We push a number on the stack identifying
+; the exception number and then jump to code that pushes the register set
+; onto the stack. We then call a general purpose C routine that will dump
+; the register contents, the trap number, and error code information
+; onto the display.
+;
+
+_TEXT segment para use16 public 'CODE'
+ ASSUME CS: _TEXT, DS: DGROUP, SS: DGROUP
+.386p
+
+extrn _TrapHandler:near
+extrn _putx:near
+extrn _GDTregister:fword
+extrn _IDTregister:fword
+extrn _InDebugger:word
+extrn SaveSP:word
+
+public Trap0,Trap1,Trap2,Trap3,Trap4,Trap5,Trap6,Trap7
+public Trap8,Trap9,TrapA,TrapB,TrapC,TrapD,TrapE,TrapF
+
+
+Trap0: TRAP_NUMBER 0,MakeTrapFrame
+Trap1: TRAP_NUMBER 1,MakeTrapFrame
+Trap2: TRAP_NUMBER 2,MakeTrapFrame
+Trap3: TRAP_NUMBER 3,MakeTrapFrame
+Trap4: TRAP_NUMBER 4,MakeTrapFrame
+Trap5: TRAP_NUMBER 5,MakeTrapFrame
+Trap6: TRAP_NUMBER 6,MakeTrapFrame
+Trap7: TRAP_NUMBER 7,MakeTrapFrame
+Trap8: TRAP_NUMBER 8,MakeTrapFrame
+Trap9: TRAP_NUMBER 9,MakeTrapFrame
+TrapA: TRAP_NUMBER 0Ah,MakeTrapFrame
+TrapB: TRAP_NUMBER 0Bh,MakeTrapFrame
+TrapC: TRAP_NUMBER 0Ch,MakeTrapFrame
+TrapD: TRAP_NUMBER 0Dh,MakeTrapFrame
+TrapE: TRAP_NUMBER 0Eh,MakeTrapFrame
+TrapF: TRAP_NUMBER 0Fh,MakeTrapFrame
+
+
+;
+; We save the user's register contents here on the stack and call
+; a C routine to display those contents.
+; Uses 42 bytes of stack. (40 for frame)
+;
+; Note that we build a stack frame that's independent of the code and
+; stack segments' "size" during execution. That way whether we enter
+; with a 16bit or 32bit stack, the arguments frame is exacely the same.
+;
+
+MakeTrapFrame:
+
+ mov eax,esp
+ push ecx
+ push edx
+ push ebx
+ push eax ; (eax)=(esp)
+ push ebp
+ push esi
+ push edi
+
+ mov ax,ds
+ push ax
+ mov ax,es
+ push ax
+ mov ax,fs
+ push ax
+ mov ax,gs
+ push ax
+ mov ax,ss
+ push ax
+ mov eax,cr3
+ push eax
+ mov eax,cr2
+ push eax
+ mov eax,cr0
+ push eax
+ mov eax,dr6
+ push eax
+ str ax
+ push ax
+;
+; Clear out debug register signals
+;
+
+ xor eax,eax
+ mov dr6,eax
+
+;
+; Get a known good data segment
+;
+ mov ax,SuDataSelector
+ mov ds,ax
+;
+; Save system registers
+;
+ mov bx,offset DGROUP:_GDTregister
+ sgdt fword ptr [bx]
+ mov bx,offset DGROUP:_IDTregister
+ sidt fword ptr [bx]
+;
+; Is the exception frame on a 16bit or 32bit stack?
+;
+ mov ax,ss
+ cmp ax,KeDataSelector
+ je Trap32
+ cmp ax,DbDataSelector
+ jne mtf8
+;
+; Most likely we took a trap while initializing the 386 kernel debugger
+; So we've got a 16bit stack that isn't ours. We need to move
+; the stack frame onto the SU module's stack.
+
+ jmp Trap16
+
+mtf8:
+;
+; Frame on a our 16bit stack so just call the trap dump routine
+;
+ mov bx,offset DGROUP:SaveSP
+ mov [bx],sp
+
+ call _TrapHandler
+
+;
+; Get rid of the junk we saved just to display
+;
+ pop eax ; get rid of ebp pushed for other returns
+ add sp,ExceptionFrame.Fgs
+;
+; Reload the user's context and return to 16bit code
+;
+ pop gs
+ pop fs
+ pop es
+ pop ds
+ pop edi
+ pop esi
+ pop ebp
+ pop eax
+ pop ebx
+ pop edx
+ pop ecx
+ pop eax ; get rid of trap #
+ pop eax ; get original eax
+ add esp,4 ; get rid of error code
+;
+; Pop IRET frame and return to where the trap occured
+;
+ OPSIZE
+ iret
+
+
+
+
+
+Trap32:
+;
+; The exception frame is on a 32bit stack so we must setup a 16bit
+; stack and then move the exception frame on to it before calling
+; the trap dump routine.
+;
+
+ mov ebx,esp
+;
+; Setup a known good stack
+;
+ mov ax,SuDataSelector
+ mov ss,ax
+ mov sp,EXPORT_STACK
+;
+; Copy the exception frame to the new stack
+;
+
+ mov ecx, (size ExceptionFrame)/2 ; # of words in frame
+ mov esi,ebx ; (esi) = offset of argument frame
+ push KeDataSelector ; (ax) = Flat 32bit segment selector
+ pop ds ; (ds:esi) points to argument frame
+ push ss ;
+ pop es ; (es) = 16bit stack selector
+ sub sp, size ExceptionFrame ; make room for the arguments
+ xor edi,edi ; clear out upper 16bits of edi
+ mov di,sp ; (es:edi) points to top of stack
+;
+; Loop and copy a word at a time.
+;
+msf1:
+ mov ax,[esi]
+ mov es:[edi],ax
+ add esi,2
+ add edi,2
+ loop msf1
+
+ push es ;
+ pop ds ; put 16bit selector back into ds
+
+;
+; Now call the general purpose exception handler
+;
+ push ebx ; save esp for return
+;
+; Save SP in order to restore the stack in case we
+; take a fault in the debugger
+;
+ mov bx,offset DGROUP:SaveSP
+ mov [bx],sp
+
+ call _TrapHandler
+
+IFDEF DEBUG0
+public DebugReturn
+DebugReturn:
+ENDIF ;DEBUG
+ pop ebx
+;
+; We may have changed the flags while in the debugger. Copy the
+; new eflag to the iret frame. After we restore the original stack
+; pointers.
+;
+
+ mov bp,sp
+ mov ecx,[bp].Feflags
+
+ mov ax,KeDataSelector
+ mov ss,ax
+ mov esp,ebx
+
+ mov [esp].Feflags,ecx
+;
+; Get rid of the junk we saved just to display
+;
+ add esp,ExceptionFrame.Fgs
+;
+; Reload the user's context
+;
+ pop gs
+ pop fs
+ pop es
+ pop ds
+ pop edi
+ pop esi
+ pop ebp
+ pop eax
+ pop ebx
+ pop edx
+ pop ecx
+ pop eax ; get rid of trap #
+ pop eax ; get original eax
+ add esp,4 ; get rid of error code
+;
+; Pop IRET frame and return to where the trap occured
+;
+ OPSIZE
+ iret
+
+
+Trap16:
+
+; The exception frame is on a 16bit stack that isn't ours. So we must
+; move the exception frame on to the SU module's stack before calling
+; the trap dump routine.
+;
+
+ mov ebx,esp
+;
+; Setup a known good stack
+;
+ mov ax,SuDataSelector
+ mov ss,ax
+ mov sp,EXPORT_STACK
+;
+; Copy the exception frame to the new stack
+;
+
+ mov ecx, (size ExceptionFrame)/2
+ mov si,bx ; (esi) = offset of argument frame
+ push DbDataSelector ;
+ pop ds ; (ds:esi) points to argument frame
+ push ss ;
+ pop es ; (es) = 16bit stack selector
+ sub sp, size ExceptionFrame ; make room for the arguments
+ mov di,sp ; (es:edi) points to top of stack
+;
+; Loop and copy a word at a time.
+;
+Trap16_10:
+ mov ax,[si]
+ mov es:[di],ax
+ add si,2
+ add di,2
+ loop Trap16_10
+
+ push es ;
+ pop ds ; put 16bit selector back into ds
+
+;
+; Now call the general purpose exception handler
+;
+
+ push ebx ; save (original esp) for return
+;
+; Save SP in order to restore the stack in case we
+; take a fault in the debugger
+;
+ mov bx,offset DGROUP:SaveSP
+ mov [bx],sp
+
+ call _TrapHandler
+
+IFDEF DEBUG0
+public Debug16Return
+Debug16Return:
+ENDIF ;DEBUG
+ pop ebx
+;
+; We may have changed the flags while in the debugger. Copy the
+; new eflag to the iret frame. After we restore the original stack
+; pointers.
+;
+
+ mov bp,sp
+ mov ecx,dword ptr [bp].Feflags
+
+ mov ax,DbDataSelector
+ mov ss,ax
+ mov esp,ebx
+
+ mov dword ptr ss:[bx].Feflags,ecx
+;
+; Get rid of the junk we saved just to display
+;
+ add sp,ExceptionFrame.Fgs
+;
+; Reload the user's context
+;
+ pop gs
+ pop fs
+ pop es
+ pop ds
+ pop edi
+ pop esi
+ pop ebp
+ pop eax
+ pop ebx
+ pop edx
+ pop ecx
+ pop eax ; get rid of trap #
+ pop eax ; get original eax
+ add esp,4 ; get rid of error code
+;
+; Pop IRET frame and return to where the trap occured
+;
+ OPSIZE
+ iret
+
+
+
+_TEXT ends
+ end
+ \ No newline at end of file
diff --git a/private/ntos/boot/startup/i386/trapdump.c b/private/ntos/boot/startup/i386/trapdump.c
new file mode 100644
index 000000000..f1e74985f
--- /dev/null
+++ b/private/ntos/boot/startup/i386/trapdump.c
@@ -0,0 +1,425 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+
+Module Name:
+
+ trap.c
+
+Author:
+
+ Thomas Parslow [TomP] Mar-01-90
+
+
+Abstract:
+
+ General purpose trap handler for 80386 boot loader. When built in
+ debugger is present, output is redirected to the com port. When no
+ debugger is present, output goes to the display.
+
+
+--*/
+
+#include "su.h"
+
+extern
+USHORT
+InDebugger;
+
+extern
+USHORT
+DebuggerPresent;
+
+extern
+UCHAR
+GDTregister;
+
+extern
+UCHAR
+IDTregister;
+
+extern
+VOID
+OutPort(
+ USHORT
+ );
+
+extern
+USHORT
+InPort(
+ VOID
+ );
+
+extern
+VOID
+ReEnterDebugger(
+ VOID
+ );
+
+extern
+USHORT
+TssKernel;
+
+extern
+USHORT
+Redirect;
+
+extern
+VOID RealMode(
+ VOID
+ );
+
+VOID
+TrapHandler(
+ IN ULONG,
+ IN USHORT
+ );
+
+VOID
+DumpProcessorContext(
+ VOID
+ );
+
+VOID
+DumpSystemRegisters(
+ VOID
+ );
+
+VOID
+DumpCommonRegisters(
+ VOID
+ );
+
+VOID
+DisplayFlags(
+ ULONG f
+ );
+
+
+VOID
+DumpTSS(
+ VOID
+ );
+
+
+ULONG
+GetAddress(
+ VOID
+ );
+
+VOID
+GetNumber(
+ PCHAR cp
+ );
+
+USHORT
+GetChar(
+ VOID
+ );
+
+VOID
+DumpAddress(
+ ULONG
+ );
+
+#define PG_FAULT_MSG " =================== PAGE FAULT ================================= \n\n"
+#define DBL_FAULT_MSG " ================== DOUBLE FAULT ================================ \n\n"
+#define GP_FAULT_MSG " ============== GENERAL PROTECTION FAULT ======================== \n\n"
+#define STK_OVERRUN_MSG " ===== STACK SEGMENT OVERRUN or NOT PRESENT FAULT =============== \n\n"
+#define EX_FAULT_MSG " ===================== EXCEPTION ================================ \n\n"
+#define DEBUG_EXCEPTION "\nDEBUG TRAP "
+#define ishex(x) ( ( x >= '0' && x <= '9') || (x >= 'A' && x <= 'F') || (x >= 'a' && x <= 'f') )
+
+
+//
+// Global Trap Frame Pointer
+//
+
+PTF TrapFrame;
+
+
+VOID
+TrapHandler(
+ IN ULONG Padding,
+ IN USHORT TF_base
+ )
+/*++
+
+Routine Description:
+
+ Prints minimal trap information
+
+Arguments:
+
+
+ 386 Trap Frame on Stack
+
+Environment:
+
+ 16-bit protect mode only.
+
+
+--*/
+
+{
+ int i;
+
+ //
+ // Initialize global trap frame pointer and print trap number
+ //
+
+ TrapFrame = (PTF)&TF_base;
+
+ //
+ // Fix esp to point to where it pointed before trap
+ //
+
+ TrapFrame->Fesp += 24;
+
+ BlPrint("\n TRAP %lx ",TrapFrame->TrapNum);
+
+ //
+ // Print the trap specific header and display processor context
+ //
+
+ switch(TrapFrame->TrapNum) {
+
+ case 1:
+ case 3:
+ puts( DEBUG_EXCEPTION );
+ DumpCommonRegisters();
+ break;
+
+ case 8:
+ puts( DBL_FAULT_MSG );
+ DumpTSS();
+ break;
+
+ case 12:
+ puts( STK_OVERRUN_MSG );
+ DumpProcessorContext();
+ break;
+
+ case 13:
+ puts( GP_FAULT_MSG );
+ DumpProcessorContext();
+ break;
+
+ case 14:
+ puts( PG_FAULT_MSG );
+ BlPrint("** At linear address %lx\n",TrapFrame->Fcr2);
+ DumpProcessorContext();
+ break;
+
+ default :
+ puts( EX_FAULT_MSG );
+ DumpProcessorContext();
+ break;
+ }
+
+ RealMode();
+ while (1); //**** WAITFOREVER *** //
+
+
+}
+
+
+VOID
+DumpProcessorContext(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Dumps all the processors registers. Called whenever a trap or fault
+ occurs.
+
+Arguments:
+
+ None
+
+Returns:
+
+ Nothing
+
+--*/
+{
+ DumpSystemRegisters();
+ DumpCommonRegisters();
+}
+
+VOID
+DumpSystemRegisters(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Dumps (writes to the display or com poirt) the x86 processor control
+ registers only. Does not dump the common registers (see
+ DumpCommonRegisters)
+
+Arguments:
+
+ None
+
+Returns:
+
+ Nothing
+
+
+--*/
+{
+ BlPrint("\n tr=%x cr0=%lx cr2=%lx cr3=%lx\n",
+ TrapFrame->Ftr,TrapFrame->Fcr0,TrapFrame->Fcr2,TrapFrame->Fcr3);
+ BlPrint(" gdt limit=%x base=%lx idt limit=%x base=%lx\n",
+ *(PUSHORT)&GDTregister,*(PULONG)(&GDTregister + 2),
+ *(PUSHORT)&IDTregister,*(PULONG)(&IDTregister + 2));
+}
+
+
+
+VOID
+DumpCommonRegisters(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Dumps (writes to the display or com poirt) the x86 processor
+ commond registers only.
+
+Arguments:
+
+ None
+
+Returns:
+
+ Nothing
+
+
+--*/
+{
+ USHORT err;
+
+ //
+ // Is the error code valid or just a padding dword
+ //
+
+ if ((TrapFrame->TrapNum == 8) || (TrapFrame->TrapNum >= 10 && TrapFrame->TrapNum <= 14) )
+ err = (USHORT)TrapFrame->Error;
+ else
+ err = 0;
+
+ //
+ // Display the processor's common registers
+ //
+
+ BlPrint("\n cs:eip=%x:%lx ss:esp=%x:%lx errcode=%x\n",
+ (USHORT)(TrapFrame->Fcs & 0xffff),TrapFrame->Feip,(USHORT)TrapFrame->Fss,TrapFrame->Fesp,err);
+ DisplayFlags(TrapFrame->Feflags);
+ BlPrint(" eax=%lx ebx=%lx ecx=%lx edx=%lx",TrapFrame->Feax,TrapFrame->Febx,TrapFrame->Fecx,TrapFrame->Fedx);
+ BlPrint(" ds=%x es=%x\n",TrapFrame->Fds,TrapFrame->Fes);
+ BlPrint(" edi=%lx esi=%lx ebp=%lx cr0=%lx",TrapFrame->Fedi,TrapFrame->Fesi,TrapFrame->Febp,TrapFrame->Fcr0);
+ BlPrint(" fs=%x gs=%x\n",TrapFrame->Ffs,TrapFrame->Fgs);
+
+}
+
+
+VOID
+DisplayFlags(
+ ULONG f
+ )
+/*++
+
+Routine Description:
+
+ Writes the value of the key flags in the flags register to
+ the display or com port.
+
+Arguments:
+
+ f - the 32bit flags word
+
+Returns:
+
+ Nothing
+
+--*/
+{
+
+ BlPrint(" flags=%lx ",f);
+ if (f & FLAG_CF) puts("Cy "); else puts("NoCy ");
+ if (f & FLAG_ZF) puts("Zr "); else puts("NoZr ");
+ if (f & FLAG_IE) puts("IntEn"); else puts("IntDis ");
+ if (f & FLAG_DF) puts("Up "); else puts("Down ");
+ if (f & FLAG_TF) puts("TrapEn \n"); else puts("TrapDis \n");
+
+}
+
+
+
+VOID
+DumpTSS(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Writes the contents of the TSS to the display or com port when
+ called after a double fault.
+
+Arguments:
+
+ None
+
+Returns:
+
+ Nothing
+
+--*/
+{
+
+ PTSS_FRAME pTss;
+
+// FP_SEG(Fp) = Fcs;
+// FP_OFF(Fp) = Fip;
+
+ pTss = (PTSS_FRAME) &TssKernel;
+
+ //
+ // Dump the outgoing TSS
+ //
+
+ BlPrint("Link %x\n",pTss->Link);
+ BlPrint("Esp0 %x\n",pTss->Esp0);
+ BlPrint("SS0 %x\n",pTss->SS0);
+ BlPrint("Esp1 %lx\n",pTss->Esp1);
+ BlPrint("Cr3 %lx\n",pTss->Cr3);
+ BlPrint("Eip %lx\n",pTss->Eip);
+ BlPrint("Eflg %lx\n",pTss->Eflags);
+ BlPrint("Eax %lx\n",pTss->Eax);
+ BlPrint("Ebx %lx\n",pTss->Ebx);
+ BlPrint("Ecx %lx\n",pTss->Ecx);
+ BlPrint("Edx %lx\n",pTss->Edx);
+ BlPrint("Esp %lx\n",pTss->Esp);
+ BlPrint("Ebp %lx\n",pTss->Ebp);
+ BlPrint("Esi %lx\n",pTss->Esi);
+ BlPrint("Edi %lx\n",pTss->Edi);
+ BlPrint("ES %x\n",pTss->ES);
+ BlPrint("CS %x\n",pTss->CS);
+ BlPrint("SS %x\n",pTss->SS);
+ BlPrint("DS %x\n",pTss->DS);
+ BlPrint("FS %x\n",pTss->FS);
+ BlPrint("GS %x\n",pTss->GS);
+ BlPrint("Ldt %x\n",pTss->Ldt);
+ RealMode();
+ while(1);
+}
+
+// END OF FILE
diff --git a/private/ntos/boot/startup/i386/types.h b/private/ntos/boot/startup/i386/types.h
new file mode 100644
index 000000000..17ac86d50
--- /dev/null
+++ b/private/ntos/boot/startup/i386/types.h
@@ -0,0 +1,383 @@
+/*
+
+File
+
+ types.h
+
+
+Description
+
+ defines and structure definitions for nt386 boot loader
+
+
+Author
+
+ Thomas Parslow [TomP]
+
+*/
+
+#define IN
+#define OUT
+#define OPTIONAL
+#define NOTHING
+#define CONST const
+
+//
+// Void
+//
+
+typedef void *PVOID; // winnt
+
+//
+// Basics
+//
+
+#define VOID void
+typedef char CHAR;
+typedef short SHORT;
+typedef long LONG;
+
+//
+// ANSI (Multi-byte Character) types
+//
+
+typedef CHAR *PCHAR;
+
+typedef double DOUBLE;
+
+//
+// Pointer to Basics
+//
+
+typedef SHORT *PSHORT; // winnt
+typedef LONG *PLONG; // winnt
+
+//
+// Unsigned Basics
+//
+
+typedef unsigned char UCHAR;
+typedef unsigned short USHORT;
+typedef unsigned long ULONG;
+
+//
+// Pointer to Unsigned Basics
+//
+
+typedef UCHAR *PUCHAR;
+typedef USHORT *PUSHORT;
+typedef ULONG *PULONG;
+
+//
+// Signed characters
+//
+
+typedef signed char SCHAR;
+typedef SCHAR *PSCHAR;
+
+//
+// Cardinal Data Types [0 - 2**N-2)
+//
+
+typedef char CCHAR; // winnt
+typedef short CSHORT;
+typedef ULONG CLONG;
+
+typedef CCHAR *PCCHAR;
+typedef CSHORT *PCSHORT;
+typedef CLONG *PCLONG;
+
+//
+// Far point to Basic
+//
+
+typedef UCHAR far * FPCHAR;
+typedef UCHAR far * FPUCHAR;
+typedef VOID far * FPVOID;
+typedef USHORT far * FPUSHORT;
+typedef ULONG far * FPULONG;
+
+//
+// Boolean
+//
+
+typedef CCHAR BOOLEAN;
+typedef BOOLEAN *PBOOLEAN;
+
+//
+// UNICODE (Wide Character) types
+//
+
+typedef unsigned short WCHAR; // wc, 16-bit UNICODE character
+
+typedef WCHAR *PWCHAR;
+typedef WCHAR *LPWCH, *PWCH;
+typedef CONST WCHAR *LPCWCH, *PCWCH;
+typedef WCHAR *NWPSTR;
+typedef WCHAR *LPWSTR, *PWSTR;
+
+//
+// Large (64-bit) integer types and operations
+//
+
+typedef struct _LARGE_INTEGER {
+ ULONG LowPart;
+ LONG HighPart;
+} LARGE_INTEGER, *PLARGE_INTEGER;
+
+typedef LARGE_INTEGER PHYSICAL_ADDRESS, *PPHYSICAL_ADDRESS;
+
+#define FP_SEG(fp) (*((unsigned *)&(fp) + 1))
+#define FP_OFF(fp) (*((unsigned *)&(fp)))
+#define toupper(x) (((x) >= 'a' && (x) <= 'z') ? x - 'a' + 'A' : x )
+#define isascii(x) (((x) >= ' ' && (x) < 0x80) ? 1 : 0)
+
+#define FLAG_CF 0x01L
+#define FLAG_ZF 0x40L
+#define FLAG_TF 0x100L
+#define FLAG_IE 0x200L
+#define FLAG_DF 0x400L
+
+#define TRUE 1
+#define FALSE 0
+#define NULL ((void *)0)
+
+typedef UCHAR far * FPCHAR;
+typedef UCHAR far * FPUCHAR;
+typedef VOID far * FPVOID;
+typedef USHORT far * FPUSHORT;
+typedef ULONG far * FPULONG;
+typedef UCHAR FAT;
+typedef FAT * PFAT;
+typedef LONG NTSTATUS;
+
+
+typedef struct _FSCONTEXT_RECORD {
+ ULONG BootDrive;
+ ULONG PointerToBPB;
+ ULONG Reserved;
+} FSCONTEXT_RECORD, *PFSCONTEXT_RECORD;
+
+typedef struct
+{
+ USHORT bytes_per_sector; // bytes per sector
+ USHORT sectors_per_cluster; // sectors per cluster
+ USHORT reserved_sectors; // sectors in reserved area
+ USHORT copies_of_fat; // number of copies of FAT
+ USHORT root_dir_entries; // number of root directory entries
+ USHORT total_number_sectors; // total number of sectors
+ USHORT dos_media_descriptor; // DOS media descriptor
+ USHORT sectors_per_fat; // number of sectors per FAT
+ USHORT sectors_per_track; // sectors per track
+ USHORT heads; // number of heads
+ ULONG hidden_sectors; // number of hidden sectors
+ ULONG BigTotalSectors; // total sectors on BIG partitions
+ USHORT bytes_per_cluster; // bytes per cluster
+ USHORT begin_files_area; // sector of beginning of files area
+ USHORT a16bit_fat; // true if 16bit fat, else 12bit fat
+ USHORT end_of_file; // end of file mark for fat
+} GBIOS_PARAMETER_BLOCK;
+
+typedef struct {
+ USHORT SpecifyBytes;
+ UCHAR WaitTime;
+ UCHAR SectorLength;
+ UCHAR LastSector;
+ UCHAR SecGapLength;
+ UCHAR DataTransfer;
+ UCHAR TrackGapLength;
+ UCHAR DataValue;
+ UCHAR HeadSettle;
+ UCHAR StartupTime;
+} DISK_BASE_TABLE;
+
+//
+// biosint register structure
+//
+
+typedef struct {
+ USHORT fn;
+ USHORT fg;
+ USHORT ax;
+ USHORT bx;
+ USHORT cx;
+ USHORT dx;
+ USHORT si;
+ USHORT es;
+} BIOSREGS;
+
+
+//
+// Trap Frame Structure when error code is present
+//
+
+typedef struct {
+ USHORT Ftr;
+ ULONG Fdr6;
+ ULONG Fcr0;
+ ULONG Fcr2;
+ ULONG Fcr3;
+ USHORT Fss;
+ USHORT Fgs;
+ USHORT Ffs;
+ USHORT Fes;
+ USHORT Fds;
+ ULONG Fedi;
+ ULONG Fesi;
+ ULONG Febp;
+ ULONG Fesp;
+ ULONG Febx;
+ ULONG Fedx;
+ ULONG Fecx;
+ ULONG TrapNum;
+ ULONG Feax;
+ ULONG Error;
+ ULONG Feip;
+ ULONG Fcs;
+ ULONG Feflags;
+
+} TF_ERRCODE, *PTF ;
+
+//
+// Task State Segment structure
+//
+
+typedef struct {
+ USHORT Link;
+ USHORT a;
+ ULONG Esp0;
+ USHORT SS0;
+ USHORT b;
+ ULONG Esp1;
+ USHORT SS1;
+ USHORT c;
+ ULONG Esp2;
+ USHORT SS2;
+ USHORT d;
+ ULONG Cr3;
+ ULONG Eip;
+ ULONG Eflags;
+ ULONG Eax;
+ ULONG Ecx;
+ ULONG Edx;
+ ULONG Ebx;
+ ULONG Esp;
+ ULONG Ebp;
+ ULONG Esi;
+ ULONG Edi;
+ USHORT ES;
+ USHORT e;
+ USHORT CS;
+ USHORT f;
+ USHORT SS;
+ USHORT g;
+ USHORT DS;
+ USHORT h;
+ USHORT FS;
+ USHORT i;
+ USHORT GS;
+ USHORT j;
+ USHORT Ldt;
+ USHORT k;
+
+} TSS_FRAME, *PTSS_FRAME;
+
+
+//
+// Overlay structure of disk bios parameter block
+//
+
+typedef struct {
+ USHORT bps;
+ UCHAR spc;
+ USHORT sra;
+ UCHAR cof;
+ USHORT rde;
+ USHORT tns;
+ UCHAR dmd;
+ USHORT spf;
+ USHORT spt;
+ USHORT noh;
+ union {
+ USHORT shs;
+ ULONG bhs; // hidden sectors
+ } hs;
+ ULONG bts; // extended total sectors
+} DISKBPB;
+
+typedef DISKBPB far * FPDISKBPB;
+
+
+
+//
+// FAT directory structure
+//
+
+typedef struct {
+ CHAR fname[11];
+ UCHAR attrb;
+ UCHAR rsrv[10];
+ USHORT time;
+ USHORT date;
+ USHORT clust;
+ ULONG size;
+
+} DIRENTRY,*PDIRENTRY,far * FPDIRENTRY;
+
+typedef struct {
+ CHAR fname[11];
+ UCHAR attrb;
+ UCHAR rsrv[10];
+ USHORT time;
+ USHORT date;
+ USHORT starting_cluster;
+ ULONG file_size;
+ ULONG fptr;
+ PUCHAR clusterbuffer;
+ USHORT cur_phys_cluster;
+ USHORT cur_file_cluster;
+} FILEDESCRIPTOR,* FILEHANDLE;
+
+/*
+typedef struct {
+
+ USHORT bff[FAT_BUFFERS];
+ USHORT usebuf;
+ FAT * fcptr;
+
+} FATCACHE;
+*/
+
+typedef struct {
+ USHORT limit;
+ USHORT base1;
+ UCHAR base2;
+ UCHAR access;
+ UCHAR limacc;
+ UCHAR base3;
+} _GDT,far *FPGDT;
+
+
+// Debugger initialization table
+
+typedef struct {
+ ULONG KdPhysicalAddress; // Physical address of the kernel debugger
+ USHORT CSprotmode; // protect mode cs for debugger to use
+ USHORT DSprotmode; // protect mode ds for debugger to use
+ USHORT GDTalias; // alias selector for GDT
+ USHORT AbiosFlag; // 0=AT-like machine, !0=Abios
+ USHORT GDTlimit; // GDT limit
+ ULONG GDTbase; // Base physical address of GDT
+ USHORT IDTlimit; // IDT limit
+ ULONG IDTbase; // IDT physical address
+ ULONG LaKdPTE; // Linear address of spare PTE
+ ULONG LaPTEs; // Linear address of PTE addresses
+ UCHAR BreakChar; // Char for debugger to break on at init
+ UCHAR Pad; // word align padding
+ USHORT SpareSelector; // GDT Selector for debugger to use
+} DEBUGGER_INIT_TABLE;
+
+
+typedef ULONG IDT,*PIDT;
+
+
diff --git a/private/ntos/boot/startup/i386/usa/strings.h b/private/ntos/boot/startup/i386/usa/strings.h
new file mode 100644
index 000000000..2503e6929
--- /dev/null
+++ b/private/ntos/boot/startup/i386/usa/strings.h
@@ -0,0 +1,44 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ strings.h
+
+Abstract:
+
+ Contains all localizable strings for startup.com
+
+Author:
+
+ John Vert (jvert) 4-Jan-1994
+
+Revision History:
+
+ John Vert (jvert) 4-Jan-1994
+ created
+
+--*/
+
+#define SU_NO_LOW_MEMORY \
+"Windows NT has found only %dK of low memory. 512k of low memory\n" \
+"is required to run Windows NT. You may need to upgrade your\n" \
+"computer or run a configuration program provided by the manufacturer.\n"
+
+#define SU_NO_EXTENDED_MEMORY \
+"Windows NT has not found enough extended memory. 7Mb of extended\n" \
+"memory is required to run Windows NT. You may need to upgrade your\n" \
+"computer or run a configuration program provided by the manufacturer.\n" \
+"\n\nMemory Map:\n"
+
+#define SU_NTLDR_CORRUPT \
+"NTLDR is corrupt. The system cannot boot."
+
+#define PG_FAULT_MSG " =================== PAGE FAULT ================================= \n\n"
+#define DBL_FAULT_MSG " ================== DOUBLE FAULT ================================ \n\n"
+#define GP_FAULT_MSG " ============== GENERAL PROTECTION FAULT ======================== \n\n"
+#define STK_OVERRUN_MSG " ===== STACK SEGMENT OVERRUN or NOT PRESENT FAULT =============== \n\n"
+#define EX_FAULT_MSG " ===================== EXCEPTION ================================ \n\n"
+#define DEBUG_EXCEPTION "\nDEBUG TRAP "
+#define PG_FAULT_ADDRESS "** At linear address %lx\n"
diff --git a/private/ntos/boot/startup/makefile b/private/ntos/boot/startup/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/boot/startup/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/boot/startup/makefile.inc b/private/ntos/boot/startup/makefile.inc
new file mode 100644
index 000000000..284ec5f60
--- /dev/null
+++ b/private/ntos/boot/startup/makefile.inc
@@ -0,0 +1,125 @@
+# Copyright (C) by Microsoft Corporation.
+#
+# MAKEFILE for NT SU.X86
+#
+# Created:
+# 91.01.18
+#
+# Author:
+# Thomas Parslow
+#
+
+!IFNDEF LANGUAGE
+LANGUAGE=usa
+!ENDIF
+
+.SUFFIXES: .com .exe .obj .lst .c .asm .def .lnk .inc
+
+
+#
+# C Compiler Definitions
+# ~~~~~~~~~~~~~~~~~~~~~~
+
+# Environment Variable to set debugging level
+# LOADER_DEBUG is the debugging level for building the OS loader, SU module, and BFSD. It should be
+# set to either -DDEBUG0 or -DDEBUG1 to enable either level 1 or 2 debugging.
+#
+!IFNDEF BASEDIR
+BASEDIR=$(_NTDRIVE)\nt
+!ENDIF
+
+
+CC= cl16
+CFLAGS= -W3 -G2s -Zelp $(LOADER_DEBUG) $(BLFLAGS)
+CINC= -I. -I$(BASEDIR)\public\sdk\inc -Ii386 -Ii386\$(LANGUAGE)
+
+
+#
+# Assembler Definitions
+# ~~~~~~~~~~~~~~~~~~~~~
+
+ASM= masm386
+AFLAGS= -Mx -z $(LOADER_DEBUG) $(GAFLAGS)
+AINC= -I\nt\public\sdk\inc -Ii386
+
+
+#
+# Linker Definitions
+# ~~~~~~~~~~~~~~~~~~
+
+LINK=link_60
+LIBS=long.lib
+DEF=
+
+
+#
+# Rules for generating objects
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+
+
+{i386\}.asm{obj\i386\}.obj:
+ $(ASM) $(AFLAGS) $(AINC) $< $@;
+
+{i386\}.asm.lst:
+ $(ASM) -l -n $(AFLAGS) $(AINC) $<;
+
+# $(CC) $(CFLAGS) $(CINC) -c $<
+
+{i386\}.c{obj\i386\}.obj:
+ $(CC) $(CFLAGS) $(CINC) -Fo$@ -c $<
+
+{}.c{obj\i386\}.obj:
+ $(CC) $(CFLAGS) $(CINC) -Fo$@ -c $<
+
+{i386\}.c.lst:
+ $(CC) $(CFLAGS) -Fc$*.cod -Fo$*.obj -dos $(CINC) -c $<
+
+
+#
+# List of object files required
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+OBJ= obj\i386\su.obj obj\i386\exp.obj obj\i386\abiosa.obj obj\i386\sudata.obj \
+obj\i386\eisaa.obj obj\i386\a20.obj obj\i386\trap.obj obj\i386\eisac.obj \
+obj\i386\main.obj obj\i386\trapdump.obj obj\i386\display.obj obj\i386\backend.obj
+
+
+#
+# Dependencies
+# ~~~~~~~~~~~~
+
+
+obj\i386\startup.com: $(OBJ)
+
+obj\i386\exp.obj exp.lst: i386\exp.asm i386\su.inc i386\macro.inc
+
+obj\i386\eisaa.obj eisaa.lst: i386\eisa.inc i386\eisaa.asm
+
+obj\i386\eisac.obj eisac.lst: i386\eisa.h i386\eisac.c
+
+obj\i386\su.obj su.lst: i386\su.asm i386\su.inc
+
+obj\i386\sudata.obj sudata.lst: i386\sudata.asm i386\su.inc i386\memmap.inc
+
+obj\i386\main.obj main.lst: i386\main.c i386\global.h i386\types.h i386\constant.h
+
+obj\i386\trap.obj trap.lst: i386\trap.asm i386\su.inc
+
+obj\i386\trapdump.obj trapdump.lst: i386\trapdump.c i386\types.h i386\constant.h
+
+obj\i386\display.obj display.lst: i386\display.c i386\types.h i386\constant.h i386\global.h
+
+obj\i386\abiosa.obj abiosa.lst: i386\abiosa.asm i386\su.inc i386\abios.inc
+
+obj\i386\backend.obj backend.lst: i386\backend.asm
+
+obj\i386\startup.com: $(OBJ) $(DOBJ) $(LIBS)
+ $(LINK) @<<
+/tiny /nod /noi +
+$(OBJ)
+obj\i386\startup.com
+
+$(LIBS)
+
+<<
diff --git a/private/ntos/boot/startup/sources b/private/ntos/boot/startup/sources
new file mode 100644
index 000000000..1180757dc
--- /dev/null
+++ b/private/ntos/boot/startup/sources
@@ -0,0 +1,54 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=startup
+
+TARGETNAME=startup.com
+TARGETPATH=obj
+TARGETTYPE=UMAPPL_NOLIB
+
+INCLUDES=\nt\public\sdk\inc;..\inc;..\..\inc;..\..\config;..\..\nthals
+
+SOURCES=
+
+i386_SOURCES=i386\su.asm \
+ i386\exp.asm \
+ i386\abiosa.asm \
+ i386\sudata.asm \
+ i386\eisaa.asm \
+ i386\eisac.c \
+ i386\main.c \
+ i386\a20.asm \
+ i386\trap.asm \
+ i386\trapdump.c \
+ i386\display.c \
+ i386\backend.asm \
+
+!IF $(386)
+
+NTTARGETFILES=obj\i386\startup.com
+
+!ENDIF
+
diff --git a/private/ntos/boot/veneer/makefile b/private/ntos/boot/veneer/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/boot/veneer/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/boot/veneer/makefile.inc b/private/ntos/boot/veneer/makefile.inc
new file mode 100644
index 000000000..b90118411
--- /dev/null
+++ b/private/ntos/boot/veneer/makefile.inc
@@ -0,0 +1,64 @@
+#
+# Copyright (c) 1995,1996 FirePower Systems, Inc.
+#
+# $RCSfile: makefile.inc $
+# $Revision: 1.9 $
+# $Date: 1996/07/02 20:32:24 $
+# $Locker: $
+#
+
+!IFNDEF LANGUAGE
+LANGUAGE=usa
+!ENDIF
+
+!IFDEF NotNow
+msg.rc msg.h msg00001.bin: msg.$(LANGUAGE)
+ mc -v msg.$(LANGUAGE)
+!ENDIF
+
+!IF $(PPC)
+
+!IFDEF NotNow
+obj\$(TARGET_DIRECTORY)\veneer.res: msg.$(LANGUAGE)
+!ENDIF
+
+!IFNDEF DDKBUILDENV
+
+VENEER=obj\$(TARGET_DIRECTORY)\veneer.lib
+
+obj\$(TARGET_DIRECTORY)\veneer.exe: $(VENEER) makefile.inc
+ -link -out:obj\$(TARGET_DIRECTORY)\veneer.exe -nodefaultlib @<<
+-machine:$(TARGET_DIRECTORY)
+-rom
+-BASE:0x50000
+-debug:notmapped
+-debugtype:coff
+-map:obj\$(TARGET_DIRECTORY)\veneer.map
+-align:0x200
+-entry:start
+obj\$(TARGET_DIRECTORY)\veneer.lib
+$(BASEDIR)\public\sdk\lib\$(TARGET_DIRECTORY)\int64.lib
+<<NOKEEP
+
+
+ -@binplace obj\$(TARGET_DIRECTORY)\veneer.exe
+
+!ELSE
+#
+# This is for building within a DDK environment...
+#
+VENEER=$(BASEDIR)\lib\$(CPU)\$(DDKBUILDENV)\veneer.lib
+
+$(TARGETPATH)\$(TARGET_DIRECTORY)\veneer.exe: $(VENEER) makefile.inc
+ -link -out:$(TARGETPATH)\$(TARGET_DIRECTORY)\veneer.exe -nodefaultlib -machine:ppc -rom -BASE:0x50000 -debug:notmapped -debugtype:coff -map:obj\ppc\veneer.map -align:0x200 -entry:start $(VENEER) $(BASEDIR)\lib\$(TARGET_DIRECTORY)\$(DDKBUILDENV)\int64.lib
+# -@binplace -d .. $(TARGETPATH)\$(TARGET_DIRECTORY)\veneer.exe
+
+$(VENEER): obj\$(CPU)\$(DDKBUILDENV)\veneer.lib
+ -copy obj\$(CPU)\$(DDKBUILDENV)\veneer.lib $(VENEER)
+
+!ENDIF # End of else clause covering ddk build environment case
+
+verno.c: $(MAIN_PPC_SOURCES)
+
+!ENDIF # End of IF $(PPC) clause
+
diff --git a/private/ntos/boot/veneer/ppc/pxcache.s b/private/ntos/boot/veneer/ppc/pxcache.s
new file mode 100644
index 000000000..74fea4e71
--- /dev/null
+++ b/private/ntos/boot/veneer/ppc/pxcache.s
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 1995 FirePower Systems, Inc.
+ *
+ * $RCSfile: pxcache.s $
+ * $Revision: 1.7 $
+ * $Date: 1996/01/11 07:54:50 $
+ * $Locker: $
+ *
+ * Derived from:
+ * Source: halfire/ppc/pxcache.s
+ * Revision: 1.6
+ * Date: 1995/04/17 21:17:37
+ */
+
+//++
+//
+// Copyright (c) 1993, 1994, 1995 IBM Corporation
+//
+// Copyright (c) 1994 MOTOROLA, INC. All Rights Reserved. This file
+// contains copyrighted material. Use of this file is restricted
+// by the provisions of a Motorola Software License Agreement.
+//
+// Module Name:
+//
+// pxcache.s
+//
+// Abstract:
+//
+// This module implements the routines to flush cache on the PowerPC.
+//
+// Author:
+//
+// Peter L. Johnston (plj@vnet.ibm.com) September 1993
+//
+// Environment:
+//
+// Kernel mode only.
+//
+// Revision History:
+// 27-Dec-93 plj Added 603 support.
+// 13-Mar-94 plj Fixed problem introduced during switch to pas,
+// added 604 support.
+// 18-Jan-95 plj Add 603+, 604+ and 620 support.
+//
+//--
+
+#include "kxppc.h"
+
+//++
+//
+// HalpSweepPhysicalRangeInBothCaches
+//
+// Force data in a given PHYSICAL address range to memory and
+// invalidate from the block in the instruction cache.
+//
+// This implementation assumes a block size of 32 bytes. It
+// will still work on the 620.
+//
+// Arguments:
+//
+// r.3 Start physical PAGE number.
+// r.4 Starting offset within page. Cache block ALIGNED.
+// r.5 Length (in bytes)
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ .set PAGE_SHIFT, 12
+
+
+ LEAF_ENTRY(HalpSweepPhysicalRangeInBothCaches)
+
+//
+// Starting physical address = (PageNumber << PAGE_SHIFT) | Offset
+//
+
+ rlwimi r.4, r.3, PAGE_SHIFT, 0xfffff000
+
+ addi r.5, r.5, 31 // bump length by block size - 1
+ srwi r.5, r.5, 5 // get number of blocks
+ mflr r.0 // save return address
+ mtctr r.5 // set loop count
+
+//
+// Interrupts MUST be disabled for the duration of this function as
+// we use srr0 and srr1 which will be destroyed by any exception or
+// interrupt.
+//
+
+ DISABLE_INTERRUPTS(r.12,r.11) // r.11 <- disabled MSR
+ // r.12 <- previous MSR
+//
+// Find ourselves in memory. This is needed as we must disable
+// both instruction and data translation. We do this while
+// interrupts are disabled only to try to avoid changing the
+// Link Register when an unwind might/could occur.
+//
+// The HAL is known to be in KSEG0 so its physical address is
+// its effective address with the top bit stripped off.
+//
+
+ bl hspribc
+hspribc:
+
+ mflr r.6 // r.6 <- &hspribc
+ rlwinm r.6, r.6, 0, 0x7fffffff // r.6 &= 0x7fffffff
+ addi r.6, r.6, hspribc.real - hspribc
+ // r.6 = real &hspribc.real
+
+ sync // ensure all previous loads and
+ // stores are complete.
+
+ mtsrr0 r.6 // address in real space
+
+ rlwinm r.11, r.11, 0, ~0x30 // turn off Data and Instr relocation
+ mtsrr1 r.11
+ rfi // leap to next instruction
+
+hspribc.real:
+ mtsrr0 r.0 // set return address
+ mtsrr1 r.12 // set old MSR value
+
+hspribc.loop:
+// XXX dcbst 0, r.4 // flush data block to memory
+ dcbf 0, r.4 // flush data block to memory
+ icbi 0, r.4 // invalidate i-cache
+ addi r.4, r.4, 32 // point to next block
+ bdnz hspribc.loop // jif more to do
+
+ sync // ensure all translations complete
+ isync // don't even *think* about getting
+ // ahead.
+ rfi // return to caller and translated
+ // mode
+
+ DUMMY_EXIT(HalpSweepPhysicalRangeInBothCaches)
diff --git a/private/ntos/boot/veneer/ppc/pxutil.s b/private/ntos/boot/veneer/ppc/pxutil.s
new file mode 100644
index 000000000..e4f5b5f2f
--- /dev/null
+++ b/private/ntos/boot/veneer/ppc/pxutil.s
@@ -0,0 +1,62 @@
+//++
+//
+// Copyright (c) 1995 FirePower Systems, Inc.
+//
+// $RCSfile: pxutil.s $
+// $Revision: 1.6 $
+// $Date: 1996/01/11 07:54:54 $
+// $Locker: $
+//
+// Copyright (c) 1994 FirePower Systems, Inc.
+//
+//
+// Module Name:
+//
+// pxutil.s
+//
+//
+// Author:
+//
+// Shin Iwamoto at FirePower Systems, Inc.
+//
+//
+// Revision History:
+// 15-Sep-94 Shin Iwamoto at FirePower Systems, Inc.
+// Changed passing argument.
+// 06-Jul-94 Shin Iwamoto at FirePower Systems, Inc.
+// Created.
+//
+//--
+
+//++
+//
+// Routine Description:
+//
+// PxInvoke
+//
+// This function is called by FwInvoke and runs in FwInvoke's context.
+// That is, sp register isn't changed and link register is lost.
+//
+//
+//--
+ .text
+
+ .globl ..PxInvoke
+..PxInvoke:
+
+ mtspr ctr,r3 // load ctr reg. with routine to call
+
+ mr r3,r5 // move argc to 1st argument
+ mr r4,r6 // move argv to 2nd argument
+ mr r5,r7 // move envp to 3rd argument
+ bctr // jump to execute routine (no return)
+
+
+//
+// TOC entries
+//
+ .reldata
+ .align 2
+ .globl PxInvoke
+PxInvoke:
+ .long ..PxInvoke,.toc
diff --git a/private/ntos/boot/veneer/ppc/sources b/private/ntos/boot/veneer/ppc/sources
new file mode 100644
index 000000000..8bfd468c9
--- /dev/null
+++ b/private/ntos/boot/veneer/ppc/sources
@@ -0,0 +1,36 @@
+#
+# Copyright (c) 1995 FirePower Systems, Inc.
+#
+# $RCSfile: sources $
+# $Revision: 1.4 $
+# $Date: 1996/01/11 07:54:58 $
+# $Locker: $
+#
+
+MAIN_PPC_SOURCES=\
+ vrmain.c \
+ vrconfig.c \
+ vrcons.c \
+ vrcpiwrp.c \
+ vrdumptr.c \
+ vrenv.c \
+ vrio.c \
+ vrdisp.c \
+ vrlib.c \
+ vrmalloc.c \
+ vrmemory.c \
+ vrload.c \
+ vrrstart.c \
+ vrmisc.c \
+ vrpehdr.c \
+ vrsup.c \
+ vrtree.c \
+ ppc\vrstart.s \
+ ppc\vrmp.s \
+ ppc\pxcache.s \
+ ppc\pxutil.s
+
+PPC_SOURCES=$(MAIN_PPC_SOURCES) \
+ verno.c
+
+NTTARGETFILES=obj\*\veneer.exe
diff --git a/private/ntos/boot/veneer/ppc/vrmp.s b/private/ntos/boot/veneer/ppc/vrmp.s
new file mode 100644
index 000000000..f47b798c2
--- /dev/null
+++ b/private/ntos/boot/veneer/ppc/vrmp.s
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 1995 FirmWorks, Mountain View CA USA. All rights reserved.
+ *
+ * $RCSfile: vrmp.s $
+ * $Revision: 1.5 $
+ * $Date: 1996/06/20 16:30:16 $
+ * $Locker: $
+ */
+
+#include "VrBAT.h"
+
+/*
+ * The PPC Open Firmware implementation uses a different protocol
+ * for MP startup than the ARC specification. In this module,
+ * we implement the ARC startup protocol.
+ *
+ * The PPC OF binding specifies that the /cpus node has
+ * a method cpu-machine-execute ( addr cpu# -- true | false )
+ * where cpu# is the cpu number and addr is the address
+ * (in the parent's address space?) at which the cpu is to
+ * begin execution.
+ *
+ * The ARC specifies that a cpu is to spin on the state of the
+ * ProcessorStart bit in the BootStatus word of the cpu's Restart Block.
+ * When ProcessorStart = 1, the cpu switches context to that saved in
+ * the SaveArea array in the Restart Block.
+ *
+ * Define here the context switch routine and the polling loop.
+ */
+ .data
+ .align 4
+ .globl naperr
+naperr:
+ .ascii "processor not sleeping"
+
+ .text
+ .align 4
+ .globl ..fatal
+
+/*
+ * VOID ArcPoll(VOID)
+ */
+ .globl ArcPoll
+ArcPoll:
+ /*
+ * We have to figure out where our BootStatus and SaveArea are.
+ * There's no way to explicitly pass variables to this routine,
+ * so our caller has helpfully stuffed them into locations
+ * ArcPoll-8 and ArcPoll-4. Retrieve them into r3 and r4.
+ * The pvr is initialized in ArcPoll-12. This is used by
+ * the IdleCPU() to check whether the machine is Multi processor
+ * worthy or not. The pvr should match for all proceesors and
+ * rev > 3.4 to be MP worthy
+ * Incidentally, we can trash all our registers as we won't
+ * ever return from this loop and this routine is not TOC-based.
+ */
+
+ bl here
+here:
+ mfpvr r5
+ mflr r1 // r1 = here
+ mr r4, r1
+ stw r5, -16(r1) // store it before moving 0x1234
+ li r2, 0x1234
+ lwz r3, -12(r1)
+ stw r2, -12(r1)
+ mr r29, r1 // save off r1 for future use
+ lwz r1, -8(r1)
+
+cputest:
+ lwz r5, -12(r29)
+ cmplw r5, r2 // is still 1234
+ beq cputest
+ li r2, 0xBAD
+ cmplw r5, r2 // is it bad to start this cpu
+ bne gonow
+napnow: // put it to sleep
+ mfmsr r5
+ li r2, 4
+ rlwinm r2,r2,16,0,31
+ or r5,r5,r2
+ mtmsr r5
+// lis r3, (naperr>>16)
+// ori r3, r3, napper
+ b ..fatal
+
+gonow:
+ //
+ // Turn off data/address translation ( I.E. go to real mode )
+ //
+ bl RealMode
+
+ /*
+ * Spin on the ProcessorStart bit (bit 23 in PPC nomenclature).
+ */
+ArcSpin:
+ lwz r2, 0(r3)
+ extrwi. r2, r2, 1, 23
+ beq ArcSpin
+
+ /*
+ * ProcessorStart is 1: reload processor state.
+ */
+ li r2, 0x789a
+ stw r2, -12(r4)
+
+ lwz r2, 0x104(r1) // CR0-7
+ mtcrf 255, r2
+ lwz r2, 0x108(r1) // XER
+ mtxer r2
+ lwz r2, 0x110(r1) // IAR
+ lis r3, 0x8000
+ andc r2, r2, r3
+ mtlr r2
+
+ lwz r0, 0x84(r1)
+ // Get r1 later.
+ lwz r2, 0x8c(r1)
+ lwz r3, 0x90(r1)
+ lwz r4, 0x94(r1)
+ lwz r5, 0x98(r1)
+ lwz r6, 0x9c(r1)
+ lwz r7, 0xa0(r1)
+ lwz r8, 0xa4(r1)
+ lwz r9, 0xa8(r1)
+ lwz r10, 0xac(r1)
+ lwz r11, 0xb0(r1)
+ lwz r12, 0xb4(r1)
+ lwz r13, 0xb8(r1)
+ lwz r14, 0xbc(r1)
+ lwz r15, 0xc0(r1)
+ lwz r16, 0xc4(r1)
+ lwz r17, 0xc8(r1)
+ lwz r18, 0xcc(r1)
+ lwz r19, 0xd0(r1)
+ lwz r20, 0xd4(r1)
+ lwz r21, 0xd8(r1)
+ lwz r22, 0xdc(r1)
+ lwz r23, 0xe0(r1)
+ lwz r24, 0xe4(r1)
+ lwz r25, 0xe8(r1)
+ lwz r26, 0xec(r1)
+ lwz r27, 0xf0(r1)
+ lwz r28, 0xf4(r1)
+ lwz r29, 0xf8(r1)
+ lwz r30, 0xfc(r1)
+ lwz r31,0x100(r1)
+
+ lwz r1, 0x88(r1)
+ blr
+
+
+/*
+ * Goto real mode via a branch and link to this routine. We'll turn off
+ * data and instruction address translation and reset the program counter
+ * so the return from this routine leaves the cpu in real mode.
+ */
+ .globl RealMode
+RealMode:
+ mflr r20
+ mfmsr r21 // get current state
+ rlwinm r21, r21, 0, ~EXTRNL_INT_ENABL // clear interrupt enable
+ mtmsr r21 // disable interrupts
+ rlwinm r21, r21, 0, ~(DATA_ADDR_XLATE | INSTR_ADDR_XLATE )
+ mtsrr1 r21 // desired initial state
+ rlwinm r20, r20, 0, 0x7fffffff // physical return addrress
+ mtsrr0 r20
+ rfi // return
+
+ .globl EndArcPoll
+EndArcPoll:
diff --git a/private/ntos/boot/veneer/ppc/vrstart.s b/private/ntos/boot/veneer/ppc/vrstart.s
new file mode 100644
index 000000000..5a934a1af
--- /dev/null
+++ b/private/ntos/boot/veneer/ppc/vrstart.s
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 1995 FirePower Systems, Inc.
+ * Copyright (c) 1994 FirmWorks, Mountain View CA USA. All rights reserved.
+ * Copyright (c) 1994 FirePower Systems Inc.
+ *
+ * $RCSfile: vrstart.s $
+ * $Revision: 1.7 $
+ * $Date: 1996/06/20 16:30:20 $
+ * $Locker: $
+ */
+
+ .text
+ .align 4
+
+ .globl start
+start:
+
+ /*
+ * We get control from the firmware here.
+ * As of 4/19/94, we're getting the following arguments:
+ * r1 initial stack pointer
+ * r2 zero (we must set up TOC)
+ * r3 reserved (residual data)
+ * r4 client program entry point
+ * r5 client interface handler
+ * r6 client program argument address
+ * r7 client program argument length
+ *
+ * Note that we're receiving all our arguments in registers;
+ * if we call C subroutines before calling main we'll
+ * have to save state...so it might not be best to use bzero()
+ * (unless we recode it in assembler).
+ */
+
+ /*
+ * XXX - We may need to remap ourselves. If so, that code goes here.
+ * XXX - Is bss zeroed? If not, do that here.
+ */
+
+ /*
+ * Set up the veneer's TOC pointer.
+ */
+
+ bl skip_toc
+ .word .toc
+skip_toc:
+ mflr r2
+ lwz r2, 0(r2)
+
+ /*
+ * Now we know where we are. Store the cif_handler, find main,
+ * and jump to it.
+ */
+ lwz r8, [toc]CifHandler(rtoc)
+ stw r5, 0(r8)
+
+ .extern main
+ lwz r8, [toc]main(rtoc)
+ lwz r8, 0(r8)
+ mtspr ctr, r8
+ bctrl // call main()
+
+ /*
+ * We should never get back here.
+ */
+ li r3, 0
+ .extern OFExit
+ lwz r8, [toc]OFExit(rtoc)
+ lwz r8, 0(r8)
+ mtspr ctr, r8
+ bctrl // call OFExit()
+
+ /*
+ * We should NEVER get here.
+ */
+ li r0, 0
+ mtlr r0
+ blr
+
+
+
+ .globl ..VrGetProcRev
+..VrGetProcRev:
+ mfpvr r.3 // get processor version
+ blr
+..VrGetProcRev.end:
+
+
+
+ .globl ..call_firmware
+..call_firmware:
+ lwz r4, [toc]CifHandler(rtoc)
+ lwz r4, 0(r4)
+ mtspr ctr, r4
+ bctr
+
+ .globl ..get_toc
+..get_toc:
+ mr r3, r2
+ blr
+
+ .reldata
+ .align 2
+ .globl call_firmware
+call_firmware:
+ .long ..call_firmware,.toc
+ .globl get_toc
+get_toc:
+ .long ..get_toc,.toc
+
+ .data
+ .align 4
+CifHandler:
+ .long 0
+
+
diff --git a/private/ntos/boot/veneer/proto.h b/private/ntos/boot/veneer/proto.h
new file mode 100644
index 000000000..4685742bf
--- /dev/null
+++ b/private/ntos/boot/veneer/proto.h
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 1995 FirePower Systems, Inc.
+ *
+ * $RCSfile: proto.h $
+ * $Revision: 1.13 $
+ * $Date: 1996/06/17 02:55:59 $
+ * $Locker: $
+ *
+ */
+
+#define prl_t CM_PARTIAL_RESOURCE_LIST
+#define prd_t CM_PARTIAL_RESOURCE_DESCRIPTOR
+
+ // vrmain.c
+
+VOID VrMoveNode(PCONFIGURATION_NODE, PCONFIGURATION_NODE,
+ PCONFIGURATION_NODE, CONFIGURATION_CLASS, CONFIGURATION_TYPE);
+LONG claimreal(PVOID, ULONG);
+
+ // vrmemory.c
+
+PMEMORY_DESCRIPTOR
+VrGetMemoryDescriptor( PMEMORY_DESCRIPTOR MemoryDescriptor );
+VOID VrCreateMemoryDescriptors( VOID );
+VOID VrMemoryInitialize( VOID );
+VOID DisplayMemory(VOID);
+
+ // vrdisp.c
+
+PARC_DISPLAY_STATUS VrGetDisplayStatus( ULONG FileId );
+ARC_STATUS VrTestUnicodeCharacter( ULONG FileId, WCHAR UnicodeCharacter );
+VOID VrDisplayInitialize( VOID );
+
+ // vrconsole.c
+
+PCHAR VrFindConsolePath(char *console);
+
+ // vrlib.c
+
+#if defined(_M_PPC) && defined(_MSC_VER) && (_MSC_VER>=1000)
+#pragma function(strcmp)
+#pragma function(strlen)
+#pragma function(strcpy)
+#pragma function(strcat)
+#endif
+
+int get_bool_prop(phandle, char *);
+int decode_int(UCHAR *);
+int get_int_prop(phandle node, char *key);
+reg * decode_reg(UCHAR *buf, int buflen, int addr_cells, int size_cells);
+reg * get_reg_prop(phandle node, char *key, int index);
+char * get_str_prop(phandle node, char *key, allocflag alloc);
+int strcmp(const char *s, const char *t);
+int strncmp(const char *s, const char *t, size_t len);
+int strncasecmp(const char *s, const char *t, size_t len);
+size_t strlen(const char *s);
+char * strcpy(char *to, const char *from);
+char * strcat(char *to, const char *from);
+VOID bcopy(char *from, char *to, int len);
+VOID bzero(char *cp, int len);
+VOID * zalloc(int size);
+VOID sleep(ULONG delay);
+int claim(void *adr, int bytes);
+VOID * alloc(int size, int align);
+int atoi(char *s);
+char * index(char *s, int c);
+char * strcsep(char *s, const char sep);
+char * strctok(char *s, const char sep);
+char * capitalize(char *s);
+VOID warn(char *fmt, ...);
+VOID fatal(char *fmt, ... );
+VOID debug(int debug_level, char *fmt, ...);
+VOID sprintf(char *, char *, ...);
+VOID putchar(char c);
+VOID puts(char *s);
+VOID gets(char *inbuf);
+
+ // vrconfig.c
+
+PCONFIGURATION_COMPONENT VrAddChild( PCONFIGURATION_COMPONENT Component,
+ PCONFIGURATION_COMPONENT NewComponent, PVOID ConfigurationData );
+ARC_STATUS VrDeleteComponent( PCONFIGURATION_COMPONENT Component );
+PCONFIGURATION_COMPONENT VrGetChild (
+ PCONFIGURATION_COMPONENT Component );
+PCONFIGURATION_COMPONENT VrGetParent(PCONFIGURATION_COMPONENT Component);
+PCONFIGURATION_COMPONENT VrGetPeer(PCONFIGURATION_COMPONENT Component);
+PCONFIGURATION_COMPONENT VrGetComponent( PCHAR Path );
+ARC_STATUS VrGetConfigurationData ( PVOID ConfigurationData,
+ PCONFIGURATION_COMPONENT Component );
+ARC_STATUS VrSaveConfiguration( VOID );
+VOID VrConfigInitialize( VOID );
+
+ // vrio.c
+
+ARC_STATUS VrOpen( PCHAR OpenPath, OPEN_MODE OpenMode, PULONG FileId );
+ARC_STATUS VrClose( ULONG FileId );
+ARC_STATUS VrRead( ULONG FileId, PVOID Buffer, ULONG Length, PULONG Count );
+ARC_STATUS VrWrite( ULONG FileId, PVOID Buffer, ULONG Length, PULONG Count );
+ARC_STATUS VrMount( PCHAR MountPath, MOUNT_OPERATION Operation );
+ARC_STATUS VrSeek( ULONG FileId, PLARGE_INTEGER Offset, SEEK_MODE SeekMode );
+ARC_STATUS VrGetDirectoryEntry( ULONG FileId, PDIRECTORY_ENTRY Buffer,
+ ULONG Length, PULONG Count );
+ARC_STATUS VrGetFileInformation( ULONG FileId, PFILE_INFORMATION pFI );
+ARC_STATUS VrGetReadStatus( ULONG FileId );
+ARC_STATUS VrSetFileInformation( ULONG FileId, ULONG AttributeFlags,
+ ULONG AttributeMask );
+VOID VrIoInitialize( VOID );
+
+
+ // vrcpiwrp.c
+
+phandle OFPeer(phandle device_id);
+phandle OFChild(phandle device_id);
+phandle OFParent(phandle device_id);
+long OFGetproplen( phandle device_id, char *name );
+long OFGetprop( phandle device_id, char *name, char *buf, ULONG buflen );
+long OFNextprop( phandle device_id, char *name, char *buf );
+long OFSetprop( phandle device_id, char *name, char *buf, ULONG buflen );
+phandle OFFinddevice( char *devicename);
+ihandle OFOpen( char *devicename);
+void OFClose(ihandle id);
+long OFRead( ihandle instance_id, PCHAR addr, ULONG len );
+long OFWrite( ihandle instance_id, PCHAR addr, ULONG len );
+long OFSeek( ihandle instance_id, ULONG poshi, ULONG poslo );
+ULONG OFClaim( PCHAR addr, ULONG size, ULONG align );
+VOID OFRelease( PCHAR addr, ULONG size );
+long OFPackageToPath( phandle device_id, char *addr, ULONG buflen );
+long OFInstanceToPath( ihandle ih, char *addr, ULONG buflen );
+phandle OFInstanceToPackage(ihandle ih);
+long OFCallMethod( ULONG n_outs, ULONG n_ins, ULONG *outp, char *method,
+ ihandle id, ... );
+long OFInterpret( ULONG n_outs, ULONG n_ins, ULONG *outp, char *cmd, ... );
+ULONG OFMilliseconds( VOID );
+VOID OFBoot( char *bootspec );
+VOID OFEnter( VOID );
+VOID OFExit( VOID );
+
+ // vrtree.c
+
+void walk_obp( phandle node, CONFIGURATION_NODE *here,
+ CONFIGURATION_NODE *parent, CONFIGURATION_NODE *peer);
+
+ // vrtrunk.c
+VOID vr_dump_config_node(PCONFIGURATION_NODE);
+prl_t * grow_prl(PCONFIGURATION_NODE node, int dev_specific);
+CONFIGURATION_NODE *add_new_child(
+ CONFIGURATION_NODE *, char *, CONFIGURATION_CLASS, CONFIGURATION_TYPE);
+
+ // vrload.c
+
+VOID VrCopyArguments( ULONG Argc, PCHAR Argv[] );
+ARC_STATUS VrGenerateDescriptor( PMEMORY_DESCRIPTOR MemoryDescriptor,
+ MEMORY_TYPE MemoryType, ULONG BasePage, ULONG PageCount );
+ARC_STATUS VrLoad( PCHAR ImagePath, ULONG TopAddress, PULONG EntryAddress,
+ PULONG LowAddress );
+ARC_STATUS VrInvoke( ULONG EntryAddress, ULONG StackAddress, ULONG Argc,
+ PCHAR Argv[], PCHAR Envp[] );
+ARC_STATUS VrExecute( PCHAR ImagePath, ULONG Argc, PCHAR Argv[], PCHAR Envp[] );
+VOID VrLoadInitialize( VOID );
+
+ // vrmalloc.c
+
+char * malloc(unsigned);
+void free(char *);
+int log2(int);
+
+
+ // vrdumptr.c
+
+VOID quick_dump_tree(PCONFIGURATION_NODE node);
+VOID dump_tree(PCONFIGURATION_NODE node);
+VOID DisplayConfig(PCONFIGURATION_COMPONENT);
+
+
+ // vrmisc.c
+
+PTIME_FIELDS VrGetTime( VOID );
+ULONG VrGetRelativeTime( VOID );
+VOID VrFlushAllCaches( VOID );
+VOID VrTimeInitialize( VOID );
+
+ // vrrstart.c
+
+VOID VrEnterInteractiveMode( VOID );
+PSYSTEM_ID VrGetSystemId( VOID );
+VOID VrPowerDown( VOID );
+VOID VrReboot( VOID );
+VOID VrRestart( VOID );
+VOID VrHalt( VOID );
+VOID VrRestartInitialize( VOID );
+
+ // vrsup.c
+
+PCONFIGURATION_NODE ArcPathToNode(PCHAR Path);
+PCHAR NodeToArcPath(PCONFIGURATION_NODE node);
+PCONFIGURATION_NODE PackageToNode(phandle ph);
+PCONFIGURATION_NODE PathToNode(PCHAR path);
+PCONFIGURATION_NODE InstanceToNode(ihandle ih);
+phandle NodeToPackage(PCONFIGURATION_NODE node);
+PCHAR NodeToPath(PCONFIGURATION_NODE node);
+ihandle NodeToInstance(PCONFIGURATION_NODE node);
+phandle FindNodeByType(char *);
+ihandle OpenPackage( phandle );
+
+ // vrenv.c
+
+PCHAR VrGetEnvironmentVariable( PCHAR Variable );
+ARC_STATUS VrSetEnvironmentVariable( PCHAR Variable, PCHAR Value );
+VOID VrEnvInitialize( VOID );
+
+ // vrpehdr.c
+
+void *load_file(ihandle bootih);
+
+ // vrstart.s
+
+int call_firmware(ULONG *);
+
+ // pxcache.s
+
+VOID PSIFlushCache(VOID);
+VOID PPCFlushAllCaches(VOID);
diff --git a/private/ntos/boot/veneer/sources b/private/ntos/boot/veneer/sources
new file mode 100644
index 000000000..9280ea3cb
--- /dev/null
+++ b/private/ntos/boot/veneer/sources
@@ -0,0 +1,49 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+Copyright (c) 1995 Motorola Corporation
+Copyright (c) 1995 FirePower Systems, Inc.
+
+Module Name:
+
+ Veneer sources.
+
+Abstract:
+
+
+Author:
+
+ $RCSfile: sources $
+ $Revision: 1.5 $
+ $Date: 1996/03/01 20:17:49 $
+ $Locker: $
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=bldr
+
+TARGETNAME=veneer
+TARGETPATH=obj
+TARGETTYPE=LIBRARY
+
+VENEER_VERSION=0x0
+VENEER_REVISION=0x9909
+
+C_DEFINES=$(C_DEFINES) -D_NTSYSTEM_ -Dppc=1 -D$(CPU)=1 -D_$(CPU)_=1 -DVENEER_VERSION=$(VENEER_VERSION) -DVENEER_REVISION=$(VENEER_REVISION)
+
+# INCLUDES=..\..\inc
+INCLUDES=$(BASEDIR)\private\ntos\inc
+
+!IFDEF DDKBUILDENV
+INCLUDES=$(BASEDIR)\SRC\HAL\INC
+!ENDIF
+
+CFLAGS= /W3 /Oxs /Zd -ZB64
+
+!IF DEFINED (BUILTBY)
+C_DEFINES=$(C_DEFINES) -DBUILTBY=$(BUILTBY)
+!ENDIF
+
+SOURCES=
+
diff --git a/private/ntos/boot/veneer/veneer.h b/private/ntos/boot/veneer/veneer.h
new file mode 100644
index 000000000..aae1b1d1c
--- /dev/null
+++ b/private/ntos/boot/veneer/veneer.h
@@ -0,0 +1,287 @@
+/*++
+ *
+ * Copyright (c) 1994,1996 FirePower Systems, Inc.
+ * Copyright (c) 1994 FirmWorks, Mountain View CA USA. All rights reserved.
+ *
+ * $RCSfile: veneer.h $
+ * $Revision: 1.20 $
+ * $Date: 1996/06/19 23:13:15 $
+ * $Locker: $
+ *
+ *
+
+
+Module Name:
+
+ veneer.h
+
+Abstract:
+
+ This module contains the private data structures and procedure
+ prototypes for the veneer for the PowerPC NT.
+
+ This module is specifically tailored for the PowerPro and PowerTop
+ systems.
+
+Author:
+
+ A. Benjamin 9-May-1994
+
+Revision History:
+ 20-Jul-94 Shin Iwamoto at FirePower Systems Inc.
+ Added VRDBG_LOAD.
+ 13-Jul-94 Shin Iwamoto at FirePower Systems Inc.
+ Added ReadAheadCount and ReadAheadBuffer[2] in FileTable.
+ 12-Jul-94 Shin Iwamoto at FirePower Systems Inc.
+ Added Delete and NetworkDevice flags in FILE_FLAGS.
+
+
+--*/
+
+
+#ifndef _VENEER
+#define _VENEER
+
+//----------------------------------------------------------------
+//
+// Headers
+//
+
+#include <windef.h>
+#include "vrheader.h"
+#include <arc.h>
+#include <arccodes.h>
+#include <stdarg.h>
+
+#ifdef putchar
+# undef putchar
+#endif
+#ifdef puts
+# undef puts
+#endif
+
+//----------------------------------------------------------------
+//
+// Define common macros....
+//
+
+//----------------------------------------------------------------
+//
+// IEEE 1275-1994 definitions
+//
+
+typedef long phandle;
+typedef long ihandle;
+
+typedef struct {
+ long hi, lo;
+ long size;
+} reg;
+
+//----------------------------------------------------------------
+//
+// Global definitions and macros
+//
+
+#define MAX_IDE_DEVICE 4
+
+#ifdef BAT_MMU
+#define CLAIM(BaseAddr, SizeOfImage) \
+ claim(BaseAddr, SizeOfImage)
+#else
+#define CLAIM(BaseAddr, SizeOfImage) \
+ claimreal(BaseAddr, SizeOfImage)
+#endif
+
+
+typedef enum {
+ NOALLOC,
+ ALLOC
+} allocflag;
+
+#define new(t) (t *)zalloc(sizeof(t));
+
+#ifdef islower
+# undef islower
+#endif
+#define islower(c) (((c) >= 'a') && ((c) <= 'z'))
+
+#ifdef toupper
+# undef toupper
+#endif
+#define toupper(c) (((c) - 'a') + 'A')
+
+//
+// Current version and revision numbers.
+// These values are in OSLoader specifications (3-49).
+//
+#define ARC_VERSION 2
+#define ARC_REVISION 0
+
+//
+// CPU type
+//
+
+typedef enum {
+ PPC_UNKNOWN = 0,
+ PPC_601 = 1,
+ PPC_603 = 3,
+ PPC_604 = 4,
+ PPC_603E = 6,
+ PPC_604E = 9,
+ nPROCESSOR_TYPE
+} PROCESSOR_TYPE;
+
+
+//
+// Definitions associated with ARC.
+//
+#define SYSTEM_BLOCK_SIGNATURE 0x53435241
+#define RSTB_SIGNATURE 0x42545352
+
+//
+// The current (1/95) PowerPC port requires a "MIPS kseg0"-like
+// mapping which aliases 0x80000000 to 0x00000000. This macro,
+// used by claim(), undoes the mapping.
+//
+#define MAP(x) ((ULONG)(x) & ~0x80000000)
+#define UNMAP(x) ((ULONG)(x) | 0x80000000)
+
+
+//----------------------------------------------------------------
+//
+// Veneer data structures and declarations
+//
+
+/*
+ * This data structure is intended to link the components of the ARC
+ * tree with the nodes of the OF tree.
+ */
+typedef struct _CONFIGURATION_NODE {
+ phandle OfPhandle;
+ CONFIGURATION_COMPONENT Component;
+ CM_PARTIAL_RESOURCE_LIST *ConfigurationData;
+ struct _CONFIGURATION_NODE *Peer, *Child, *Parent;
+ char *ComponentName;
+ int Wildcard;
+ char *WildcardAddrPath;
+} CONFIGURATION_NODE, *PCONFIGURATION_NODE;
+
+
+//
+// Define the vendor specific entry point numbers.
+//
+typedef enum _VENDOR_ENTRY {
+ MaximumVendorRoutine
+ } VENDOR_ENTRY;
+
+//
+// Define file table structure.
+//
+#define FILE_TABLE_SIZE 32
+
+typedef struct _FILE_FLAGS {
+ ULONG Open : 1;
+ ULONG Read : 1;
+ ULONG Write : 1;
+ ULONG Delete : 1;
+ ULONG Device : 1;
+ ULONG Partition : 1;
+ ULONG DisplayDevice : 1;
+ ULONG RemovableDevice : 1;
+ ULONG NetworkDevice : 1;
+} FILE_FLAGS, *PFILE_FLAGS;
+
+#define MAX_PATH_NAME_SIZE 128
+
+typedef struct _FILE_TABLE_ENTRY {
+ ihandle IHandle;
+ FILE_FLAGS Flags;
+ LARGE_INTEGER Position;
+ PCHAR PathName;
+ LONG ReadAheadCount;
+ CHAR ReadAheadBuffer[2];
+} FILE_TABLE_ENTRY, *PFILE_TABLE_ENTRY;
+extern FILE_TABLE_ENTRY FileTable[];
+
+//
+// Define the keyboard and mouse id strings.
+//
+#define KBD_IDENTIFIER "PCAT_ENHANCED"
+#define MOUSE_IDENTIFIER "PS2 MOUSE"
+
+
+//----------------------------------------------------------------
+//
+// External/Global variable declarations
+//
+
+extern int VrDebug;
+extern CONFIGURATION_NODE *RootNode;
+extern ihandle ConsoleIn, ConsoleOut;
+extern BOOLEAN use_bat_mapping;
+
+//----------------------------------------------------------------
+//
+// Function prototypes
+//
+
+//
+// Useful macros for pragma message, ie. #pragma message(REVIEW "some text")
+//
+#define QUOTE(x) #x
+#define IQUOTE(x) QUOTE(x)
+#define REVIEW __FILE__ "(" IQUOTE(__LINE__) ") : REVIEW -> "
+
+//----------------------------------------------------------------
+//
+// Debugging definitions and macros
+//
+
+#define STATIC static
+
+#define VRDBG_VR 0x00000001 // printout "ARC" interface activity.
+#define VRDBG_OF 0x00000002
+#define VRDBG_TEST 0x00000004
+#define VRDBG_TREE 0x00000008
+#define VRDBG_MEM 0x00000010
+#define VRDBG_MAIN 0x00000020
+#define VRDBG_ENTRY 0x00000040
+#define VRDBG_PE 0x00000080
+#define VRDBG_CONF 0x00000100
+#define VRDBG_OPEN 0x00000200
+#define VRDBG_CONFIG 0x00000400
+#define VRDBG_LOAD 0x00000800
+#define VRDBG_RDWR 0x00001000
+#define VRDBG_ARGV 0x00002000
+#define VRDBG_ENV 0x00004000 // printout environment values and variables
+#define VRDBG_DUMP 0x00008000
+#define VRDBG_HOLDIT 0x00010000
+#define SANDALFOOT 0x00020000
+//#define CDROMHACK 0x00040000
+#define VRDBG_TMP 0x00080000
+#define VRDBG_ARCDATA 0x00100000
+#define VRDBG_SCSI 0x00200000 // print out scsi node activity
+#define VRDBG_IDE 0x00400000 // print out ide node activity
+#define VRDBG_TIME 0x00800000
+#define VRDBG_ALL 0xffffffff
+
+#define VRASSERT(_exp) \
+ if (!(_exp)) { \
+ warn("Assertion Failure: line %d, File %s\n",\
+ __LINE__, __FILE__); \
+ warn("Veneer Assertion Failure:" #_exp "\n"); \
+ ArcHalt();\
+ }
+
+#define DBGSET(_value) ((_value)&(VrDebug))
+#define VRDBG(_value, _str) \
+ { \
+ if (DBGSET(_value)) { \
+ _str; \
+ } \
+ }
+
+#include "proto.h"
+
+#endif // _VENEER
diff --git a/private/ntos/boot/veneer/verno.c b/private/ntos/boot/veneer/verno.c
new file mode 100644
index 000000000..0ed3e5fd8
--- /dev/null
+++ b/private/ntos/boot/veneer/verno.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 1995,1996 FirePower Systems, Inc.
+ *
+ * $RCSfile: verno.c $
+ * $Revision: 1.15 $
+ * $Date: 1996/06/08 00:59:34 $
+ * $Locker: $
+ */
+
+#include "veneer.h"
+
+#define VENEER_MAJOR 3
+#define VENEER_MINOR 00
+#define __BLDSTAMP__ __DATE__ " - " __TIME__
+
+#define SALUTATION "Open Firmware ARC Interface Version %d.%d (%s)\n"
+#define VERSION "FirmWorks,ENG,%d.%d,%s,%s,GENERAL"
+
+
+void
+Salutation(void)
+{
+ warn(SALUTATION, VENEER_MAJOR, VENEER_MINOR, __BLDSTAMP__);
+}
+
+
+char *
+VeneerVersion(void)
+{
+ static char buf[128];
+
+ sprintf(buf, VERSION, VENEER_MAJOR, VENEER_MINOR, __DATE__, __TIME__);
+ return (buf);
+}
diff --git a/private/ntos/boot/veneer/vrbat.h b/private/ntos/boot/veneer/vrbat.h
new file mode 100644
index 000000000..696a7dede
--- /dev/null
+++ b/private/ntos/boot/veneer/vrbat.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 1995 FirmWorks, Mountain View CA USA. All rights reserved.
+ * Copyright (c) 1996 FirePower, Inc.
+ *
+ * $RCSfile: vrbat.h $
+ * $Revision: 1.2 $
+ * $Date: 1996/01/16 18:05:24 $
+ * $Locker: $
+ */
+
+#ifndef VRBAT_H
+#define VRBAT_H
+
+/*
+ ***********************************************************************
+ *
+ * MSR bit definitions
+ *
+ ***********************************************************************
+ */
+#define INSTR_ADDR_XLATE 0x00000020 // Instruction Addr xlate
+#define DATA_ADDR_XLATE 0x00000010 // Data Addr xlate
+#define EXTRNL_INT_ENABL 0x00008000 // EE bit
+#define PRIVILEDGES 0x00004000 // PR bit for supervisor/user
+ // mode. Setting this bit to 1
+ // restricts access to user only
+#define XCPT_LE_MODE 0x00010000 // take exceptions in little
+ // endian mode.
+#define LITTLE_ENDIAN 0x00000001 // run little endian mode
+#define MCHNE_CHK_EN 0x00001000 // Machine Check Enable
+#define FLOAT_PNT_EN 0x00002000
+
+/*
+************************************************************************
+**
+** Block Address Translation registers
+**
+************************************************************************
+*/
+//
+// Here are defines for the UPPER 32 bit bat register:
+//
+#define PAGE_INDEX_BITS 0xfffe0000
+#define BEPI(x) ( x & PAGE_INDEX_BITS )
+
+#define A_128K_BLOCK_SIZE 0x00000000
+#define A_256K_BLOCK_SIZE 0x00000004
+#define A_512K_BLOCK_SIZE 0x0000000c
+#define A_1MEG_BLOCK_SIZE 0x0000001c
+#define A_2MEG_BLOCK_SIZE 0x0000003c
+#define A_4MEG_BLOCK_SIZE 0x0000007c
+#define AN_8MEG_BLOCK_SIZE 0x000000fc
+#define A_16MB_BLOCK_SIZE 0x000001fc
+#define A_32MB_BLOCK_SIZE 0x000003fc
+#define A_64MB_BLOCK_SIZE 0x000007fc
+#define A_128M_BLOCK_SIZE 0x00000ffc
+#define A_256M_BLOCK_SIZE 0x00001ffc
+
+#define SUPERVISOR_ONLY 0x00000002
+#define USER_ACCESS 0x00000001
+
+//
+// The Lower BAT Register
+//
+#define BRPN(x) ( (x >> 8) & PAGE_INDEX_BITS)
+
+//
+// WIMG: VIMVENDERS BITS:
+//
+#define WRITE_THROUGH 0x00000040
+#define CACHE_INHIBIT 0x00000020
+#define MEMORY_COHRNCY 0x00000010
+#define GUARDED_BLOCK 0x00000008 // for IBAT use only....
+
+#define PAGE_RW_ACCESS 0x00000002
+#define PAGE_RO_ACCESS 0x00000001
+#define PAGE_UNAVAILBL 0x00000000
+
+
+//
+// define the special purpose register values for
+// use with the "mfspr, mtspr" instructions
+//
+#define SDR1 25
+#define IBAT0_UPPER 528
+#define IBAT0_LOWER 529
+#define IBAT1_UPPER 530
+#define IBAT1_LOWER 531
+#define IBAT2_UPPER 532
+#define IBAT2_LOWER 533
+#define IBAT3_UPPER 534
+#define IBAT3_LOWER 535
+
+#define DBAT0_UPPER 536
+#define DBAT0_LOWER 537
+#define DBAT1_UPPER 538
+#define DBAT1_LOWER 539
+#define DBAT2_UPPER 540
+#define DBAT2_LOWER 541
+#define DBAT3_UPPER 542
+#define DBAT3_LOWER 543
+
+//
+// data which written to the BAT's upper register
+// will turn off it's translation abilities
+//
+#define INVALIDATE 0x00000000
+#define KSEG0 0x80000000
+#define LDW(x,y) addi x, 0, (y&0xffff) ;\
+ addis x, 0, (y>>16)
+
+#endif //VRBAT_H
diff --git a/private/ntos/boot/veneer/vrconfig.c b/private/ntos/boot/veneer/vrconfig.c
new file mode 100644
index 000000000..e09fcd2c4
--- /dev/null
+++ b/private/ntos/boot/veneer/vrconfig.c
@@ -0,0 +1,567 @@
+/*++
+ *
+ * Copyright (c) 1995 FirePower Systems, Inc.
+ *
+ * $RCSfile: vrconfig.c $
+ * $Revision: 1.10 $
+ * $Date: 1996/04/15 02:56:07 $
+ * $Locker: $
+ *
+
+
+Module Name:
+
+ vrconfig.c
+
+Abstract:
+
+ This module contains the configuration functions.
+
+Author:
+
+ A. Benjamin 2-May-1994
+
+Revision History:
+09-06-94 Shin Iwamoto at FirePower Systems Inc.
+ Added checking ConfigurationData in VrGetConfigurationData().
+ Added checking Componet in VrGetParent() and VrGetPeer().
+09-01-94 Shin Iwamoto at FirePower Systems Inc.
+ Added to be an error if the ConfigurationDataLength field of
+ NewComponent is non-zero and the COnfigurationData parameter is null.
+07-22-94 Shin Iwamoto at FirePower Systems Inc.
+ Added VrAddChild() and VrDeleteComponent().
+07-21-94 Shin Iwamoto at FirePower Systems Inc.
+ Moved the intialization of vector table for VrGetEnvironmentVariable
+ and VrGetMemoryDescriptor into vrenv.c.
+07-20-94 Shin Iwamoto at FirePower Systems Inc.
+ Moved VrSystemInit() and VrNotYet() to vrmain.c and then
+ renamed VrSystemInit() with VrConfigInitialize() for only
+ initializing the vector table.
+
+--*/
+
+
+#include "veneer.h"
+
+
+/*
+ * Name: VrAddChild
+ *
+ * Description:
+ * This function adds a new component entry as a child of Component,
+ * including an identifier string if the IdentifierLength field of
+ * NewComponent is non-zero, and configuration data if the
+ * ConfigurationDataLength field of NewComponent is non-zero and the
+ * ConfigurationData parameter is present. If Componet is NULL,
+ * the root component is being added.
+ *
+ * Arguments:
+ * Component - Supplies a pointer to a configuration component.
+ * NewComponent- Supplies a pointer to a new configuration component
+ * to be added as a child of Component.
+ * ConfigurationData - Supplies an optional pointer to a configuration
+ * data buffer.
+ *
+ * Return Value:
+ * Returns a pointer to the new configuration component entry.
+ * If the create operation was unsuccessful, NULL is returned.
+ *
+ */
+PCONFIGURATION_COMPONENT
+VrAddChild(
+ IN PCONFIGURATION_COMPONENT Component,
+ IN PCONFIGURATION_COMPONENT NewComponent,
+ IN PVOID ConfigurationData OPTIONAL
+ )
+{
+ PCONFIGURATION_NODE ConfNode;
+ PCONFIGURATION_NODE ChildNode;
+ PCONFIGURATION_NODE ParentNode;
+
+ //
+ // If there is not enough space for the new component, retrun NULL.
+ //
+ ConfNode = new(CONFIGURATION_NODE);
+ if ((PCHAR) ConfNode == NULL) {
+ return (PCONFIGURATION_COMPONENT) NULL;
+ }
+
+ //
+ // Fill in new configuration entry with Identifier and ConfigurationData.
+ //
+ bcopy((PCHAR)NewComponent, (PCHAR)&ConfNode->Component,
+ sizeof(CONFIGURATION_COMPONENT));
+ if (NewComponent->IdentifierLength != 0) {
+ ConfNode->Component.Identifier = malloc(NewComponent->IdentifierLength);
+ if (ConfNode->Component.Identifier == NULL) {
+ ConfNode->Component.IdentifierLength = 0;
+ goto ErrorAddChild;
+ }
+ bcopy(NewComponent->Identifier, ConfNode->Component.Identifier,
+ NewComponent->IdentifierLength);
+ } else {
+ ConfNode->Component.Identifier = NULL; // For safety
+ }
+
+ if (NewComponent->ConfigurationDataLength != 0) {
+ if (ConfigurationData == NULL) {
+ ConfNode->Component.ConfigurationDataLength = 0;
+ goto ErrorAddChild;
+ }
+ ConfNode->ConfigurationData =
+ (CM_PARTIAL_RESOURCE_LIST *)
+ malloc(NewComponent->ConfigurationDataLength);
+
+ if (ConfNode->ConfigurationData == NULL) {
+ ConfNode->Component.ConfigurationDataLength = 0;
+ goto ErrorAddChild;
+ }
+ bcopy(ConfigurationData, (PCHAR)(ConfNode->ConfigurationData),
+ NewComponent->ConfigurationDataLength);
+ }
+
+ //
+ // If Component is NULL and the new Class is system, the root component
+ // is being added, otherwise the new is added according to Component.
+ //
+ if ((Component == NULL) && (NewComponent->Class == SystemClass)) {
+
+ //
+ // If the root component is being added, replace the root component.
+ // However, some information such as phandle are adhered.
+ // XXXX Is it Ok?
+ //
+ ConfNode->Peer = RootNode->Peer;
+ ConfNode->Child = RootNode->Child;
+ ConfNode->Parent = NULL;
+ ConfNode->OfPhandle = RootNode->OfPhandle;
+ RootNode = ConfNode;
+
+ //
+ // The parent of the old parent's children is changed.
+ //
+ ChildNode = ConfNode->Child;
+ while(ChildNode != NULL) {
+ ChildNode->Parent = ConfNode;
+ ChildNode = ChildNode->Peer;
+ }
+
+ } else {
+ if (Component == NULL) {
+ ParentNode = RootNode;
+ } else {
+ ParentNode = CONTAINING_RECORD(Component,
+ CONFIGURATION_NODE,
+ Component);
+ }
+ ConfNode->Peer = ParentNode->Child;
+ ParentNode->Child = ConfNode;
+ ConfNode->Child = NULL;
+ ConfNode->Parent = ParentNode;
+ ConfNode->OfPhandle = OFChild(ParentNode->OfPhandle);
+ if (!(ConfNode->OfPhandle)) { // This "can't happen."
+ goto ErrorAddChild;
+ }
+ }
+
+
+ return (&ConfNode->Component);
+
+
+ ErrorAddChild:
+ if (ConfNode->Component.IdentifierLength != 0) {
+ free(ConfNode->Component.Identifier);
+ }
+ if (ConfNode->Component.ConfigurationDataLength != 0) {
+ free((PVOID)ConfNode->ConfigurationData);
+ }
+ bzero((char *)ConfNode, sizeof(CONFIGURATION_NODE)); // For safety
+ free((char *) ConfNode);
+ return (PCONFIGURATION_COMPONENT) NULL;
+}
+
+
+/*
+ * Name: VrDeleteComponent
+ *
+ * Description:
+ * This function deletes a component entry. If the entry has one or more
+ * children, an error is returned, otherwise the entry is deleted.
+ * Deleting the entry will implicitly delete the identifier string and
+ * the configuration data.
+ *
+ * Arguments:
+ * Component - Supplies a pointer to a configuration component.
+ *
+ * Return Value:
+ * Returns ESUCCESS if the entry was successfully deleted, otherwise retunrs
+ * EINVAL or EACCES.
+ *
+ */
+ARC_STATUS
+VrDeleteComponent(
+ IN PCONFIGURATION_COMPONENT Component
+ )
+{
+ PCONFIGURATION_NODE ConfNode;
+ PCONFIGURATION_NODE SearchNode;
+
+ if (Component == NULL) {
+ return EINVAL;
+ }
+ if (!(Component->Version == ARC_VERSION &&
+ Component->Revision == ARC_REVISION)) {
+ return EINVAL;
+ }
+
+ ConfNode = CONTAINING_RECORD(Component,
+ CONFIGURATION_NODE,
+ Component);
+
+ //
+ // If Component's parent field is NULL, return EINVAL.
+ //
+ if (ConfNode->Parent == NULL) {
+ return EINVAL;
+ }
+
+ //
+ // If Component has children, return EACCES.
+ //
+ if (ConfNode->Child != NULL) {
+ return EACCES;
+ }
+
+ //
+ // Find the entry that points to Component, and point it to
+ // Components's peer. If this is Components's parent, update the child
+ // pointer, otherwise this is apeer and update the peer pointer.
+ //
+ SearchNode = ConfNode->Parent;
+ if (SearchNode->Child == ConfNode) {
+ SearchNode->Child = ConfNode->Peer;
+ } else {
+ SearchNode = SearchNode->Child;
+ while (SearchNode->Peer != ConfNode) {
+ SearchNode = SearchNode->Peer;
+ }
+ SearchNode->Peer = ConfNode->Peer;
+ }
+
+ //
+ // Free Conponent with Identifier and ConfigurationData, if any.
+ //
+ if (ConfNode->Component.IdentifierLength != 0) {
+ free(ConfNode->Component.Identifier);
+ }
+ if (ConfNode->Component.ConfigurationDataLength != 0) {
+ free((PVOID)ConfNode->ConfigurationData);
+ }
+ bzero((char *)ConfNode, sizeof(CONFIGURATION_NODE)); // For safety
+ free((char *) ConfNode);
+
+ return ESUCCESS;
+}
+
+
+/*++
+
+Routine Description:
+
+ The system configuration data structure is organized as a tree of
+ component structures. This function returns a pointer to the first
+ child of a configuration node.
+
+ If Component is null, then a pointer to the root node is returned.
+
+Arguments:
+
+ Component - pointer to a component structure.
+
+Return Value:
+
+ Returns a pointer to the structure of the child of component
+ if one exists, otherwise it returns a null pointer.
+
+--*/
+
+PCONFIGURATION_COMPONENT
+VrGetChild (
+ IN PCONFIGURATION_COMPONENT Component OPTIONAL
+ )
+{
+ PCONFIGURATION_NODE OfLink;
+
+ debug(VRDBG_VR, "VrGetChild: Entry - Component: %x\n", Component);
+
+ if (Component == (PCONFIGURATION_COMPONENT)NULL) {
+ debug(VRDBG_VR, "VrGetChild: Root %x\n", &RootNode->Component);
+ return &RootNode->Component;
+ }
+
+ OfLink = CONTAINING_RECORD(Component,
+ CONFIGURATION_NODE,
+ Component);
+
+ if (OfLink->Child == NULL ) {
+ debug(VRDBG_VR, "VrGetChild: NULL\n");
+ return NULL;
+ } else {
+ debug(VRDBG_VR, "VrGetChild: Child %x (%s)\n",
+ &OfLink->Child->Component, OfLink->Child->ComponentName);
+ return &OfLink->Child->Component;
+ }
+}
+
+PCONFIGURATION_COMPONENT
+VrGetParent(IN PCONFIGURATION_COMPONENT Component)
+{
+PCONFIGURATION_NODE OfLink;
+
+ debug(VRDBG_VR, "VrGetParent: Entry - Component: %x\n", Component);
+
+ if (Component == NULL) {
+ return NULL;
+ }
+ if (!(Component->Version == ARC_VERSION &&
+ Component->Revision == ARC_REVISION)) {
+ return NULL;
+ }
+
+ OfLink = CONTAINING_RECORD(Component,
+ CONFIGURATION_NODE,
+ Component);
+ if (OfLink->Parent == NULL) {
+ debug(VRDBG_VR, "VrGetParent: Exit-1\n");
+ return NULL;
+ } else {
+ debug(VRDBG_VR, "VrGetParent: Exit-2\n");
+ return &OfLink->Parent->Component;
+ }
+}
+
+PCONFIGURATION_COMPONENT
+VrGetPeer(IN PCONFIGURATION_COMPONENT Component)
+{
+ PCONFIGURATION_NODE OfNode;
+
+ debug(VRDBG_VR, "VrGetPeer: Entry - Component: %x\n", Component);
+
+ if (Component == NULL) {
+ return NULL;
+ }
+ if (!(Component->Version == ARC_VERSION &&
+ Component->Revision == ARC_REVISION)) {
+ return NULL;
+ }
+
+ OfNode = CONTAINING_RECORD(Component,
+ CONFIGURATION_NODE,
+ Component);
+ if (OfNode->Peer == NULL ) {
+ debug(VRDBG_VR, "VrGetPeer: NULL\n");
+ return NULL;
+ } else {
+ debug(VRDBG_VR, "VrGetPeer: Peer %x (%s)\n",
+ &OfNode->Peer->Component, OfNode->Peer->ComponentName);
+ return &OfNode->Peer->Component;
+ }
+}
+
+
+/*++
+ GetComponent - This function returns a pointer to the component structure
+ that best matches the path string pointed to by Path. The search algorithm
+ searches for each component starting with the first and continues
+ until either the string has been exhausted or no component mathes the
+ string.
+
+ BUBUG The spec. specifies the following two inconsistent return values
+
+ 1. The function returns a pointer to the last successfully matched
+ component.
+
+ 2. If the path is invalid or if a component structure does not
+ exist, this function returns a null pointer.
+--*/
+
+PCONFIGURATION_COMPONENT
+VrGetComponent(
+ IN PCHAR Path
+ )
+{
+ PCONFIGURATION_NODE Node;
+
+ debug(VRDBG_VR, "VrGetComponent: Entry - Path: %s\n", Path);
+
+ if (Node = ArcPathToNode(Path)) {
+ debug(VRDBG_VR, "VrGetComponent: Exit; found %x (%s)\n",
+ &Node->Component, Node->ComponentName);
+ return (&Node->Component);
+ } else {
+ debug(VRDBG_VR, "VrGetComponent: No match found!\n");
+ return (NULL);
+ }
+}
+
+
+/*++
+
+Routine Description:
+
+ This functions returns the configuration data associated with Component
+ in the buffer supplied by ConfigurationData. The length of the data
+ is stored in the Component structure.
+
+Arguments:
+
+ ConfigurationData - Supplies a pointer to a buffer to receive the
+ configuration data.
+
+ Component - Supplies a pointer to a configuration component.
+
+Return Value:
+
+ If the configuration data is successfully copied into the buffer
+ provided by ConfigurationData, ESUCCESS is returned. Otherwise one of
+ the following error codes is returned.
+
+ EINVAL Component is not a valid configuration component, or the
+ configuration is invalid.
+
+--*/
+
+ARC_STATUS
+VrGetConfigurationData (
+ OUT PVOID ConfigurationData,
+ IN PCONFIGURATION_COMPONENT Component
+ )
+{
+ PCONFIGURATION_NODE Node;
+ ULONG DataSize;
+
+ debug(VRDBG_VR, "VrGetConfigurationData: Entry - Config.Data: %x Comp.: %x\n",
+ ConfigurationData, Component);
+
+ if (Component == NULL) {
+ return EINVAL;
+ }
+ DataSize = Component->ConfigurationDataLength;
+
+ //
+ // check the passing parameters
+ //
+ if (DataSize == 0) {
+ return EINVAL;
+ }
+
+ Node = CONTAINING_RECORD( Component, CONFIGURATION_NODE, Component );
+
+#ifdef TOO_STRINGENT
+ //
+ // If Component's Parent field is NULL, return EINVAL.
+ //
+ if (Node->Parent == NULL) {
+ return EINVAL;
+ }
+
+ //
+ // If the Component doesn't point to a valid configuration component,
+ // return EINVAL.
+ //
+ if (!(Node->ConfigurationData->Version == ARC_VERSION &&
+ Node->ConfigurationData->Revision == ARC_REVISION)) {
+ return EINVAL;
+ }
+#endif
+
+ //
+ // Copy the data.
+ //
+
+ bcopy((PCHAR)Node->ConfigurationData, ConfigurationData, DataSize);
+
+ debug(VRDBG_VR, "VrGetConfigurationData: Exit; copied %d bytes from %x\n",
+ DataSize, Node->ConfigurationData);
+
+ return ESUCCESS;
+}
+
+
+/*
+ * Name: VrSaveConfiguration
+ *
+ * Description:
+ * This function stores all of the configuration entries into NVRAM,
+ * including the associated identifier strings and configuration data.
+ *
+ * Arguments:
+ * None.
+ *
+ * Return Value:
+ * Returns ESUCCESS if thesave completed successfully, otherwise returns
+ * ENOSPC.
+ *
+ */
+ARC_STATUS
+VrSaveConfiguration(
+ VOID
+ )
+{
+ //
+ // Open Firmware doesn't batch the NVRAM writes; thus this always succeeds.
+ //
+ return ESUCCESS;
+}
+
+
+/*++
+
+Routine Description:
+
+ This routine initializes the firmware vector in the system parameter
+ block.
+
+Arguments:
+
+ None.
+
+
+Return Value:
+
+ None.
+
+--*/
+
+VOID
+VrConfigInitialize(
+ VOID
+ )
+{
+ debug(VRDBG_ENTRY, "VrConfigInitialize BEGIN....\n");
+ (PARC_ADD_CHILD_ROUTINE)
+ SYSTEM_BLOCK->FirmwareVector[AddChildRoutine] = VrAddChild;
+
+ (PARC_DELETE_COMPONENT_ROUTINE)
+ SYSTEM_BLOCK->FirmwareVector[DeleteComponentRoutine] =
+ VrDeleteComponent;
+ (PARC_GET_CHILD_ROUTINE)
+ SYSTEM_BLOCK->FirmwareVector[GetChildRoutine] = VrGetChild;
+
+ (PARC_GET_PARENT_ROUTINE)
+ SYSTEM_BLOCK->FirmwareVector[GetParentRoutine] = VrGetParent;
+
+ (PARC_GET_PEER_ROUTINE)
+ SYSTEM_BLOCK->FirmwareVector[GetPeerRoutine] = VrGetPeer;
+
+ (PARC_GET_DATA_ROUTINE)
+ SYSTEM_BLOCK->FirmwareVector[GetDataRoutine] =
+ VrGetConfigurationData;
+ (PARC_GET_COMPONENT_ROUTINE)
+ SYSTEM_BLOCK->FirmwareVector[GetComponentRoutine] =
+ VrGetComponent;
+ (PARC_SAVE_CONFIGURATION_ROUTINE)
+ SYSTEM_BLOCK->FirmwareVector[SaveConfigurationRoutine] =
+ VrSaveConfiguration;
+ debug(VRDBG_ENTRY, "VrConfigInitialize ....END\n");
+}
diff --git a/private/ntos/boot/veneer/vrcons.c b/private/ntos/boot/veneer/vrcons.c
new file mode 100644
index 000000000..e28a188f6
--- /dev/null
+++ b/private/ntos/boot/veneer/vrcons.c
@@ -0,0 +1,55 @@
+/*++
+
+ Copyright (c) 1995 FirePower Systems, Inc.
+
+ $RCSfile: vrcons.c $
+ $Revision: 1.6 $
+ $Date: 1996/02/17 00:34:54 $
+ $Locker: $
+
+Copyright (c) 1994 FirmWorks, Mountain View CA USA. All rights reserved.
+
+Module Name:
+
+ vrconsole.c
+
+--*/
+
+#include "veneer.h"
+
+ihandle ConsoleIn = 0, ConsoleOut = 0;
+
+/*
+ * Look up either the stdin or stdout and return an NT path to
+ * the device. The console argument should be either "stdin" or
+ * "stdout".
+ */
+
+PCHAR
+VrFindConsolePath(char *console)
+{
+ phandle chosen;
+ ihandle console_ih;
+ PCONFIGURATION_NODE node;
+
+ chosen = OFFinddevice("/chosen");
+ console_ih = get_int_prop(chosen, console);
+
+ if (console_ih == -1) {
+ return (NULL);
+ }
+
+ if (strcmp(console, "stdin") == 0) {
+ ConsoleIn = console_ih;
+ }
+ if (strcmp(console, "stdout") == 0) {
+ ConsoleOut = console_ih;
+ }
+
+ node = InstanceToNode(console_ih);
+ if (node == NULL) {
+ fatal("VrFindConsolePath: cannot locate %s node\n", console);
+ }
+
+ return (NodeToArcPath(node));
+}
diff --git a/private/ntos/boot/veneer/vrcpiwrp.c b/private/ntos/boot/veneer/vrcpiwrp.c
new file mode 100644
index 000000000..dfd9d0461
--- /dev/null
+++ b/private/ntos/boot/veneer/vrcpiwrp.c
@@ -0,0 +1,525 @@
+/*++
+ *
+ * Copyright (c) 1995 FirePower Systems, Inc.
+ * Copyright (c) 1994 FirmWorks, Mountain View CA USA. All rights reserved.
+ *
+ * $RCSfile: vrcpiwrp.c $
+ * $Revision: 1.12 $
+ * $Date: 1996/02/26 20:17:32 $
+ * $Locker: $
+ *
+
+
+
+Module Name:
+
+ vrcpiwrp.c
+
+Abstract:
+
+ This module implements the wrapper for the P1275 boot firmware client
+ program interface. There is a wrapper routine for each of the client
+ interface service. The wrapper routine constructs a client interface
+ argument array as illustraed in the figure below, places its address
+ in r3 and transfers control to the client interface handler. The
+ return address of the wrapper routine is placed in lr register.
+
+ The Client interface handler performs the service specified in the
+ argument array and return to wrapper routine which in turn return
+ to the client program. The client interface handler places the return
+ value (success or failure) in %r3.
+
+
+ Layout of the argument array
+
+ +--------------------------------------+
+ | Name of the client interface service |
+ +--------------------------------------+
+ | Number of input arguments |
+ +--------------------------------------+
+ | Number of return values |
+ +--------------------------------------+
+ | Input arguments (arg1, ..., argN) |
+ +--------------------------------------+
+ | Returned values (ret1, ..., retN) |
+ +--------------------------------------+
+
+Author:
+
+ A. Benjamin 27-Apr-1994
+
+Revision History:
+07-20-94 Shin Iwamoto at FirePower Systems Inc.
+ Added OFBoot and OFEnter.
+
+
+--*/
+
+
+#include "veneer.h"
+
+#define VR_CIF_HANDLER_IN 3
+
+//
+// Device tree routines
+//
+
+//
+// Peer() - This routines outputs the identifier(phandle) of the device node that is
+// the next sibling of the specified device node.
+//
+// Inputs:
+// phandle - identifier of a device node
+//
+// Outputs:
+// sibling_phandle - identifier of the next sibling.
+// Zero if there are no more siblings.
+//
+
+//
+// peer
+//
+phandle
+OFPeer(phandle device_id)
+{
+ ULONG argarray[] = { (ULONG)"peer",1,1,0,0};
+ argarray[VR_CIF_HANDLER_IN+0] = device_id;
+ if (call_firmware(argarray) != 0) {
+ return (phandle)0;
+ }
+ return ((phandle)argarray[VR_CIF_HANDLER_IN+1]);
+}
+
+//
+//child
+//
+phandle
+OFChild(phandle device_id)
+{
+ ULONG argarray[] = { (ULONG)"child",1,1,0,0};
+ argarray[VR_CIF_HANDLER_IN+0] = device_id;
+ if (call_firmware(argarray) != 0) {
+ return (phandle)0;
+ }
+ return ((phandle)argarray[VR_CIF_HANDLER_IN+1]);
+}
+//
+// parent
+//
+phandle
+OFParent(phandle device_id)
+{
+ ULONG argarray[] = { (ULONG)"parent",1,1,0,0};
+ argarray[VR_CIF_HANDLER_IN+0] = device_id;
+ if (call_firmware(argarray) != 0) {
+ return (phandle)0;
+ }
+ return ((phandle)argarray[VR_CIF_HANDLER_IN+1]);
+}
+//
+//getproplen
+//
+long
+OFGetproplen(
+ phandle device_id,
+ char *name
+ )
+{
+ ULONG argarray[] = { (ULONG)"getproplen",2,1,0,0,0};
+ argarray[VR_CIF_HANDLER_IN+0] = (long)device_id;
+ argarray[VR_CIF_HANDLER_IN+1] = (long)name;
+ if (call_firmware(argarray) != 0) {
+ return (-1);
+ }
+ return (argarray[VR_CIF_HANDLER_IN+2]);
+}
+//
+//getprop
+//
+long
+OFGetprop(
+ phandle device_id,
+ char *name,
+ char *buf,
+ ULONG buflen
+ )
+{
+ ULONG argarray[] = { (ULONG)"getprop",4,1,0,0,0,0,0};
+ argarray[VR_CIF_HANDLER_IN+0] = (long)device_id;
+ argarray[VR_CIF_HANDLER_IN+1] = (long)name;
+ argarray[VR_CIF_HANDLER_IN+2] = (long)buf;
+ argarray[VR_CIF_HANDLER_IN+3] = buflen;
+ if (call_firmware(argarray) != 0) {
+ return (-1);
+ }
+ return (argarray[VR_CIF_HANDLER_IN+4]);
+}
+//
+//nextprop
+//
+long
+OFNextprop(
+ phandle device_id,
+ char *name,
+ char *buf
+ )
+{
+ ULONG argarray[] = { (ULONG)"nextprop",3,1,0,0,0,0};
+ argarray[VR_CIF_HANDLER_IN+0] = (long)device_id;
+ argarray[VR_CIF_HANDLER_IN+1] = (long)name;
+ argarray[VR_CIF_HANDLER_IN+2] = (long)buf;
+ if (call_firmware(argarray) != 0) {
+ return (-1);
+ }
+ return (argarray[VR_CIF_HANDLER_IN+3]);
+}
+//
+//setprop
+//
+long
+OFSetprop(
+ phandle device_id,
+ char *name,
+ char *buf,
+ ULONG buflen
+ )
+{
+ ULONG argarray[] = { (ULONG)"setprop",4,1,0,0,0,0,0};
+ argarray[VR_CIF_HANDLER_IN+0] = (long)device_id;
+ argarray[VR_CIF_HANDLER_IN+1] = (long)name;
+ argarray[VR_CIF_HANDLER_IN+2] = (long)buf;
+ argarray[VR_CIF_HANDLER_IN+3] = buflen;
+ if (call_firmware(argarray) != 0) {
+ return (-1);
+ }
+ return (argarray[VR_CIF_HANDLER_IN+4]);
+}
+
+//
+// finddevice
+//
+phandle
+OFFinddevice( char *devicename)
+{
+ ULONG argarray[] = { (ULONG)"finddevice",1,1,0,0};
+
+ argarray[VR_CIF_HANDLER_IN+0] = (long)devicename;
+ if (call_firmware(argarray) != 0) {
+ return (phandle)0;
+ }
+ return ((phandle) argarray[VR_CIF_HANDLER_IN+1]);
+}
+
+//
+// open
+//
+ihandle
+OFOpen( char *devicename)
+{
+ ULONG argarray[] = { (ULONG)"open",1,1,0,0};
+
+ debug(VRDBG_OF, "OFOpen('%s')\n", devicename);
+ argarray[VR_CIF_HANDLER_IN+0] = (long)devicename;
+ if (call_firmware(argarray) != 0) {
+ return (ihandle)0;
+ }
+ return ((ihandle) argarray[VR_CIF_HANDLER_IN+1]);
+}
+
+//
+// close
+//
+void
+OFClose(ihandle id)
+{
+ ULONG argarray[] = { (ULONG)"close",1,1,0,0};
+ argarray[VR_CIF_HANDLER_IN+0] = (long)id;
+ if (call_firmware(argarray) != 0) {
+ warn("OFClose(%x) failed\n", id);
+ }
+
+}
+//
+//read
+//
+long
+OFRead(
+ ihandle instance_id,
+ PCHAR addr,
+ ULONG len
+ )
+{
+ ULONG argarray[] = { (ULONG)"read",3,1,0,0,0,0};
+
+ argarray[VR_CIF_HANDLER_IN+0] = (long) instance_id;
+ argarray[VR_CIF_HANDLER_IN+1] = (ULONG)addr;
+ argarray[VR_CIF_HANDLER_IN+2] = len;
+ if (call_firmware(argarray) != 0) {
+ return (-1);
+ }
+ return (argarray[VR_CIF_HANDLER_IN+3]);
+}
+//
+//write
+//
+long
+OFWrite(
+ ihandle instance_id,
+ PCHAR addr,
+ ULONG len
+ )
+{
+ ULONG argarray[] = { (ULONG)"write",3,1,0,0,0,0};
+
+ argarray[VR_CIF_HANDLER_IN+0] = (long) instance_id;
+ argarray[VR_CIF_HANDLER_IN+1] = (ULONG)addr;
+ argarray[VR_CIF_HANDLER_IN+2] = len;
+ if (call_firmware(argarray) != 0) {
+ return (-1);
+ }
+ return (argarray[VR_CIF_HANDLER_IN+3]);
+}
+//
+// seek
+//
+long
+OFSeek(
+ ihandle instance_id,
+ ULONG poshi,
+ ULONG poslo
+ )
+{
+ ULONG argarray[] = { (ULONG)"seek",3,1,0,0,0,0};
+
+ argarray[VR_CIF_HANDLER_IN+0] = (long) instance_id;
+ argarray[VR_CIF_HANDLER_IN+1] = poshi;
+ argarray[VR_CIF_HANDLER_IN+2] = poslo;
+ if (call_firmware(argarray) != 0) {
+ return (-1);
+ }
+ return (argarray[VR_CIF_HANDLER_IN+3]);
+}
+//
+// claim
+//
+ULONG
+OFClaim(
+ PCHAR addr,
+ ULONG size,
+ ULONG align
+ )
+{
+ ULONG argarray[] = { (ULONG)"claim",3,1,0,0,0,0};
+
+ argarray[VR_CIF_HANDLER_IN+0] = (ULONG)addr;
+ argarray[VR_CIF_HANDLER_IN+1] = size;
+ argarray[VR_CIF_HANDLER_IN+2] = align;
+ if (call_firmware(argarray) != 0) {
+ return (ULONG)0;
+ }
+ return (argarray[VR_CIF_HANDLER_IN+3]);
+}
+//
+// release
+//
+VOID
+OFRelease(
+ PCHAR addr,
+ ULONG size
+ )
+{
+ ULONG argarray[] = { (ULONG)"release",2,0,0,0};
+ argarray[VR_CIF_HANDLER_IN+0] = (ULONG)addr;
+ argarray[VR_CIF_HANDLER_IN+1] = size;
+ call_firmware(argarray);
+}
+
+//
+// package-to-path
+//
+long
+OFPackageToPath(
+ phandle device_id,
+ char *addr,
+ ULONG buflen
+ )
+{
+ ULONG argarray[] = { (ULONG)"package-to-path",3,1,0,0,0,0};
+
+ argarray[VR_CIF_HANDLER_IN+0] = (ULONG)device_id;
+ argarray[VR_CIF_HANDLER_IN+1] = (ULONG)addr;
+ argarray[VR_CIF_HANDLER_IN+2] = buflen;
+ if (call_firmware(argarray) != 0) {
+ return (-1);
+ }
+ return ((LONG)argarray[VR_CIF_HANDLER_IN+3]);
+}
+
+//
+// instance-to-path
+//
+long
+OFInstanceToPath(
+ ihandle ih,
+ char *addr,
+ ULONG buflen
+ )
+{
+ ULONG argarray[] = { (ULONG)"instance-to-path",3,1,0,0,0,0};
+
+ argarray[VR_CIF_HANDLER_IN+0] = (ULONG)ih;
+ argarray[VR_CIF_HANDLER_IN+1] = (ULONG)addr;
+ argarray[VR_CIF_HANDLER_IN+2] = buflen;
+ if (call_firmware(argarray) != 0) {
+ return (-1);
+ }
+ return ((LONG)argarray[VR_CIF_HANDLER_IN+3]);
+}
+
+//
+// instance-to-package
+//
+phandle
+OFInstanceToPackage(ihandle ih)
+{
+ ULONG argarray[] = { (ULONG)"instance-to-package",1,1,0,0};
+
+ argarray[VR_CIF_HANDLER_IN+0] = (ULONG)ih;
+ if (call_firmware(argarray) != 0) {
+ return (-1);
+ }
+ return ((LONG)argarray[VR_CIF_HANDLER_IN+1]);
+}
+
+//
+// call-method
+//
+long
+OFCallMethod(
+ ULONG n_outs,
+ ULONG n_ins,
+ ULONG *outp,
+ char *method,
+ ihandle id,
+ ...
+ )
+{
+ ULONG *argarray, i;
+ va_list ins;
+ int res;
+
+ argarray = (ULONG *) zalloc((n_ins + n_outs + 4) * sizeof(ULONG));
+ argarray[0] = (ULONG) "call-method";
+ argarray[1] = (ULONG) n_ins;
+ argarray[2] = (ULONG) n_outs + 1;
+ argarray[VR_CIF_HANDLER_IN+0] = (ULONG)method;
+ argarray[VR_CIF_HANDLER_IN+1] = (ULONG)id;
+ va_start(ins, id);
+ for (i = 2; i < n_ins; ++i) {
+ argarray[VR_CIF_HANDLER_IN+i] = va_arg(ins, ULONG);
+ }
+ va_end(ins);
+
+ if ((res = call_firmware(argarray)) != 0) {
+ debug(VRDBG_OF, "OFCallMethod: call_firmware() != 0\n");
+ return (-1);
+ }
+ debug(VRDBG_OF, "OFCallMethod: catch_res %x return %x\n",
+ argarray[VR_CIF_HANDLER_IN+n_ins],
+ argarray[VR_CIF_HANDLER_IN+n_ins+1]);
+ for (i = 0; i < n_outs; ++i)
+ outp[i] = argarray[VR_CIF_HANDLER_IN + n_ins + 1 + i];
+ return ((LONG)argarray[VR_CIF_HANDLER_IN+n_ins]);
+}
+
+//
+// interpret
+//
+long
+OFInterpret(
+ ULONG n_outs,
+ ULONG n_ins,
+ ULONG *outp,
+ char *cmd,
+ ...
+ )
+{
+ ULONG *argarray, i;
+ va_list ins;
+ int res;
+
+ argarray = (ULONG *) zalloc((n_ins + (n_outs + 1) + 3) * sizeof(ULONG));
+ argarray[0] = (ULONG) "interpret";
+ argarray[1] = (ULONG) n_ins;
+ argarray[2] = (ULONG) n_outs + 1;
+ argarray[VR_CIF_HANDLER_IN+0] = (ULONG)cmd;
+ va_start(ins, cmd);
+ for (i = 1; i < n_ins; ++i) {
+ argarray[VR_CIF_HANDLER_IN+i] = va_arg(ins, ULONG);
+ }
+ va_end(ins);
+
+ if ((res = call_firmware(argarray)) != 0) {
+ debug(VRDBG_OF, "OFCallMethod: call_firmware() != 0\n");
+ return (-1);
+ }
+ debug(VRDBG_OF, "OFCallMethod: catch_res %x return %x\n",
+ argarray[VR_CIF_HANDLER_IN+n_ins],
+ argarray[VR_CIF_HANDLER_IN+n_ins+1]);
+ for (i = 0; i < n_outs; ++i)
+ outp[i] = argarray[VR_CIF_HANDLER_IN + n_ins + 1 + i];
+ return ((LONG)argarray[VR_CIF_HANDLER_IN+n_ins]);
+}
+
+//
+// milliseconds
+//
+ULONG
+OFMilliseconds( VOID )
+{
+ ULONG argarray[] = { (ULONG)"milliseconds",0,1,0};
+ if (call_firmware(argarray) != 0) {
+ return (ULONG)0;
+ }
+ return (argarray[VR_CIF_HANDLER_IN+0]);
+}
+
+
+//
+// boot
+//
+VOID
+OFBoot(
+ char *bootspec
+ )
+{
+ ULONG argarray[] = { (ULONG)"boot",1,0,0};
+
+ argarray[VR_CIF_HANDLER_IN+0] = (ULONG)bootspec;
+ call_firmware(argarray);
+}
+
+
+//
+// enter
+//
+VOID
+OFEnter( VOID )
+{
+ ULONG argarray[] = { (ULONG)"enter",0,0};
+
+ call_firmware(argarray);
+}
+
+
+//
+// exit
+//
+VOID
+OFExit( VOID )
+{
+ ULONG argarray[] = { (ULONG)"exit",0,0};
+
+ warn("Program complete - please reboot.\n");
+ call_firmware(argarray);
+}
diff --git a/private/ntos/boot/veneer/vrdisp.c b/private/ntos/boot/veneer/vrdisp.c
new file mode 100644
index 000000000..e158c677e
--- /dev/null
+++ b/private/ntos/boot/veneer/vrdisp.c
@@ -0,0 +1,169 @@
+/*
+ *
+ * Copyright (c) 1995 FirePower Systems, Inc.
+ *
+ * $RCSfile: vrdisp.c $
+ * $Revision: 1.7 $
+ * $Date: 1996/04/15 02:56:02 $
+ * $Locker: $
+ *
+ *
+ *
+ * Module Name:
+ * vrdisp.c
+ *
+ * Author:
+ * Shin Iwamoto at FirePower Systems Inc.
+ *
+ * History:
+ * 16-Jun-94 Shin Iwamoto at FirePower Systems Inc.
+ * Returned always EINVAL in VrTestUnicodeCharacter().
+ * 18-May-94 Shin Iwamoto at FirePower Systems Inc.
+ * Added for DispalDevice flag.
+ * Added some comments.
+ * 05-May-94 Shin Iwamoto at FirePower Systems Inc.
+ * Created roughly.
+ *
+ */
+
+
+#include "veneer.h"
+
+
+//
+// Static data.
+//
+STATIC ARC_DISPLAY_STATUS DisplayStatus = {
+ //
+ // Assume bold, (1), white, (7), foreground and blue, (4)
+ // background because the only known programs that use the
+ // "get current colors" feature is arcinst which uses white
+ // on blue. Anyway, every other Microsoft ARC client we have
+ // seen uses the same color scheme.
+ //
+ 0, 0, 80, 32, 7, 4, 1, 0, 0
+};
+
+
+/*
+ * Name: VrGetDisplayStatus
+ *
+ * Description:
+ * This function returns a pointer to a display status structure.
+ *
+ * Arguments:
+ * FileId - Supplies the file table index.
+ *
+ * Return Value:
+ * If the device associated with FileId is not a display device
+ * or is not a valid file descriptor, then return a null pointer.
+ * Otherwise, returns the display status structure.
+ *
+ */
+PARC_DISPLAY_STATUS
+VrGetDisplayStatus(
+ IN ULONG FileId
+ )
+{
+ PARC_DISPLAY_STATUS PDisplayStatus = &DisplayStatus;
+ phandle ph;
+ int lines;
+
+ if (FileId == 1) { // stdout
+ ph = OFFinddevice("/chosen");
+ lines = get_int_prop(ph, "stdout-#lines");
+ if (lines != -1) {
+ PDisplayStatus->CursorMaxYPosition = lines;
+ }
+ return PDisplayStatus;
+ }
+ if (FileId >= FILE_TABLE_SIZE) {
+ return (PARC_DISPLAY_STATUS)NULL;
+ }
+ if (!(FileTable[FileId].Flags.Open == 1
+ && FileTable[FileId].Flags.Write == 1)) {
+
+ return (PARC_DISPLAY_STATUS)NULL;
+ }
+ if (FileTable[FileId].Flags.DisplayDevice != 1) {
+ return (PARC_DISPLAY_STATUS)NULL;
+ }
+
+ ph = OFInstanceToPackage(FileTable[FileId].IHandle);
+ lines = get_int_prop(ph, "stdout-#lines");
+ if (lines != -1) {
+ PDisplayStatus->CursorMaxYPosition = lines;
+ }
+
+ return PDisplayStatus;
+}
+
+
+/*
+ * Name: VrTestUnicodeCharacter
+ *
+ * Description:
+ * This function tests whether or not the display driver associated
+ * with FileId is capable of rendering the Unicode character.
+ *
+ * Arguments:
+ * FileId - Supplies the file table index.
+ * UnicodeCharacter - Supplies the character to be tested.
+ *
+ * Return Value:
+ *
+ */
+ARC_STATUS
+VrTestUnicodeCharacter(
+ IN ULONG FileId,
+ IN WCHAR UnicodeCharacter
+ )
+{
+ if (FileId >= FILE_TABLE_SIZE) {
+ return EBADF;
+ }
+ if (!((FileTable[FileId].Flags.Open == 1) &&
+ (FileTable[FileId].Flags.Write == 1))) {
+
+ return EBADF;
+ }
+ if (FileTable[FileId].Flags.DisplayDevice != 1) {
+ return EBADF;
+ }
+
+ //
+ // Open Firmware has not capability to render any Unicode character.
+ // But it supports 8-bit through. (Mr. Tooch said. '94.06.15)
+ //
+ return EINVAL;
+}
+
+
+/*
+ * Name: VrDisplayInitialize
+ *
+ * Description:
+ * This function initializes the Dispaly entry points in the firmware
+ * transfer vector.
+ *
+ * Arguments:
+ * None.
+ *
+ * Return Value:
+ * None.
+ *
+ */
+VOID
+VrDisplayInitialize(
+ VOID
+ )
+{
+ debug(VRDBG_ENTRY, "VrDisplayInitialize BEGIN.....\n");
+ //
+ // Initialize the Display entry points in the firmware transfer vector.
+ //
+ (PARC_GET_DISPLAY_STATUS_ROUTINE)
+ SYSTEM_BLOCK->FirmwareVector[GetDisplayStatusRoutine] =
+ VrGetDisplayStatus;
+ debug(VRDBG_ENTRY, "VrDisplayInitialize .....END\n");
+}
diff --git a/private/ntos/boot/veneer/vrdumptr.c b/private/ntos/boot/veneer/vrdumptr.c
new file mode 100644
index 000000000..fc789a72d
--- /dev/null
+++ b/private/ntos/boot/veneer/vrdumptr.c
@@ -0,0 +1,212 @@
+/*
+ *
+ * Copyright (c) 1995 FirePower Systems, Inc.
+ * Copyright (c) 1994 FirmWorks, Mountain View CA USA. All rights reserved.
+ *
+ * $RCSfile: vrdumptr.c $
+ * $Revision: 1.7 $
+ * $Date: 1996/02/17 00:35:53 $
+ * $Locker: $
+ *
+ *
+ *
+ * Module Name:
+ * vrdumptr.c
+ *
+ * Author:
+ * Shin Iwamoto at FirePower Systems Inc.
+ *
+ * History:
+ * 11-May-94 Shin Iwamoto at FirePower Systems Inc.
+ * Created.
+ *
+ */
+
+
+#include "veneer.h"
+
+PCHAR
+ClassTable[] = {"System",
+ "Processor",
+ "Cache",
+ "Adapter",
+ "Controller",
+ "Peripheral",
+ "Memory"};
+PCHAR
+TypeTable[] = {"ArcSystem",
+ "CentralProcessor",
+ "FloatingPointProcessor",
+ "PrimaryIcache",
+ "PrimaryDcache",
+ "SecondaryIcache",
+ "SecondaryDcache",
+ "SecondaryCache",
+ "EisaAdapter",
+ "TcAdapter",
+ "ScsiAdapter",
+ "DtiAdapter",
+ "MultiFunctionAdapter",
+ "DiskController",
+ "TapeController",
+ "CdromController",
+ "WormController",
+ "SerialController",
+ "NetworkController",
+ "DisplayController",
+ "ParallelController",
+ "PointerController",
+ "KeyboardController",
+ "AudioController",
+ "OtherController",
+ "DiskPeripheral",
+ "FloppyDiskPeripheral",
+ "TapePeripheral",
+ "ModemPeripheral",
+ "MonitorPeripheral",
+ "PrinterPeripheral",
+ "PointerPeripheral",
+ "KeyboardPeripheral",
+ "TerminalPeripheral",
+ "OtherPeripheral",
+ "LinePeripheral",
+ "NetworkPeripheral",
+ "SystemMemory"};
+PCHAR
+ResourceTypeTable[]
+ = {"CmResourceTypeNull",
+ "CmResourceTypePort",
+ "CmResourceTypeInterrupt",
+ "CmResourceTypeMemory",
+ "CmResourceTypeDma",
+ "CmResourceTypeDeviceSpecific"};
+PCHAR
+ShareDispositionTable[]
+ = {"CmResourceShareUndetermined",
+ "CmResourceShareDeviceExclusive",
+ "CmResourceShareDriverExclusive",
+ "CmResourceShareShared"};
+
+STATIC VOID DisplayConfData(PCM_PARTIAL_RESOURCE_DESCRIPTOR);
+
+VOID
+quick_dump_tree(PCONFIGURATION_NODE node)
+{
+ PCONFIGURATION_COMPONENT P = &node->Component;
+ extern int level;
+
+ if (P->IdentifierLength) {
+ debug(VRDBG_CONFIG, "%x %s %s(%d) [%s]\n", node,
+ TypeTable[P->Type], node->ComponentName, P->Key,
+ P->Identifier);
+ } else {
+ debug(VRDBG_CONFIG, "%x %s %s(%d)\n", node,
+ TypeTable[P->Type], node->ComponentName, P->Key);
+ }
+
+ if (node->Child) {
+ ++level;
+ quick_dump_tree(node->Child);
+ --level;
+ }
+ if (node->Peer) {
+ quick_dump_tree(node->Peer);
+ }
+}
+
+VOID
+dump_tree(PCONFIGURATION_NODE node)
+{
+ debug(VRDBG_DUMP, "\n");
+ debug(VRDBG_DUMP, "dump_tree %x '%s'\n", node, node->ComponentName);
+ debug(VRDBG_DUMP, "\tparent '%s' peer '%s' child '%s'\n",
+ node->Parent ? node->Parent->ComponentName : "",
+ node->Peer ? node->Peer->ComponentName : "",
+ node->Child ? node->Child->ComponentName : "");
+ DisplayConfig(&node->Component);
+
+ if (node->Child) {
+ dump_tree(node->Child);
+ }
+ if (node->Peer) {
+ dump_tree(node->Peer);
+ }
+}
+
+VOID
+DisplayConfig(
+ PCONFIGURATION_COMPONENT P
+ )
+{
+ PCM_PARTIAL_RESOURCE_LIST ConfList;
+ PCM_PARTIAL_RESOURCE_DESCRIPTOR ConfData;
+ int count;
+
+ warn("\tClass=%s, Type=%s, Key=0x%x, Flags=0x%x\n",
+ ClassTable[P->Class], TypeTable[P->Type], P->Key, P->Flags);
+ warn(
+ "\tVersion=%d, Revision=%d, AffinityMask=0x%x\n",
+ P->Version, P->Revision, P->AffinityMask);
+ warn("\tIdentifierLength=%d, Identifier='%s'\n",
+ P->IdentifierLength,
+ P->IdentifierLength ? P->Identifier : "");
+
+ count = P->ConfigurationDataLength;
+ warn("\tConfLen=%d\n", count);
+ if (count == 0) {
+ return;
+ }
+
+ ConfList =
+ (PCM_PARTIAL_RESOURCE_LIST)malloc(count);
+ if (VrGetConfigurationData(ConfList, P)) {
+ free((char *) ConfList);
+ return;
+ }
+
+ warn("\tVersion=%d, Revision=%d, Count=%d\n",
+ ConfList->Version, ConfList->Revision, ConfList->Count);
+ if (ConfList->Version == 1 && ConfList->Revision == 0) {
+ // pre-803 releases
+ free((char *) ConfList);
+ return;
+ }
+ count = ConfList->Count;
+ ConfData = ConfList->PartialDescriptors;
+ while (count-- > 0) {
+ warn(
+ "\t\tType=%s\n\t\tShareDesposition=%s\n\t\tFlags=0x%x",
+ ResourceTypeTable[ConfData->Type],
+ ShareDispositionTable[ConfData->ShareDisposition],
+ ConfData->Flags);
+ if (ConfData->Type == CmResourceTypeDeviceSpecific) {
+ int len = ConfData->u.DeviceSpecificData.DataSize;
+ int *data = (int *) ((char *) ConfData +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
+ warn(" Data length=%d", len);
+ while (len > 0) {
+ warn( "\n\t\t%x %x %x", *data, *(data+1), *(data+2));
+ len -= 3 * sizeof(int);
+ data += 3;
+ }
+ ConfData += 1;
+ (char *) ConfData = (char *) ConfData + len;
+ warn("\n");
+ } else {
+ warn( "\n\t\t%x %x %x\n", ConfData->u.Dma.Channel,
+ ConfData->u.Dma.Port, ConfData->u.Dma.Reserved1);
+ ConfData += 1;
+ }
+ }
+ free((char *) ConfList);
+}
+
+STATIC VOID
+DisplayConfData(
+ PCM_PARTIAL_RESOURCE_DESCRIPTOR P
+ )
+{
+ warn("\nType=%s, ShareDesposition=%s, Flags=0x%x\n",
+ ResourceTypeTable[P->Type],
+ ShareDispositionTable[P->ShareDisposition], P->Flags);
+}
diff --git a/private/ntos/boot/veneer/vrenv.c b/private/ntos/boot/veneer/vrenv.c
new file mode 100644
index 000000000..5f8a4a9e3
--- /dev/null
+++ b/private/ntos/boot/veneer/vrenv.c
@@ -0,0 +1,254 @@
+/*++
+ *
+ * Copyright (c) 1994 FirePower Systems, Inc.
+ * Copyright (c) 1995 FirePower Systems, Inc.
+ *
+ * $RCSfile: vrenv.c $
+ * $Revision: 1.13 $
+ * $Date: 1996/06/19 23:13:26 $
+ * $Locker: $
+ *
+
+
+Module Name:
+
+ vrenv.c
+
+Abstract:
+
+ This module contains environment variable functions.
+
+Author:
+
+ A. Benjamin 9-May-1994
+
+Revision History:
+08-08-94 Shin Iwamoto at FirePower Systems Inc.
+ Made OptionsPhandle global static, and set the vales
+ in VrEnvInitialize.
+07-21-94 Shin Iwamoto at FirePower Systems Inc.
+ Added VrEnvInitialize().
+
+--*/
+
+
+#include "veneer.h"
+#define MAX_ARGC 16
+#define MAX_ENVC 16
+
+extern char *VrArgv[MAX_ARGC], *VrEnvp[MAX_ENVC];
+STATIC phandle OptionsPhandle = 0;
+STATIC VOID VrEnvOpen(VOID);
+PCHAR FindInLocalEnv( PCHAR Variable );
+PCHAR ConvertToUpper( PCHAR Orig );
+PCHAR GetEnvVar( PCHAR Variable );
+PCHAR VrCanonicalName( IN PCHAR Variable);
+
+PCHAR
+VrCanonicalName(
+ IN PCHAR Variable
+ )
+{
+ static char CanonicalName[32];
+
+ if (strlen(Variable) > 31) {
+ fatal(
+ "Veneer: Environment variable name %s is longer than 31 characters\n",
+ Variable);
+ }
+ strcpy(CanonicalName, Variable);
+ return (capitalize(CanonicalName));
+}
+
+/*
+ *
+ * ROUTINE: VrGetEnvironmentVariable( PCHAR Variable )
+ *
+ * DESCRIPTION:
+ * Exported Interface to an arc program. This routine will check
+ * the environment passed to the program for the variable before calling
+ * back into the firmware. Since ARC enforces no case sensitivity on
+ * variables, this routine will force all variables to upper case before
+ * checking the local environment.
+ *
+ */
+
+PCHAR
+VrGetEnvironmentVariable(
+ IN PCHAR Variable
+ )
+{
+ PCHAR Value = NULL;
+
+
+ debug(VRDBG_ENV, "VrGetEnvironmentVariable: Entry - Variable: '%s'\n",
+ Variable ? Variable : "NULL");
+
+ if ((Value = FindInLocalEnv(Variable)) == NULL) {
+ Value = GetEnvVar(Variable);
+ }
+
+ debug(VRDBG_ENV, "VrGetEnvironmentVariable: Exit '%s'\n",
+ Value ? Value : "NULL");
+ return Value;
+}
+
+
+ARC_STATUS
+VrSetEnvironmentVariable(
+ IN PCHAR Variable,
+ IN PCHAR Value
+ )
+{
+ long retval;
+
+ debug(VRDBG_ENV,
+ "VrSetEnvironmentVariable: Entry - Variable: '%s' Value '%s'\n",
+ Variable, Value);
+
+ if (OptionsPhandle == 0) {
+ VrEnvOpen();
+ }
+ retval = OFSetprop(OptionsPhandle, VrCanonicalName(Variable),
+ Value, strlen(Value));
+ retval = (retval != (long) strlen(Value));
+
+ debug(VRDBG_ENV, "VrGetEnvironmentVariable: Exit '%s'\n", retval);
+ return retval;
+}
+
+
+/*
+ * Name: VrEnvInitialize
+ *
+ * Description:
+ * This function initializes the Environment entry points in the firmware
+ * transfer vector and the file table.
+ *
+ * Arguments:
+ * None.
+ *
+ * Return Value:
+ * None.
+ *
+ */
+VOID
+VrEnvInitialize(VOID)
+{
+ //
+ // Initialize the I/O entry points in the firmware transfer vector.
+ //
+ debug(VRDBG_ENTRY, "VrEnvInitialize: BEGIN......\n");
+ (PARC_GET_ENVIRONMENT_ROUTINE)
+ SYSTEM_BLOCK->FirmwareVector[GetEnvironmentRoutine]
+ = VrGetEnvironmentVariable;
+ (PARC_SET_ENVIRONMENT_ROUTINE)
+ SYSTEM_BLOCK->FirmwareVector[SetEnvironmentRoutine]
+ = VrSetEnvironmentVariable;
+ debug(VRDBG_ENTRY, "VrEnvInitialize: .....END\n");
+}
+
+/*
+ * Name: VrEnvOpen
+ *
+ * Description:
+ * This function gets the phandle for the Open Firmware options node
+ * so that Open Firmware configuration variables can be later accessed.
+ *
+ * Arguments:
+ * None.
+ *
+ * Return Value:
+ * None.
+ *
+ */
+STATIC VOID
+VrEnvOpen(VOID)
+{
+ OptionsPhandle = OFFinddevice("/options");
+ if (OptionsPhandle == 0) {
+ fatal("Veneer: Cannot access /options\n");
+ }
+}
+
+/*
+ * ROUTINE: FindInLocalEnv( PCHAR Variable )
+ *
+ * DESCRIPTION:
+ * Force the passed in variable to upper case, check the local environ-
+ * ment array for this variable and return it's contents if found. Assume
+ * that the environment array is all upper case, at least for the key.
+ *
+ * RETURN:
+ * returns a pointer to data of type CHAR. Null if no var found.
+ */
+
+PCHAR
+FindInLocalEnv(
+ IN PCHAR Variable
+ )
+{
+ PCHAR Value = NULL;
+ PCHAR alpha;
+ ULONG count=0,i=0;
+
+ //
+ // set the incoming variable to all upper case...
+ //
+ alpha = VrCanonicalName(Variable);
+ debug(VRDBG_ENV, "FindInLocalEnv: Entry - Variable: '%s'\n",alpha);
+
+ //
+ // Run through the VrEnvp array looking for a match. Since the VrEnvp
+ // array should all be upper case values, we shouldn't need to worry
+ // about case.
+ //
+ while( VrEnvp[count] && *(VrEnvp[count]) ){
+
+ // Compare the capitalized version of the Variable passed in with
+ // each entry in the VrEnvp array for a length equal to the Variable
+ // less the null terminator.
+ //
+ if (!strncmp(VrEnvp[count], alpha, (strlen(alpha)-1))) {
+ // we've found our match. Now return pointer to this value
+ return(VrEnvp[count]+strlen(alpha));
+ }
+
+ //
+ // reset and try again
+ //
+ count++;
+ }
+
+ //
+ // if we fall out of the loop, it's because we didn't match anything.
+ //
+ return((PCHAR)NULL);
+}
+
+/*
+ * ROUTINE: GetEnvVar( PCHAR Variable )
+ *
+ * DESCRIPTION:
+ * This call is an internal only call that actually delves into the
+ * OpenFirmware to retrieve a value.
+ *
+ * RETURN:
+ * returns a pointer to data of type CHAR. Null if no var found. The
+ * returned value is the contents of the variable found.
+ */
+PCHAR
+GetEnvVar(
+ IN PCHAR Variable
+ )
+{
+ PCHAR Value = NULL;
+
+ debug(VRDBG_ENV, "GetEnvVar: Entry - Variable: '%s'\n",Variable);
+ if (OptionsPhandle == 0) {
+ VrEnvOpen();
+ }
+ Value= get_str_prop(OptionsPhandle, VrCanonicalName(Variable), NOALLOC);
+ return Value;
+}
+
diff --git a/private/ntos/boot/veneer/vrheader.h b/private/ntos/boot/veneer/vrheader.h
new file mode 100644
index 000000000..8f757bb1e
--- /dev/null
+++ b/private/ntos/boot/veneer/vrheader.h
@@ -0,0 +1,325 @@
+/*
+ * Copyright (c) 1995 FirePower Systems, Inc.
+ *
+ * $RCSfile: vrheader.h $
+ * $Revision: 1.10 $
+ * $Date: 1996/01/11 08:03:25 $
+ * $Locker: $
+ *
+ */
+
+/*
+ * From nt/public/sdk/inc/ntdef.h
+ */
+
+//
+// Physical address.
+//
+
+typedef LARGE_INTEGER PHYSICAL_ADDRESS, *PPHYSICAL_ADDRESS;
+
+//
+// Cardinal Data Types [0 - 2**N-2)
+//
+
+typedef char CCHAR; // winnt
+typedef short CSHORT;
+typedef ULONG CLONG;
+
+typedef CCHAR *PCCHAR;
+typedef CSHORT *PCSHORT;
+typedef CLONG *PCLONG;
+
+
+
+/*
+ * From nt/public/sdk/inc/ntconfig.h
+ */
+
+//
+// Defines the Type in the RESOURCE_DESCRIPTOR
+//
+
+typedef enum _CM_RESOURCE_TYPE {
+ CmResourceTypeNull = 0, // Reserved
+ CmResourceTypePort,
+ CmResourceTypeInterrupt,
+ CmResourceTypeMemory,
+ CmResourceTypeDma,
+ CmResourceTypeDeviceSpecific,
+ CmResourceTypeMaximum
+} CM_RESOURCE_TYPE;
+
+//
+// Defines the ShareDisposition in the RESOURCE_DESCRIPTOR
+//
+
+typedef enum _CM_SHARE_DISPOSITION {
+ CmResourceShareUndetermined = 0, // Reserved
+ CmResourceShareDeviceExclusive,
+ CmResourceShareDriverExclusive,
+ CmResourceShareShared
+} CM_SHARE_DISPOSITION;
+
+//
+// Define the bit masks for Flags when type is CmResourceTypeInterrupt
+//
+
+#define CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE 0
+#define CM_RESOURCE_INTERRUPT_LATCHED 1
+
+//
+// Define the bit masks for Flags when type is CmResourceTypeInterrupt
+//
+
+#define CM_RESOURCE_MEMORY_READ_WRITE 0
+#define CM_RESOURCE_MEMORY_READ_ONLY 1
+#define CM_RESOURCE_MEMORY_WRITE_ONLY 2
+
+//
+// Define the bit masks for Flags when type is CmResourceTypePort
+//
+
+#define CM_RESOURCE_PORT_MEMORY 0
+#define CM_RESOURCE_PORT_IO 1
+
+
+//
+// This structure defines one type of resource used by a driver.
+//
+// There can only be *1* DeviceSpecificData block. It must be located at
+// the end of all resource descriptors in a full descriptor block.
+//
+
+//
+// BUGBUG Make sure alignment is made properly by compiler; otherwise move
+// flags back to the top of the structure (common to all members of the
+// union).
+//
+
+#pragma pack(4)
+typedef struct _CM_PARTIAL_RESOURCE_DESCRIPTOR {
+ UCHAR Type;
+ UCHAR ShareDisposition;
+ USHORT Flags;
+ union {
+
+ //
+ // Range of port numbers, inclusive. These are physical, bus
+ // relative. The value should be the same as the one passed to
+ // HalTranslateBusAddress().
+ //
+
+ struct {
+ PHYSICAL_ADDRESS Start;
+ ULONG Length;
+ } Port;
+
+ //
+ // IRQL and vector. Should be same values as were passed to
+ // HalGetInterruptVector().
+ //
+
+ struct {
+ ULONG Level;
+ ULONG Vector;
+ ULONG Affinity;
+ } Interrupt;
+
+ //
+ // Range of memory addresses, inclusive. These are physical, bus
+ // relative. The value should be the same as the one passed to
+ // HalTranslateBusAddress().
+ //
+
+ struct {
+ PHYSICAL_ADDRESS Start; // 64 bit physical addresses.
+ ULONG Length;
+ } Memory;
+
+ //
+ // Physical DMA channel.
+ //
+
+ struct {
+ ULONG Channel;
+ ULONG Port;
+ ULONG Reserved1;
+ } Dma;
+
+ //
+ // Device Specific information defined by the driver.
+ // The DataSize field indicates the size of the data in bytes. The
+ // data is located immediately after the DeviceSpecificData field in
+ // the structure.
+ //
+
+ struct {
+ ULONG DataSize;
+ ULONG Reserved1;
+ ULONG Reserved2;
+ } DeviceSpecificData;
+ } u;
+} CM_PARTIAL_RESOURCE_DESCRIPTOR, *PCM_PARTIAL_RESOURCE_DESCRIPTOR;
+#pragma pack()
+
+//
+// A Partial Resource List is what can be found in the ARC firmware
+// or will be generated by ntdetect.com.
+// The configuration manager will transform this structure into a Full
+// resource descriptor when it is about to store it in the regsitry.
+//
+// Note: There must a be a convention to the order of fields of same type,
+// (defined on a device by device basis) so that the fields can make sense
+// to a driver (i.e. when multiple memory ranges are necessary).
+//
+
+typedef struct _CM_PARTIAL_RESOURCE_LIST {
+ USHORT Version;
+ USHORT Revision;
+ ULONG Count;
+ CM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptors[1];
+} CM_PARTIAL_RESOURCE_LIST, *PCM_PARTIAL_RESOURCE_LIST;
+
+//
+// Define the structures used to interpret configuration data of
+// \\Registry\machine\hardware\description tree.
+// Basically, these structures are used to interpret component
+// sepcific data.
+//
+
+//
+// Define DEVICE_FLAGS
+//
+
+typedef struct _DEVICE_FLAGS {
+ ULONG Failed : 1;
+ ULONG ReadOnly : 1;
+ ULONG Removable : 1;
+ ULONG ConsoleIn : 1;
+ ULONG ConsoleOut : 1;
+ ULONG Input : 1;
+ ULONG Output : 1;
+} DEVICE_FLAGS, *PDEVICE_FLAGS;
+
+//
+// Define Component Information structure
+//
+
+typedef struct _CM_COMPONENT_INFORMATION {
+ DEVICE_FLAGS Flags;
+ ULONG Version;
+ ULONG Key;
+ ULONG AffinityMask;
+} CM_COMPONENT_INFORMATION, *PCM_COMPONENT_INFORMATION;
+
+
+/*
+ * From nt/public/sdk/inc/ntppc.h
+ */
+
+#define KSEG0_BASE 0x00000000 /* ? 0x800000000 */
+
+
+/*
+ * From nt/private/ntos/inc/nthal.h
+ */
+
+//
+// Time conversion routines
+//
+
+typedef struct _TIME_FIELDS {
+ CSHORT Year; // range [1601...]
+ CSHORT Month; // range [1..12]
+ CSHORT Day; // range [1..31]
+ CSHORT Hour; // range [0..23]
+ CSHORT Minute; // range [0..59]
+ CSHORT Second; // range [0..59]
+ CSHORT Milliseconds;// range [0..999]
+ CSHORT Weekday; // range [0..6] == [Sunday..Saturday]
+} TIME_FIELDS;
+typedef TIME_FIELDS *PTIME_FIELDS;
+
+//
+// PowerPC page size = 4 KB
+//
+
+#define PAGE_SIZE (ULONG)0x1000
+
+//
+// Define the number of trailing zeroes in a page aligned virtual address.
+// This is used as the shift count when shifting virtual addresses to
+// virtual page numbers.
+//
+
+#define PAGE_SHIFT 12L
+
+//
+// The device data record for the Floppy peripheral.
+//
+
+typedef struct _CM_FLOPPY_DEVICE_DATA {
+ USHORT Version;
+ USHORT Revision;
+ CHAR Size[8];
+ ULONG MaxDensity;
+ ULONG MountDensity;
+ //
+ // New data fields for version >= 2.0
+ //
+ UCHAR StepRateHeadUnloadTime;
+ UCHAR HeadLoadTime;
+ UCHAR MotorOffTime;
+ UCHAR SectorLengthCode;
+ UCHAR SectorPerTrack;
+ UCHAR ReadWriteGapLength;
+ UCHAR DataTransferLength;
+ UCHAR FormatGapLength;
+ UCHAR FormatFillCharacter;
+ UCHAR HeadSettleTime;
+ UCHAR MotorSettleTime;
+ UCHAR MaximumTrackValue;
+ UCHAR DataTransferRate;
+} CM_FLOPPY_DEVICE_DATA, *PCM_FLOPPY_DEVICE_DATA;
+
+//
+// The device data record for the serial controller.
+//
+
+typedef struct _CM_SERIAL_DEVICE_DATA {
+ USHORT Version;
+ USHORT Revision;
+ ULONG BaudClock;
+} CM_SERIAL_DEVICE_DATA, *PCM_SERIAL_DEVICE_DATA;
+
+/*
+********************************************************************************
+**
+** The following is derived from fparch.h in the nthals\halfire\ppc
+** directory
+**
+**
+**
+********************************************************************************
+*/
+//
+// These names are not sacrosanct, and should be revised upon input from Susan,
+// Jim, and anyone else interested.
+//
+enum scope_use {
+ ENG,
+ MFG,
+ TEST,
+ CUST
+ };
+
+enum rel_state {
+ GENERAL,
+ OFFICIAL,
+ TESTING,
+ CONTROLLED,
+ LAB
+ };
+
+
diff --git a/private/ntos/boot/veneer/vrio.c b/private/ntos/boot/veneer/vrio.c
new file mode 100644
index 000000000..c0a1bd2ae
--- /dev/null
+++ b/private/ntos/boot/veneer/vrio.c
@@ -0,0 +1,1425 @@
+/*
+ *
+ * Copyright (c) 1995 FirePower Systems, Inc.
+ * Copyright (c) 1994 FirePower Systems Inc.
+ * Copyright (c) 1994 FirmWorks, Mountain View CA USA. All rights reserved.
+ *
+ * $RCSfile: vrio.c $
+ * $Revision: 1.9 $
+ * $Date: 1996/04/15 02:55:53 $
+ * $Locker: $
+ *
+ *
+ * Module Name:
+ * vrio.c
+ *
+ * Author:
+ * Shin Iwamoto at FirePower Systems Inc.
+ *
+ * History:
+ * 26-Sep-94 Shin Iwamoto at FirePower Systems Inc.
+ * Added checking SeekMode in VrSeek().
+ * 15-Sep-94 Shin Iwamoto at FirePower Systems Inc.
+ * Added saving the area pointed to by OpenPath in VrOpen().
+ * 15-Jul-94 Shin Iwamoto at FirePower Systems Inc.
+ * Added for XXX_SEEK_IS_BUSTED in VrSeek().
+ * 14-Jul-94 Shin Iwamoto at FirePower Systems Inc.
+ * Added ONE_IO_SIZE in VrRead() and VrWrite().
+ * 13-Jul-94 Shin Iwamoto at FirePower Systems Inc.
+ * Added ENOSPC checking in VrWrite().
+ * Added for reading ahead in VrGetReadStatus() and VrRead().
+ * 11-Jul-94 Shin Iwamoto at FirePower Systems Inc.
+ * Added some debugging facilities in VrOpen. These were
+ * from checked-in veneer source code.
+ * 16-Jun-94 Shin Iwamoto at FirePower Systems Inc.
+ * Added when a serial device doesn't read in VrRead().
+ * 15-Jun-94 Shin Iwamoto at FirePower Systems Inc.
+ * When OpenPath inclues console, the path is for a device.
+ * So, FilePath was set to null.
+ * 13-Jun-94 Shin Iwamoto at FirePower Systems Inc.
+ * Added debugging statements.
+ * Modified some porting from Mike Tooch at FirmWorks.
+ * 18-May-94 Shin Iwamoto at FirePower Systems Inc.
+ * Added for unsinged long size in VrWrite.
+ * Added a part of VrMount.
+ * Added that DirectoryFile flag is ignored in
+ * VrSetFileInformation().
+ * Added for Delete flag in FileTable in
+ * VrRead(), VrWrite(), VrSeek(), VrGetReadStatus()
+ * Added some comments.
+ * and VrSetFileInformation().
+ * 17-May-94 Shin Iwamoto at FirePower Systems Inc.
+ * Added for NetworkDevice in GetDeviceAttribute().
+ * Added for unsinged long size in VrRead.
+ * 12-May-94 Shin Iwamoto at FirePower Systems Inc.
+ * Changed the name, strlen and strncmp to
+ * VfStrlen and VfStrncmp.
+ * 11-May-94 Shin Iwamoto at FirePower Systems Inc.
+ * Added FIleTable. Changed rootnode to RootNode.
+ * Put cast PCAHR to the first parameter of bzero.
+ * Changed OFPhandle to OfPhandle.
+ * Changed the name of VrFindCOnfigurationNode.
+ * 10-May-94 Shin Iwamoto at FirePower Systems Inc.
+ * Changed Vr{Open|Close|Read|Write|Seek} because of
+ * changing the file table structure.
+ * 05-May-94 Shin Iwamoto at FirePower Systems Inc.
+ * Created.
+ *
+ */
+
+
+#include "veneer.h"
+
+//
+// Some switches
+//
+
+#define MAX_OPEN_PATH_SIZE MAX_PATH_NAME_SIZE
+#define ONE_IO_SIZE 1024*1024
+
+#define ZERO_LARGE 0
+#define NOT_ZERO_LARGE 1
+
+#define Minimum(X,Y) ((X) < (Y) ? (X) : (Y))
+
+
+//
+// File Table definition
+//
+FILE_TABLE_ENTRY FileTable[FILE_TABLE_SIZE];
+
+
+//
+// Function declarations
+//
+STATIC ARC_STATUS
+GetFileTableEntry(
+ OUT PULONG
+ );
+STATIC ARC_STATUS
+GetDeviceAttribute(
+ IN ULONG,
+ IN PCONFIGURATION_NODE
+ );
+STATIC VOID
+AddLargeInt(
+ PLARGE_INTEGER,
+ PLARGE_INTEGER
+ );
+STATIC VOID
+MoveLargeInt(
+ PLARGE_INTEGER,
+ PLARGE_INTEGER
+ );
+STATIC LONG
+IsLarge(
+ PLARGE_INTEGER
+ );
+STATIC VOID
+DecrementLarge(
+ PLARGE_INTEGER
+ );
+
+
+
+/*
+ * Name: VrOpen
+ *
+ * Description:
+ * This function opens the file specified by OpenPath.
+ * The pathname is translated into the devicename for Open Firmware,
+ * then OFOpen is called with the devicename.
+ *
+ * Arguments:
+ * OpenPath - ARC compliant pathname of the device/file to be opened.
+ * OpenMode - Supplies the mode in which the file is opened.
+ * FileId - Pointer to a variable that receives the fileid for
+ * this pathname.
+ *
+ * Return Value:
+ * If the file is successfully opened returns ESUCCESS otherwise
+ * returns an unsuccessful status.
+ *
+ */
+ARC_STATUS
+VrOpen(
+ IN PCHAR OpenPath,
+ IN OPEN_MODE OpenMode,
+ OUT PULONG FileId
+ )
+{
+ PCHAR FilePath, DevicePath, Partition, Console;
+ ihandle IHandle;
+ ARC_STATUS Status;
+ PCONFIGURATION_NODE ConfNode;
+ PCHAR pstr1;
+ LONG DevSpecLen;
+
+ debug(VRDBG_OPEN, "VrOpen: Entry - Path: %s Mode: %x\n",
+ OpenPath, OpenMode);
+
+ if (strlen(OpenPath) >= MAX_OPEN_PATH_SIZE) {
+ debug(VRDBG_OPEN, "VrOpen: ENAMETOOLONG: '%s'\n", OpenPath);
+ return ENAMETOOLONG;
+ }
+
+ //
+ // Find Partition, Console and FilePath in OpenPath.
+ //
+ FilePath = NULL;
+ Partition = NULL;
+ Console = NULL;
+ for (pstr1 = OpenPath; *pstr1; pstr1++) {
+ if (strncmp(pstr1, "partition", 9) == 0) {
+ Partition = pstr1;
+ while (*pstr1++ != ')') {
+ ;
+ }
+ FilePath = pstr1;
+ break;
+ } else if (strncmp(pstr1, "console", 7) == 0) {
+ Console = pstr1;
+ while (*pstr1++ != ')') {
+ ;
+ }
+ if (*pstr1 != '\0') {
+ return EINVAL;
+ }
+ FilePath = NULL; // Console is a device.
+ break;
+ }
+ else if (*pstr1 == ')') {
+ FilePath = pstr1+1;
+ }
+ }
+ //
+ // Did we eventually wind up with a FilePath after all?
+ //
+ if ((FilePath != NULL) && (strlen(FilePath) == 0)) {
+ FilePath = NULL;
+ }
+ debug(VRDBG_OPEN, "VrOpen: Partition '%s' FilePath '%s'\n",
+ Partition == NULL ? "NULL" : Partition,
+ FilePath == NULL ? "NULL" : FilePath);
+
+ //
+ // Check open mode for a device.
+ //
+ if ((FilePath == NULL) && (OpenMode > ArcOpenReadWrite)) {
+ debug(VRDBG_OPEN, "VrOpen: EINVAL: '%s'\n", OpenPath);
+ return EINVAL;
+ }
+
+ //
+ // Extract the device name from OpenPath.
+ //
+ ConfNode = ArcPathToNode(OpenPath);
+ if (ConfNode == NULL) {
+ debug(VRDBG_OPEN, "VrOpen: ENODEV: '%s'\n", OpenPath);
+ return ENODEV;
+ }
+
+ //
+ // Translate the device name into the device path for Open Firmware.
+ // Add space for the partition and file components.
+ //
+ pstr1 = NodeToPath(ConfNode);
+ DevSpecLen = strlen(pstr1) + 16; // Enough for a partition specifier.
+ if (FilePath != NULL) {
+ DevSpecLen += strlen(FilePath);
+ }
+ DevicePath = zalloc(DevSpecLen);
+ strcpy(DevicePath, pstr1);
+ free(pstr1);
+
+ //
+ // Get a free entry in the file table.
+ //
+ if (Status = GetFileTableEntry(FileId)) {
+ debug(VRDBG_OPEN, "VrOpen: GetFileTableEntry returned %x\n", Status);
+ return Status;
+ }
+
+ //
+ // Set flags in the FileTable.
+ //
+ if (Status = GetDeviceAttribute(*FileId, ConfNode)) {
+ debug(VRDBG_OPEN, "VrOpen: GetDeviceAttribute returned %x\n", Status);
+ return Status;
+ }
+
+ if ((Partition == NULL) && (FilePath == NULL)) { // A device (not file)
+ FileTable[*FileId].Flags.Device = 1;
+ strcat(DevicePath, ":0");
+ } else { // A file (not a device)
+ //
+ // Convert the partition and the filename (if they exist) as follows:
+ //
+ // [partition(key1)][<filepath>]
+ // --> :[key1][,<filepath>]
+ //
+ strcat(DevicePath, ":");
+ if (Partition != NULL) {
+ FileTable[*FileId].Flags.Partition = (FilePath == NULL);
+ pstr1 = Partition;
+ while (*pstr1++ != '(') {
+ ;
+ }
+ if (*pstr1 == ')') {
+ strcat(DevicePath, "0");
+ } else {
+ PCHAR pstr2;
+
+ pstr2 = DevicePath + strlen(DevicePath);
+ do {
+ *pstr2++ = *pstr1++;
+ } while (*pstr1 != ')');
+ *pstr2 = '\0';
+ }
+ }
+ if (FilePath != NULL) {
+ strcat(DevicePath, ",");
+ strcat(DevicePath, FilePath);
+ }
+ }
+
+ //
+ // Now we can open the device path (including the file path).
+ //
+ IHandle = OFOpen(DevicePath);
+ debug(VRDBG_OPEN, "OFOpen: IHandle: %x\n", IHandle);
+ FileTable[*FileId].PathName = DevicePath;
+
+ //
+ // Checking related to OpenMode.
+ //
+ switch (OpenMode) {
+ case ArcCreateWriteOnly:
+ case ArcCreateReadWrite:
+ if (IHandle != 0) {
+ (VOID)OFClose(IHandle);
+ return EACCES;
+ }
+ break;
+ default:
+ if (IHandle == 0) {
+ return EIO;
+ }
+ }
+
+ FileTable[*FileId].Flags.Open = 1;
+ FileTable[*FileId].IHandle = IHandle;
+
+ debug(VRDBG_OPEN, "VrOpen: Exit - FileId: %d IHandle: %x\n",
+ *FileId, IHandle);
+
+ return ESUCCESS;
+}
+
+
+/*
+ * Name: VrClose
+ *
+ * Description:
+ * This function closes a file or a device if it is opened.
+ *
+ * Arguments:
+ * FileId - Supplies the file table index.
+ *
+ * Return Value:
+ * If the specified file is open, then a close is attempted via
+ * OFClose and ESUCCESS is returned. Otherwise, return an unsuccessful
+ * status.
+ *
+ */
+ARC_STATUS
+VrClose(
+ IN ULONG FileId
+ )
+{
+ debug(VRDBG_OPEN, "VrClose: Entry - FileId: %d\n", FileId);
+
+ if (FileId >= FILE_TABLE_SIZE) {
+ return EBADF;
+ }
+ if (FileTable[FileId].Flags.Open != 1) {
+ return EACCES;
+ }
+
+ //
+ // Close the file.
+ //
+ (VOID)OFClose(FileTable[FileId].IHandle);
+
+ //
+ // Release the file table entry.
+ //
+ // FileTable[FileId].Flags.Open = 0;
+ bzero((PCHAR)&FileTable[FileId], sizeof(FILE_TABLE_ENTRY));
+ free(FileTable[FileId].PathName);
+
+ debug(VRDBG_OPEN, "VrClose: Exit\n");
+
+ return ESUCCESS;
+}
+
+
+/*
+ * Name: VrRead
+ *
+ * Description:
+ * This function reads data from the device of file specified by FileId
+ * into the buffer pointed to by Buffer.
+ *
+ * Arguments:
+ * FileId - Supplies the file table index.
+ * Buffer - Supplies a pointer to the buffer that receives the read
+ * data.
+ * Length - Supplies the maximum number of bytes to be read.
+ * If this field contains the value zero, then no bytes
+ * are read.
+ * Count - Supplies a pointer to a variable that receives the number
+ * of bytes actually transfered.
+ *
+ * Return Value:
+ * If the specified file is open for read, then a read is attempted
+ * and the status of the operation is retuned. Otherwise, return
+ * an unsuccessful status.
+ *
+ */
+
+STATIC CHAR consin_readahead = 0;
+
+ARC_STATUS
+VrRead(
+ IN ULONG FileId,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ )
+{
+ LARGE_INTEGER LInteger;
+ PCHAR buf = (PCHAR) Buffer;
+
+ if (FileId == 0) { // stdin
+ if (consin_readahead) {
+ *buf = consin_readahead;
+ consin_readahead = 0;
+ *Count = 1;
+ } else {
+ if (ConsoleIn == 0) {
+ (void) VrFindConsolePath("stdin");
+ }
+ while (((LONG)*Count = OFRead(ConsoleIn, Buffer, Length)) <= 0){
+ ;
+ }
+ }
+ return ESUCCESS;
+ }
+
+ debug(VRDBG_RDWR, "VrRead: Entry - FileId: %d Buf: %x len: %d\n",
+ FileId, Buffer, Length);
+
+ //
+ // If Length is zero, return as if the function were successful.
+ //
+ if (Length == 0) {
+ *Count = 0;
+ return ESUCCESS;
+ }
+ if (FileId == 1) {
+ return EBADF;
+ }
+
+ if (FileId >= FILE_TABLE_SIZE) {
+ return EBADF;
+ }
+ if (!(FileTable[FileId].Flags.Open == 1
+ && FileTable[FileId].Flags.Read == 1)) {
+ return EACCES;
+ }
+ if (FileTable[FileId].Flags.Delete == 1) {
+ return EACCES;
+ }
+
+#ifdef NO_UNSIGNED_LONG_IO
+ //
+ // Calls the read routine.
+ //
+ (LONG)*Count = OFRead(FileTable[FileId].IHandle, Buffer, Length);
+ if ((LONG)*Count == -1) {
+ return EIO; // XXXX
+ }
+
+#else // NO_UNSIGNED_LONG_IO
+ //
+ // Initialize Counter.
+ //
+ *Count = 0;
+
+ //
+ // Checking read ahead buffer. If already read, the copy the buffer
+ // into Buffer.
+ //
+ if (FileTable[FileId].ReadAheadCount != 0) {
+ *Count = FileTable[FileId].ReadAheadCount;
+ bcopy(FileTable[FileId].ReadAheadBuffer, Buffer, *Count);
+ Buffer = (PCHAR)Buffer + *Count;
+ Length -= *Count;
+ FileTable[FileId].ReadAheadCount = 0;
+ }
+
+ //
+ // Calls the read routine.
+ //
+ while (Length > 0) {
+ LONG SingleReadSize;
+ LONG ReadCount;
+
+ SingleReadSize = Minimum(Length, ONE_IO_SIZE);
+ ReadCount = OFRead(FileTable[FileId].IHandle, Buffer, SingleReadSize);
+ if (ReadCount == -1) {
+ LONG Status;
+
+ //
+ // If an error in the second or later read happes,
+ // the offset must be put back using OFSeek.
+ // In reading ahead, this is useful.
+ //
+ if (*Count != 0) {
+ Status = OFSeek(FileTable[FileId].IHandle,
+ FileTable[FileId].Position.HighPart,
+ FileTable[FileId].Position.LowPart);
+ //
+ // Ignore Status.
+ //
+ }
+ return EIO; // XXXX
+ }
+
+ //
+ // Retry to read, when the device is serial and there is no data.
+ //
+ if ((ReadCount == -2) && (*Count == 0)) {
+ continue;
+ }
+
+ //
+ // Update the number of bytes read successfully.
+ //
+ *Count += ReadCount;
+
+ //
+ // If the device represented by FileId is a network device,
+ // read one time. If not yet read, continue.
+ //
+ if (FileTable[FileId].Flags.NetworkDevice == 1) {
+ if ((ReadCount == 0) && (*Count == 0)) {
+ continue;
+ }
+ return ESUCCESS;
+ }
+
+ //
+ // Find EOF, then break this loop.
+ //
+ if (ReadCount < SingleReadSize) {
+ break;
+ }
+
+ //
+ // Update the remaining length and the buffer to point to
+ // the next position.
+ //
+ Length -= SingleReadSize;
+ Buffer = (PCHAR)Buffer + SingleReadSize;
+ }
+#endif // NO_UNSIGNED_LONG_IO
+
+ //
+ // Calculates the position of the file.
+ //
+ LInteger.HighPart = 0;
+ LInteger.LowPart = *Count;
+ AddLargeInt(&FileTable[FileId].Position, &LInteger);
+
+ debug(VRDBG_RDWR, "VrRead: Exit ReadCount: %d\n", *Count);
+
+ return ESUCCESS;
+}
+
+
+/*
+ * Name: VrWrite
+ *
+ * Description:
+ * This function writes data from memory starting from the buffer
+ * pointed to by Buffer to the device specified by FileId.
+ * Upon completion of a successful write, the byte offset for FileId
+ * is updated; otherwise the byte offset is left unchanged.
+ *
+ * Arguments:
+ * FileId - Supplies the file table index.
+ * Buffer - Supplies a pointer to the buffer that contains
+ * the write data.
+ * Length - Supplies the number of bytes to be written.
+ * Count - Supplies a pointer to a variable that contains
+ * the number of bytes actually transfered.
+ *
+ * Return Value:
+ * If the specified file is open for write, then a write is attempted
+ * using OFWrite and a status is returned. Otherwise, return
+ * an unsuccessful status.
+ *
+ */
+ARC_STATUS
+VrWrite(
+ IN ULONG FileId,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ )
+{
+ LARGE_INTEGER LInteger;
+ ARC_STATUS Status;
+
+ if (FileId == 1) { // stdout
+ *Count = OFWrite(ConsoleOut, Buffer, Length);
+ return ESUCCESS;
+ }
+
+ debug(VRDBG_RDWR, "VrWrite: Entry - FileId: %d Buf: %x len: %d\n",
+ FileId, Buffer, Length);
+
+ //
+ // If Length is zero, return as if the function were successful.
+ //
+ if (Length == 0) {
+ *Count = 0;
+ return ESUCCESS;
+ }
+ if (FileId == 0) {
+ return EBADF;
+ }
+
+ if (FileId >= FILE_TABLE_SIZE) {
+ return EBADF;
+ }
+ if (!(FileTable[FileId].Flags.Open == 1
+ && FileTable[FileId].Flags.Write == 1)) {
+ return EACCES;
+ }
+ if (FileTable[FileId].Flags.Delete == 1) {
+ return EACCES;
+ }
+
+ //
+ // If Length bytes cannot be placed into a network packet,
+ // return ENOSPC without sending the packet, placing the number of bytes
+ // that could be written in Count.
+ //
+ if (FileTable[FileId].Flags.NetworkDevice == 1) {
+ ULONG MaxFrameSize;
+
+ MaxFrameSize = get_int_prop(OFFinddevice(FileTable[FileId].PathName),
+ "max-frame-size");
+ if (Length > MaxFrameSize) {
+ *Count = MaxFrameSize;
+ return ENOSPC;
+ }
+ }
+
+#ifdef NO_UNSIGNED_LONG_IO
+ //
+ // Calls the write routine.
+ //
+ Status = ESUCCESS;
+ (LONG)*Count = OFWrite(FileTable[FileId].IHandle, Buffer, Length);
+ if ((LONG)*Count == -1) {
+ return EIO; // XXXX
+ }
+
+#else // NO_UNSIGNED_LONG_IO
+
+ Status = ESUCCESS;
+ *Count = 0;
+ while (Length > 0) {
+ LONG SingleWriteSize;
+ LONG WriteCount;
+
+ SingleWriteSize = Minimum(Length, ONE_IO_SIZE);
+ WriteCount = OFWrite(FileTable[FileId].IHandle, Buffer,
+ SingleWriteSize);
+ if (WriteCount == -1) {
+ LONG SeekStatus;
+
+ //
+ // If an error in the second or later read happens,
+ // the offset must be put back using OFSeek.
+ //
+ if (*Count != 0) {
+ SeekStatus = OFSeek(FileTable[FileId].IHandle,
+ FileTable[FileId].Position.HighPart,
+ FileTable[FileId].Position.LowPart);
+ //
+ // Ignore Status.
+ //
+ }
+ return EIO; // XXXX
+ }
+
+ //
+ // Update the number of bytes written successfully.
+ //
+ *Count += WriteCount;
+
+ //
+ // If the device represented by FileId is a network device,
+ // write one time. If not yet written, continue.
+ //
+ if (FileTable[FileId].Flags.NetworkDevice == 1) {
+ if (WriteCount == 0) {
+ continue;
+ }
+ return ESUCCESS;
+ }
+
+ //
+ // Find that the device is full.
+ //
+ if (WriteCount < SingleWriteSize) {
+ Status = ENOSPC;
+ break;
+ }
+
+ //
+ // Update the remaining length and the buffer to point to
+ // the next position.
+ //
+ Length -= SingleWriteSize;
+ Buffer = (PCHAR)Buffer + SingleWriteSize;
+ }
+#endif // NO_UNSIGNED_LONG_IO
+
+ //
+ // Calculates the position of the file.
+ //
+ LInteger.HighPart = 0;
+ LInteger.LowPart = *Count;
+ AddLargeInt(&FileTable[FileId].Position, &LInteger);
+
+ if (FileId >= 2) {
+ debug(VRDBG_RDWR, "VrWrite: Exit WrtCount: %d, Status: %d\n",
+ *Count, Status);
+ }
+
+ return Status;
+}
+
+
+/*
+ * Name: VrMount
+ *
+ * Description:
+ * This function is used to load and unload media for devices that
+ * support removale media.
+ *
+ * Arguments:
+ * MountPath - Supplies a pointer to the variable that contains
+ * the path of the device.
+ * Operation - Supplies a indication whether the media is to be
+ * loaded or unloaded.
+ *
+ * Return Value:
+ * If the specified path is for device, then a mount is attempted
+ * a status is returned. Otherwise, return an unsuccessful status.
+ *
+ */
+ARC_STATUS
+VrMount(
+ IN PCHAR MountPath,
+ IN MOUNT_OPERATION Operation
+ )
+{
+ PCONFIGURATION_NODE ConfNode;
+ PCHAR FilePath, pstr1;
+
+ debug(VRDBG_OPEN, "VrMount: Entry - MountPath: %s Operation: %d\n",
+ MountPath, Operation);
+
+ //
+ // Check that the MountPath is a device.
+ //
+ FilePath = MountPath;
+ for (pstr1 = MountPath; *pstr1; pstr1++) {
+ if (strncmp(pstr1, "partition", 9) == 0) {
+ return EINVAL;
+ } else if (strncmp(pstr1, "console", 7) == 0) {
+ return EINVAL;
+ } else if (*pstr1 == ')') {
+ FilePath = pstr1+1;
+ }
+ }
+ if (FilePath == MountPath || FilePath[0] != '\0') {
+ return EINVAL;
+ }
+
+ //
+ // Find the configuration node using the MountPath.
+ //
+ ConfNode = ArcPathToNode(MountPath);
+ if (ConfNode == NULL) {
+ return ENOENT;
+ }
+
+ //
+ // Check that the device is removable.
+ //
+ if (!(ConfNode->Component.Flags.Removable)) {
+ return ENOENT; // XXXX
+ }
+
+ //
+ // Translate the device name into the device path for Open Firmware.
+ //
+ // XXXX
+ // How do I mount/unmount ?
+ // If Operation is MountUnloadMedia for not mounted device,
+ // return ENXIO;
+
+ debug(VRDBG_OPEN, "VrMount: Exit\n");
+
+ return ESUCCESS;
+}
+
+
+/*
+ * Name: VrSeek
+ *
+ * Description:
+ * This function changes the byte offset associated with the device,
+ * partition, or file specified by FileId.
+ *
+ * Arguments:
+ * FileId - Supplies the file table index.
+ * Offset - Supplies a poiner to a structure that contains
+ * the offset value.
+ * SeekMode - Supplies the type of positioning to be performed.
+ *
+ * Return Value:
+ * If the specified file is open, then a seek is attempted and
+ * the status of the operation is returned. Otherwise, return
+ * an unsuccessful status.
+ *
+ */
+ARC_STATUS
+VrSeek(
+ IN ULONG FileId,
+ IN PLARGE_INTEGER Offset,
+ IN SEEK_MODE SeekMode
+ )
+{
+ LONG Status;
+
+ debug(VRDBG_RDWR, "VrSeek: Entry - FileId: %d Offset: %x.%x Mode: %x\n",
+ FileId, Offset->HighPart, Offset->LowPart, SeekMode);
+
+ if (FileId >= FILE_TABLE_SIZE) {
+ return EBADF;
+ }
+ if (FileTable[FileId].Flags.Open != 1) {
+ return EACCES;
+ }
+ if (FileTable[FileId].Flags.Delete == 1) {
+ return EACCES;
+ }
+ if (!(SeekMode == SeekRelative || SeekMode == SeekAbsolute)) {
+ return EINVAL;
+ }
+
+ //
+ // If the specified device is Network, only set Offset into FileTable
+ // because the Offset is interpreted to be a count of input to ignore.
+ // The offset is cleared after reading the input packet.
+ //
+ if (FileTable[FileId].Flags.NetworkDevice == 1) {
+ (VOID)MoveLargeInt(&FileTable[FileId].Position, Offset);
+ return ESUCCESS;
+ }
+
+ //
+ // Set the file position according to SeekMode.
+ //
+ if (SeekMode == SeekRelative) {
+ (VOID)AddLargeInt(&FileTable[FileId].Position, Offset);
+ } else {
+ (VOID)MoveLargeInt(&FileTable[FileId].Position, Offset);
+ }
+
+ //
+ // If FileId is for Network device, the input packets are ignored
+ // according to Offset and then return with ESUCCESS.
+ //
+ if (FileTable[FileId].Flags.NetworkDevice == 1) {
+ while (IsLarge(&FileTable[FileId].Position) == NOT_ZERO_LARGE) {
+ LONG ReadSize;
+ CHAR Buffer[4];
+
+ if ((ReadSize = OFRead(FileTable[FileId].IHandle, Buffer, 1))
+ == -1) {
+ return EIO;
+ }
+ if (ReadSize == 0) {
+ continue;
+ }
+ DecrementLarge(&FileTable[FileId].Position);
+ }
+ return ESUCCESS;
+ }
+
+ Status = OFSeek(FileTable[FileId].IHandle,
+ FileTable[FileId].Position.HighPart,
+ FileTable[FileId].Position.LowPart);
+ if (Status == -1) {
+ return EINVAL; // XXXX
+ }
+
+ debug(VRDBG_RDWR, "VrSeek: Exit\n");
+
+ return ESUCCESS;
+}
+
+
+/*
+ * Name: VrGetDirectoryEntry
+ *
+ * Description:
+ * This function reads directory entries from the system partition
+ * directory file specified by FileId.
+ *
+ * Arguments:
+ * FileId - Supplies the file table index.
+ * Buffer - Supplies a pointer to a buffer for the entry data.
+ * Length - Supplies the number of entries to retrieve.
+ * Count - Supplies a pointeer to the number of entries read
+ * into the buffer.
+ *
+ * Return Value:
+ * If the specified file is open for read, then the read is attempted
+ * and the status is returned. Otherwise, retrun an unsuccessful status.
+ *
+ */
+ARC_STATUS
+VrGetDirectoryEntry(
+ IN ULONG FileId,
+ OUT PDIRECTORY_ENTRY Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ )
+{
+ debug(VRDBG_OPEN, "VrGetDirectoryEntry: Entry - FileId: %d Length: %d\n",
+ FileId, Length);
+
+ if (FileId >= FILE_TABLE_SIZE) {
+ return EBADF;
+ }
+ if (FileTable[FileId].Flags.Device) {
+ return ENOTDIR;
+ }
+ if (!(FileTable[FileId].Flags.Open == 1
+ && FileTable[FileId].Flags.Read == 1)) {
+ return EBADF;
+ }
+
+ // XXXX
+ // Get Director Entry if (FileID != directory) return ENOTDIR;
+
+ debug(VRDBG_OPEN, "VrGetDirectoryEntry: Exit\n");
+
+ return ESUCCESS;
+}
+
+
+/*
+ * Name: VrGetFileInformation
+ *
+ * Description:
+ * This function retunrs an information structure about the specified
+ * file or partition.
+ *
+ * Arguments:
+ * FileId - Supplies the file table index.
+ * FileInformation - Supplies a pointer to the location of the file
+ * information data.
+ *
+ * Return Value:
+ * If the specified file is open, then getting the file information is
+ * attempted and the status is returned. Otherwise, retrun an unsuccessful
+ * status.
+ *
+ */
+ARC_STATUS
+VrGetFileInformation(
+ IN ULONG FileId,
+ OUT PFILE_INFORMATION pFI
+ )
+{
+ PFILE_TABLE_ENTRY fte;
+ ihandle ih;
+ PCONFIGURATION_NODE node;
+ ULONG size_thang[2];
+
+ debug(VRDBG_OPEN, "VrGetFileInformation: Entry - FileId: %d\n", FileId);
+
+ if (FileId >= FILE_TABLE_SIZE) {
+ debug(VRDBG_OPEN, "VrGetFileInformation: Exit EBADF\n");
+ return EBADF;
+ }
+ fte = &FileTable[FileId];
+ if (fte->Flags.Open != 1) {
+ debug(VRDBG_OPEN, "VrGetFileInformation: Exit EACCES\n");
+ return EACCES;
+ }
+ if (fte->Flags.Device == 1) {
+ debug(VRDBG_OPEN, "VrGetFileInformation: Exit EINVAL\n");
+ return EINVAL;
+ }
+
+ ih = fte->IHandle;
+ node = InstanceToNode(ih);
+ pFI->CurrentPosition = fte->Position;
+ pFI->Type = node->Component.Type;
+
+ (void) OFCallMethod(2, 2, size_thang, "size", ih);
+ pFI->EndingAddress.HighPart = size_thang[0];
+ pFI->EndingAddress.LowPart = size_thang[1];
+
+ if (fte->Flags.Partition == 1) {
+ (void) OFCallMethod( 1, 2, &(pFI->StartingAddress.HighPart),
+ "offset-high", ih);
+ (void) OFCallMethod( 1, 2, &(pFI->StartingAddress.LowPart),
+ "offset-low", ih);
+ AddLargeInt(&pFI->EndingAddress, &pFI->StartingAddress);
+ pFI->FileName[0] = '\0';
+ pFI->FileNameLength = 0;
+ } else {
+ /*
+ * It's a file.
+ */
+ pFI->StartingAddress.HighPart = 0;
+ pFI->StartingAddress.LowPart = 0;
+ strcpy(pFI->FileName, fte->PathName); // XXX s.b. strncpy(&,&,32)
+ pFI->FileNameLength = strlen(fte->PathName) + 1;
+ }
+#ifdef XXX
+ pFI->Attributes = // Get this from the firmware, somehow.
+#endif
+ debug(VRDBG_OPEN, "VrGetFileInformation:\n");
+ debug(VRDBG_OPEN, "\tStarting %x.%x\n", pFI->StartingAddress.HighPart,
+ pFI->StartingAddress.LowPart);
+ debug(VRDBG_OPEN, "\tEnding %x.%x\n", pFI->EndingAddress.HighPart,
+ pFI->EndingAddress.LowPart);
+ debug(VRDBG_OPEN, "\tCurrent %x.%x\n", pFI->CurrentPosition.HighPart,
+ pFI->CurrentPosition.LowPart);
+ debug(VRDBG_OPEN, "\tType %d FileNameLength %d\n", pFI->Type,
+ pFI->FileNameLength);
+ debug(VRDBG_OPEN, "\tFileName '%s'\n",
+ pFI->FileNameLength ? pFI->FileName : "NULL");
+ return ESUCCESS;
+}
+
+/*
+ * Name: VrGetReadStatus
+ *
+ * Description:
+ * This function determines if any bytes would be returned if a read
+ * operation were performed on FileId.
+ *
+ * Arguments:
+ * FileId - Supplies the file table index.
+ *
+ * Return Value:
+ * If the specified file is open, then the getting read status is
+ * attempted and the status is returned. Otherwise, retrun an unsuccessful
+ * status.
+ *
+ */
+ARC_STATUS
+VrGetReadStatus(
+ IN ULONG FileId
+ )
+{
+ LONG Count;
+
+ if (FileId == 0) { // stdin
+ if (consin_readahead != 0) {
+ return (ESUCCESS);
+ }
+ if (ConsoleIn == 0) {
+ (void) VrFindConsolePath("stdin");
+ }
+ if (OFRead(ConsoleIn, &consin_readahead, 1) != 1) {
+ return (EAGAIN);
+ }
+ return (ESUCCESS);
+ }
+
+ debug(VRDBG_RDWR, "VrGetReadStatus: Entry - FileId: %d\n", FileId);
+
+ if (FileId >= FILE_TABLE_SIZE) {
+ return EBADF;
+ }
+ if (!(FileTable[FileId].Flags.Open == 1
+ && FileTable[FileId].Flags.Read == 1)) {
+ return EACCES;
+ }
+ if (FileTable[FileId].Flags.Delete == 1) {
+ return EACCES;
+ }
+
+ //
+ // Try to read one byte.
+ //
+ Count = OFRead(FileTable[FileId].IHandle,
+ FileTable[FileId].ReadAheadBuffer,
+ 1);
+ if (Count != 1) {
+ FileTable[FileId].ReadAheadCount = 0; // For safety.
+ debug(VRDBG_RDWR, "VrGetReadStatus: Exit - with EAGAIN\n");
+ return EAGAIN;
+ }
+
+ //
+ // Now read ahead one byte.
+ //
+ FileTable[FileId].ReadAheadCount = 1;
+
+ if (FileId >= 2) {
+ debug(VRDBG_RDWR, "VrGetReadStatus: Exit\n");
+ }
+
+ return ESUCCESS;
+}
+
+
+/*
+ * Name: VrSetFileInformation
+ *
+ * Description:
+ * This function sets the file attributes for the specified FileId.
+ *
+ * Arguments:
+ * FileId - Supplies the file table index.
+ * AttributeFlags - Supplies the attributes to be set for the file.
+ * AttributeMask - Supplies the attribute Mask.
+ *
+ * Return Value:
+ * If the specified file is open, then the setting file information is
+ * attempted and the status is returned. Otherwise, retrun an unsuccessful
+ * status.
+ *
+ */
+ARC_STATUS
+VrSetFileInformation(
+ IN ULONG FileId,
+ IN ULONG AttributeFlags,
+ IN ULONG AttributeMask
+ )
+{
+ debug(VRDBG_OPEN, "VrSetFileInformation: Entry - FileId: %d AttributeFlags: %x AttributeMask: %x\n",
+ FileId, AttributeFlags, AttributeMask);
+
+ if (FileId >= FILE_TABLE_SIZE) {
+ return EBADF;
+ }
+ if (!(FileTable[FileId].Flags.Open == 1)) {
+ return EACCES;
+ }
+ if (FileTable[FileId].Flags.Device == 1) {
+ return EINVAL;
+ }
+
+ //
+ // The attribute DirectoryFile is ignored for this function.
+ //
+ AttributeMask &= ~ArcDirectoryFile;
+
+ //
+ // A file is marked for deletion by setting the DeleteFile flag
+ // in voth the AttributeFlags and AttributeMask parameters.
+ // In this case, the file can be access only by Close().
+ //
+ if ((AttributeMask & ArcDeleteFile) && (AttributeFlags & ArcDeleteFile)) {
+
+ //
+ // When the file is a derectroy which is not empty or a read-only file,
+ // EACCESS is retuned.
+ //
+ // XXXX not empy check is needed
+ //
+ if (!(FileTable[FileId].Flags.Read == 1
+ && FileTable[FileId].Flags.Write == 0)) {
+ return EACCES;
+ }
+
+
+ FileTable[FileId].Flags.Delete = 1;
+ }
+
+ // XXX return OFSetFileInformation(FileId, Buffer, Length, Count);
+
+ debug(VRDBG_OPEN, "VrSetFileInformation: Exit\n");
+ return(ESUCCESS);
+}
+
+
+/*
+ * Name: VrIoInitialize
+ *
+ * Description:
+ * This function initializes the I/O entry points in the firmware
+ * transfer vector and the file table.
+ *
+ * Arguments:
+ * None.
+ *
+ * Return Value:
+ * None.
+ *
+ */
+VOID
+VrIoInitialize(
+ VOID
+ )
+{
+ ULONG Index;
+
+ //
+ // Initialize the I/O entry points in the firmware transfer vector.
+ //
+ debug(VRDBG_ENTRY, "VrIoInitialize BEGIN......\n");
+ (PARC_CLOSE_ROUTINE) SYSTEM_BLOCK->FirmwareVector[CloseRoutine] = VrClose;
+ (PARC_MOUNT_ROUTINE) SYSTEM_BLOCK->FirmwareVector[MountRoutine] = VrMount;
+ (PARC_OPEN_ROUTINE) SYSTEM_BLOCK->FirmwareVector[OpenRoutine] = VrOpen;
+ (PARC_READ_ROUTINE) SYSTEM_BLOCK->FirmwareVector[ReadRoutine] = VrRead;
+ (PARC_SEEK_ROUTINE) SYSTEM_BLOCK->FirmwareVector[SeekRoutine] = VrSeek;
+ (PARC_WRITE_ROUTINE) SYSTEM_BLOCK->FirmwareVector[WriteRoutine] = VrWrite;
+
+ (PARC_READ_STATUS_ROUTINE)
+ SYSTEM_BLOCK->FirmwareVector[ReadStatusRoutine] = VrGetReadStatus;
+
+ (PARC_GET_FILE_INFO_ROUTINE)
+ SYSTEM_BLOCK->FirmwareVector[GetFileInformationRoutine] =
+ VrGetFileInformation;
+ (PARC_SET_FILE_INFO_ROUTINE)
+ SYSTEM_BLOCK->FirmwareVector[SetFileInformationRoutine] =
+ VrSetFileInformation;
+ (PARC_GET_DIRECTORY_ENTRY_ROUTINE)
+ SYSTEM_BLOCK->FirmwareVector[GetDirectoryEntryRoutine] =
+ VrGetDirectoryEntry;
+
+ //
+ // Initialize the file table.
+ //
+ for (Index = 0; Index < FILE_TABLE_SIZE; Index++) {
+ FileTable[Index].Flags.Open = 0;
+ }
+
+ debug(VRDBG_ENTRY, "VrIoInitialize ......END\n");
+ return;
+}
+
+
+/*
+ * Name: GetFileTableEntry (internal)
+ *
+ * Description:
+ * This function looks for an unused entry in the FileTable.
+ *
+ * Arguments:
+ * Entry - Pointer to the variable that gets an index
+ * for the file table.
+ *
+ * Return Value:
+ *
+ * Returns ESUCCESS if a free entry is found
+ * or EMFILE if no entry is available.
+ *
+ */
+STATIC ARC_STATUS
+GetFileTableEntry(
+ OUT PULONG Entry
+ )
+{
+ ULONG Index;
+
+ for (Index = 2; Index < FILE_TABLE_SIZE; Index++) {
+ if (FileTable[Index].Flags.Open == 0) {
+#ifdef notdef
+ FileTable[Index].Position.LowPart = 0;
+ FileTable[Index].Position.HighPart = 0;
+#endif // notdef
+ bzero((PCHAR)&FileTable[Index], sizeof(FILE_TABLE_ENTRY));
+ *Entry = Index;
+ return ESUCCESS;
+ }
+ }
+ return EMFILE;
+}
+
+
+/*
+ * Name: GetDeviceAttribute (internal)
+ *
+ * Description:
+ * This function sets the specified File Table entry to the attribute.
+ *
+ * Arguments:
+ * FileId - Supplies the file table index.
+ * ConfNode - Supplies a pointer to the Configuration Node.
+ *
+ * Return Value:
+ * If the Configuration node is not peripheral, then return ENODEV.
+ * Otherwise, returns ESUCCESS.
+ *
+ */
+STATIC ARC_STATUS
+GetDeviceAttribute(
+ IN ULONG FileId,
+ IN PCONFIGURATION_NODE ConfNode
+ )
+{
+ if (ConfNode->Component.Class != PeripheralClass) {
+ warn("GetDeviceAttribute: node %s(%d) not PeripheralClass.\n",
+ ConfNode->ComponentName, ConfNode->Component.Key);
+ return ENODEV;
+ }
+
+ if (ConfNode->Component.Type == MonitorPeripheral) {
+ FileTable[FileId].Flags.DisplayDevice = 1;
+ }
+ if (ConfNode->Component.Flags.Removable) {
+ FileTable[FileId].Flags.RemovableDevice = 1;
+ }
+ if (ConfNode->Component.Type == NetworkPeripheral) {
+ FileTable[FileId].Flags.NetworkDevice = 1;
+ }
+ if (ConfNode->Component.Flags.Input) {
+ FileTable[FileId].Flags.Read = 1;
+ }
+ if (ConfNode->Component.Flags.Output &&
+ !(ConfNode->Component.Flags.ReadOnly)) {
+ FileTable[FileId].Flags.Write = 1;
+ }
+
+ return ESUCCESS;
+}
+
+
+/*
+ * Name: AddLargeInt (internal)
+ *
+ * Description:
+ * This function adds a large integer into another large ingeger.
+ *
+ * Arguments:
+ * Position - Supplies a pointer to a variable to be added.
+ * Value - Supplies a pointer to a variable to add.
+ *
+ * Return Value:
+ * None.
+ *
+ */
+STATIC VOID
+AddLargeInt(
+ PLARGE_INTEGER Position,
+ PLARGE_INTEGER Value
+ )
+{
+ if ((Position->LowPart += Value->LowPart) < Value->LowPart) {
+ Position->HighPart++;
+ }
+ Position->HighPart += Value->HighPart;
+}
+
+
+/*
+ * Name: DecrementLarge (internal)
+ *
+ * Description:
+ * This function decrements a large integer.
+ *
+ * Arguments:
+ * Position - Supplies a pointer to a variable to be decremented.
+ *
+ * Return Value:
+ * None.
+ *
+ */
+STATIC VOID
+DecrementLarge(
+ PLARGE_INTEGER Position
+ )
+{
+ ULONG ULong = Position->LowPart;
+
+ Position->LowPart--;
+ if (Position->LowPart > ULong) {
+ Position->HighPart--;
+ }
+}
+
+
+/*
+ * Name: MoveLargeInt (internal)
+ *
+ * Description:
+ * This function copies a large integer into another large ingeger.
+ *
+ * Arguments:
+ * Position - Supplies a pointer to a variable to be copied.
+ * Value - Supplies a pointer to a variable to copy.
+ *
+ * Return Value:
+ * None.
+ *
+ */
+STATIC VOID
+MoveLargeInt(
+ PLARGE_INTEGER Position,
+ PLARGE_INTEGER Value
+ )
+{
+ Position->LowPart = Value->LowPart;
+ Position->HighPart = Value->HighPart;
+}
+
+
+/*
+ * Name: IsLarge (internal)
+ *
+ * Description:
+ * This function determines whether a large integer contains zero.
+ *
+ * Arguments:
+ * Position - Supplies a pointer to a variable to be checked.
+ *
+ * Return Value:
+ * If the large integer is zero, then returns ZERO_LARGE. Otherwise,
+ * returns NOT_ZERO_LARGE.
+ *
+ */
+STATIC LONG
+IsLarge(
+ PLARGE_INTEGER Position
+ )
+{
+ if (Position->LowPart != 0) {
+ return NOT_ZERO_LARGE;
+ }
+ if (Position->HighPart != 0) {
+ return NOT_ZERO_LARGE;
+ }
+ return ZERO_LARGE;
+}
+
diff --git a/private/ntos/boot/veneer/vrlib.c b/private/ntos/boot/veneer/vrlib.c
new file mode 100644
index 000000000..6d8753887
--- /dev/null
+++ b/private/ntos/boot/veneer/vrlib.c
@@ -0,0 +1,614 @@
+/*
+ *
+ * Copyright (c) 1994 FirmWorks, Mountain View CA USA. All rights reserved.
+ * Copyright (c) 1995 FirePower Systems, Inc.
+ * Copyright (c) 1996 FirePower Systems, Inc.
+ *
+ * $RCSfile: vrlib.c $
+ * $Revision: 1.14 $
+ * $Date: 1996/06/27 18:36:55 $
+ * $Locker: $
+ */
+
+#include "veneer.h"
+
+STATIC VOID doprnt(VOID (*)(), char *, va_list);
+STATIC VOID printbase(VOID (*)(), ULONG x, int base);
+
+int
+get_bool_prop(phandle node, char *key)
+{
+ return(OFGetproplen(node, key) != -1);
+}
+
+int
+decode_int(UCHAR *p)
+{
+ ULONG i = *p++ << 8;
+ i = (i + *p++) << 8;
+ i = (i + *p++) << 8;
+ return (i + *p);
+}
+
+int
+get_int_prop(phandle node, char *key)
+{
+ int res;
+ char buf[sizeof(int)];
+
+ res = OFGetprop(node, key, buf, sizeof(int));
+ if (res != sizeof(int)) {
+ return(-1);
+ }
+ /*
+ * The NT veneer is always little-endian.
+ */
+ return(decode_int((UCHAR *) buf));
+}
+
+reg *
+decode_reg(UCHAR *buf, int buflen, int addr_cells, int size_cells)
+{
+ static reg staticreg;
+ reg *r = &staticreg;
+
+ bzero((PCHAR) r, sizeof(reg));
+
+ if (buflen < addr_cells + size_cells) {
+ fatal("reg property smaller than #address-cell plus #size-cells\n");
+ }
+
+ r->lo = decode_int(buf + ((addr_cells-1) * 4));
+ r->hi = decode_int(buf);
+ r->size = decode_int(buf + ((addr_cells + size_cells - 1) * 4));
+
+ return (r);
+}
+
+reg *
+get_reg_prop(phandle node, char *key, int index)
+{
+ int res;
+ char *buf;
+ reg *regp;
+ int len = OFGetproplen(node, key);
+ int addr_cells, size_cells, offset;
+
+ buf = (char *)malloc(len);
+ res = OFGetprop(node, key, buf, len);
+ if (res != len) {
+ fatal("get_reg_prop(node %x, key '%s', len %x) returned %x\n",
+ node, key, len, res);
+ free(buf);
+ return ((reg *) 0);
+ }
+
+
+ addr_cells = get_int_prop(OFParent(node), "#address-cells");
+ if (addr_cells < 0) {
+ addr_cells = 2;
+ }
+ size_cells = get_int_prop(OFParent(node), "#size-cells");
+ if (size_cells < 0) {
+ size_cells = 1;
+ }
+
+ offset = index * (addr_cells + size_cells) * 4;
+ key = buf + offset;
+ len -= offset;
+ if (len) {
+ debug(VRDBG_TEST, "key %x len %x\n", key, len);
+ regp = decode_reg(key, len, addr_cells, size_cells);
+ } else {
+ debug(VRDBG_TEST, "returning NULL regp\n");
+ regp = NULL;
+ }
+
+ free(buf);
+ return (regp);
+}
+
+char *
+get_str_prop(phandle node, char *key, allocflag alloc)
+{
+ int len, res;
+ static char *priv_buf, priv_buf_len = 0;
+ char *cp;
+
+ len = OFGetproplen(node, key);
+ if (len == -1 || len == 0) {
+ return((char *) 0);
+ }
+
+ /*
+ * Leave room for a null terminator, on the off chance that the
+ * property isn't null-terminated.
+ */
+ len += 1;
+ if (alloc == ALLOC) {
+ cp = (char *) zalloc(len);
+ } else {
+ if (len > priv_buf_len) {
+ if (priv_buf_len) {
+ free(priv_buf);
+ }
+ priv_buf = (char *) zalloc(len);
+ priv_buf_len = len;
+ } else {
+ bzero(priv_buf, len);
+ }
+ cp = priv_buf;
+ }
+ len -= 1;
+
+ res = OFGetprop(node, key, cp, len);
+ if (res != len) {
+ fatal( "get_str_prop(node %x, key '%s', len %x) returned len %x\n",
+ node, key, len, res);
+ return((char *) 0);
+ }
+ return(cp);
+}
+
+int
+strcmp(const char *s, const char *t)
+{
+ int i;
+
+ for (i = 0; s[i] == t[i]; ++i) {
+ if (s[i] == '\0') {
+ return (0);
+ }
+ }
+ return((int) (s[i] - t[i]));
+}
+
+
+int
+strncmp(const char *s, const char *t, size_t len)
+{
+ int i;
+
+ for (i = 0; (s[i] == t[i]) && (i != (int) len); ++i) {
+ if (s[i] == '\0') {
+ return (0);
+ }
+ }
+ if (i == (int) len) {
+ return(0);
+ }
+ return((int) (s[i] - t[i]));
+}
+
+int
+strncasecmp(const char *s, const char *t, size_t len)
+{
+ int i;
+ char s1 = 0, t1 = 0;
+
+ for (i = 0; i != (int) len; ++i) {
+ if (s[i] == '\0') {
+ return (0);
+ }
+ s1 = s[i];
+ if (s1 >= 'a' && s1 <= 'z') {
+ s1 -= 0x20;
+ }
+ t1 = t[i];
+ if (t1 >= 'a' && t1 <= 'z') {
+ t1 -= 0x20;
+ }
+ if (s1 == t1) {
+ break;
+ }
+ }
+ if (i == (int) len) {
+ return(0);
+ }
+ return((int) (s1 - t1));
+}
+
+size_t
+strlen(const char *s)
+{
+ int i;
+
+ for (i = 0; s[i] != '\0'; ++i) {
+ ;
+ }
+ return((size_t) i);
+}
+
+char *
+strcpy(char *to, const char *from)
+{
+ int i = 0;
+
+ while (to[i] = from[i]) {
+ i += 1;
+ }
+ return(to);
+}
+
+char *
+strcat(char *to, const char *from)
+{
+ char *ret = to;
+
+ while (*to) {
+ to += 1;
+ }
+ strcpy(to, from);
+ return (ret);
+}
+
+VOID
+bcopy(char *from, char *to, int len)
+{
+ while (len--) {
+ *to++ = *from++;
+ }
+}
+
+VOID
+bzero(char *cp, int len)
+{
+ while (len--) {
+ *(cp + len) = 0;
+ }
+}
+
+VOID *
+zalloc(int size)
+{
+ VOID *vp;
+
+ vp = malloc(size);
+ bzero(vp, size);
+ return (vp);
+}
+
+VOID
+sleep(ULONG delay)
+{
+ delay += VrGetRelativeTime();
+ while (VrGetRelativeTime() < delay) {
+ ;
+ }
+}
+
+int
+claim(void *adr, int bytes)
+{
+ return(OFClaim((PCHAR) MAP(adr), bytes, 0));
+}
+
+VOID *
+alloc(int size, int align)
+{
+ return((VOID *) OFClaim(0, size, align));
+}
+
+int
+atoi(char *s)
+{
+ int temp = 0, base = 10;
+ char *start;
+
+ if (*s == '0') {
+ ++s;
+ if (*s == 'x') {
+ ++s;
+ base = 16;
+ } else {
+ base = 8;
+ }
+ }
+ start = s;
+again:
+ while (*s) {
+ switch (*s) {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ temp = (temp * base) + (*s++ - '0');
+ break;
+ case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+ if (base == 10) {
+ base = 16;
+ temp = 0;
+ s = start;
+ goto again;
+ }
+ temp = (temp * base) + (*s++ - 'a' + 10);
+ break;
+ case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+ if (base == 10) {
+ base = 16;
+ temp = 0;
+ s = start;
+ goto again;
+ }
+ temp = (temp * base) + (*s++ - 'A' + 10);
+ break;
+ default:
+ return (temp);
+ }
+ }
+ return (temp);
+}
+
+char *
+index(char *s, int c)
+{
+ while (*s) {
+ if (*s == c) {
+ return (s);
+ }
+ ++s;
+ }
+ return ((char *) 0);
+}
+
+char *
+strcsep(char *s, const char sep)
+{
+ static char *saved_str = NULL;
+ char *temp;
+
+ if (s != NULL) {
+ saved_str = s;
+ }
+ if (saved_str == NULL) {
+ return(NULL);
+ }
+ s = index(saved_str, sep);
+ if (s != NULL) {
+ *s++ = '\0';
+ }
+ temp = saved_str;
+ saved_str = s;
+ return(temp);
+}
+
+char *
+strctok(char *s, const char sep)
+{
+ static char *saved_str = NULL;
+ char *temp;
+
+ if (s != NULL) {
+ saved_str = s;
+ }
+ if (saved_str == NULL) {
+ return(NULL);
+ }
+ s = index(saved_str, sep);
+ if (s != NULL) {
+ *s++ = '\0';
+ while (*s && (*s == sep)) {
+ ++s;
+ }
+ }
+ temp = saved_str;
+ saved_str = s;
+ return(temp);
+}
+
+char *
+capitalize(char *s)
+{
+ char *p;
+
+ p = s;
+ while (*p) {
+ *p = islower(*p) ? toupper(*p) : *p;
+ ++p;
+ }
+ return(s);
+}
+
+
+
+STATIC ihandle stdout = 0;
+STATIC char outbuf[128];
+STATIC int outbufc = 0;
+
+VOID
+putchar(char c)
+{
+ phandle ph;
+
+ if (stdout == 0) {
+ ph = OFFinddevice("/chosen");
+ if (ph == -1) {
+ /* What to do here?!? */
+ while (1) {
+ ;
+ }
+ }
+ stdout = get_int_prop(ph, "stdout");
+ }
+
+ if (c == '\n') {
+ outbuf[outbufc++] = '\r';
+ }
+ outbuf[outbufc++] = c;
+ if ((c == '\n') || (outbufc == 127)) {
+ OFWrite(stdout, outbuf, outbufc);
+ outbufc = 0;
+ return;
+ }
+}
+
+VOID
+puts(char *s)
+{
+ int count;
+
+ if (stdout == 0) {
+ putchar(*s++);
+ }
+ if (outbufc) {
+ OFWrite(stdout, outbuf, outbufc);
+ outbufc = 0;
+ }
+ if (count = strlen(s)) {
+ OFWrite(stdout, s, count);
+ }
+ putchar('\n');
+}
+
+STATIC ihandle stdin = 0;
+
+VOID
+gets(char *inbuf)
+{
+ int count;
+ phandle ph;
+
+ if (stdin == 0) {
+ ph = OFFinddevice("/chosen");
+ if (ph == -1) {
+ /* What to do here?!? */
+ while (1) {
+ ;
+ }
+ }
+ stdin = get_int_prop(ph, "stdin");
+ }
+
+ count = OFRead(stdin, inbuf, 127);
+ inbuf[count] = '\0';
+}
+
+#include <stdarg.h>
+
+VOID
+warn(char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ doprnt(putchar, fmt, args);
+ va_end(args);
+}
+
+VOID
+fatal(char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ doprnt(putchar, fmt, args);
+ OFExit();
+ va_end(args);
+}
+
+int level = 0;
+
+VOID
+debug(int debug_level, char *fmt, ...)
+{
+ va_list args;
+ int i;
+
+ if (!(debug_level & VrDebug)) {
+ return;
+ }
+ va_start(args, fmt);
+ for (i = 0; i < level; ++i) {
+ putchar('\t');
+ }
+ doprnt(putchar, fmt, args);
+ va_end(args);
+}
+
+STATIC char *sprintf_buf;
+
+STATIC VOID
+putbuf(char c)
+{
+ *sprintf_buf++ = c;
+}
+
+VOID
+sprintf(char *buf, char *fmt, ...)
+{
+ va_list args;
+
+ sprintf_buf = buf;
+ va_start(args, fmt);
+ doprnt(putbuf, fmt, args);
+ va_end(args);
+ putbuf('\0');
+}
+
+STATIC VOID
+doprnt(VOID (*func)(), char *fmt, va_list args)
+{
+ ULONG x;
+ LONG l;
+ char c, *s;
+
+ while (c = *fmt++) {
+ if (c != '%') {
+ func(c);
+ continue;
+ }
+ switch (c = *fmt++) {
+ case 'x':
+ x = va_arg(args, ULONG);
+ printbase(func, x, 16);
+ break;
+ case 'o':
+ x = va_arg(args, ULONG);
+ printbase(func, x, 8);
+ break;
+ case 'd':
+ l = va_arg(args, LONG);
+ if (l < 0) {
+ func('-');
+ l = -l;
+ }
+ printbase(func, (ULONG) l, 10);
+ break;
+ case 'c':
+ c = va_arg(args, char);
+ func(c);
+ break;
+ case 's':
+ s = va_arg(args, char *);
+ while (*s) {
+ func(*s++);
+ }
+ break;
+ default:
+ func(c);
+ break;
+ }
+ }
+}
+
+STATIC VOID
+printbase(VOID (*func)(), ULONG x, int base)
+{
+ static char itoa[] = "0123456789abcdef";
+ ULONG j;
+ char buf[16], *s = buf;
+
+ if (x == 0) {
+ func('0');
+ return;
+ }
+ bzero(buf, 16);
+ while (x) {
+ j = x % base;
+ *s++ = itoa[j];
+ x -= j;
+ x /= base;
+ }
+
+ for (--s; s >= buf; --s) {
+ func(*s);
+ }
+}
diff --git a/private/ntos/boot/veneer/vrload.c b/private/ntos/boot/veneer/vrload.c
new file mode 100644
index 000000000..9fdfc412d
--- /dev/null
+++ b/private/ntos/boot/veneer/vrload.c
@@ -0,0 +1,1035 @@
+/*
+ *
+ * Copyright (c) 1995 FirePower Systems, Inc.
+ * Copyright (c) 1994 FirePower Systems Inc.
+ *
+ * $RCSfile: vrload.c $
+ * $Revision: 1.12 $
+ * $Date: 1996/04/15 02:55:48 $
+ * $Locker: $
+ *
+ *
+ * Module Name:
+ * vrload.c
+ *
+ * Author:
+ * Shin Iwamoto at FirePower Systems Inc.
+ *
+ * History:
+ * 28-Jul-94 Shin Iwamoto at FirePower Systems Inc.
+ * Added for DOS signature of PE in VrLoad();
+ * 18-Jul-94 Shin Iwamoto at FirePower Systems Inc.
+ * Created.
+ */
+
+
+#include "veneer.h"
+
+#define XXX_MAKE_DESCRIPTOR
+
+//
+// This must be defined in some header file. But for 3.5 it is not defined.
+//
+#define IMAGE_FILE_16BIT_MACHINE 0x0040
+
+
+typedef struct _VR_MEMORY_DESCRIPTOR {
+ struct _VR_MEMORY_DESCRIPTOR *NextEntry;
+ MEMORY_DESCRIPTOR MemoryEntry;
+} VR_MEMORY_DESCRIPTOR, *PVR_MEMORY_DESCRIPTOR;
+
+extern PVR_MEMORY_DESCRIPTOR VrMemoryListOrig;
+
+//
+// Some type definitions.
+//
+typedef struct _SECTION_RELOCATION_ENTRY {
+ ULONG FixupValue;
+ ULONG PointerToRelocations;
+ USHORT NumberOfRelocations;
+} SECTION_RELOCATION_ENTRY, *PSECTION_RELOCATION_ENTRY;
+
+//
+// Some definitions.
+//
+// These must be defined in veneer.h or ntimage.h?
+//
+#define HEADER_CHAR (IMAGE_FILE_EXECUTABLE_IMAGE | \
+ IMAGE_FILE_BYTES_REVERSED_LO | \
+ IMAGE_FILE_32BIT_MACHINE | \
+ IMAGE_FILE_BYTES_REVERSED_HI)
+#define HEADER_NOCHAR (IMAGE_FILE_16BIT_MACHINE | \
+ IMAGE_FILE_DLL)
+#define OPTIONAL_MAGIC_STD 0x010B
+
+//
+// Section numbers for local relocation entries
+//
+#define R_SN_TEXT 0
+#define R_SN_DATA 1
+#define R_SN_BSS 2
+#define R_SN_MAX 3
+
+
+#define MAX_ARGUMENT (512 - sizeof(ULONG) - 16*sizeof(PUCHAR))
+typedef struct _SAVED_ARGUMENTS {
+ ULONG Argc;
+ PUCHAR Argv[16];
+ UCHAR Arguments[MAX_ARGUMENT];
+} SAVED_ARGUMENTS, *PSAVED_ARGUMENTS;
+
+
+STATIC PSAVED_ARGUMENTS SavedArgs;
+STATIC ULONG VrActualBasePage;
+STATIC ULONG VrPageCount;
+
+
+//
+// Function declarations.
+//
+ARC_STATUS
+VrRelocateImage(
+ IN ULONG FileId,
+ IN PSECTION_RELOCATION_ENTRY RelocationTable,
+ IN ULONG NumberOfSections,
+ IN ULONG PointerToSymbolTable
+ );
+VOID
+VrCopyArguments(
+ IN ULONG Argc,
+ IN PCHAR Argv[]
+ );
+ARC_STATUS
+VrGenerateDescriptor(
+ IN PMEMORY_DESCRIPTOR MemoryDescriptor,
+ IN MEMORY_TYPE MemoryType,
+ IN ULONG BasePage,
+ IN ULONG PageCount
+ );
+VOID
+VrResetMemory(
+ VOID
+ );
+VOID
+PxInvoke(
+ IN ULONG EntryAddress,
+ IN ULONG StackAddress,
+ IN ULONG Argc,
+ IN PCHAR Argv[],
+ IN PCHAR Envp[]
+ );
+VOID
+InsertMemDescriptor(
+ IN PVR_MEMORY_DESCRIPTOR MemDescriptor
+ );
+
+
+/*
+ * Name: VrLoad
+ *
+ * Description:
+ * This function reads a program into memory at a specified address
+ * an;d stores the execution address.
+ *
+ * Arguments:
+ * ImagePath - Supplies a pointer to the path of the file to load.
+ * TopAddress - Supplies the top address of a region of memory into
+ * which the file is to be loaded.
+ * EntryAddress- Supplies a pointer to a variable to receive the entry
+ * point of the image, if defined.
+ * LoaAddress - Supplies a pointer to a variable to receive the low address
+ * of the loaded file.
+ *
+ * Return Value:
+ * ESUCCESS is returned if the specified image file is loaded successfully.
+ * Otherwise, an unsuccessufl status is returned that describes the reason
+ * for failure.
+ *
+ */
+ARC_STATUS
+VrLoad(
+ IN PCHAR ImagePath,
+ IN ULONG TopAddress,
+ OUT PULONG EntryAddress,
+ OUT PULONG LowAddress
+ )
+{
+ PSECTION_RELOCATION_ENTRY RelocationTable;
+ IMAGE_DOS_HEADER DosHeader;
+ IMAGE_FILE_HEADER FileHeader;
+ IMAGE_OPTIONAL_HEADER OptionalHeader;
+ PIMAGE_SECTION_HEADER SectionHeader, SHeader;
+ ULONG FileId, NumberOfSections, Count;
+ ULONG ActualBase, ClaimSize, SectionOffset;
+ LARGE_INTEGER SeekPosition;
+ ARC_STATUS Status;
+ LONG NT_Signature;
+ LONG size, i;
+ PCHAR ReadAddr;
+ ULONG ReadSize;
+
+
+ debug(VRDBG_LOAD, "VrLoad: Entry - ImagePath: %s TopAddress: %x\n",
+ ImagePath, TopAddress);
+
+ //
+ // Attempt to open the load file.
+ //
+ if ((Status = VrOpen(ImagePath, ArcOpenReadOnly, &FileId)) != ESUCCESS) {
+ return Status;
+ }
+
+ //
+ // Read DOS Signature.
+ //
+ if ((Status = VrRead(FileId, &DosHeader, 2, &Count)) != ESUCCESS) {
+ (VOID)VrClose(FileId);
+ return Status;
+ }
+
+ //
+ // If the file isn't a PE file including DOS header,
+ // it's probably a COFF file.
+ //
+ if (DosHeader.e_magic != IMAGE_DOS_SIGNATURE) {
+ bcopy((char *)&DosHeader, (char *)&FileHeader, 2);
+ ReadAddr = (PCHAR)&FileHeader + 2;
+ ReadSize = IMAGE_SIZEOF_FILE_HEADER - 2;
+ goto DirectCOFF;
+ }
+
+ //
+ // Read the remainder of DOS header.
+ //
+ if ((Status = VrRead(FileId, (PCHAR)&DosHeader+2, sizeof(DosHeader) - 2,
+ &Count)) != ESUCCESS) {
+ (VOID)VrClose(FileId);
+ return Status;
+ }
+ if (Count != sizeof(DosHeader) - 2) {
+ (VOID)VrClose(FileId);
+ return EBADF; // XXXX
+ }
+ SeekPosition.HighPart = 0;
+ SeekPosition.LowPart = DosHeader.e_lfanew;
+ if (Status = VrSeek(FileId, &SeekPosition, SeekAbsolute)) {
+ (VOID)VrClose(FileId);
+ return EBADF; // XXXX
+ }
+
+ //
+ // Read NT Signature and confirm it.
+ //
+ if ((Status = VrRead(FileId, &NT_Signature, sizeof(NT_Signature), &Count))
+ != ESUCCESS) {
+ (VOID)VrClose(FileId);
+ return Status;
+ }
+ if (Count != sizeof(NT_Signature) || NT_Signature != IMAGE_NT_SIGNATURE) {
+ (VOID)VrClose(FileId);
+ return EBADF; // XXXX
+ }
+
+ ReadAddr = (PCHAR)&FileHeader;
+ ReadSize = IMAGE_SIZEOF_FILE_HEADER;
+
+ DirectCOFF:
+ //
+ // Read the image header from the file.
+ //
+ if ((Status = VrRead(FileId, ReadAddr, ReadSize, &Count)) != ESUCCESS) {
+ (VOID)VrClose(FileId);
+ return Status;
+ }
+ if (Count != ReadSize) {
+ (VOID)VrClose(FileId);
+ return EBADF; // XXXX
+ }
+
+ //
+ // Check the header.
+ //
+ if ((FileHeader.Machine != IMAGE_FILE_MACHINE_POWERPC) ||
+ ((FileHeader.Characteristics & HEADER_CHAR) != HEADER_CHAR) ||
+ ((FileHeader.Characteristics & HEADER_NOCHAR) != 0) ) {
+
+ (VOID)VrClose(FileId);
+ return ENOEXEC;
+ }
+
+ //
+ // Read the optional header.
+ //
+ if ((Status = VrRead(FileId, &OptionalHeader,
+ FileHeader.SizeOfOptionalHeader, &Count)) != ESUCCESS) {
+ (VOID)VrClose(FileId);
+ return Status;
+ }
+ if (Count != FileHeader.SizeOfOptionalHeader) {
+ (VOID)VrClose(FileId);
+ return EBADF; // XXXX
+ }
+
+ //
+ // More check with the optional header.
+ //
+ if (OptionalHeader.Magic != OPTIONAL_MAGIC_STD) {
+ (VOID)VrClose(FileId);
+ return ENOEXEC;
+ }
+
+ //
+ // If the image cannot be relocated, set the ActualBase to the code
+ // base, and compute the image size by subtracting the code base from
+ // the data base plus the data size. If the image can be relocated,
+ // set ActualBase to the TopAddress minus the image size, compute
+ // image size by adding the code size, initialized data, and
+ // uninitialized data.
+ //
+ if ((FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED) != 0) {
+ ActualBase = OptionalHeader.BaseOfCode;
+ ClaimSize = OptionalHeader.BaseOfData +
+ OptionalHeader.SizeOfInitializedData - ActualBase;
+ } else {
+ ClaimSize = OptionalHeader.SizeOfCode +
+ OptionalHeader.SizeOfInitializedData +
+ OptionalHeader.SizeOfUninitializedData;
+ // ActualBase = OptionalHeader.ImageBase;
+#ifdef XXX_I_KNOW_PE
+ ActualBase = (TopAddress - ClaimSize) & ~(PAGE_SIZE - 1);
+#else
+ ActualBase = OptionalHeader.ImageBase;
+ ActualBase &= 0x7fffffff;
+#endif XXX_I_KNOW_PE
+ }
+
+ //
+ // Allocate and read the section headers.
+ //
+ size = FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
+ SectionHeader = (PIMAGE_SECTION_HEADER)malloc(size);
+ if ((Status = VrRead(FileId, (PCHAR)SectionHeader, size, &Count))
+ != ESUCCESS) {
+ (VOID)VrClose(FileId);
+ return Status;
+ }
+ if (Count != (ULONG) size) {
+ (VOID)VrClose(FileId);
+ return EBADF; // XXXX
+ }
+
+ //
+ //
+ //
+ NumberOfSections = FileHeader.NumberOfSections;
+ if (strcmp((PCHAR)(SectionHeader[NumberOfSections-1].Name), ".debug")
+ == 0) {
+ NumberOfSections--;
+ ClaimSize -= SectionHeader[NumberOfSections].SizeOfRawData;
+ }
+
+ //
+ // Allocate the relocation table.
+ //
+ size = NumberOfSections * sizeof(SECTION_RELOCATION_ENTRY);
+ RelocationTable = (PSECTION_RELOCATION_ENTRY) malloc(size);
+
+ //
+ // Zero the relocation table.
+ //
+ bzero((char *)RelocationTable, size);
+
+ //
+ // Convert ClaimSize to be page-aligned.
+ //
+ ClaimSize = (ClaimSize + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
+
+ //
+ // Convert ActualBase and ClaimSize to be in units of pages instead of
+ // bytes. This is the interface between VrExecute and VrLoad.
+ //
+ VrActualBasePage = (ActualBase & 0x7fffffff) >> PAGE_SHIFT;
+ VrPageCount = ClaimSize >> PAGE_SHIFT;
+
+ //
+ // Claim memory at specified virtual address
+ //
+ if (claim((void *)ActualBase, ClaimSize) == -1) {
+ fatal("Veneer: Couldn't claim %x bytes of VM at %x\n",
+ ClaimSize, ActualBase);
+ }
+
+ //
+ // Set output parametes.
+ //
+ *LowAddress = ActualBase;
+#ifdef XXX_I_KNOW_PE
+ *EntryAddress = ActualBase
+ + (OptionalHeader.AddressOfEntryPoint - OptionalHeader.BaseOfCode);
+#else
+ *EntryAddress = ActualBase + OptionalHeader.AddressOfEntryPoint;
+#endif XXX_I_KNOW_PE
+
+ //
+ // Scan through the sections and either read them into memory or
+ // clear the memory as appropriate.
+ //
+ SectionOffset = 0;
+ for (i = 0, SHeader = SectionHeader; (ULONG) i < NumberOfSections;
+ i++, SHeader++) {
+ ULONG SectionBase;
+
+ if ((FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED) != 0) {
+ SectionBase = SHeader->VirtualAddress;
+ } else {
+#ifdef XXX_I_KNOW_PE
+ SectionBase = ActualBase + SectionOffset;
+#else
+ SectionBase = ActualBase + SHeader->VirtualAddress;
+#endif XXX_I_KNOW_PE
+
+ (RelocationTable+i)->PointerToRelocations =
+ SHeader->PointerToRelocations;
+ (RelocationTable+i)->NumberOfRelocations =
+ SHeader->NumberOfRelocations;
+ (RelocationTable+i)->FixupValue =
+ SectionBase - SHeader->VirtualAddress;
+ }
+
+ //
+ // If the section is code or initialized data, then read
+ // the code or data into memory.
+ //
+ if ((SHeader->Characteristics & ( IMAGE_SCN_CNT_CODE |
+ IMAGE_SCN_CNT_INITIALIZED_DATA) ) != 0) {
+ SeekPosition.LowPart = SHeader->PointerToRawData;
+ SeekPosition.HighPart = 0;
+ if ((Status = VrSeek(FileId, &SeekPosition, SeekAbsolute))
+ != ESUCCESS) {
+ break;
+ }
+ if ((Status = VrRead(FileId, (PVOID)SectionBase,
+ SHeader->SizeOfRawData, &Count)) != ESUCCESS) {
+ break;
+ }
+ if (Count != SHeader->SizeOfRawData) {
+ Status = EBADF; // XXXX
+ break;
+ }
+
+ //
+ // Set the offset of the next section.
+ //
+ SectionOffset += SHeader->SizeOfRawData;
+ } else
+ if ((SHeader->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
+ != 0) {
+ bzero((PVOID)SectionBase, SHeader->SizeOfRawData);
+
+ //
+ // Set the offset of the next section.
+ //
+ SectionOffset += SHeader->SizeOfRawData;
+ }
+ }
+
+ //
+ // If code has to be relocated, do so.
+ //
+ if ((FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED) == 0) {
+ if (ActualBase != OptionalHeader.ImageBase) {
+ Status = VrRelocateImage( FileId, RelocationTable,
+ NumberOfSections,
+ FileHeader.PointerToSymbolTable);
+ }
+ }
+
+ //
+ // Deallocate allocated area and close the file.
+ //
+ free((char*) SectionHeader);
+ free((char*) RelocationTable);
+ (VOID)VrClose(FileId);
+
+ debug(VRDBG_LOAD, "VrLoad: Exit - EntryAddress: %x LowAddress: %x Status:%d\n",
+ *EntryAddress, *LowAddress, Status);
+
+ return Status;
+}
+
+
+
+/*
+ * Name: VrInvoke
+ *
+ * Description:
+ * This function invokes a previously loaded program.
+ *
+ * Arguments:
+ * EntryAddress- Supplies the execution address of the program to be loaded.
+ * StackAddress- Supplies the stack address that is used to reset the stack
+ * pointer before the program is invoked.
+ * Argc - Supplies the argument count for the program.
+ * Argv - Supplies a pointer to the argument list for the program.
+ * Envp - Supplies a pointer to the environment for the program.
+ *
+ * Return Value:
+ * ESUCCESS is returned if the address is invalid.
+ * EFAULT indicates an invalid address.
+ *
+ */
+ARC_STATUS
+VrInvoke(
+ IN ULONG EntryAddress,
+ IN ULONG StackAddress,
+ IN ULONG Argc,
+ IN PCHAR Argv[],
+ IN PCHAR Envp[]
+ )
+{
+ //
+ // Check for aligend address.
+ //
+ if ((EntryAddress & 0x3) == 0 && (StackAddress & 0x3) == 0) {
+#ifdef notdef
+ free(VrDescriptorMemory);
+ VrMemoryListOrig = (PVR_MEMORY_DESCRIPTOR)NULL;
+#endif // notdef
+
+ PxInvoke(EntryAddress, StackAddress, Argc, Argv, Envp);
+ } else {
+ return EFAULT;
+ }
+
+ return ESUCCESS;
+}
+
+
+
+/*
+ * Name: VrExecute
+ *
+ * Description:
+ * This function reads the program specified by ImagePath into memory
+ * and then starts the program. If the loaded program returns, then
+ * control returns to the platform firmware, not to the caller.
+ *
+ * Arguments:
+ * ImagePath - Supplies a pointer to the pathname of the program
+ * to be loaded.
+ * Argc - Supplies the argument count for the program.
+ * Argv - Supplies a pointer to the argument list for the program.
+ * Envp - Supplies a pointer to the environment for the program.
+ *
+ * Return Value:
+ * ESUCCESS is returned if the address is invalid.
+ * EFAULT indicates an invalid address.
+ *
+ */
+ARC_STATUS
+VrExecute(
+ IN PCHAR ImagePath,
+ IN ULONG Argc,
+ IN PCHAR Argv[],
+ IN PCHAR Envp[]
+ )
+{
+ ARC_STATUS Status;
+ PMEMORY_DESCRIPTOR MemoryDescriptor;
+ ULONG BottomAddress;
+ CHAR TempPath[256];
+ PULONG TransferRoutine;
+
+ if (strlen(ImagePath) >= sizeof(TempPath)) {
+ return ENAMETOOLONG;
+ }
+
+ //
+ // Copy the Arguments to a safe place as they can be in the running
+ // program space which can be overwritten by the program about
+ // to be loaded.
+ //
+ (VOID)VrCopyArguments(Argc, Argv);
+ strcpy(TempPath, ImagePath);
+
+ //
+ // Reinitialize the memory descriptors
+ //
+ VrResetMemory();
+
+ //
+ // Look for a piece of free memory.
+ //
+ MemoryDescriptor = VrGetMemoryDescriptor(NULL);
+ while (MemoryDescriptor != NULL ) {
+
+ //
+ // If the memory is at least 4 megabytes and is free attempt to
+ // load the program.
+ //
+ if ((MemoryDescriptor->MemoryType == MemoryFree)
+ && (MemoryDescriptor->PageCount >= 1024)) {
+
+ //
+ // Set the top address to the top of the descriptor.
+ //
+ Status = VrLoad(TempPath,
+ ((MemoryDescriptor->BasePage + MemoryDescriptor->PageCount)
+ << PAGE_SHIFT),
+ (PULONG)&TransferRoutine,
+ &BottomAddress);
+
+ if (Status == ESUCCESS) {
+
+ //
+ // Find the actual area of memory that was used, and generate
+ // a descriptor for it. Also, claim the according memory
+ // from OpenFirmware.
+ //
+#ifdef XXX_MAKE_DESCRIPTOR
+ MemoryDescriptor = VrGetMemoryDescriptor(NULL);
+ while (MemoryDescriptor != NULL) {
+ if ((MemoryDescriptor->MemoryType == MemoryFree)
+ && (VrActualBasePage >= MemoryDescriptor->BasePage)
+ && ((VrActualBasePage + VrPageCount) <=
+ (MemoryDescriptor->BasePage
+ + MemoryDescriptor->PageCount)) ) {
+ break;
+ }
+ MemoryDescriptor = VrGetMemoryDescriptor(MemoryDescriptor);
+ }
+ if (MemoryDescriptor != NULL) {
+ Status = VrGenerateDescriptor(MemoryDescriptor,
+#ifdef EXEC_MEM_TO_LOADED
+ MemoryLoadedProgram,
+#else
+ MemoryFirmwareTemporary,
+#endif // EXEC_MEM_TO_LOADED
+ VrActualBasePage,
+ VrPageCount);
+ if (Status != ESUCCESS) {
+ return Status;
+ }
+#endif // XXX_MAKE_DESCRIPTOR
+
+
+ Status = VrInvoke((ULONG)TransferRoutine,
+ BottomAddress,
+ SavedArgs->Argc,
+ SavedArgs->Argv,
+ Envp );
+#ifdef EXEC_MEM_TO_LOADED
+#else
+ MemoryDescriptor->MemoryType = MemoryLoadedProgram;
+#endif // EXEC_MEM_TO_LOADED
+ return Status;
+
+#ifdef XXX_MAKE_DESCRIPTOR
+ }
+#endif // XXX_MAKE_DESCRIPTOR
+ }
+ if (Status != ENOMEM) {
+ return Status;
+ }
+ }
+
+ MemoryDescriptor = VrGetMemoryDescriptor(MemoryDescriptor);
+ }
+
+ return ENOMEM;
+}
+
+
+/*
+ * Name: VrLoadInitialize
+ *
+ * Description:
+ * This routine initializes the firmware load services.
+ *
+ * Arguments:
+ * None.
+ *
+ * Return Value:
+ * None.
+ *
+ */
+VOID
+VrLoadInitialize(
+ VOID
+ )
+{
+ debug(VRDBG_ENTRY, "VrLoadInitialize BEGIN....\n");
+ (PARC_LOAD_ROUTINE)
+ SYSTEM_BLOCK->FirmwareVector[LoadRoutine] = VrLoad;
+
+ (PARC_INVOKE_ROUTINE)
+ SYSTEM_BLOCK->FirmwareVector[InvokeRoutine] = VrInvoke;
+
+ (PARC_EXECUTE_ROUTINE)
+ SYSTEM_BLOCK->FirmwareVector[ExecuteRoutine] = VrExecute;
+
+ SavedArgs = new(SAVED_ARGUMENTS);
+ debug(VRDBG_ENTRY, "VrLoadInitialize ....END\n");
+}
+
+
+/*
+ * Name: VrRelocateImage
+ *
+ * Description:
+ * This function relocates an image file that was not loaded into memory
+ * at the prefered address.
+ *
+ * Arguments:
+ * FileId - Supplies the file identifier for the image file.
+ * RelocationTable
+ * - Supplies a pointer to a table of section relocation info.
+ *
+ * Return Value:
+ * ESUCCESS is returned in the scan if\s successful. Otherwise, return
+ * an unsuccessful status.
+ *
+ */
+STATIC
+ARC_STATUS
+VrRelocateImage(
+ IN ULONG FileId,
+ IN PSECTION_RELOCATION_ENTRY RelocationTable,
+ IN ULONG NumberOfSections,
+ IN ULONG PointerToSymbolTable
+ )
+{
+ IMAGE_RELOCATION RelocationEntry;
+ IMAGE_SYMBOL ImageSymbol;
+ LARGE_INTEGER SeekPosition;
+ ULONG Section, Index, Count, Offset;
+ PULONG FixupAddress;
+ ARC_STATUS Status;
+
+ //
+ // Read the relocation table for each section.
+ //
+ for (Section = 0; Section < NumberOfSections; Section++) {
+ for (Index = 0; Index < RelocationTable[Section].NumberOfRelocations;
+ Index++) {
+ if (Index == 0) {
+ SeekPosition.LowPart =
+ RelocationTable[Section].PointerToRelocations;
+ SeekPosition.HighPart = 0;
+ if ((Status = VrSeek(FileId, &SeekPosition, SeekAbsolute))
+ != ESUCCESS) {
+ return Status;
+ }
+ }
+ if ((Status = VrRead(FileId, (PCHAR)&RelocationEntry,
+ sizeof(RelocationEntry), &Count)) != ESUCCESS) {
+ return Status;
+ }
+ if (Count != sizeof(RelocationEntry)) {
+ return EBADF;
+ }
+
+ //
+ // Get the address for the fixup.
+ //
+ FixupAddress = (PULONG)RelocationEntry.VirtualAddress
+ + RelocationTable[Section].FixupValue;
+
+ //
+ // Read the symbol table.
+ //
+ SeekPosition.LowPart = PointerToSymbolTable
+ + RelocationEntry.SymbolTableIndex * sizeof(IMAGE_SYMBOL);
+ if ((Status = VrRead(FileId, (PCHAR)&ImageSymbol,
+ sizeof(ImageSymbol), &Count)) != ESUCCESS) {
+ return Status;
+ }
+ if (Count != sizeof(ImageSymbol)) {
+ return EBADF;
+ }
+
+ //
+ // Apply the fixup.
+ //
+ if (ImageSymbol.StorageClass != IMAGE_SYM_CLASS_EXTERNAL) {
+ Offset = RelocationTable[ImageSymbol.SectionNumber].FixupValue;
+ } else {
+ Offset = 0;
+ }
+
+ switch (RelocationEntry.Type) {
+
+ //
+ // Absolute - no fixup required.
+ //
+ case IMAGE_REL_PPC_ABSOLUTE:
+ break;
+
+ //
+ // 32-bit address - relocate the entire address.
+ //
+ case IMAGE_REL_PPC_ADDR32:
+ *FixupAddress += (ULONG)Offset;
+ break;
+
+ //
+ // 26-bit address, 26-bit PC-relative offset
+ //
+ case IMAGE_REL_PPC_ADDR24:
+ case IMAGE_REL_PPC_REL24:
+ *FixupAddress = ((*FixupAddress) & 0xfc000003) +
+ ((*FixupAddress) & 0x03fffffc + (Offset << 2)) & 0x03fffffc;
+ break;
+
+ //
+ // 16-bit address, 16-bit offset from TOC base
+ //
+ case IMAGE_REL_PPC_ADDR16:
+ case IMAGE_REL_PPC_TOCREL16:
+ *FixupAddress = ((*FixupAddress) & 0xffff0000) +
+ ((*FixupAddress) & 0x0000ffff + Offset) & 0x0000ffff;
+ break;
+
+ //
+ // 14-bit address, 14-bit PC-relative offset,
+ // 14-bit offset from TOC base
+ //
+ case IMAGE_REL_PPC_ADDR14:
+ case IMAGE_REL_PPC_REL14:
+ case IMAGE_REL_PPC_TOCREL14:
+ *FixupAddress = ((*FixupAddress) & 0xffff0003) +
+ ((*FixupAddress) & 0x0000fffc + (Offset << 2)) & 0x0000fffc;
+ break;
+
+ default:
+ fatal("Veneer: unknown relocation type %d\n",
+ RelocationEntry.Type);
+ }
+ }
+ }
+
+ return ESUCCESS;
+}
+
+
+/*
+ * Name: VrCopyArguments
+ *
+ * Description:
+ * This routine copies the supplied arguments into the Veneer space.
+ *
+ * Arguments:
+ * Argc, Argv - Supply the arguments to be copied.
+ *
+ * Return Value:
+ * None.
+ *
+ */
+STATIC VOID
+VrCopyArguments(
+ IN ULONG Argc,
+ IN PCHAR Argv[]
+ )
+{
+ PUCHAR Source, Destination;
+ ULONG Index;
+
+ SavedArgs->Argc = Argc;
+ Destination = &SavedArgs->Arguments[0];
+ for (Index = 0; Index < Argc; Index++) {
+ Source = Argv[Index];
+ SavedArgs->Argv[Index] = Destination;
+ while (*Destination++ = *Source++) ;
+ }
+}
+
+
+/*
+ * Name: VrResetMemory
+ *
+ * Description:
+ * This loops through and clears all of the appropriate memory,
+ * releasing the memory to OpenFirmware, and then calls VrCreateMemory
+ * to reset the memory descriptors.
+ *
+ * Arguments:
+ * None.
+ *
+ * Return Value:
+ * None.
+ *
+ */
+VOID
+VrResetMemory(
+ VOID
+ )
+{
+ PMEMORY_DESCRIPTOR MemoryDescriptor;
+ PVR_MEMORY_DESCRIPTOR CurDesc, FreeDesc;
+
+ //
+ // Release all memory not used by the firmware.
+ //
+ MemoryDescriptor = VrGetMemoryDescriptor(NULL);
+ while (MemoryDescriptor != NULL) {
+
+#ifdef notdef
+ DisplayMemoryDescriptor(MemoryDescriptor);
+#endif // notdef
+
+ if ((MemoryDescriptor->MemoryType == MemoryLoadedProgram) ||
+ (MemoryDescriptor->MemoryType == MemoryFreeContiguous)) {
+
+ bzero((PVOID) (MemoryDescriptor->BasePage << PAGE_SHIFT),
+ (MemoryDescriptor->PageCount << PAGE_SHIFT));
+
+ OFRelease((PVOID)(MemoryDescriptor->BasePage << PAGE_SHIFT),
+ (MemoryDescriptor->PageCount << PAGE_SHIFT));
+ }
+
+ MemoryDescriptor = VrGetMemoryDescriptor(MemoryDescriptor);
+ }
+
+ CurDesc = VrMemoryListOrig;
+ while(CurDesc != NULL) {
+ FreeDesc = CurDesc;
+ CurDesc = CurDesc->NextEntry;
+ free((char*)FreeDesc);
+ }
+ VrMemoryListOrig = (PVR_MEMORY_DESCRIPTOR) NULL;
+ VrCreateMemoryDescriptors();
+}
+
+
+/*
+ * Name: VrGenerateDescriptor
+ *
+ * Description:
+ * This routine allocates a new memory descriptor to describe the
+ * specified region of memory.
+ *
+ * Arguments:
+ * MemoryDescriptor - Supplies a pointer to a free memory descriptor
+ * from which the specified memory is to be allocated.
+ * MemoryType - Supplies the type that is assigned to the allocated
+ * memory.
+ * BasePage - Supplies the base page number.
+ * PageCount - Supplies the number of pages.
+ *
+ * Return Value:
+ *
+ */
+ARC_STATUS
+VrGenerateDescriptor(
+ IN PMEMORY_DESCRIPTOR MemoryDescriptor,
+ IN MEMORY_TYPE MemoryType,
+ IN ULONG BasePage,
+ IN ULONG PageCount
+ )
+{
+ PVR_MEMORY_DESCRIPTOR MemDescriptor, NewDescriptor;
+ ULONG Offset;
+
+
+ MemDescriptor = (PVR_MEMORY_DESCRIPTOR) MemoryDescriptor;
+
+ //
+ // Claim the memory from OpenFirmware.
+ //
+ if ((claim((void *)(BasePage << PAGE_SHIFT), PageCount << PAGE_SHIFT))
+ == -1) {
+ return ENOMEM;
+ }
+
+ //
+ // If the specified region totally consumes the free region, then no
+ // additional descriptors need to be allocated. If the specified region
+ // is at the start or end of the free region, then only one descriptor
+ // needs to be allocated. Otherwise, two additional descriptors need to
+ // be allocated.
+ //
+ Offset = BasePage - MemDescriptor->MemoryEntry.BasePage;
+ if ((Offset == 0) && (PageCount == MemDescriptor->MemoryEntry.PageCount)) {
+
+ //
+ // The specified region totally consumes the free region.
+ //
+ MemDescriptor->MemoryEntry.MemoryType = MemoryType;
+
+ } else {
+
+ //
+ // A memory descriptor must be generated to describe the allocated
+ // memory.
+ //
+ NewDescriptor = new(VR_MEMORY_DESCRIPTOR);
+ NewDescriptor->MemoryEntry.MemoryType = MemoryType;
+ NewDescriptor->MemoryEntry.BasePage = BasePage;
+ NewDescriptor->MemoryEntry.PageCount = PageCount;
+
+ //
+ // Insert Memory Descriptor List.
+ //
+ InsertMemDescriptor(NewDescriptor);
+
+ //
+ // Determine whether an additional memory descriptor must be generated.
+ //
+ if (BasePage == MemDescriptor->MemoryEntry.BasePage) {
+ MemDescriptor->MemoryEntry.BasePage += PageCount;
+ MemDescriptor->MemoryEntry.PageCount -= PageCount;
+ } else {
+ if ((Offset + PageCount) == (MemDescriptor->MemoryEntry.BasePage +
+ MemDescriptor->MemoryEntry.PageCount)) {
+
+ //
+ // The specified region lies at the end of the free region.
+ //
+ MemDescriptor->MemoryEntry.PageCount -= PageCount;
+
+ } else {
+
+ //
+ // The specified region lies in the middle of the free region.
+ // Another memory descriptor must be generated.
+ //
+ NewDescriptor = new(VR_MEMORY_DESCRIPTOR);
+ NewDescriptor->MemoryEntry.MemoryType = MemoryFree;
+ NewDescriptor->MemoryEntry.BasePage = BasePage + PageCount;
+ NewDescriptor->MemoryEntry.PageCount =
+ MemDescriptor->MemoryEntry.PageCount - PageCount - Offset;
+
+ //
+ // Insert Memory Descriptor List.
+ //
+ InsertMemDescriptor(NewDescriptor);
+
+
+ MemDescriptor->MemoryEntry.PageCount = Offset;
+ }
+ }
+ }
+
+ return ESUCCESS;
+}
+
+
+VOID
+InsertMemDescriptor(
+ IN PVR_MEMORY_DESCRIPTOR MemDescriptor
+ )
+{
+ PVR_MEMORY_DESCRIPTOR Entry;
+
+ for (Entry = VrMemoryListOrig; Entry; Entry = Entry->NextEntry) {
+ if ((Entry->MemoryEntry.BasePage < MemDescriptor->MemoryEntry.BasePage)
+ && ((Entry->NextEntry == NULL) ||
+ (Entry->NextEntry->MemoryEntry.BasePage >
+ MemDescriptor->MemoryEntry.BasePage))) {
+
+ MemDescriptor->NextEntry = Entry->NextEntry;
+ Entry->NextEntry = MemDescriptor;
+ break;
+ }
+ }
+}
diff --git a/private/ntos/boot/veneer/vrmain.c b/private/ntos/boot/veneer/vrmain.c
new file mode 100644
index 000000000..a90970420
--- /dev/null
+++ b/private/ntos/boot/veneer/vrmain.c
@@ -0,0 +1,1314 @@
+/*
+ * Copyright (c) 1994, 1996 FirePower Systems, Inc.
+ * Copyright 1994 FirmWorks, Mountain View CA USA. All rights reserved.
+ *
+ * $RCSfile: vrmain.c $
+ * $Revision: 1.41 $
+ * $Date: 1996/06/25 03:02:44 $
+ * $Locker: $
+ *
+ *
+ *
+ *
+ *
+ * HISTORY
+ * 09-21-94 Shin Iwamoto at FirePower Systems Inc.
+ * Added some information in the system parameter block,
+ * such as signature.
+ * 07-21-94 Shin Iwamoto at FirePower Systems Inc.
+ * Added calling VrEnvInitialize() and VrMemoryInitialize()
+ * in VrInitSystem().
+ * 07-20-94 Shin Iwamoto at FirePower Systems Inc.
+ * Moved here from VrInitSystem() and VrNotYet() originally
+ * in vrconfig.c.
+ *
+ */
+
+
+#include "veneer.h"
+
+
+int VrDebug = 0;
+BOOLEAN use_bat_mapping;
+
+/*
+ * Bootdev is either specified in the command line or if not is the device
+ * whence you booted.
+ * See create_argv() below for the magic used to fill in XYZZY.
+ */
+char *Bootpath = 0;
+char *Osloader = 0;
+char *SystemPath = 0;
+
+#define STR_XYZZY "xyzzy"
+#define STR_OSLOADER "\\os\\winnt\\osloader.exe"
+#define STR_OSLOADFN "\\WINNT"
+#define STR_OSLOADPART STR_XYZZY
+#define STR_LDIDENT "Windows NT 3.5"
+#define STR_FWSEARCH STR_XYZZY
+#define STR_FWTEST STR_XYZZY
+
+#define MAX_ARGC 16
+#define MAX_ENVC 16
+char *VrArgv[MAX_ARGC], *VrEnvp[MAX_ENVC];
+int VrArgc, VrEnvc;
+
+#define NEITHER 0
+#define ARGVONLY 1
+#define ENVONLY 2
+#define BOTH 3
+
+struct argv_tab {
+ char *key;
+ char *val;
+ int which;
+
+} argv_tab[MAX_ARGC] = {
+ { "OsLoader", STR_OSLOADER, BOTH },
+ { "SystemPartition", STR_XYZZY, BOTH },
+ { "OSLoadFilename", STR_OSLOADFN, BOTH },
+ { "OSLoadPartition", STR_OSLOADPART, BOTH },
+ { "OSLoadOptions", "nodebug", BOTH },
+ { "LoadIdentifier", STR_LDIDENT, BOTH },
+ { "AutoLoad", "yes", ENVONLY },
+ { "FWSearchPath", STR_FWSEARCH, ENVONLY },
+ { "LastKnownGood", "False", ENVONLY },
+ { "FWTEST", STR_FWTEST, ENVONLY }
+};
+
+STATIC VOID parse_args(VOID);
+STATIC VOID find_boot_dev(VOID);
+STATIC VOID collect_argv(VOID);
+STATIC VOID create_argv(VOID);
+STATIC VOID update_argv(char *, char *);
+STATIC VOID add_argv(char *, char *);
+STATIC VOID read_ARC_env_vars(VOID);
+STATIC VOID add_envp(char *, char *);
+STATIC VOID VrInitSystem (VOID);
+STATIC VOID VrInitSystemBlock (VOID);
+STATIC VOID VrNotYet(VOID);
+STATIC VOID VrKseg0(VOID);
+STATIC VOID move_amd_to_isa_hack(VOID);
+STATIC VOID move_ide_to_isa_hack(VOID);
+STATIC VOID move_scsi_children_to_ide_hack(VOID);
+STATIC VOID move_multi_to_root(PCONFIGURATION_NODE);
+STATIC CHAR *choose_args( char *, char *, int);
+PCHAR VrCanonicalName( IN PCHAR Variable);
+
+/* LONG claimreal(PVOID, ULONG); */
+STATIC LONG claimphys(PVOID, ULONG, ULONG);
+STATIC LONG map(PVOID, PVOID, ULONG, ULONG);
+STATIC VOID check_mmu_type (VOID);
+extern ULONG VrGetProcRev();
+
+typedef VOID (*VR_NOT_YET_ROUTINE) (VOID);
+
+main(VOID *resid, VOID *entry, int (cif_handler)(long *))
+{
+ ihandle bootih;
+ ULONG FileId;
+ ARC_STATUS res;
+ void (*jump_osloader)(int, char **, char**);
+ extern VOID Salutation();
+
+ Salutation();
+
+ VrInitSystemBlock();
+
+ check_mmu_type();
+
+ read_ARC_env_vars();
+
+ /*
+ * Do something with the arg string.
+ */
+ parse_args();
+
+ //
+ // Set up the "kseg0" translation.
+ //
+ VrKseg0();
+
+ //
+ // Build the device tree.
+ //
+ debug(VRDBG_MAIN, "Building the device tree...\n");
+ walk_obp((phandle) 0,
+ (PCONFIGURATION_NODE) 0,
+ (PCONFIGURATION_NODE) 0,
+ (PCONFIGURATION_NODE) 0
+ );
+
+ //
+ // Move all MultiFunction adapters (usually PCI or ISA,
+ // presumably) to be children of the System Class (i.e., RootNode).
+ // This is because the NT kernel prefers to limit the complexity
+ // of nested bus nodes.
+ //
+
+ debug(VRDBG_MAIN, "main: move all multi nodes to children of root...\n");
+ move_multi_to_root(RootNode);
+
+ debug(VRDBG_MAIN, "main: AMD nodes become children of isa...\n");
+ move_amd_to_isa_hack();
+
+ debug(VRDBG_MAIN, "Done with the device tree.\n");
+ if (VrDebug & VRDBG_DUMP) {
+ dump_tree(RootNode);
+ sleep(10);
+ } else if (VrDebug & VRDBG_CONFIG) {
+ quick_dump_tree(RootNode);
+ sleep(10);
+ }
+
+ //
+ // Build the system parameter block.
+ //
+ debug(VRDBG_MAIN, "main: Build the system parameter block...\n");
+ VrInitSystem();
+
+ //
+ // Determine the boot path and translate it to ARC form.
+ //
+ debug(VRDBG_MAIN, "main: find boot device...\n");
+ find_boot_dev();
+ debug(VRDBG_MAIN, "main: create argument and environment lists...\n");
+ create_argv();
+ warn("Booting from '%s'\n", VrArgv[0]);
+
+ res = VrOpen(VrArgv[0], ArcOpenReadOnly, &FileId);
+ if (res != ESUCCESS) {
+ fatal("VrOpen returned %x\n", res);
+ }
+
+ debug(VRDBG_MAIN, "main: setup boot ihandle, jump_osloader handle...\n");
+ bootih = FileTable[FileId].IHandle;
+ jump_osloader = load_file(bootih);
+ VrClose(FileId);
+ VrFlushAllCaches();
+
+ debug(VRDBG_MAIN, "main: create memory descriptor list...\n");
+ VrCreateMemoryDescriptors();
+ if (VrDebug & VRDBG_MEM) {
+ DisplayMemory();
+ }
+
+ if (VrDebug & VRDBG_HOLDIT) {
+
+ warn("Jumping to 0x%x\n", (char *)jump_osloader);
+ puts("This time for sure!");
+ OFEnter();
+ } else {
+ puts("\233H\233J"); // Clear screen
+ }
+ debug(VRDBG_MAIN, "main: launch OSLOADER!!! ...\n");
+ jump_osloader(VrArgc, VrArgv, VrEnvp);
+ OFExit();
+ return (0);
+}
+
+STATIC VOID
+check_mmu_type(VOID)
+{
+ ihandle ih;
+
+ ih = get_int_prop (OFFinddevice("/chosen"), "cpu");
+ if (ih == -1) {
+ use_bat_mapping = TRUE;
+ } else {
+ use_bat_mapping =
+ (OFGetproplen(OFInstanceToPackage(ih),"603-translation") == -1);
+ }
+}
+
+#define NEXT_TOKEN() if ((bootargs = strctok(NULL, ' ')) == NULL) return;
+
+STATIC VOID
+parse_args(VOID)
+{
+ phandle ph;
+ char *bootargs;
+ char *key, *val;
+ struct argv_tab *atp = argv_tab;
+
+ ph = OFFinddevice("/chosen");
+ if (ph == 0) {
+ warn("parse_args: No phandle for '/chosen'\n");
+ return;
+ }
+
+ debug(VRDBG_MAIN, "parse_args: /chosen phandle %x\n", ph);
+ bootargs = get_str_prop(ph, "bootargs", ALLOC);
+ if (bootargs == NULL || *bootargs == '\0') {
+ return;
+ }
+ debug(VRDBG_MAIN, "bootargs: '%s'\n", bootargs);
+
+ bootargs = strctok(bootargs, ' ');
+ if (bootargs[0] != '-') {
+
+ debug(VRDBG_MAIN, "Boot file '%s'\n", bootargs);
+ if (bootargs[0] == '\\') {
+
+ //
+ // We're just specifying the file to boot:
+ // update the OsLoader argument but nothing else.
+ //
+ update_argv("OsLoader", bootargs);
+
+ } else {
+
+ //
+ // Without a leading backslash, bootargs presumably
+ // contains a full device path.
+ // If so, update both Bootpath and OsLoader.
+ //
+ Bootpath = bootargs;
+ if (key = index(Bootpath, '\\')) {
+ val = (char *) malloc(strlen(key)+1);
+ strcpy(val, key);
+ update_argv("OsLoader", val);
+ *key = '\0';
+ }
+ }
+
+ debug(VRDBG_MAIN, "Bootpath '%s'\n", Bootpath);
+ for ( ; atp->key != NULL; ++atp) {
+ if (strcmp("OsLoader", atp->key) == 0) {
+ debug(VRDBG_MAIN, "OsLoader '%s'\n", atp->val);
+ break;
+ }
+ }
+ NEXT_TOKEN();
+ }
+
+ while (bootargs && (*bootargs != '\0')) {
+ if (strncmp(bootargs, "-vrdebug", 8) == 0) {
+ NEXT_TOKEN();
+ debug(VRDBG_MAIN, "-vrdebug: '%s'\n", bootargs);
+ VrDebug = atoi(bootargs);
+ continue;
+ }
+ if (strncmp(bootargs, "-env", 4) == 0) {
+ NEXT_TOKEN();
+ key = bootargs;
+ NEXT_TOKEN();
+ val = bootargs;
+ debug(VRDBG_MAIN, "-env: '%s' '%s'\n", key, val);
+ update_argv(key, val);
+ }
+ if (strncmp(bootargs, "-h", 2) == 0) {
+ VrDebug |= VRDBG_HOLDIT;
+ }
+ NEXT_TOKEN();
+ }
+}
+
+STATIC VOID
+update_argv(char *key, char *val)
+{
+ struct argv_tab *atp = argv_tab;
+
+ for ( ; atp->key != NULL; ++atp) {
+ if (strcmp(key, atp->key) == 0) {
+ atp->val = val;
+ return;
+ }
+ }
+ if (atp >= &argv_tab[MAX_ARGC]) {
+ warn("You can't define any more argument variables\n");
+ return;
+ }
+ atp->key = key;
+ atp->val = val;
+ atp->which = BOTH;
+}
+
+#define CSI '\233'
+#define ESC '\033'
+
+STATIC INT
+select_boot(VOID)
+{
+ char *ids[16];
+ char *prop, c;
+ int i= 0, choices, chosen, countdown, csi, count;
+ debug(VRDBG_ENTRY,"select_boot: VOID BEGIN....\n");
+
+ //
+ // Determine how long to display the list of options:
+ //
+ prop = VrGetEnvironmentVariable("COUNTDOWN");
+ if (prop == NULL) {
+ countdown = 10;
+ } else {
+ countdown = atoi(prop);
+ }
+
+ //
+ // get the text list of possible options.
+ //
+ prop = VrGetEnvironmentVariable("LOADIDENTIFIER");
+ if (prop == NULL) {
+ return(0);
+ }
+
+ //
+ // tokenize the string of load options, creating pointers to each
+ // component of the string. Don't use strctok, since we need to
+ // worry about detecting null entries in the OsLoadOptions list.
+ //
+ ids[i++] = prop; // stuff the first one in the array....
+ while ((prop = index(prop, ';')) != NULL) {
+ *prop = '\0'; // change the separator to a null
+ prop++;
+ ids[i++] = prop;
+ }
+ choices = i;
+ while (i < 16) {
+ ids[i++] = NULL;
+ }
+
+ //
+ // here be the wheel of fortune: Makes yer choice and be off wid ya
+ //
+ chosen = 0;
+ csi = 0;
+ warn("\233H\233J"); // Clear screen
+ Salutation();
+ puts("\233""24;1HMake selection using arrow keys and 'Enter', or press ESC to cancel");
+ countdown += VrGetRelativeTime();
+again:
+ for (i = 0; i < choices; ++i) {
+ if (i == chosen) {
+ warn("\233%d;1H\233K\233%d;3H\233""7m* %s\233""m\n",
+ i+3, i+3, ids[i]);
+ } else {
+ warn("\233%d;1H\233K\233%d;5H%s\n", i+3, i+3, ids[i]);
+ }
+ }
+ i = 0;
+ warn("\233%d;1H\233K\n", choices+5);
+ while (VrGetReadStatus(0)) {
+ if (countdown == -1) {
+ continue;
+ }
+ if (VrGetRelativeTime() > (unsigned) countdown) {
+ goto out;
+ }
+ if (VrGetRelativeTime() != (unsigned) i) {
+ warn("\233%d;1H\233K\233%d;5HSeconds remaining: %d\n",
+ choices+5, choices+5, countdown - VrGetRelativeTime());
+ i = VrGetRelativeTime();
+ }
+ }
+ countdown = -1;
+ (void) VrRead(0, &c, 1, &count);
+ if (csi) {
+ switch (c) {
+ case 'A': chosen = max(chosen - 1, 0); break;
+ case 'B': chosen = min(chosen + 1, choices-1); break;
+ }
+ csi = 0;
+ } else {
+ switch (c) {
+ case CSI: csi = 1; break;
+ case '\r': goto out;
+ case '\n': goto out;
+ case ESC: OFExit();
+
+ case 'k': // vi
+ case '\020': // emacs
+ case '+': // good guesses
+ case '<':
+ chosen = max(chosen - 1, 0); break;
+ case 'j':
+ case '\016':
+ case '-':
+ case '>':
+ chosen = min(chosen + 1, choices-1); break;
+
+ case '\t':
+ if (++chosen == choices) {
+ chosen = 0;
+ }
+ break;
+ }
+ }
+ goto again;
+
+out:
+ warn("\233H\233J"); // Clear screen
+ //
+ // Given the chosen number, pull out the corresponding string, and
+ // setup the Bootpath and SystemPath variables:
+ //
+ Bootpath = choose_args("OSLOADER", "OsLoader", chosen);
+ SystemPath = choose_args("SYSTEMPARTITION", "SystemPartition", chosen);
+
+ //
+ // get the rest of the options.....
+ //
+ choose_args("OSLOADPARTITION", "OSLoadPartition", chosen);
+ choose_args("OSLOADOPTIONS", "OSLoadOptions", chosen);
+ choose_args("LOADIDENTIFIER", "LoadIdentifier", chosen);
+ choose_args("OSLOADFILENAME", "OSLoadFilename", chosen);
+
+ debug(VRDBG_ENTRY,"select_boot: VOID ....END\n");
+ return(1);
+}
+
+STATIC CHAR *
+choose_args( char *EnvVar, char *Varrrg, int achoice )
+{
+ char *prop, *cp;
+ int i= 0;
+ debug(VRDBG_ENTRY,
+ "choose_args: EnvVar: %s Varrrg: %s achoice: 0x%x BEGIN....\n",
+ *EnvVar, *Varrrg, achoice);
+ prop = VrGetEnvironmentVariable(EnvVar);
+ //debug(VRDBG_TEST, "\n@%d: prop is currently...%s:\n",i,prop);
+ if (prop == NULL) {
+ return(0);
+ }
+ prop = strcsep(prop, ';');
+ for (i = 0; i < achoice; ++i) {
+ if ((prop = strcsep(NULL, ';')) == NULL) {
+ return(0);
+ }
+ }
+ cp = zalloc(strlen(prop) +1 );
+ strcpy(cp, prop);
+ update_argv(Varrrg, cp);
+ //debug(VRDBG_TEST, "@%d: cp is set to...%s:\n",i,cp);
+ debug(VRDBG_ENTRY, "choose_args: ....END\n");
+ return( cp );
+}
+
+STATIC VOID
+find_boot_dev(VOID)
+{
+ phandle ph;
+ char *bootpath;
+ PCONFIGURATION_NODE node;
+
+ if (Bootpath) {
+ debug(VRDBG_MAIN, "Bootpath has been set from the command line\n");
+ return;
+ }
+ if (select_boot()) {
+ debug(VRDBG_MAIN, "We chose a boot device from LOADIDENTIFIER menu.\n");
+ return;
+ }
+
+ // Use whatever device we booted the veneer from.
+ ph = OFFinddevice("/chosen");
+ bootpath = get_str_prop(ph, "bootpath", NOALLOC);
+ if (bootpath == NULL) {
+ warn("find_boot_dev: No property '/chosen:bootpath'\n");
+ return;
+ }
+ debug(VRDBG_MAIN, "find_boot_dev: bootpath (len %d) '%s'\n",
+ strlen(bootpath), bootpath);
+ node = PathToNode(bootpath);
+ if (node == NULL) {
+ warn("find_boot_dev: Couldn't find node for '%s'\n", bootpath);
+ return;
+ }
+ Bootpath = NodeToArcPath(node);
+ bootpath = (char *)malloc(strlen(Bootpath) + strlen("partition(1)") + 1);
+ strcpy(bootpath, Bootpath);
+ strcat(bootpath, "partition(1)"); /* XXX */
+ free(Bootpath);
+ Bootpath = bootpath;
+ debug(VRDBG_MAIN, "find_boot_dev: bootpath '%s'\n", Bootpath);
+}
+
+/*
+ *
+ * ROUTINE: VOID read_ARC_env_vars(VOID)
+ *
+ * DESCRIPTIN:
+ * Initialize the arc argument table with the values contained in open
+ * firmware.
+ *
+ */
+
+STATIC VOID
+read_ARC_env_vars(VOID)
+{
+ struct argv_tab *atp;
+ char *val, *newval;
+
+ //
+ // for each variable in the argv_tab array, find the actual value
+ // this system has in firmware.
+ //
+ for (atp = argv_tab; atp < &argv_tab[MAX_ARGC] && atp->key; ++atp) {
+ if ((val = VrGetEnvironmentVariable(atp->key)) != NULL) {
+ newval = (char *) malloc(strlen(val) + 1);
+ strcpy(newval, val);
+ atp->val = newval;
+ }
+ }
+}
+
+STATIC VOID
+create_argv(VOID)
+{
+ struct argv_tab *atp;
+ char *osloader, *old_osloader = "";
+ char *buf;
+ phandle ph;
+ extern char *VeneerVersion();
+
+ /*
+ * First instantiate the boot partition string in the
+ * OS Loader arguments table. By the way, when we find
+ * STR_OSLOADER, save it to produce the argv[0] and OsLoader
+ * arguments.
+ */
+ for (atp = argv_tab; atp < &argv_tab[MAX_ARGC] && atp->key; ++atp) {
+ if (strcmp(atp->val, STR_XYZZY) == 0) {
+ atp->val = Bootpath;
+ }
+ if (strcmp(atp->key, "OsLoader") == 0) {
+ old_osloader = atp->val;
+ }
+ }
+
+ /*
+ * Initialize the argv/envp arrays.
+ */
+ VrArgc = VrEnvc = 0;
+ bzero((PCHAR) VrArgv, MAX_ARGC * sizeof(PCHAR));
+ bzero((PCHAR) VrEnvp, MAX_ENVC * sizeof(PCHAR));
+ VrEnvp[VrEnvc] = "";
+
+ /*
+ * Construct argv[0], the boot string (special case).
+ */
+ if (old_osloader[0] == '\\') {
+ osloader = zalloc(strlen(Bootpath) + strlen(old_osloader) + 1);
+ strcpy(osloader, Bootpath);
+ strcat(osloader, old_osloader);
+ } else {
+ osloader = old_osloader;
+ }
+ add_argv("", osloader);
+
+ /*
+ * Now walk the argv table, building the argv and envp
+ * arrays. When we encounter OsLoader, be sure to use the
+ * buffer we just built, rather than the table value.
+ */
+ for (atp = argv_tab; atp < &argv_tab[MAX_ARGC] && atp->key; ++atp) {
+ if (strcmp(atp->key, "OsLoader") == 0) {
+ atp->val = osloader;
+ }
+ if (atp->which != ENVONLY) {
+ add_argv(atp->key, atp->val);
+ }
+ if (atp->which != ARGVONLY) {
+ add_envp(atp->key, atp->val);
+ }
+ if (strcmp(atp->key, "SystemPartition" ) == 0 ){
+ atp->val = SystemPath;
+ }
+ }
+
+ /*
+ * Record the version strings.
+ */
+ ph = OFFinddevice("/openprom");
+ add_envp("FirmwareVersion", get_str_prop(ph, "model", NOALLOC));
+ add_envp("VeneerVersion", VeneerVersion());
+
+ /*
+ * Finally, take care of the console paths, set at runtime.
+ */
+ buf = VrFindConsolePath("stdin");
+ add_argv("ConsoleIn", buf);
+ add_envp("ConsoleIn", buf);
+ free(buf);
+
+ buf = VrFindConsolePath("stdout");
+ add_argv("ConsoleOut", buf);
+ add_envp("ConsoleOut", buf);
+ free(buf);
+}
+
+
+STATIC VOID
+add_argv(PCHAR key, PCHAR val)
+{
+ char *buf;
+ int len;
+
+ len = strlen(key);
+ if (len) {
+ len += 1; // for '='
+ }
+ len += strlen(val);
+ buf = (char *) zalloc(len+1);
+ strcpy(buf, key);
+ if (*buf != '\0') {
+ strcat(buf, "=");
+ }
+ strcat(buf, val);
+ VrArgv[VrArgc] = buf;
+ if ((buf = index(buf, ';')) != NULL) {
+ *buf = '\0';
+ }
+ debug(VRDBG_ARGV, "Argv[%d]: %s\n", VrArgc, VrArgv[VrArgc]);
+ VrArgc += 1;
+}
+
+/*
+ * ROUTINE: VOID add_envp( PCHAR, PCHAR )
+ *
+ * DESCRIPTION:
+ * Add the passed in name string and value into an array
+ * of string/value pairs that describes the environment for
+ * the arc program to be executed. The entry in the array is
+ * of the form "name=value", and is added to the beginning of
+ * the array.
+ *
+ * RETURN:
+ * Returns nothing.
+ *
+ */
+
+STATIC VOID
+add_envp(PCHAR key, PCHAR val)
+{
+ char *buf;
+ int len;
+
+ len = strlen(key);
+ if (len) {
+ len += 1; // for '='
+ }
+ len += strlen(val);
+ buf = (char *) zalloc(len+1);
+ strcpy(buf, VrCanonicalName(key));
+ if (*buf != '\0') {
+ strcat(buf, "=");
+ }
+ strcat(buf, val);
+ VrEnvp[VrEnvc+1] = VrEnvp[VrEnvc];
+ VrEnvp[VrEnvc] = buf;
+ debug(VRDBG_ENV, " Env[%d]: %s\n", VrEnvc, VrEnvp[VrEnvc]);
+ VrEnvc += 1;
+}
+
+static
+int
+is_mp_capable(ULONG VerRev)
+{
+ ULONG ver = (VerRev >> 16) & 0xFFFF;
+ ULONG rev = VerRev & 0xFFFF;
+
+ switch(ver) {
+
+ case PPC_604:
+ if ( rev > 0x0304 )
+ return(1);
+ break;
+
+ case PPC_604E:
+ return(1);
+
+ default:
+ return(0);
+
+ }
+ return(0);
+
+}
+
+
+//
+// The routines that follow initialize the System Parameter Block,
+// Firmware Vector Table, and Restart Blocks.
+//
+// Note the use of MAP() and UNMAP() macros. The kernel requires that
+// addresses in the System Parameter Block and Restart Blocks be
+// VIRTUAL, not physical. Therefore, all addresses that may be presented
+// to the kernel must be mapped to KSEG0; i.e., they must be in the
+// range starting at 0x80000000.
+//
+
+STATIC PRESTART_BLOCK last_rstb = 0;
+
+STATIC PRESTART_BLOCK
+InitRestartBlocks(PCONFIGURATION_NODE node, PRESTART_BLOCK rstb)
+{
+ PRESTART_BLOCK new_rstb;
+
+ debug(VRDBG_ENTRY, "InitRestartBlocks: Begin(0x%x, 0x%x)...\n",node, rstb);
+ VRDBG(VRDBG_ENTRY, vr_dump_config_node(node));
+
+ if (node->Component.Class == ProcessorClass &&
+ node->Component.Type == CentralProcessor) {
+
+ // Figure out where the next node's space should be.
+ if (rstb) {
+ new_rstb = (PRESTART_BLOCK) ((PCHAR) rstb + sizeof(RESTART_BLOCK));
+ } else {
+ new_rstb = (PRESTART_BLOCK) ((PCHAR) SYSTEM_BLOCK +
+ SYSTEM_BLOCK->Length + SYSTEM_BLOCK->FirmwareVectorLength);
+ }
+
+ // Claim the space and turn it into a restart block.
+ if (CLAIM((VOID *)new_rstb, sizeof(RESTART_BLOCK)) == -1) {
+ fatal("Couldn't claim RESTART BLOCK\n");
+ }
+
+ if (rstb) {
+ rstb->NextRestartBlock = (PRESTART_BLOCK) UNMAP(new_rstb);
+ }
+ rstb = new_rstb;
+ last_rstb = new_rstb;
+
+ bzero((PCHAR) rstb, sizeof(RESTART_BLOCK));
+ rstb->Signature = ARC_RESTART_BLOCK_SIGNATURE;
+ rstb->Version = 1;
+ rstb->Revision = 2;
+ rstb->Length = sizeof(RESTART_BLOCK);
+ rstb->SaveAreaLength = sizeof(PPC_RESTART_STATE);
+// rstb->BootStatus.BootFinished = 1;
+ rstb->BootStatus.ProcessorReady = 1;
+ rstb->ProcessorId = node->Component.Key;
+ if (rstb->ProcessorId == 0) {
+ rstb->BootStatus.ProcessorStart = 1;
+ rstb->BootStatus.ProcessorRunning = 1;
+ } else {
+ rstb->BootStatus.ProcessorStart = 0;
+ }
+ }
+
+ if (node->Child) {
+ rstb = InitRestartBlocks(node->Child, rstb);
+ }
+ if (node->Peer) {
+ rstb = InitRestartBlocks(node->Peer, rstb);
+ }
+
+ debug(VRDBG_ENTRY, "InitRestartBlocks: ....Exit\n");
+ return (rstb);
+}
+
+STATIC VOID
+SumRestartBlocks(PRESTART_BLOCK rstb)
+{
+ PLONG up = (PLONG) rstb;
+ LONG accum = 0;
+
+ debug(VRDBG_ENTRY, "SumRestartBlocks: Begin(0x%x)....\n", rstb);
+ rstb->CheckSum = 0;
+ while (up < (PLONG) ((PCHAR) rstb + sizeof(RESTART_BLOCK))) {
+ accum += *up++;
+ }
+ rstb->CheckSum = -accum;
+ debug(VRDBG_ENTRY, "SumRestartBlocks: ....Exit\n", rstb);
+}
+
+STATIC int
+IdleCPU(PRESTART_BLOCK rstb, int stopFlag)
+{
+ STATIC PVOID IdleLoop = 0;
+ STATIC PULONG Bootp;
+ STATIC ULONG ProcRev=0;
+ STATIC INT mismatchFlag = 0;
+ ULONG IdleLoopSize;
+ ULONG res, timeout;
+ extern PVOID ArcPoll, EndArcPoll;
+
+ // cpu0 is always successful so that we can have a
+ // uniprocessor system in hand
+ if (rstb->ProcessorId == 0) {
+ ProcRev = VrGetProcRev();
+ if (!is_mp_capable(ProcRev))
+ mismatchFlag = 1;
+ return(0);
+ }
+
+ // The processor idle loop must be in FirmwarePermanent memory,
+ // so that it's not disturbed by kernel startup. Identify a piece
+ // of memory just after the last restart block and copy in the
+ // idle loop code.
+
+ if (IdleLoop == 0) {
+ IdleLoop = (PCHAR) last_rstb + sizeof(RESTART_BLOCK);
+ IdleLoopSize = (ULONG) &EndArcPoll - (ULONG) &ArcPoll;
+
+ // Pad to make room for BootStatus and SaveArea variables.
+ Bootp = (PULONG) IdleLoop;
+ (PCHAR) IdleLoop += 3 * sizeof(ULONG);
+ IdleLoopSize += 3 * sizeof(ULONG);
+
+ if (CLAIM(IdleLoop, IdleLoopSize) == -1) {
+ fatal("Couldn't claim MP idle loop\n");
+ }
+ bcopy((PCHAR) &ArcPoll, IdleLoop, IdleLoopSize);
+ VrFlushAllCaches();
+ }
+
+ //
+ // Set this processor spinning in the new idle loop.
+ // XXX - To do: change this to CIF.
+ // Since we're running in virtual mode that is mapped virtual 0
+ // to physical 0, this assignment translates directly into the
+ // real mode addresses the IdleCPU routine will end up executing.
+ //
+ Bootp[0] = 0; // processor version returned by the cpu
+ Bootp[1] = (ULONG) &rstb->BootStatus;
+ Bootp[2] = (ULONG) &rstb->u.SaveArea;
+
+ // Give the other processor plenty of time to start up: he may be
+ // executing debug printouts and other slow tasks before switching.
+ // Five seconds should be more than adequate.
+
+ debug(VRDBG_TMP, "Executing non 0 processor at 0x%x\n", IdleLoop);
+ res = 0;
+ if (OFInterpret(1, 3, &res, "cpu-execute-code", rstb->ProcessorId, IdleLoop) != 0) {
+ return(-1);
+ }
+ if (res == 0)
+ return(-1);
+
+ //
+ // wait a small amount of time for the other processor to
+ // start up. Since VrGetRelative time returns the time since
+ // power-on/reset, tack on a few seconds for the waiting period.
+ //
+ //timeout = VrGetRelativeTime() + (5 * 1000);
+ timeout = VrGetRelativeTime() + (5 * 1); // 5 seconds should be
+ // long enough
+
+ do {
+ if (Bootp[1] == 0x1234) {
+ debug(VRDBG_TMP,"ProcRev = 0x%x; return = 0x%x\n",
+ Bootp[0], Bootp[1]);
+ if ( Bootp[0] != ProcRev || mismatchFlag || stopFlag) {
+ Bootp[1] = 0xBAD;
+ return(-1);
+ } else {
+ Bootp[1] = 0xCAFE;
+ return(0);
+ }
+ }
+ } while (VrGetRelativeTime() < timeout);
+ fatal("Processor %d failed to enter MP idle loop.\n", rstb->ProcessorId);
+}
+
+
+/*
+ * Routine Description:
+ * This routine initializes the firmware vector in the system parameter
+ * block.
+ *
+ * Arguments:
+ * None.
+ *
+ * Return Value:
+ * None.
+ *
+ */
+
+STATIC VOID
+VrInitSystem(VOID)
+{
+ LONG i;
+ LONG FirmwareVectorLen;
+ PRESTART_BLOCK rstb, PrevRstb;
+ int NumOfCpu = 0 , NumProc = 0;
+ ULONG ProcMask = 0, maskscan = 0;
+ PCHAR evp;
+
+ debug(VRDBG_ENTRY, "VrInitSystem: BEGIN....\n");
+ //
+ // Initialize the system parameter block
+ //
+ FirmwareVectorLen = (ULONG)MaximumRoutine * sizeof(ULONG);
+ i = sizeof(SYSTEM_PARAMETER_BLOCK) + FirmwareVectorLen;
+ debug(VRDBG_ENTRY, "VrInitSystem: i(0x%x), FirmwareVectorLen(0x%x) set:\n",
+ i, FirmwareVectorLen);
+
+#if 0
+ //
+ // THis is now down in a different routine called by main.
+ //
+ //
+ // attempting to setup all the claiming early on
+ //
+ if (use_bat_mapping) {
+ res = claim((PVOID) SYSTEM_BLOCK, i);
+ } else {
+ res = claimreal((PVOID) SYSTEM_BLOCK, i);
+ }
+ if (res == -1) {
+ fatal("Couldn't claim SYSTEM PARAMETER BLOCK\n");
+ }
+ bzero((PCHAR)SYSTEM_BLOCK, i);
+#endif
+
+
+ debug(VRDBG_ENTRY, "VrInitSystem: Init SYSTEM_BLOCK.. \n");
+ SYSTEM_BLOCK->Signature = SYSTEM_BLOCK_SIGNATURE;
+ SYSTEM_BLOCK->Version = ARC_VERSION;
+ SYSTEM_BLOCK->Revision = ARC_REVISION;
+ SYSTEM_BLOCK->Length = sizeof(SYSTEM_PARAMETER_BLOCK);
+
+ SYSTEM_BLOCK->FirmwareVector =
+ (PVOID) UNMAP((PCHAR) SYSTEM_BLOCK + SYSTEM_BLOCK->Length);
+ SYSTEM_BLOCK->FirmwareVectorLength = FirmwareVectorLen;
+
+ //
+ // Initialize the restart blocks.
+ //
+ debug(VRDBG_ENTRY, "VrInitSystem: Init restart blocks\n");
+ SYSTEM_BLOCK->RestartBlock = (PRESTART_BLOCK) UNMAP((PCHAR) SYSTEM_BLOCK +
+ SYSTEM_BLOCK->Length + SYSTEM_BLOCK->FirmwareVectorLength);
+ if (InitRestartBlocks(RootNode, 0)) {
+ rstb = (PRESTART_BLOCK) MAP(SYSTEM_BLOCK->RestartBlock);
+ PrevRstb = 0;
+ NumOfCpu = 0;
+ ProcMask = 0xFFFFFFFF;
+ if ( (evp = VrGetEnvironmentVariable("PROCESSORS")) != NULL )
+ ProcMask = atoi(evp) | 1;
+ maskscan = 1;
+ while (rstb) {
+ SumRestartBlocks(rstb);
+
+ if (IdleCPU(rstb,(ProcMask&maskscan) == 0 ) == -1) {
+ ProcMask &= ~maskscan; // clear the bit
+ // remove the restart block
+ PrevRstb->NextRestartBlock = rstb->NextRestartBlock;
+ } else {
+ NumOfCpu++;
+ PrevRstb = rstb;
+ }
+ maskscan <<= 1;
+ rstb = (PRESTART_BLOCK) MAP(PrevRstb->NextRestartBlock);
+ }
+ } else {
+ SYSTEM_BLOCK->RestartBlock = 0;
+ }
+
+
+ //
+ // Temporarily make all firmware vector to point to an error routine.
+ //
+ for (i=LoadRoutine; i < MaximumRoutine; i++) {
+ (VR_NOT_YET_ROUTINE)SYSTEM_BLOCK->FirmwareVector[i] = VrNotYet;
+ }
+
+ //
+ // Initialize the firmware vectors for other functions.
+ //
+ VrEnvInitialize();
+ VrMemoryInitialize();
+ VrIoInitialize();
+ VrDisplayInitialize();
+ VrLoadInitialize();
+ VrRestartInitialize();
+ VrConfigInitialize();
+ VrTimeInitialize();
+ debug(VRDBG_ENTRY, "VrInitSystem: .....END\n");
+}
+
+STATIC VOID
+VrNotYet( VOID )
+{
+ fatal("This ARC function is not yet implemented\n");
+}
+
+
+STATIC VOID
+move_multi_to_root(PCONFIGURATION_NODE node)
+{
+ PCONFIGURATION_NODE child = node->Child;
+ PCONFIGURATION_NODE peer = node->Peer;
+ PCONFIGURATION_NODE n;
+ ULONG key;
+
+ debug(VRDBG_ENTRY, "move_multi_to_root: node 0x%x\n", node);
+ if (node == 0) {
+ debug(VRDBG_TREE, "move_multi_to_root: node is 0, return.\n");
+ return;
+ }
+ debug(VRDBG_TREE, "MMTR: move node: 0x%x to child of ROOT\n",node);
+ VRDBG(VRDBG_TREE, vr_dump_config_node(node));
+
+ // Examine the first child, and keep promoting it/them until
+ // the first child is no longer of type multi.
+
+ while ( (child) && (child->Component.Type == MultiFunctionAdapter)) {
+ for (n = RootNode->Child, key = 0; n->Peer; n = n->Peer) {
+ if (n->Component.Type == MultiFunctionAdapter) {
+ key = max(key, n->Component.Key);
+ }
+ }
+ if (n->Component.Type == MultiFunctionAdapter) {
+ key = max(key, n->Component.Key);
+ }
+ child->Parent = RootNode;
+ n->Peer = child;
+ node->Child = child->Peer;
+ child->Peer = 0;
+ child->Component.Key = key + 1;
+ child = node->Child;
+ }
+
+ // Process the entire Child branch.
+
+ move_multi_to_root(child);
+
+ // Now for the Peer branch: first, if our parent is the root,
+ // there's no need to promote the peer node, so skip the next step.
+
+ if (node->Parent != RootNode) {
+
+ // As before, promote peers until the peer isn't a multi node...
+
+ while (peer && peer->Component.Type == MultiFunctionAdapter) {
+ for (n = RootNode->Child, key = 0; n->Peer; n = n->Peer) {
+ if (n->Component.Type == MultiFunctionAdapter) {
+ key = max(key, n->Component.Key);
+ }
+ }
+ if (n->Component.Type == MultiFunctionAdapter) {
+ key = max(key, n->Component.Key);
+ }
+ peer->Parent = RootNode;
+ n->Peer = peer;
+ node->Peer = peer->Peer;
+ peer->Peer = 0;
+ peer->Component.Key = key + 1;
+ peer = node->Peer;
+ }
+ }
+
+ // ...and process the Peer branch. Since our traversal is depth-first
+ // and promoted nodes are appended to the RootNode's Child's Peer branch
+ // (and are thus processed last), this routine should suffice to traverse
+ // the entire tree.
+
+ move_multi_to_root(peer);
+}
+
+
+LONG
+claimreal(PVOID addr, ULONG size)
+{
+ if (claimphys((PVOID) MAP(addr), size, 0) == -1) {
+ return(-1);
+ }
+ return(map((PVOID) MAP(addr), addr, size, (ULONG) -1));
+}
+
+STATIC LONG
+claimphys(PVOID physical, ULONG size, ULONG align)
+{
+ static ihandle memih = 0;
+ ULONG base;
+
+ if (memih == 0) {
+ if((memih = get_int_prop(OFFinddevice("/chosen"), "memory")) == 0) {
+ fatal("Couldn't open the memory node");
+ }
+ }
+ return(OFCallMethod(1, 5, &base,
+ "claim", memih, align, size, (ULONG) physical));
+}
+
+STATIC LONG
+map(PVOID physical, PVOID virtual, ULONG size, ULONG mode)
+{
+ static ihandle mmuih = 0;
+
+ if (mmuih == 0) {
+ if((mmuih = get_int_prop(OFFinddevice("/chosen"), "mmu")) == 0) {
+ fatal("Couldn't open the MMU node");
+ }
+ }
+ return(OFCallMethod(0, 6, 0,
+ "map", mmuih, mode, size, virtual, (ULONG) physical));
+}
+
+/*
+ * Because the PowerPC port is based on the MIPS port, and no one saw fit
+ * to re-examine assumptions in the light of the PowerPC architecture,
+ * the NT kernel et al. are expected to reside in kseg0 (8000.0000-a000.000).
+ * Set up a virtual mapping for this region.
+ */
+STATIC VOID
+VrKseg0(VOID)
+{
+ ihandle ih;
+
+ debug(VRDBG_MAIN, "Mapping in kseg0...\n");
+ ih = get_int_prop(OFFinddevice("/chosen"), "mmu");
+ if (ih == 0) {
+ fatal("Couldn't open the MMU node; kseg0 translation not set up.\n");
+ }
+ OFCallMethod(0, 6, 0, "map", ih, -2, 0x800000, 0x80000000, 0);
+ return;
+}
+
+/*
+ * XXX - This is a hack for the AMD79C974 Ethernet chip driver: the driver
+ * assumes the chip is on the ISA bus.
+ */
+
+STATIC void
+move_amd_to_isa_hack(void)
+{
+ phandle ph;
+ PCONFIGURATION_NODE amdnode, peernode, isanode;
+
+ if ((ph = OFFinddevice("/pci/AMD,79c970@4")) == -1) {
+ debug(VRDBG_MAIN, "No AMD ethernet found\n");
+ return;
+ }
+
+ peernode = PathToNode("/pci");
+ peernode = peernode->Child;
+
+ if (peernode->OfPhandle == ph) {
+ amdnode = peernode;
+ peernode->Parent->Child = peernode->Peer;
+ } else {
+ while (peernode->Peer && (peernode->Peer->OfPhandle != ph)) {
+ peernode = peernode->Peer;
+ }
+ amdnode = peernode->Peer;
+ peernode->Peer = amdnode->Peer;
+ }
+
+ isanode = PathToNode("/pci/isa");
+ if (isanode->Child == NULL) {
+ isanode->Child = amdnode;
+ amdnode->Peer = NULL;
+ } else {
+ peernode = isanode->Child;
+ while (peernode->Peer) {
+ peernode = peernode->Peer;
+ }
+ amdnode->Peer = peernode->Peer;
+ peernode->Peer = amdnode;
+ }
+ amdnode->Parent = isanode;
+}
+
+STATIC void
+move_ide_to_isa_hack(void)
+{
+ PCONFIGURATION_NODE node, idenode = 0, isanode;
+ int lastkey = 0;
+
+ isanode = PathToNode("/pci/isa");
+ node = isanode->Child;
+ while (node) {
+ if (strcmp(node->ComponentName, "disk") == 0) {
+ lastkey = max(lastkey, (int) node->Component.Key);
+ }
+ if (strcmp(node->Component.Identifier, "IDE") == 0) {
+ idenode = node;
+ }
+ node = node->Peer;
+ }
+ if (idenode == 0) {
+ return;
+ }
+
+ node = isanode->Child;
+ while (node->Peer != idenode) {
+ node = node->Peer;
+ }
+ node->Peer = node->Peer->Peer; /* Bypass ide node */
+ while (node->Peer) {
+ node = node->Peer;
+ }
+ node->Peer = idenode->Child;
+
+ while (node->Peer) {
+ node->Peer->Parent = node->Parent;
+ if (strcmp(node->Peer->ComponentName, "disk") == 0) {
+ node->Peer->Component.Key = ++lastkey;
+ }
+ node = node->Peer;
+ }
+}
+
+/*
+ * move_scsi_children_to_ide_hack() moves the children (e.g. disk and cdrom)
+ * of the SCSI node to be children of the IDE node, and changes the IDE's
+ * phandle pointer to point to the Open Firmware SCSI node.
+ *
+ * This egregious hack is necessary for the initial release of IBM's "Harley"
+ * evaluation system. On that system, IBM's portable boot loader misrepresents
+ * the hardware by reporting the SCSI disk and SCSI CD-ROM devices as children
+ * of the IDE node in the ARC tree! The IDE and SCSI nodes themselves are in
+ * the correct places in the ARC tree, but the children are in the wrong
+ * place. The enviroment variables that specify the locations of the OSLOADER
+ * and so forth collude in this fiction by specifying paths like
+ * multi(1)scsi(0)disk(0)rdisk(3)partition(2), which is the path through
+ * the IDE node (which, for reasons not specific to Harley, is of class
+ * "scsi"). I do not know exactly what NT does in order to compensate for
+ * this lie.
+ */
+
+STATIC void
+move_scsi_children_to_ide_hack(void)
+{
+ PCONFIGURATION_NODE node, idenode = 0, scsinode = 0;
+
+ if (OFGetproplen(OFFinddevice("/openprom"),"arc-scsi-to-ide") < 0) {
+ return;
+ }
+
+ idenode = PathToNode("/pci/isa/ide");
+ scsinode = PathToNode("/pci/scsi");
+
+ if (idenode == 0 || scsinode == 0) {
+ return;
+ }
+
+ /* Move SCSI children underneath IDE */
+ idenode->Child = scsinode->Child;
+
+ scsinode->Child = 0;
+
+ /* Reparent SCSI children to IDE */
+ for (node = idenode->Child; node != 0; node = node->Peer) {
+ node->Parent = idenode; /* Reparent nodes */
+ }
+
+ /* Point the IDE node to the Open Firmware SCSI node so Open will work */
+ idenode->OfPhandle = scsinode->OfPhandle;
+
+ idenode->Component.Type = ScsiAdapter;
+ idenode->ComponentName = "scsi";
+}
+
+STATIC VOID
+VrInitSystemBlock()
+{
+ LONG i;
+ LONG FirmwareVectorLen;
+ //
+ // Initialize the system parameter block
+ //
+ FirmwareVectorLen = (ULONG)MaximumRoutine * sizeof(ULONG);
+ i = sizeof(SYSTEM_PARAMETER_BLOCK) + FirmwareVectorLen;
+
+ if (CLAIM((PVOID) SYSTEM_BLOCK, i) == -1) {
+ fatal("Couldn't claim SYSTEM PARAMETER BLOCK\n");
+ }
+ bzero((PCHAR)SYSTEM_BLOCK, i);
+ return;
+}
+
diff --git a/private/ntos/boot/veneer/vrmalloc.c b/private/ntos/boot/veneer/vrmalloc.c
new file mode 100644
index 000000000..c0872f254
--- /dev/null
+++ b/private/ntos/boot/veneer/vrmalloc.c
@@ -0,0 +1,355 @@
+/*
+ *
+ * Copyright 1994 FirmWorks, Mountain View CA USA. All rights reserved.
+ * Copyright (c) 1995 FirePower Systems, Inc.
+ *
+ * $RCSfile: vrmalloc.c $
+ * $Revision: 1.6 $
+ * $Date: 1996/02/17 00:41:29 $
+ * $Locker: $
+ *
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * A "smarter" malloc William L. Sebok
+ * Sept. 24, 1984
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * If n = the size of an area rounded DOWN to the nearest power of two,
+ * all free areas of memory whose length is the same index n is organized
+ * into a chain with other free areas of index n. A request for memory
+ * takes the first item in the chain whose index is the size of the
+ * request rounded UP to the nearest power of two. If this chain is
+ * empty the next higher chain is examined. If no larger chain has memory
+ * then new memory is allocated. Only the amount of new memory needed is
+ * allocated. Any old free memory left after an allocation is returned
+ * to the free list. Extra new memory returned because of rounding
+ * to page boundaries is returned to free list.
+ *
+ * All memory areas (free or busy) handled by malloc are also chained
+ * sequentially by increasing address. When memory is freed it is
+ * merged with adjacent free areas, if any. If a free area of memory
+ * ends at the end of memory (i.e. at the break), the break is
+ * contracted, freeing the memory back to the system.
+ *
+ * Notes:
+ * ov_length field includes sizeof(struct overhead)
+ * adjacency chain includes all memory, allocated plus free.
+ */
+
+#include "veneer.h"
+
+#define MAGIC_FREE 0x548a934c
+#define MAGIC_BUSY 0xc139569a
+
+#define NBUCKETS 24
+#define NALIGN 4
+
+struct qelem {
+ struct qelem *q_forw;
+ struct qelem *q_back;
+};
+
+struct overhead {
+ struct qelem ov_adj; /* adjacency chain pointers */
+ struct qelem ov_buk; /* bucket chain pointers */
+ long ov_magic;
+ unsigned long ov_length;
+};
+
+char endfree = 0;
+struct qelem adjhead = { &adjhead, &adjhead };
+struct qelem buckets[NBUCKETS] = {
+ &buckets[0], &buckets[0],
+ &buckets[1], &buckets[1],
+ &buckets[2], &buckets[2],
+ &buckets[3], &buckets[3],
+ &buckets[4], &buckets[4],
+ &buckets[5], &buckets[5],
+ &buckets[6], &buckets[6],
+ &buckets[7], &buckets[7],
+ &buckets[8], &buckets[8],
+ &buckets[9], &buckets[9],
+ &buckets[10], &buckets[10],
+ &buckets[11], &buckets[11],
+ &buckets[12], &buckets[12],
+ &buckets[13], &buckets[13],
+ &buckets[14], &buckets[14],
+ &buckets[15], &buckets[15],
+ &buckets[16], &buckets[16],
+ &buckets[17], &buckets[17],
+ &buckets[18], &buckets[18],
+ &buckets[19], &buckets[19],
+ &buckets[20], &buckets[20],
+ &buckets[21], &buckets[21],
+ &buckets[22], &buckets[22],
+ &buckets[23], &buckets[23],
+};
+
+/*
+ * The following macros depend on the order of the elements in struct overhead
+ */
+#define TOADJ(p) ((struct qelem *)(p))
+#define FROMADJ(p) ((struct overhead *)(p))
+#define FROMBUK(p) ((struct overhead *)( (char *)p - sizeof(struct qelem)))
+#define TOBUK(p) ((struct qelem *)( (char *)p + sizeof(struct qelem)))
+
+#ifndef CURBRK
+#define CURBRK sbrk(0)
+#endif CURBRK
+
+STATIC void insque(), remque();
+
+#ifdef NULL
+#undef NULL
+#endif
+#define NULL 0
+#ifdef debug
+# define ASSERT(p,q) if (!(p)) fatal(q)
+#else
+# define ASSERT(p,q)
+#endif
+
+#define ALIGN(n, granule) ((n + ((granule)-1)) & ~((granule)-1))
+
+char *
+malloc(nbytes)
+ unsigned nbytes;
+{
+ register struct overhead *p, *q;
+ register int surplus = 0;
+ register struct qelem *bucket;
+ nbytes = ALIGN(nbytes, NALIGN) + sizeof(struct overhead);
+ bucket = &buckets[log2(nbytes-1) + 1]; /* log2 rounded up */
+ for (p = NULL; bucket < &buckets[NBUCKETS]; bucket++) {
+ if (bucket->q_forw != bucket) {
+ /* remove from bucket chain */
+ p = FROMBUK(bucket->q_forw);
+ ASSERT(p->ov_magic == MAGIC_FREE, "\nmalloc: Entry \
+not marked FREE found on Free List!\n");
+ remque(TOBUK(p));
+ surplus = p->ov_length - nbytes;
+ break;
+ }
+ }
+ if (p == NULL) {
+#ifdef USE_SBRK
+ register int i;
+ p = (struct overhead *)CURBRK;
+ if ((int)p == -1) {
+ return(NULL);
+ }
+ if (i = (int)p&(NALIGN-1)) {
+ sbrk(NALIGN-i);
+ }
+ p = (struct overhead *)sbrk(nbytes);
+ if ((int)p == -1) {
+ return(NULL);
+ }
+ q = (struct overhead *)CURBRK;
+ if ((int)q == -1) {
+ return(NULL);
+ }
+ p->ov_length = (char *)q - (char *)p;
+ surplus = p->ov_length - nbytes;
+ /* add to end of adjacency chain */
+ ASSERT((FROMADJ(adjhead.q_back)) < p, "\nmalloc: Entry in \
+adjacency chain found with address lower than Chain head!\n" );
+ insque(TOADJ(p),adjhead.q_back);
+#else
+ struct qelem *pp;
+ int alloc_size = ALIGN(nbytes, PAGE_SIZE);
+
+ p = (struct overhead *)alloc(alloc_size, NALIGN);
+ if ((int)p == -1) {
+ return(NULL);
+ }
+ p->ov_length = alloc_size;
+ surplus = p->ov_length - nbytes;
+
+ /* add to adjacency chain in the correct place */
+ for (pp = adjhead.q_forw; pp != &adjhead; pp = pp->q_forw) {
+ if (p < FROMADJ(pp)) {
+ break;
+ }
+ }
+ ASSERT(pp == &adjhead || (p < FROMADJ(pp)),
+ "\nmalloc: Bogus insertion in adjacency list\n");
+ insque(TOADJ(p),pp->q_back);
+#endif
+ }
+ if (surplus > sizeof(struct overhead)) {
+ /* if big enough, split it up */
+ q = (struct overhead *)( (char *)p + nbytes);
+ q->ov_length = surplus;
+ p->ov_length = nbytes;
+ q->ov_magic = MAGIC_FREE;
+ /* add surplus into adjacency chain */
+ insque(TOADJ(q),TOADJ(p));
+ /* add surplus into bucket chain */
+ insque(TOBUK(q),&buckets[log2(surplus)]);
+ }
+ p->ov_magic = MAGIC_BUSY;
+ return((char*)p + sizeof(struct overhead));
+}
+
+void
+free(mem)
+register char *mem;
+{
+ register struct overhead *p, *q;
+ if (mem == NULL) {
+ return;
+ }
+ p = (struct overhead *)(mem - sizeof(struct overhead));
+ if (p->ov_magic == MAGIC_FREE) {
+ return;
+ }
+ if (p->ov_magic != MAGIC_BUSY) {
+ fatal("attempt to free memory not allocated with malloc!\n");
+ }
+ q = FROMADJ((TOADJ(p))->q_back);
+ if (q != FROMADJ(&adjhead)) { /* q is not the first list item */
+ ASSERT(q < p, "\nfree: While trying to merge a free area with \
+a lower adjacent free area,\n addresses were found out of order!\n");
+ /* If lower segment can be merged */
+ if ((q->ov_magic == MAGIC_FREE) &&
+ ((char *)q + q->ov_length == (char *)p) ) {
+
+ /* remove lower address area from bucket chain */
+ remque(TOBUK(q));
+ /* remove upper address area from adjacency chain */
+ remque(TOADJ(p));
+ q->ov_length += p->ov_length;
+ p->ov_magic = NULL;
+ p = q;
+ }
+ }
+ q = FROMADJ((TOADJ(p))->q_forw);
+ if (q != FROMADJ(&adjhead)) { /* q is not the last list item */
+ /* upper segment can be merged */
+ ASSERT(q > p, "\nfree: While trying to merge a free area with \
+a higher adjacent free area,\n addresses were found out of order!\n");
+ if ( (q->ov_magic == MAGIC_FREE) &&
+ ((char *)p + p->ov_length == (char *)q) ) {
+
+ /* remove upper from bucket chain */
+ remque(TOBUK(q));
+ /* remove upper from adjacency chain */
+ remque(TOADJ(q));
+ p->ov_length += q->ov_length;
+ q->ov_magic = NULL;
+ }
+ }
+#ifdef USE_SBRK
+ /* freed area is at end of memory */
+ if ((endfree && adjhead.q_back == TOADJ(p)) &&
+ ((char*)p + p->ov_length == (char *)CURBRK) ) {
+
+ /* remove from end of adjacency chain */
+ remque(adjhead.q_back);
+ /* release memory to system */
+ sbrk( -((int)(p->ov_length)));
+ return;
+ }
+#endif
+ p->ov_magic = MAGIC_FREE;
+ /* place in bucket chain */
+ insque(TOBUK(p),&buckets[log2(p->ov_length)]);
+ return;
+}
+
+char *
+realloc(mem,nbytes)
+register char *mem; unsigned nbytes;
+{
+ register char *newmem;
+ register struct overhead *p, *q;
+ register int surplus;
+ if (mem == NULL) {
+ return(malloc(nbytes));
+ }
+ if(mem > (char*)FROMADJ(adjhead.q_back) + sizeof(struct overhead)) {
+ return(NULL);
+ }
+
+ p = (struct overhead *)(mem - sizeof(struct overhead));
+ nbytes = (nbytes + (NALIGN-1)) & (~(NALIGN-1));
+ if ( (p->ov_magic == MAGIC_BUSY) && (q = FROMADJ(adjhead.q_back)) != p
+ && (q->ov_magic != MAGIC_FREE || (FROMADJ(q->ov_adj.q_back) != p)) ) {
+
+ free(mem);
+ }
+ if( (p->ov_magic == MAGIC_BUSY || p->ov_magic == MAGIC_FREE)
+ && (surplus = p->ov_length - nbytes - sizeof(struct overhead)) >= 0 ) {
+ if (surplus > sizeof(struct overhead)) {
+ /* return surplus to free list */
+ nbytes += sizeof(struct overhead);
+#ifdef USE_SBRK
+ /* freed area is at end of memory */
+ if ( endfree && adjhead.q_back == TOADJ(p)
+ && (char*)p + p->ov_length == (char *)CURBRK ) {
+ /* release memory to system */
+ sbrk(-surplus);
+ } else
+#endif
+ {
+ q = (struct overhead *)( (char *)p + nbytes);
+ q->ov_length = surplus;
+ q->ov_magic = MAGIC_FREE;
+ insque(TOADJ(q),TOADJ(p));
+ insque(TOBUK(q),&buckets[log2(surplus)]);
+ }
+ p->ov_length = nbytes;
+ }
+ if (p->ov_magic == MAGIC_FREE) {
+ remque(TOBUK(p));
+ p->ov_magic = MAGIC_BUSY;
+ }
+ return(mem);
+ }
+ newmem = malloc(nbytes);
+ if (newmem != mem && newmem != NULL) {
+ register unsigned n;
+ if (p->ov_magic == MAGIC_BUSY || p->ov_magic == MAGIC_FREE) {
+ n = p->ov_length - sizeof(struct overhead);
+ nbytes = (nbytes < n) ? nbytes : n ;
+ }
+ bcopy(mem,newmem,nbytes);
+ }
+ if (p->ov_magic == MAGIC_BUSY) {
+ free(mem);
+ }
+ return(newmem);
+}
+
+log2(n)
+register int n;
+{
+ register int i = 0;
+ while ((n >>= 1) > 0) {
+ i++;
+ }
+ return(i);
+}
+
+void
+insque(item,queu)
+register struct qelem *item, *queu;
+{
+ register struct qelem *pueu;
+ pueu = queu->q_forw;
+ item->q_forw = pueu;
+ item->q_back = queu;
+ queu->q_forw = item;
+ pueu->q_back = item;
+}
+
+void
+remque(item)
+register struct qelem *item;
+{
+ register struct qelem *queu, *pueu;
+ pueu = item->q_forw;
+ queu = item->q_back;
+ queu->q_forw = pueu;
+ pueu->q_back = queu;
+}
diff --git a/private/ntos/boot/veneer/vrmemory.c b/private/ntos/boot/veneer/vrmemory.c
new file mode 100644
index 000000000..da9568e7c
--- /dev/null
+++ b/private/ntos/boot/veneer/vrmemory.c
@@ -0,0 +1,481 @@
+/*
+ *
+ * Copyright (c) 1994 FirePower Systems, Inc.
+ * Copyright (c) 1995 FirePower Systems, Inc.
+ *
+ * $RCSfile: vrmemory.c $
+ * $Revision: 1.19 $
+ * $Date: 1996/06/17 02:55:43 $
+ * $Locker: $
+ *
+ * Module Name:
+ * vrmemory.c
+ *
+ * Authour:
+ * Shin Iwamoto at FirePower Systems, Inc.
+ *
+ * History:
+ * 10-Sep-94 Shin Iwamoto at FirePower Systems, Inc.
+ * Added for ExecuteProg. Added comments.
+ * 07-Sep-94 Shin Iwamoto at FirePower Systems, Inc.
+ * Recreated.
+ */
+
+
+#include "veneer.h"
+
+//
+// Define memory allocation structure.
+//
+typedef struct _VR_MEMORY_DESCRIPTOR {
+ struct _VR_MEMORY_DESCRIPTOR *NextEntry;
+ MEMORY_DESCRIPTOR MemoryEntry;
+} VR_MEMORY_DESCRIPTOR, *PVR_MEMORY_DESCRIPTOR;
+
+PVR_MEMORY_DESCRIPTOR VrMemoryListOrig = (PVR_MEMORY_DESCRIPTOR) NULL;
+
+//
+// Function declaration
+//
+STATIC PVR_MEMORY_DESCRIPTOR SearchMemoryList(ULONG, ULONG);
+STATIC VOID SplitDesc(PVR_MEMORY_DESCRIPTOR, ULONG, ULONG, MEMORY_TYPE);
+
+STATIC PCHAR
+MemoryTypeTable[] = {
+ "MemoryExceptionBlock",
+ "MemorySystemBlock",
+ "MemoryFree",
+ "MemoryBad",
+ "MemoryLoadedProgram",
+ "MemoryFirmwareTemporary",
+ "MemoryFirmwarePermanent",
+ "MemoryFreeContiguous",
+ "MemorySpecialMemory"
+};
+
+
+/*
+ * Name: VrGetmemoryDescriptor
+ *
+ * Description:
+ * This routine returns a pointer to the next memory descriptor. If
+ * the specified memory descriptor is NULL, then a pointer to the
+ * first memory descriptor is returned. If there are no more memory
+ * descriptors, then NULL is returned.
+ *
+ * Arguments:
+ * MemoryDescriptor - Supplies a optional pointer to a memory descriptor.
+ *
+ * Return Value:
+ * If there are any more entries in the memory descriptor list, the
+ * address of the next descriptor is returned. Otherwise, NULL is
+ * returned.
+ *
+ */
+PMEMORY_DESCRIPTOR
+VrGetMemoryDescriptor(
+ IN PMEMORY_DESCRIPTOR MemoryDescriptor OPTIONAL
+ )
+{
+ PMEMORY_DESCRIPTOR P;
+ PVR_MEMORY_DESCRIPTOR Entry;
+
+ debug(VRDBG_MEM, "VrGetMemoryDescriptor(%x): ", MemoryDescriptor);
+
+ if (MemoryDescriptor == (PMEMORY_DESCRIPTOR) NULL) {
+ P = &(VrMemoryListOrig->MemoryEntry);
+ debug(VRDBG_MEM, "%x (%s %x %x)\n", P, MemoryTypeTable[P->MemoryType],
+ P->BasePage, P->PageCount);
+ return (P);
+ }
+
+ for (Entry = VrMemoryListOrig; Entry; Entry = Entry->NextEntry) {
+ if (&Entry->MemoryEntry == MemoryDescriptor) {
+ break;
+ }
+ }
+ if (Entry->NextEntry == NULL) {
+ debug(VRDBG_MEM, "NULL\n");
+ return ((PMEMORY_DESCRIPTOR) NULL);
+ } else {
+ P = &(Entry->NextEntry->MemoryEntry);
+ debug(VRDBG_MEM, "%x (%s %x %x)\n", P, MemoryTypeTable[P->MemoryType],
+ P->BasePage, P->PageCount);
+ return (P);
+ }
+}
+
+
+/*
+ * Name: VrCreateMemoryDescriptor
+ *
+ * Description:
+ * This function creates the list of memory descriptors.
+ *
+ */
+VOID
+VrCreateMemoryDescriptors(
+ VOID
+ )
+{
+ phandle ph;
+ char *regp;
+ reg *cur_reg;
+ int addr_cells, size_cells, regsize;
+ PVR_MEMORY_DESCRIPTOR pre_desc, cur_desc;
+ PVR_MEMORY_DESCRIPTOR FoundDesc;
+ ULONG proplen, cur_basepage, cur_pagecount;
+ ULONG i;
+ debug(VRDBG_MEM|VRDBG_ENTRY,
+ "VrCreateMemoryDescriptors:____________________BEGIN...\n");
+
+ //
+ // Get phandle for /memory.
+ //
+ ph = OFFinddevice("/chosen");
+ if (ph == -1) {
+ fatal("Cannot access /chosen node.\n");
+ }
+ ph = OFInstanceToPackage(get_int_prop(ph, "memory"));
+ if (ph == -1) {
+ fatal("Cannot access /memory node.\n");
+ }
+
+ //
+ // Get information of installed memory from OpenFirmware.
+ //
+ if ((proplen = OFGetproplen(ph, "reg")) <= 0) {
+ fatal("No memory reg structs. proplen = %d\n", proplen);
+ }
+ regp = malloc(proplen);
+ if (OFGetprop(ph, "reg", regp, proplen) != (long) proplen) {
+ warn("Getprop(memory.reg) return != %d\n", proplen);
+ }
+ //
+ // How big are the descriptors? How many "cells" are required to
+ // represent addresses.
+ //
+ addr_cells = get_int_prop(OFParent(ph), "#address-cells");
+ if (addr_cells == -1) {
+ addr_cells = 2;
+ }
+
+ //
+ // How many ints is an address cell?
+ //
+ size_cells = get_int_prop(OFParent(ph), "#size-cells");
+ if (size_cells == -1) {
+ size_cells = 1;
+ }
+
+ regsize = (addr_cells + size_cells) * sizeof(int);
+ debug(VRDBG_MEM, "regsize: %x, proplen: %x\n",regsize, proplen);
+
+
+ //
+ // Look at the "reg" property list for the /memory node. This list
+ // shows what memory the firmware has already "claimed" for any reason.
+ //
+ pre_desc = (PVR_MEMORY_DESCRIPTOR) &VrMemoryListOrig;
+ debug(VRDBG_MEM, "VrCreateMemoryDescriptors: Base Page Page Count\n");
+ for (i = 0; i < proplen/regsize; i++) {
+ cur_desc = new(VR_MEMORY_DESCRIPTOR);
+ cur_desc->NextEntry = NULL;
+ pre_desc->NextEntry = cur_desc;
+ cur_desc->MemoryEntry.MemoryType = MemoryFirmwareTemporary;
+ cur_reg = decode_reg( regp + (i * regsize),
+ regsize,
+ addr_cells,
+ size_cells
+ );
+ cur_desc->MemoryEntry.BasePage =
+ (cur_reg->lo >> PAGE_SHIFT) + (cur_reg->hi << (32-PAGE_SHIFT));
+
+ cur_desc->MemoryEntry.PageCount = cur_reg->size >> PAGE_SHIFT;
+ debug(VRDBG_MEM, "\t\t\t\t\t0x%x\t0x%x\n",
+ cur_desc->MemoryEntry.BasePage,cur_desc->MemoryEntry.PageCount);
+
+ pre_desc = cur_desc;
+
+ }
+
+ //
+ // Release the area for "reg" property
+ //
+ free(regp);
+
+ //
+ // Get information of available memory from OpenFirmware.
+ //
+ if ((proplen = OFGetproplen(ph, "available")) <= 0) {
+ fatal("No memory available structs. proplen = %d\n", proplen);
+ }
+ regp = malloc(proplen);
+ if (OFGetprop(ph, "available", regp, proplen) != (long) proplen) {
+ warn("Getprop(memory.available) return != %d\n", proplen);
+ }
+
+ //
+ // Search the chunk specified by each "available" memory
+ // in the installed memory. Then make the chunk MemoryFree.
+ //
+ for (i = 0; i < proplen/regsize; i++) {
+ cur_reg = decode_reg(regp + (i * regsize), regsize, 1, 1);
+ cur_basepage =
+ (cur_reg->lo >> PAGE_SHIFT) + (cur_reg->hi << (32-PAGE_SHIFT));
+
+ cur_pagecount = cur_reg->size >> PAGE_SHIFT;
+
+ FoundDesc = SearchMemoryList(cur_basepage, cur_pagecount);
+ if (FoundDesc == NULL) {
+ fatal("Available memory (0x%x, 0x%x) is not in installed memory",
+ cur_basepage, cur_pagecount);
+ }
+
+ if ((FoundDesc->MemoryEntry.BasePage == cur_basepage) &&
+ (FoundDesc->MemoryEntry.PageCount == cur_pagecount)) {
+
+ FoundDesc->MemoryEntry.MemoryType = MemoryFree;
+ } else {
+ SplitDesc(FoundDesc, cur_basepage, cur_pagecount, MemoryFree);
+ }
+ debug(VRDBG_MEM, "\t\t\t\t\t0x%x\t0x%x\n",
+ FoundDesc->MemoryEntry.BasePage, FoundDesc->MemoryEntry.PageCount);
+ }
+
+ //
+ // Release the area for "available" property
+ //
+ free(regp);
+
+ //
+ // For some memory chunks, mark specific attributes.
+ //
+ cur_desc = VrMemoryListOrig;
+ while (cur_desc != NULL) {
+ PMEMORY_DESCRIPTOR cur_mem;
+
+ cur_mem = &cur_desc->MemoryEntry;
+
+ //
+ // The loaded program must be MemoryLoadedProgram.
+ //
+
+ if ( cur_mem->BasePage == 0x600) {
+ cur_mem->MemoryType = MemoryLoadedProgram;
+ }
+
+ //
+ // The first N pages are marked Permanent.
+ //
+
+ if ( cur_mem->BasePage == 0x0) {
+ cur_mem->MemoryType = MemoryFirmwarePermanent;
+ }
+
+ //
+ // If a descriptor crosses the 8MB line, split it.
+ //
+
+ if (cur_mem->BasePage < 0x800 &&
+ (cur_mem->BasePage + cur_mem->PageCount > 0x800)) {
+
+ SplitDesc(cur_desc, cur_mem->BasePage,
+ 0x800 - cur_mem->BasePage, MemoryFree);
+ }
+
+ //
+ // Descriptors > 8MB are marked FirmwareTemporary.
+ //
+
+ if (cur_mem->MemoryType == MemoryFree && cur_mem->BasePage >= 0x800) {
+ cur_mem->MemoryType = MemoryFirmwareTemporary;
+ }
+ cur_desc = cur_desc->NextEntry;
+ }
+ debug(VRDBG_MEM|VRDBG_ENTRY,
+ "VrCreateMemoryDescriptors:____________________...END\n");
+}
+
+
+/*
+ * Name: VrMemoryInitialize
+ *
+ * Description:
+ * This function initializes the Memory entry points in the firmware
+ * transfer vector and the file table.
+ *
+ * Arguments:
+ * None.
+ *
+ * Return Value:
+ * None.
+ *
+ */
+VOID
+VrMemoryInitialize(
+ VOID
+ )
+{
+ //
+ // Initialize the I/O entry points in the firmware transfer vector.
+ //
+ debug(VRDBG_ENTRY, "VrMemoryInitialize: BEGIN....\n");
+ (PARC_MEMORY_ROUTINE) SYSTEM_BLOCK->FirmwareVector[MemoryRoutine] =
+ VrGetMemoryDescriptor;
+ debug(VRDBG_ENTRY, "VrMemoryInitialize: ....END\n");
+}
+
+
+STATIC
+PVR_MEMORY_DESCRIPTOR
+SearchMemoryList(
+ ULONG CurBasePage,
+ ULONG CurPageCount
+ )
+{
+ PVR_MEMORY_DESCRIPTOR search_desc;
+
+ search_desc = VrMemoryListOrig;
+ while(search_desc != NULL) {
+ if (search_desc->MemoryEntry.BasePage <= CurBasePage
+ && search_desc->MemoryEntry.BasePage +
+ search_desc->MemoryEntry.PageCount >= CurBasePage+CurPageCount) {
+
+ return search_desc;
+ }
+ search_desc = search_desc->NextEntry;
+ }
+ return (PVR_MEMORY_DESCRIPTOR) NULL;
+}
+
+/*
+ *
+ * Routine: VOID SplitDesc(PVR_MEMORY_DESCRIPTOR, ULONG, ULONG, MEMORY_TYPE)
+ *
+ *
+ * Description:
+ * This routine is called to split a memory descriptor into two
+ pieces. The only issue is whether the left over piece is the
+ first or the second of the two pieces.
+
+ The original descriptor looks like.....
+
+ CurBasePage
+ |-----------------------PageCount-------------->|
+ ________________________________________________
+ | |
+ | Original Type (OType) |
+ | |
+ | |
+ ------------------------------------------------
+
+ The new arrangement will have pieces that are either
+
+
+ CurBasePage
+ |---------CurPageCount-------->|
+ ________________________________________________
+ | | |
+ | Original Piece, | New Piece |
+ | MemType passed in | OType |
+ | | |
+ ------------------------------------------------
+
+ OR it will look like:.....
+
+ CurBasePage
+ | |--CurPageCount->|
+ ________________________________________________
+ | | |
+ | OType, Original Descript. | New Piece |
+ | | MemType |
+ | | |
+ ------------------------------------------------
+ *
+ */
+
+STATIC
+VOID
+SplitDesc(
+ PVR_MEMORY_DESCRIPTOR MemDesc,
+ ULONG CurBasePage,
+ ULONG CurPageCount,
+ MEMORY_TYPE MemType
+ )
+{
+ PVR_MEMORY_DESCRIPTOR new_desc;
+
+ //
+ // If the descriptor passed in points the the base page passed in,
+ // then take the current descriptor and retype it the MemType, size
+ // it as CurPageCount, and then create a new descriptor to describe
+ // what's left over maintaining the original mem type.
+ //
+ if (MemDesc->MemoryEntry.BasePage == CurBasePage) {
+ new_desc = new(VR_MEMORY_DESCRIPTOR);
+ new_desc->NextEntry = MemDesc->NextEntry;
+ MemDesc->NextEntry = new_desc;
+
+ new_desc->MemoryEntry.MemoryType = MemDesc->MemoryEntry.MemoryType;
+ new_desc->MemoryEntry.BasePage =
+ MemDesc->MemoryEntry.BasePage + CurPageCount;
+
+ new_desc->MemoryEntry.PageCount =
+ MemDesc->MemoryEntry.PageCount - CurPageCount;
+
+ MemDesc->MemoryEntry.MemoryType = MemType;
+ MemDesc->MemoryEntry.BasePage = CurBasePage;
+ MemDesc->MemoryEntry.PageCount = CurPageCount;
+
+ return;
+ }
+
+ //
+ // If the base page value passed in is not the base page of the
+ // descriptor passed in, then the size and type refer to a region to
+ // carve out of the end of this descriptor rather than the beginning.
+ //
+ new_desc = new(VR_MEMORY_DESCRIPTOR);
+ new_desc->NextEntry = MemDesc->NextEntry;
+ MemDesc->NextEntry = new_desc;
+
+ new_desc->MemoryEntry.MemoryType = MemType;
+ new_desc->MemoryEntry.BasePage = CurBasePage;
+ new_desc->MemoryEntry.PageCount = CurPageCount;
+
+ MemDesc->MemoryEntry.PageCount -= CurPageCount;
+
+ if (MemDesc->MemoryEntry.BasePage + MemDesc->MemoryEntry.PageCount
+ != new_desc->MemoryEntry.BasePage) {
+ ULONG old_size = MemDesc->MemoryEntry.PageCount;
+
+ new_desc = new(VR_MEMORY_DESCRIPTOR);
+ new_desc->NextEntry = MemDesc->NextEntry->NextEntry;
+ MemDesc->NextEntry->NextEntry = new_desc;
+
+ MemDesc->MemoryEntry.PageCount =
+ MemDesc->NextEntry->MemoryEntry.BasePage -
+ MemDesc->MemoryEntry.BasePage;
+
+ new_desc->MemoryEntry.MemoryType = MemDesc->MemoryEntry.MemoryType;
+ new_desc->MemoryEntry.BasePage =
+ MemDesc->NextEntry->MemoryEntry.BasePage +
+ MemDesc->NextEntry->MemoryEntry.PageCount;
+
+ new_desc->MemoryEntry.PageCount =
+ old_size - MemDesc->MemoryEntry.PageCount;
+ }
+
+ return;
+}
+
+VOID
+DisplayMemory(VOID)
+{
+ PMEMORY_DESCRIPTOR P = NULL;
+ while ((P = VrGetMemoryDescriptor(P)) != NULL) {
+ debug(VRDBG_MEM, "MemoryType=%s, BasePage=0x%x, PageCount=0x%x\n",
+ MemoryTypeTable[P->MemoryType], P->BasePage, P->PageCount);
+ }
+}
diff --git a/private/ntos/boot/veneer/vrmisc.c b/private/ntos/boot/veneer/vrmisc.c
new file mode 100644
index 000000000..e91bd966e
--- /dev/null
+++ b/private/ntos/boot/veneer/vrmisc.c
@@ -0,0 +1,221 @@
+/*
+ *
+ * Copyright (c) 1995 FirePower Systems, Inc.
+ * Copyright (c) 1994 FirePower Systems Inc.
+ *
+ * $RCSfile: vrmisc.c $
+ * $Revision: 1.10 $
+ * $Date: 1996/06/17 02:55:38 $
+ * $Locker: $
+ *
+ *
+ * Module Name:
+ * vrmisc.c
+ *
+ * Author:
+ * Shin Iwamoto at FirePower Systems Inc.
+ *
+ * History:
+ * 07-Sep-94 Shin Iwamoto at FirePower System Inc.
+ * Modifying the existence of L2 cache.
+ * 16-Jun-94 Shin Iwamoto at FirePower System Inc.
+ * Changed the property getting code using get_str_prop()
+ * in VrGetTime().
+ * 14-Jun-94 Shin Iwamoto at FirePower System Inc.
+ * Added a pointer to VRTime because a type mismatch happened.
+ * 19-May-94 Shin Iwamoto at FirePower System Inc.
+ * Added some logic in VrGetTime().
+ * Added some comments.
+ * 05-May-94 Shin Iwamoto at FirePower System Inc.
+ * Created.
+ *
+ */
+
+
+#include "veneer.h"
+
+//
+// Static data.
+//
+STATIC TIME_FIELDS VrTime;
+STATIC LONG StartTime; // XXXX structure
+
+
+/*
+ * Name: VrGetTime
+ *
+ * Description:
+ * This function returns a pointer to a time structure.
+ *
+ * Arguments:
+ * None.
+ *
+ * Return Value:
+ * Returns a pointer to a time structure. If the time infomation is
+ * valid, valid data is returned, otherwise all fields are returned
+ * as zero.
+ *
+ */
+PTIME_FIELDS
+VrGetTime(VOID)
+{
+ PTIME_FIELDS PVrTime = &VrTime; // Satisfy the compiler.
+ phandle ph;
+ ihandle ih;
+ int res[7];
+
+ //
+ // "The experienced programmer puts a known elephant in
+ // Cairo so the search will always terminate."
+ //
+ VrTime.Year = 0;
+ VrTime.Month = 0;
+ VrTime.Day = 0;
+ VrTime.Hour = 0;
+ VrTime.Minute = 0;
+ VrTime.Second = 0;
+ VrTime.Milliseconds = 0;
+ VrTime.Weekday = 0;
+
+ ph = FindNodeByType("rtc");
+ if (ph == 0) {
+ warn("VrGetTime: Could not find the RTC node.\n");
+ goto out;
+ }
+ ih = OpenPackage(ph);
+ if (ih == 0) {
+ goto out;
+ }
+ OFCallMethod(7, 2, res, "get-time", ih);
+ OFClose(ih);
+ if (res[0] != 0) {
+ goto out;
+ }
+
+ VrTime.Year = res[6];
+ VrTime.Month = res[5];
+ VrTime.Day = res[4];
+ VrTime.Hour = res[3];
+ VrTime.Minute = res[2];
+ VrTime.Second = res[1];
+
+out:
+ return (PVrTime);
+}
+
+
+/*
+ * Name: VrGetRelativeTime
+ *
+ * Description:
+ * This routine returns the time in seconds since Veneer starts.
+ *
+ * Arguments:
+ * None.
+ *
+ * Return Value:
+ * If the time information is valid, valid data is returned.
+ * Otherwise a zero is returned.
+ *
+ */
+ULONG
+VrGetRelativeTime( VOID )
+{
+ return OFMilliseconds()/1000;
+}
+
+
+/*
+ * Name: VrTimeInitialize
+ *
+ * Description:
+ * This function initializes the time routine addresses in the firmware
+ * transfer vector and the internal counter for the relative time.
+ *
+ * Arguments:
+ * None.
+ *
+ * Return Value:
+ * None.
+ *
+ */
+VOID
+VrTimeInitialize(
+ VOID
+ )
+{
+ debug(VRDBG_ENTRY, "VrTimeInitialize BEGIN....\n");
+ //
+ // Initialize the Time routine addresses in the firmware transfer vector.
+ //
+ (PARC_GET_TIME_ROUTINE)
+ SYSTEM_BLOCK->FirmwareVector[GetTimeRoutine] = VrGetTime;
+
+ (PARC_GET_RELATIVE_TIME_ROUTINE)
+ SYSTEM_BLOCK->FirmwareVector[GetRelativeTimeRoutine] =
+ VrGetRelativeTime;
+ (PARC_FLUSH_ALL_CACHES_ROUTINE)
+ SYSTEM_BLOCK->FirmwareVector[FlushAllCachesRoutine] =
+ VrFlushAllCaches;
+ debug(VRDBG_ENTRY, "VrTimeInitialize ....END\n");
+
+}
+
+VOID
+VrFlushAllCaches(VOID)
+{
+ ULONG start;
+ phandle ph;
+ char *regp;
+ reg *cur_reg;
+ int i, size_cells, addr_cells, proplen, regsize;
+ extern VOID HalpSweepPhysicalRangeInBothCaches(ULONG, ULONG, ULONG);
+
+ /*
+ * Flush each chunk of physical memory. Use the memory scanning
+ * code from vrmemory.c; see that file for comments.
+ */
+
+ ph = OFFinddevice("/chosen");
+ if (ph == -1) {
+ fatal("Cannot access /chosen node.\n");
+ }
+ ph = OFInstanceToPackage(get_int_prop(ph, "memory"));
+
+ if (ph == -1) {
+ fatal("Cannot access /memory node.\n");
+ }
+
+ if ((proplen = OFGetproplen(ph, "reg")) <= 0) {
+ fatal("No memory reg structs. proplen = %d\n", proplen);
+ }
+ regp = malloc(proplen);
+ if (OFGetprop(ph, "reg", regp, proplen) != (long) proplen) {
+ fatal("Getprop(memory.reg) return != %d\n", proplen);
+ }
+
+ addr_cells = get_int_prop(OFParent(ph), "#address-cells");
+ if (addr_cells == -1) {
+ addr_cells = 2;
+ }
+ size_cells = get_int_prop(OFParent(ph), "#size-cells");
+ if (size_cells == -1) {
+ size_cells = 1;
+ }
+ regsize = (addr_cells + size_cells) * sizeof(int);
+
+
+ for (i = 0; i < proplen/regsize; i++) {
+ cur_reg = decode_reg( regp + (i * regsize),
+ regsize,
+ addr_cells,
+ size_cells
+ );
+ start = cur_reg->lo >> PAGE_SHIFT;
+ start += cur_reg->hi << (32-PAGE_SHIFT);
+ HalpSweepPhysicalRangeInBothCaches(start, 0, cur_reg->size);
+ }
+
+ free(regp);
+
+}
diff --git a/private/ntos/boot/veneer/vrpehdr.c b/private/ntos/boot/veneer/vrpehdr.c
new file mode 100644
index 000000000..d8528ac55
--- /dev/null
+++ b/private/ntos/boot/veneer/vrpehdr.c
@@ -0,0 +1,138 @@
+/*++
+ *
+ * Copyright (c) 1996 FirePower Systems, Inc.
+ * Copyright (c) 1995 FirePower Systems, Inc.
+ * Copyright (c) 1994 FirmWorks, Mountain View CA USA. All rights reserved.
+ * Copyright (c) 1994 FirePower Systems Inc.
+ *
+ * $RCSfile: vrpehdr.c $
+ * $Revision: 1.7 $
+ * $Date: 1996/02/17 00:50:30 $
+ * $Locker: $
+
+Module Name:
+
+ vrpehdr.c
+
+Abstract:
+
+ These routines read and parse the Microsoft PE header.
+
+Author:
+
+ Mike Tuciarone 9-May-1994
+
+
+Revision History:
+
+--*/
+
+
+#include "veneer.h"
+
+
+
+
+#define HEADER_CHR (IMAGE_FILE_EXECUTABLE_IMAGE | \
+ IMAGE_FILE_BYTES_REVERSED_LO | \
+ IMAGE_FILE_32BIT_MACHINE | \
+ IMAGE_FILE_BYTES_REVERSED_HI)
+
+/*
+ * For some reason NT 3.5 changed the OSLoader header.
+ */
+#define HEADER_CHR_35 (IMAGE_FILE_EXECUTABLE_IMAGE | \
+ IMAGE_FILE_32BIT_MACHINE | \
+ IMAGE_FILE_LINE_NUMS_STRIPPED)
+
+void *
+load_file(ihandle bootih)
+{
+ IMAGE_FILE_HEADER FileHdr;
+ IMAGE_OPTIONAL_HEADER OptHdr;
+ IMAGE_SECTION_HEADER *SecHdr, *hdr;
+ int res, size, i;
+ PCHAR BaseAddr;
+
+ if ((res = OFRead(bootih, (char *) &FileHdr, IMAGE_SIZEOF_FILE_HEADER))
+ != IMAGE_SIZEOF_FILE_HEADER) {
+ fatal("Couldn't read entire file header: got %d\n", res);
+ }
+
+ /*
+ * Sanity check.
+ */
+ if (FileHdr.Machine != IMAGE_FILE_MACHINE_POWERPC) {
+ fatal("Wrong machine type: %x\n", FileHdr.Machine);
+ }
+#ifdef NOT
+ /*
+ * Don't bother to check the flags. They change every release anyway.
+ */
+ if ((FileHdr.Characteristics & HEADER_CHR ) != HEADER_CHR &&
+ (FileHdr.Characteristics & HEADER_CHR_35) != HEADER_CHR_35) {
+ fatal("Wrong header characteristics: %x\n",
+ FileHdr.Characteristics);
+ }
+#endif
+
+ size = FileHdr.SizeOfOptionalHeader;
+ if ((res = OFRead(bootih, (char *) &OptHdr, size)) != size) {
+ fatal("Couldn't read optional header: expect %x got %x\n",
+ size, res);
+ }
+
+ /*
+ * More sanity.
+ */
+ if (OptHdr.Magic != 0x010b) {
+ fatal("Wrong magic number in header: %x\n", OptHdr.Magic);
+ }
+
+ /*
+ * Compute image size and claim memory at specified virtual address.
+ * We assume the SizeOfImage field is sufficient.
+ */
+ BaseAddr = (PCHAR) OptHdr.ImageBase;
+ if (CLAIM(BaseAddr, OptHdr.SizeOfImage) == -1) {
+ fatal("Couldn't claim %x bytes of VM at %x\n",
+ OptHdr.SizeOfImage, BaseAddr);
+ }
+ bzero(BaseAddr, OptHdr.SizeOfImage);
+
+ /*
+ * Allocate section headers.
+ */
+ size = FileHdr.NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
+ SecHdr = (PIMAGE_SECTION_HEADER) malloc(size);
+ if ((res = OFRead(bootih, (char *) SecHdr, size)) != size) {
+ fatal("Couldn't read section headers: expect %x got %x\n",
+ size, res);
+ }
+
+ /*
+ * Loop through section headers, reading in each piece at the
+ * specified virtual address.
+ */
+ for (i = 0; i < FileHdr.NumberOfSections; ++i) {
+ hdr = &SecHdr[i];
+ debug(VRDBG_PE, "Processing section %d: %s\n", i, hdr->Name);
+ if (hdr->SizeOfRawData == 0) {
+ continue;
+ }
+ if (OFSeek(bootih, 0, hdr->PointerToRawData) == -1) {
+ fatal("seek to offset %x failed\n",
+ hdr->PointerToRawData);
+ }
+ res = OFRead(bootih,
+ (PCHAR) hdr->VirtualAddress + (ULONG) BaseAddr,
+ hdr->SizeOfRawData);
+ if ((ULONG)res != hdr->SizeOfRawData) {
+ fatal("Couldn't read data: exp %x got %x\n",
+ hdr->SizeOfRawData, res);
+ }
+ }
+ free((char *)SecHdr);
+
+ return (void *)(BaseAddr + OptHdr.AddressOfEntryPoint);
+}
diff --git a/private/ntos/boot/veneer/vrrstart.c b/private/ntos/boot/veneer/vrrstart.c
new file mode 100644
index 000000000..7d4ebc3f6
--- /dev/null
+++ b/private/ntos/boot/veneer/vrrstart.c
@@ -0,0 +1,274 @@
+/*
+ *
+ * Copyright (c) 1994 FirePower Systems Inc.
+ * Copyright (c) 1995 FirePower Systems, Inc.
+ *
+ * $RCSfile: vrrstart.c $
+ * $Revision: 1.7 $
+ * $Date: 1996/04/15 02:55:36 $
+ * $Locker: $
+ *
+ *
+ * Module Name:
+ * vrrstart.c
+ *
+ * Author:
+ * Shin Iwamoto at FirePower Systems Inc.
+ *
+ * History:
+ * 16-Jun-94 Shin Iwamoto at FirePower Systems Inc.
+ * Changed the property getting code using get_str_prop()
+ * in VrGetSystemId().
+ * 14-Jun-94 Shin Iwamoto at FirePower Systems Inc.
+ * Added the pointer to SystemId because type mismatch happened.
+ * 19-May-94 Shin Iwamoto at FirePower Systems Inc.
+ * Added some comments.
+ * 13-May-94 Shin Iwamoto at FirePower Systems Inc.
+ * Added jump-logic to the restart address in VrRestart().
+ * Added VrRestartInitialize().
+ * 12-May-94 Shin Iwamoto at FirePower Systems Inc.
+ * Created.
+ *
+ */
+
+
+
+#include "veneer.h"
+
+
+//
+// Static data.
+//
+STATIC SYSTEM_ID SystemId;
+
+
+/*
+ * Name: VrEnterInteractiveMode
+ *
+ * Description:
+ * This function terminates the executing program and enters
+ * interactive mode.
+ *
+ * Arguments:
+ * None.
+ *
+ * Return Value:
+ * None.
+ *
+ */
+VOID
+VrEnterInteractiveMode(
+ VOID
+ )
+{
+ (VOID)OFEnter();
+}
+
+
+/*
+ * Name: VrGetSystemId
+ *
+ * Description:
+ * This function returns a pointer to a system identification
+ * structure that contains information used to uniquely identify
+ * each system.
+ *
+ * Arguments:
+ * None.
+ *
+ * Return Value:
+ * The 16-byte system identification structure is returned.
+ *
+ */
+PSYSTEM_ID
+VrGetSystemId(
+ VOID
+ )
+{
+ phandle PHandle;
+ PCHAR Property;
+ PSYSTEM_ID PSystemId = &SystemId;
+
+ if ((LONG)(PHandle = OFFinddevice("/")) == -1) {
+ fatal("Veneer: cannot find the root node in Open Firmware.\n");
+ }
+
+ if ((Property = get_str_prop(PHandle, "name", NOALLOC)) == (PCHAR)NULL) {
+ fatal("Veneer: cannot get the name property for the root node.\n");
+ }
+ bcopy(Property, SystemId.VendorId, 8);
+
+ if ((Property = get_str_prop(PHandle, "id", NOALLOC)) == (PCHAR)NULL) {
+ fatal("Veneer: cannot get the name property for the root node.\n");
+ }
+ bcopy(Property, SystemId.ProductId, 8);
+
+ return PSystemId;
+}
+
+
+/*
+ * Name: VrPowerDown
+ *
+ * Description:
+ * This function is identical to the VrHalt() with the additional
+ * feature that, the power to a system is removed if the system is
+ * equipped so.
+ *
+ * Arguments:
+ * None.
+ *
+ * Return Value:
+ * None.
+ *
+ */
+VOID
+VrPowerDown(VOID)
+{
+ // XXX - This must use the HALT interface; see the PPC binding.
+ OFExit();
+}
+
+
+/*
+ * Name: VrReboot
+ *
+ * Description:
+ * This function reboots the system with the same parameters used
+ * for the previous system load sequence. If the parameters cannot
+ * be reproduced, then the default system load sequence is performed.
+ *
+ * Arguments:
+ * None.
+ *
+ * Return Value:
+ * None.
+ *
+ */
+VOID
+VrReboot(
+ VOID
+ )
+{
+ // XXXX
+ // Make sure that this funciton reboots the system with the same
+ // parameters used for the previous system load sequence. If the
+ // parameters cannot be reporduced, then the default system load
+ // sequence is performed.
+ (VOID)OFBoot((PCHAR)NULL);
+}
+
+
+/*
+ * Name: VrRestart
+ *
+ * Description:
+ * This function performs the equivalent of a power-on reset.
+ *
+ * Arguments:
+ * None.
+ *
+ * Return Value:
+ * None.
+ *
+ */
+VOID
+VrRestart(
+ VOID
+ )
+{
+
+ PRESTART_BLOCK PRestartBlock;
+
+ //
+ // Detect the presence of a valid Restart Block
+ //
+ PRestartBlock = SYSTEM_BLOCK->RestartBlock;
+ while (PRestartBlock != (PRESTART_BLOCK)NULL) {
+ if (PRestartBlock->Signature == RSTB_SIGNATURE &&
+ (PRestartBlock->Version == ARC_VERSION) &&
+ (PRestartBlock->Revision == ARC_REVISION)) {
+
+ break;
+ }
+ PRestartBlock = PRestartBlock->NextRestartBlock;
+ }
+
+ //
+ // Perform a normal power-on sequence if a valid RestartBlock
+ // is not found.
+ //
+ if (PRestartBlock == (PRESTART_BLOCK)NULL) {
+ (VOID)OFBoot((PCHAR)NULL);
+ }
+ //
+ // Reboot the system.
+ //
+
+ //
+ // Goto the RestartAddress, not return;
+ //
+ (VOID)(*(VOID (*)())(PRestartBlock->RestartAddress))();
+}
+
+
+/*
+ * Name: VrHalt
+ *
+ * Description:
+ * This function exits the program.
+ *
+ * Arguments:
+ * None.
+ *
+ * Return Value:
+ * None.
+ *
+ */
+VOID
+VrHalt(
+ VOID
+ )
+{
+ (VOID)OFExit();
+}
+
+
+/*
+ * Name: VrRestartInitialize
+ *
+ * Description:
+ * This function initializes restart routine addresses in the firmware
+ * transfer vector.
+ *
+ * Arguments:
+ * None.
+ *
+ * Return Value:
+ * None.
+ *
+ */
+VOID
+VrRestartInitialize(
+ VOID
+ )
+{
+ debug(VRDBG_ENTRY, "VrRestartInitialize BEGIN....\n");
+ //
+ // Initialize Restart routine addresses in the firmware transfer vector.
+ //
+ (PARC_INTERACTIVE_MODE_ROUTINE)
+ SYSTEM_BLOCK->FirmwareVector[InteractiveModeRoutine] =
+ VrEnterInteractiveMode;
+ (PARC_GET_SYSTEM_ID_ROUTINE)
+ SYSTEM_BLOCK->FirmwareVector[GetSystemIdRoutine] = VrGetSystemId;
+ (PARC_POWERDOWN_ROUTINE)
+ SYSTEM_BLOCK->FirmwareVector[PowerDownRoutine] = VrPowerDown;
+ (PARC_REBOOT_ROUTINE)
+ SYSTEM_BLOCK->FirmwareVector[RebootRoutine] = VrReboot;
+ (PARC_RESTART_ROUTINE)
+ SYSTEM_BLOCK->FirmwareVector[RestartRoutine] = VrRestart;
+ (PARC_HALT_ROUTINE)
+ SYSTEM_BLOCK->FirmwareVector[HaltRoutine] = VrHalt;
+ debug(VRDBG_ENTRY, "VrRestartInitialize ....END\n");
+}
diff --git a/private/ntos/boot/veneer/vrsup.c b/private/ntos/boot/veneer/vrsup.c
new file mode 100644
index 000000000..4b067dd67
--- /dev/null
+++ b/private/ntos/boot/veneer/vrsup.c
@@ -0,0 +1,369 @@
+/*++
+ *
+ * Copyright (c) 1995 FirePower Systems, Inc.
+ * Copyright (c) 1994 FirmWorks, Mountain View CA USA. All rights reserved.
+ * Copyright (c) 1994 FirePower Systems, Inc.
+ *
+ * $RCSfile: vrsup.c $
+ * $Revision: 1.7 $
+ * $Date: 1996/02/17 00:42:16 $
+ * $Locker: $
+ *
+
+
+Module Name:
+
+ vrsup.c
+
+Abstract:
+
+ A given physical device may be represented by a variety
+ of objects. More importantly, the veneer must be able to
+ translate freely between these objects.
+
+ ______________ ____________________
+ | 1275 | | ARC |
+ | | | |
+ | | | |
+ | Path | | ArcPath |
+ | \ | | / |
+ | \ | | / |
+ | \ | | / |
+ | \ | | / |
+ | \| |/ |
+ | \ / |
+ | |\ /| |
+ | | \ / | |
+ | | \ / | |
+ | | \ / | |
+ | | \ / | |
+ | | \ / | |
+ | | \ / | |
+ | Package---+-------Node | |
+ | | / \ | |
+ | | / \ | |
+ | | / \ | |
+ | | / \ | |
+ | | / \ | |
+ | | / \ | |
+ | |/ \| |
+ | / \ |
+ | /| |\ |
+ | / | | \ |
+ | / | | \ |
+ | Instance | | File Descriptor |
+ | | | |
+ |______________| |____________________|
+
+ 1275 objects include the "Package," the "Instance,"
+ and the device specifier, here simply termed the "Path."
+ ARC objects include the ARC device specifier, here the
+ "ArcPath," and the File Descriptor which does not appear
+ in this module.
+
+ The CONFIGURATION_NODE object, a.k.a. the "Node," is the
+ central data object in the veneer, and is used to translate
+ from 1275 to ARC and vice versa.
+
+ This file contains the routines which do path traversal
+ and translation for both 1275 and ARC trees. The general
+ form of the publicly accessible functions is
+
+ P<yyy> <xxx>To<yyy>(P<xxx>);
+
+ where <xxx> and <yyy> are one of
+
+ Path
+ Package
+ Instance
+ Node
+ ArcPath
+
+ and P<xxx> and P<yyy> are types <xxx> and <yyy> if
+ <xxx> and <yyy> are scalar, and pointers-to-<xxx>/<yyy>
+ if not.
+
+ This sounds a lot more confusing than it is; see below.
+
+Author:
+
+ Mike Tuciarone 9-May-1994
+--*/
+
+
+#include "veneer.h"
+
+/*
+ * Given a configuration node, traverse the Veneer Configuration tree
+ * looking for a matching component name. Call this initially with
+ * Node = RootNode. Return the matching node (if any).
+ */
+STATIC PCONFIGURATION_NODE
+DoArcPathToNode(
+ PCHAR Path,
+ PCONFIGURATION_NODE Node
+ )
+{
+ PCONFIGURATION_NODE MatchedNode;
+ CHAR *name, *cp;
+ LONG TokenLen;
+ ULONG Key = 0;
+
+ if (Node == NULL) {
+ return (0);
+ }
+
+ if (cp = index(Path, '(')) {
+ TokenLen = cp - Path;
+ cp += 1;
+ Key = atoi(cp);
+ } else {
+ TokenLen = strlen(Path);
+ }
+
+ if (Node == RootNode) {
+ Node = RootNode->Child;
+ }
+
+ name = Node->ComponentName;
+ if (!strncmp(name, Path, TokenLen) && (Key == Node->Component.Key)) {
+ /*
+ * A match! Trim off the matching component.
+ */
+ debug(VRDBG_CONF,
+ "ArcPathToNode: path '%s' matched node '%s' %x\n",
+ Path, Node->ComponentName, Node->OfPhandle);
+ cp = index(Path, ')');
+ if (cp == NULL) {
+ fatal("Malformed string: '%s'\n", Path);
+ }
+ cp += 1;
+ if (*cp == '\0') {
+ debug(VRDBG_CONF,
+ "String exhausted, returning %x\n", Node);
+ return(Node);
+ }
+ /*
+ * If this call returns non-NULL, then we had a match
+ * further down the tree. Otherwise this is the best
+ * we can do: return this node.
+ */
+ MatchedNode = DoArcPathToNode(cp, Node->Child);
+ debug(VRDBG_CONF, "ArcPathToNode('%s') returning %x\n",
+ Path, MatchedNode ? MatchedNode->OfPhandle : 0);
+ return(MatchedNode ? MatchedNode : Node);
+ }
+ if (Node->Peer) {
+ return(DoArcPathToNode(Path, Node->Peer));
+ }
+ return (0);
+}
+
+/*
+ * External entry point:
+ */
+PCONFIGURATION_NODE
+ArcPathToNode(PCHAR Path)
+{
+ return (DoArcPathToNode(Path, RootNode));
+}
+
+
+/*
+ * Create the fully-qualified ARC path to describe the argument node.
+ */
+PCHAR
+NodeToArcPath(PCONFIGURATION_NODE node)
+{
+ CHAR *oldbuf, *newbuf;
+ LONG len;
+
+ // Add 3 to each length for the key.
+ len = 1;
+ newbuf = zalloc(len);
+ do {
+ oldbuf = newbuf;
+ len += strlen(node->ComponentName) + 3;
+ newbuf = zalloc(len);
+ strcpy(newbuf, node->ComponentName);
+ strcat(newbuf, "( )");
+ newbuf[strlen(newbuf) - 2] = (char) node->Component.Key + '0';
+ strcat(newbuf, oldbuf);
+ free(oldbuf);
+ } while ((node = node->Parent) && node != RootNode);
+
+ return (newbuf);
+}
+
+
+/*
+ * Search the tree rooted at Node for a node containing the phandle Ph.
+ * NOTE: Phandles are not unique! This routine does a depth-first
+ * search to find the *deepest* node matching the phandle.
+ */
+STATIC PCONFIGURATION_NODE
+FindNodeUsingPhandle(PCONFIGURATION_NODE Node, phandle Ph)
+{
+ PCONFIGURATION_NODE Found;
+ extern int level;
+
+ debug(VRDBG_CONF, "FindNodeUsingPhandle: Node %x (%s) phandle %x\n",
+ Node, Node ? Node->ComponentName : "NULL", Ph);
+ if (Node == NULL) {
+ return (NULL);
+ }
+ /*
+ * First check to see if this node matches *and* is a wildcard.
+ * If so, return immediately.
+ */
+ if (Node->OfPhandle == Ph && Node->Wildcard) {
+ debug(VRDBG_CONF, "FindNodeUsingPhandle: return %x\n", Node);
+ return (Node);
+ }
+ /*
+ * Check descendants, since the terminal node may be a child of
+ * this one. See the comments in add_new_child() in vrtree.c.
+ */
+ level++;
+ Found = FindNodeUsingPhandle(Node->Child, Ph);
+ level--;
+ if (Found) {
+ debug(VRDBG_CONF, "FindNodeUsingPhandle: return %x\n", Node);
+ return (Found);
+ }
+ if (Node->OfPhandle == Ph) {
+ debug(VRDBG_CONF, "FindNodeUsingPhandle: return %x\n", Node);
+ return (Node);
+ }
+ return (FindNodeUsingPhandle(Node->Peer, Ph));
+}
+
+PCONFIGURATION_NODE
+PackageToNode(phandle ph)
+{
+ return (FindNodeUsingPhandle(RootNode, ph));
+}
+
+PCONFIGURATION_NODE
+PathToNode(PCHAR path)
+{
+ PCONFIGURATION_NODE node, tmpnode;
+ phandle ph;
+ PCHAR cp;
+
+ ph = OFFinddevice(path);
+ node = FindNodeUsingPhandle(RootNode, ph);
+ if (node->Wildcard) {
+ // trim off final address
+ while ((cp = index(path, '@')) != NULL) {
+ path = cp + 1;
+ }
+ // XXX run decode-unit on it
+ // XXX search peers for match using wildcard criteria
+ if ((tmpnode = FindNodeUsingPhandle(node->Child, ph)) != NULL) {
+ return (tmpnode);
+ }
+ }
+ return (node);
+}
+
+PCONFIGURATION_NODE
+InstanceToNode(ihandle ih)
+{
+ char buf[1024];
+
+ OFInstanceToPath(ih, buf, 1024);
+ return (PathToNode(buf));
+}
+
+phandle
+NodeToPackage(PCONFIGURATION_NODE node)
+{
+ return (node->OfPhandle); // "It's a gift to be simple..."
+}
+
+PCHAR
+NodeToPath(PCONFIGURATION_NODE node)
+{
+ phandle ph = NodeToPackage(node);
+ int len;
+ char *bufp;
+
+ //
+ // Translate the device name into the device path for Open Firmware.
+ // Add 1 to the reported length to account for the null terminator.
+ // (See IEEE 1275-1994, Sec. 6.3.2.2.)
+ //
+ len = OFPackageToPath(ph, (char *)0, 0) + 1;
+ bufp = (char *) zalloc(len);
+ (VOID) OFPackageToPath(ph, bufp, len);
+ debug(VRDBG_CONF, "NodeToPath found '%s'\n", bufp);
+
+ if (node->Wildcard) {
+ char *newp;
+
+ while (node->Parent->Wildcard) {
+ node = node->Parent;
+ }
+ // XXX Generate AddrPath by running encode-unit
+ // XXX on wildcard criteria
+ len += strlen(node->WildcardAddrPath);
+ newp = (char *) zalloc(len);
+ strcpy(newp, bufp);
+ free(bufp);
+ bufp = newp;
+ debug(VRDBG_CONF, "NodeToPath adding '%s'\n",
+ node->WildcardAddrPath);
+ strcat(bufp, node->WildcardAddrPath);
+ }
+ debug(VRDBG_CONF, "NodeToPath returning '%s'\n", bufp);
+ return (bufp);
+}
+
+/*
+ * This routine is hopelessly naive. See VrOpen() for a version
+ * that's been around.
+ */
+ihandle
+NodeToInstance(PCONFIGURATION_NODE node)
+{
+ char *path = NodeToPath(node);
+ ihandle ih = OFOpen(path);
+
+ free(path);
+ return (ih);
+}
+
+STATIC phandle
+DoFindNodeByType(char *type, phandle ph)
+{
+ phandle res;
+
+ if (ph == 0) {
+ return(0);
+ }
+ if (strcmp(get_str_prop(ph, "device_type", NOALLOC), type) == 0) {
+ return(ph);
+ }
+ res = DoFindNodeByType(type, OFChild(ph));
+ if (res != 0) {
+ return(res);
+ }
+ return(DoFindNodeByType(type, OFPeer(ph)));
+}
+
+phandle
+FindNodeByType(char *type)
+{
+ return(DoFindNodeByType(type, OFPeer(0)));
+}
+
+ihandle
+OpenPackage(phandle ph)
+{
+ char buf[256];
+
+ (void) OFPackageToPath(ph, buf, 256);
+ return (OFOpen(buf));
+}
+
diff --git a/private/ntos/boot/veneer/vrtree.c b/private/ntos/boot/veneer/vrtree.c
new file mode 100644
index 000000000..9d33fd651
--- /dev/null
+++ b/private/ntos/boot/veneer/vrtree.c
@@ -0,0 +1,2012 @@
+/*
+ * Copyright (c) 1995,1996 FirePower Systems, Inc.
+ * Copyright (c) 1994 FirmWorks, Mountain View CA USA. All rights reserved.
+ *
+ * $RCSfile: vrtree.c $
+ * $Revision: 1.51 $
+ * $Date: 1996/06/19 23:13:29 $
+ * $Locker: $
+ *
+ *
+ */
+
+#include "veneer.h"
+#include "vrtree.h"
+
+extern CHAR *VeneerVersion();
+
+/*
+ * This table contains some rudimentary plug-n-play-style mappings
+ * to assist in assigning the proper Identifiers to device nodes.
+ */
+static struct pnp_info {
+ unsigned int port;
+ char *id;
+} pnp_data[] = {
+ { 0x278, "LPT3" },
+ { 0x2bc, "LPT4" },
+ { 0x2e8, "COM4" },
+ { 0x2f8, "COM2" },
+ { 0x378, "LPT2" },
+ { 0x3bc, "LPT1" },
+ { 0x3e8, "COM3" },
+ { 0x3f8, "COM1" },
+ { 0x000, "Tooch did this." }
+};
+
+
+CONFIGURATION_NODE *RootNode;
+STATIC CONFIGURATION_NODE *DisplayNode = 0;
+
+STATIC int convert_node(CONFIGURATION_NODE *);
+STATIC CONFIGURATION_NODE *convert_controller(CONFIGURATION_NODE *);
+STATIC CONFIGURATION_NODE *add_new_child(
+ CONFIGURATION_NODE *, char *, CONFIGURATION_CLASS, CONFIGURATION_TYPE);
+STATIC int convert_name(CONFIGURATION_NODE *);
+STATIC VOID convert_config(CONFIGURATION_NODE *);
+STATIC VOID convert_cache(PCONFIGURATION_NODE);
+STATIC int convert_PCI_device(PCONFIGURATION_NODE);
+STATIC CONFIGURATION_NODE *convert_SCSI_device(PCONFIGURATION_NODE);
+STATIC CONFIGURATION_NODE *convert_IDE_device(PCONFIGURATION_NODE);
+STATIC VOID convert_system_node(PCONFIGURATION_NODE);
+STATIC VOID update_display_node(PCONFIGURATION_NODE);
+STATIC VOID configure_pci_node(reg *, PCONFIGURATION_NODE );
+
+STATIC int default_interrupt_level = 0;
+STATIC int level_equals_vector = FALSE;
+STATIC int default_interrupt_affinity = -1;
+STATIC int default_affinity = -1;
+STATIC int init_key_array[64];
+STATIC int *key_array = init_key_array;
+
+/*
+ * Traverse the OF tree. For each node, figure out what it corresponds
+ * to in an ARC tree and construct the Component and resource
+ * description data structures. Call this initially with node = 0
+ * so peer() finds the root node. See 6.3.2.2.
+ *
+ * At each node, build a CONFIGURATION_NODE and attempt to convert the
+ * node to an ARC component. If this conversion fails, free the
+ * CONFIGURATION_NODE and move on, continuing to pass "here." Otherwise
+ * move on, and pass "here" = "newlink." This way unconverted nodes
+ * are pruned out of the tree.
+ */
+
+void
+walk_obp(
+ phandle ph,
+ CONFIGURATION_NODE *here,
+ CONFIGURATION_NODE *parent,
+ CONFIGURATION_NODE *peer)
+{
+ phandle newph;
+ CONFIGURATION_NODE *newlink;
+ int *saved_key_array;
+ extern int level; // for debug output
+
+ //VRASSERT((parent) || ((parent == 0) && (here == 0) && (peer == 0)));
+ debug(VRDBG_TREE, "\n");
+ debug(VRDBG_TREE, "walk_obp: phandle 0x%x (%d)\n", ph, level);
+ debug(VRDBG_TREE, "walk_obp:\there 0x%x parent 0x%x peer 0x%x\n",
+ here, parent, peer);
+
+ if (newph = OFChild(ph)) {
+ //
+ // Here we descend to a new level of the tree. Increment "level"
+ // so that debugging printouts reflect the level of the tree,
+ // and allocate a new "key_array" since counts reset at each
+ // level of the tree. See convert_node() for the use of
+ // key_array.
+ //
+ //
+ level++;
+ saved_key_array = key_array;
+ key_array = (int *) zalloc(64 * sizeof(int)); //"Enough" slots.
+ newlink = new(CONFIGURATION_NODE);
+ newlink->OfPhandle = newph;
+ debug(VRDBG_TREE, "walk_obp:\tNew Child node: 0x%x\n", newlink);
+
+ //
+ // If there's already an ARC Node "HERE", then set the newlink's
+ // parent to point to the node "HERE".
+ //
+ if (here) {
+ newlink->Parent = here;
+ } else {
+ newlink->Parent = parent;
+ }
+ if (convert_node(newlink)) {
+ if (here) {
+ if (here->Child == 0) {
+ here->Child = newlink;
+ walk_obp(newph, newlink, here, 0);
+ } else {
+ CONFIGURATION_NODE *tmplink;
+ debug(VRDBG_TREE, "walk_obp: newlink = here->Child(0x%x)\n",
+ here->Child);
+ tmplink = here->Child;
+ while (tmplink->Peer) {
+ tmplink = tmplink->Peer;
+ }
+
+ tmplink->Peer = newlink;
+ VRDBG(VRDBG_TREE, vr_dump_config_node(tmplink));
+ walk_obp(newph, newlink, here, 0);
+ }
+ } else if (peer) {
+ newlink->Peer = peer->Peer;
+ peer->Peer = newlink;
+ walk_obp(newph, newlink, parent, newlink);
+ while (peer->Peer) {
+ peer = peer->Peer;
+ }
+ } else if (parent) {
+ newlink->Peer = parent->Child;
+ parent->Child = newlink;
+ walk_obp(newph, newlink, here, 0);
+ peer = newlink;
+ while (peer->Peer) {
+ peer = peer->Peer;
+ }
+ }
+ } else {
+ debug(VRDBG_TREE, "walk_obp: FREE CHILD NODE 0x%x\n", newlink);
+ free((char *)newlink);
+ if (here) {
+ walk_obp(newph, 0, here, 0);
+ } else {
+ walk_obp(newph, 0, parent, peer);
+ }
+ }
+ //
+ // Ascend: restore level and key_array.
+ //
+ level--;
+ key_array = saved_key_array;
+ }
+
+ if (newph = OFPeer(ph)) {
+ newlink = new(CONFIGURATION_NODE);
+ debug(VRDBG_TREE, "walk_obp:\tnew Peer node: 0x%x\n", newlink);
+ if (ph == 0) {
+ RootNode = newlink;
+ }
+ newlink->OfPhandle = newph;
+ newlink->Parent = parent;
+ if (convert_node(newlink)) {
+ if (here) {
+ if (here->Peer == 0) {
+ here->Peer = newlink;
+ } else {
+ CONFIGURATION_NODE *tmplink;
+ debug(VRDBG_TREE, "walk_obp: newlink = here->Peer(0x%x)\n",
+ here->Peer);
+ tmplink = here->Peer;
+ while (tmplink->Peer) {
+ tmplink = tmplink->Peer;
+ }
+ tmplink->Peer = newlink;
+ VRDBG(VRDBG_TREE, vr_dump_config_node(tmplink));
+ }
+ } else {
+ if (peer) {
+ newlink->Peer = peer->Peer;
+ peer->Peer = newlink;
+ } else {
+ if (parent) {
+ newlink->Peer = parent->Child;
+ parent->Child = newlink;
+ }
+ }
+ }
+ walk_obp(newph, newlink, parent, newlink);
+ } else {
+ debug(VRDBG_TREE, "walk_obp: FREE PEER NODE 0x%x\n", newlink);
+ free((char *)newlink);
+ if (here) {
+ walk_obp(newph, 0, parent, here);
+ } else {
+ walk_obp(newph, 0, parent, peer);
+ }
+ }
+ }
+ debug(VRDBG_TREE, "walk_obp =====================> exit(%d)\n",level);
+}
+
+STATIC int
+convert_node(CONFIGURATION_NODE *node)
+{
+ phandle ph = node->OfPhandle;
+ PCONFIGURATION_COMPONENT Component = &node->Component;
+ PCHAR arcid;
+ LONG key=-1;
+
+ debug(VRDBG_TREE, "convert_node: node(0x%x) Begin ....\n", node);
+ node->ComponentName = get_str_prop(ph, "name", ALLOC);
+ if (node->ComponentName == 0) {
+ debug(VRDBG_TREE, "convert_node: NULL ComponentName. return FALSE\n");
+ return FALSE;
+ }
+ if (convert_name(node) == 0) {
+ debug(VRDBG_TREE, "convert_node: convert_name returned 0...\n", node);
+ return FALSE;
+ }
+ Component->Revision = ARC_REVISION;
+ Component->Version = ARC_VERSION;
+ Component->AffinityMask = default_affinity;
+
+ switch(Component->Class) {
+ case ProcessorClass:
+ break;
+ case CacheClass:
+ convert_cache(node);
+ break;
+
+ case ControllerClass:
+ Component->Key = key_array[Component->Type]++;
+ if((node = convert_controller(node)) == 0 ) {
+ debug(VRDBG_TEST|VRDBG_TREE,
+ "Convert_node: failed convert_controller, return FALSE\n");
+ return(FALSE);
+ }
+ convert_config(node);
+ break;
+
+ default:
+ Component->Key = key_array[Component->Type]++;
+ convert_config(node);
+ break;
+ }
+
+ if (arcid = get_str_prop(ph, "arc-identifier", ALLOC)) {
+ node->Component.Identifier = arcid;
+ node->Component.IdentifierLength = strlen(arcid) + 1;
+ }
+
+ if ((key = get_int_prop(ph, "arc-key")) != -1) {
+ node->Component.Key = key;
+ }
+ debug(VRDBG_TREE|VRDBG_ENTRY,
+ "convert_node: ... returning true\n");
+ return(TRUE);
+}
+
+STATIC int
+convert_name(CONFIGURATION_NODE *node)
+{
+ char *name = node->ComponentName;
+ char *type = get_str_prop(node->OfPhandle, "device_type", NOALLOC);
+ char **id = &node->Component.Identifier;
+ char *cp, *String=0;
+ int result = 1;
+ static int ncpus = 0;
+
+ //
+ // The conversion is based upon device_type, or if that fails,
+ // name. As a first approximation the ARC node's Identifier, if
+ // converted, is set to the OFW node's name property.
+ // This is OK, as later in the process the "arc-identifier"
+ // property can override the Identifier set here. See above.
+ //
+
+ debug(VRDBG_TREE, "convert_name: node(0x%x) is type %s \n",
+ node, TypeNames[node->Component.Type]);
+ *id = name;
+ if (cp = index(name, ',')) {
+ *cp = '-';
+ }
+
+ //
+ // If Parent == 0, we can assume this is the root node.
+ //
+ if (node->Parent == 0) {
+ node->Component.Class = SystemClass;
+ node->Component.Type = ArcSystem;
+
+ //
+ // OFW, name is Company, Model
+ //
+ String = get_str_prop(node->OfPhandle, "name", ALLOC);
+ node->Component.Identifier = index(String, ',');
+ if (node->Component.Identifier == NULL) {
+ node->Component.Identifier = String;
+ } else {
+ node->Component.Identifier++;
+ }
+
+ debug(VRDBG_TEST, "convert_name: node %x (%s)", node, name);
+ debug(VRDBG_TEST, "convert_name: OFW String (%s)\n", String);
+ debug(VRDBG_TEST, "convert_name: Identifier (%s)\n",
+ node->Component.Identifier);
+ goto found;
+ }
+
+ if (type == 0) {
+ goto just_name;
+ }
+
+ //
+ // First try to match on device-type.
+ // This is enough in many cases.
+ //
+ if (strcmp(type, "cpu") == 0) {
+ node->Component.Class = ProcessorClass;
+ node->Component.Type = CentralProcessor;
+ node->Component.Key = get_int_prop(node->OfPhandle, "reg");
+ if (node->Component.Key == -1) {
+ node->Component.Key = ncpus++;
+ }
+ cp = index(name, '-') + 1;
+ *id = (char *) zalloc(13);
+ strcpy(*id, "PowerPC(");
+ strcat(*id, cp);
+ strcat(*id, ")");
+ if (get_int_prop(node->OfPhandle, "i-cache-size")) {
+ convert_cache(add_new_child(node,
+ "cache", CacheClass, PrimaryIcache));
+ }
+
+ //
+ // The following block is to support old FirePower ROMs.
+ // If version 510 ROMs are ever desupported, this block
+ // can be deleted.
+ //
+
+ if (strcmp(
+ get_str_prop(OFParent(node->OfPhandle), "name", NOALLOC),
+ "cpus") != 0) {
+
+ //
+ // This is a 510 rom: it builds a single processor
+ // node even if it's an MP machine. We need to
+ // probe and report all CPUs ourselves.
+ // Since we know 501-rom-equipped machines have
+ // 1 or 2 processors, the job isn't that bad:
+ // we look at mailbox[1] and see if the contents
+ // are equal to "processor ready" (1). If so,
+ // we are dual-proc.
+ //
+
+ PULONG mbox = (PULONG) 0x2f88;
+ CONFIGURATION_NODE *peer;
+
+ if (*mbox == 1) {
+ peer = new(CONFIGURATION_NODE);
+ bcopy((PCHAR) node, (PCHAR) peer, sizeof(CONFIGURATION_NODE));
+ node->Peer = peer;
+ peer->Component.Revision = ARC_REVISION;
+ peer->Component.Version = ARC_VERSION;
+ peer->Component.Key = ncpus++;
+ peer->Component.AffinityMask = 1 << peer->Component.Key;
+ peer->Child = 0;
+ peer->Component.IdentifierLength =
+ strlen(peer->Component.Identifier) + 1;
+ convert_cache(add_new_child(peer,
+ "cache", CacheClass, PrimaryIcache));
+ }
+ }
+
+ goto found;
+
+ } else if (strcmp(type, "cache") == 0) {
+ //
+ // What does the cache architecture of the system
+ // look like? OF reports processor caches in the cpu node,
+ // so that case is handled above. This must be a discrete
+ // off-chip cache of some kind. Is it bound to a particular
+ // processor, or is it a system-wide cache, or what?
+ //
+ // PReP machines call for a "transparent" Level-2 cache.
+ // Currently, these should be reported to NT as children
+ // of the root node--thus this code. IT IS CRUCIAL that
+ // this routine return FALSE, because we want to explicitly
+ // build a child of the root node, and we do NOT want to
+ // allow a node to be built in our present location.
+ //
+ // XXX - This may need to be re-examined in a future release
+ // as system architectures develop.
+ //
+
+ PCONFIGURATION_NODE newnode;
+
+ newnode = add_new_child(RootNode, "cache", CacheClass, SecondaryCache);
+ newnode->OfPhandle = node->OfPhandle;
+ convert_cache(newnode);
+ debug(VRDBG_TREE,"convert_node: node %s (0x%x) has new parent: ROOT.\n",
+ newnode->ComponentName, newnode);
+ return (0);
+
+ } else if (strcmp(type, "pci") == 0) {
+ node->Component.Class = AdapterClass;
+ node->Component.Type = MultiFunctionAdapter;
+ node->ComponentName = "multi";
+ *id = "PCI";
+ goto found;
+
+ } else if (strcmp(type, "isa") == 0) {
+ node->Component.Class = AdapterClass;
+ node->Component.Type = MultiFunctionAdapter;
+ node->ComponentName = "multi";
+ *id = "ISA";
+ goto found;
+
+ } else if (strncmp(type, "scsi", 4) == 0) {
+ node->Component.Class = AdapterClass;
+ node->Component.Type = ScsiAdapter;
+ node->ComponentName = "scsi";
+ String = get_str_prop(node->OfPhandle, "model", NOALLOC);
+ debug(VRDBG_TEST, "String(name)is ...%s:", String);
+ *id = (char *) zalloc(16);
+ if(strcmp(String, "NCR,53C810") == 0) {
+ *id = "NCRC810";
+ debug(VRDBG_TEST|VRDBG_SCSI,
+ "nodeID =......%s:\n", node->Component.Identifier);
+ goto found;
+ }
+ if(strcmp(String, "AMD 53C794") == 0) {
+ *id = "AMD53C974";
+ debug(VRDBG_TEST|VRDBG_SCSI,
+ "nodeID =......%s:\n", node->Component.Identifier);
+ goto found;
+ }
+ if (strncmp(String, "ADPT,AIC-78",11) == 0) {
+ *id = "AIC78XX";
+ debug(VRDBG_TEST|VRDBG_SCSI,
+ "nodeID =......%s:\n", node->Component.Identifier);
+ goto found;
+ }
+
+ *id = "UNKNOWN SCSI";
+ goto found;
+
+ } else if (strcmp(type, "ide") == 0) {
+
+ node->Component.Class = AdapterClass;
+ node->Component.Type = ScsiAdapter;
+ node->ComponentName = "scsi";
+ node->Component.Flags.Input = 1;
+ node->Component.Flags.Output = 1;
+ *id = "IDE";
+ goto found;
+
+ //
+ // Don't change the names on controllers yet. They all
+ // get treated again in convert_controller() to build
+ // their child peripheral nodes, etc. Leave the current
+ // names intact so we can distinguish between e.g.
+ // hard disk and floppy.
+ //
+ } else
+ if (strcmp(type, "block") == 0) {
+ node->Component.Class = ControllerClass;
+ if (strcmp(name, "disk") == 0) {
+ node->Component.Type = DiskController;
+ } else
+ if (strcmp(name, "floppy") == 0) {
+ node->Component.Type = DiskController;
+ } else
+ if (strcmp(name, "cdrom") == 0) {
+ node->Component.Type = CdromController;
+ } else
+ if (strcmp(name, "worm") == 0) {
+ node->Component.Type = WormController;
+ } else {
+ node->Component.Type = OtherController;
+ }
+ goto found;
+
+ } else if (strcmp(type, "byte") == 0) {
+ node->Component.Class = ControllerClass;
+ node->Component.Type = TapeController;
+ goto found;
+
+ } else if (strcmp(type, "display") == 0) {
+ node->Component.Class = ControllerClass;
+ node->Component.Type = DisplayController;
+ String = get_str_prop(node->OfPhandle, "model", ALLOC);
+ if (String == NULL) {
+ String = get_str_prop(node->OfPhandle, "name", ALLOC);
+ }
+ if (strcmp(String,"FirePower,Powerized_Display" ) == 0) {
+ node->Component.Identifier = "Powerized Graphics";
+ } else {
+ node->Component.Identifier = capitalize(String);
+ }
+ if (String == NULL) {
+ node->Component.Identifier = "VGA";
+ }
+
+ update_display_node(node);
+
+ goto found;
+
+ } else if (strcmp(type, "network") == 0) {
+ node->Component.Class = ControllerClass;
+ node->Component.Type = NetworkController;
+
+ //
+ // The stuff that follows is legacy support.
+ // See the comments for "I8042PRT" below.
+ //
+ String = get_str_prop(node->OfPhandle, "name", NOALLOC);
+ debug(VRDBG_TEST, "NetWork String(name)is ...%s:", String);
+ *id = (char *) zalloc(16);
+ if(strcmp(String, "pci1011,2") == 0) {
+ *id = "DC21x4";
+ goto found;
+ }
+ if(strcmp(String, "AMD,79c970") == 0) {
+ *id = "AMD79C970";
+ goto found;
+ }
+ *id = "UNKNOWN NETWORK";
+ goto found;
+
+ } else if (strcmp(type, "serial") == 0) {
+ node->Component.Class = ControllerClass;
+ node->Component.Type = SerialController;
+ goto found;
+
+ } else if (strcmp(type, "parallel") == 0) {
+ node->Component.Class = ControllerClass;
+ node->Component.Type = ParallelController;
+ goto found;
+
+ //
+ // For both keyboard and mouse below, the Identifier really
+ // should come from an "arc-identifier" property. Alas,
+ // there are machines in the field with ROM versions that
+ // don't have the arc-identifier property, so this legacy
+ // code will have to stay here forever.
+ //
+
+ } else if (strcmp(type, "keyboard") == 0) {
+ node->Component.Class = ControllerClass;
+ node->Component.Type = KeyboardController;
+ *id = get_str_prop(OFParent(node->OfPhandle), "name", ALLOC);
+ if (strcmp(*id, "8042") == 0) {
+ free(*id);
+ *id = "I8042PRT";
+ }
+ goto found;
+
+ } else if (strcmp(type, "mouse") == 0) {
+ node->Component.Class = ControllerClass;
+ node->Component.Type = PointerController;
+ *id = get_str_prop(OFParent(node->OfPhandle), "name", ALLOC);
+ if (strcmp(*id, "8042") == 0) {
+ free(*id);
+ *id = "I8042PRT";
+ }
+ goto found;
+ }
+
+just_name:
+
+ //
+ // Device-type wasn't enough. We'll try matching
+ // on name now.
+ //
+ if (strcmp(name, "audio") == 0) {
+ node->Component.Class = ControllerClass;
+ node->Component.Type = AudioController;
+ goto found;
+
+ } else if (strcmp(name, "memory") == 0) {
+ node->Component.Class = MemoryClass;
+ node->Component.Type = SystemMemory;
+ //
+ // "memory" nodes have two properties of interest:
+ // a "reg" prop which describes actual installed memory,
+ // and an "available" prop which describes the memory
+ // that hasn't been allocated. We'll pick up the
+ // reg prop later, in convert_config().
+ //
+ goto found;
+
+ } else if (strcmp(node->Parent->Component.Identifier, "PCI") == 0) {
+ //
+ // This is presumably a PCI expansion card, but without
+ // an FCode expansion ROM.
+ //
+ if (convert_PCI_device(node) == 0) {
+ result = 0;
+ }
+ goto found;
+
+ } else {
+ //
+ // Else what?
+ //
+ debug(VRDBG_TREE, "convert_name: node '%s' (0x%x) is unmatched!\n",
+ name, node);
+ return (0);
+ }
+found:
+ //
+ // NOTE: the IdentifierLength *includes* the null terminator.
+ //
+
+ if (*id) {
+ if (*id == name) {
+ char *newid = zalloc(strlen(*id) + 1);
+ strcpy(newid, *id);
+ *id = newid;
+ }
+ node->Component.IdentifierLength =
+ strlen(*id) + 1;
+ }
+ debug(VRDBG_TREE,
+ "convert_name: node %s (%x) type '%s' is Class %s Type %s ID: %s\n",
+ name, node, type ? type : "",
+ ClassNames[node->Component.Class], TypeNames[node->Component.Type],
+ node->Component.IdentifierLength ? node->Component.Identifier : "");
+ return (result);
+}
+
+STATIC CONFIGURATION_NODE *
+convert_controller(CONFIGURATION_NODE *node)
+{
+ phandle ph = node->OfPhandle;
+ PCONFIGURATION_COMPONENT Component = &node->Component;
+ char *name = node->ComponentName;
+
+ debug(VRDBG_TREE, "convert_controller: node(0x%x) is type %s \n",
+ node, TypeNames[node->Component.Type]);
+ if (OFChild(ph)) {
+ debug(VRDBG_TREE, "Controller node %x '%s' already has a child (%s)!\n",
+ Component, name,get_str_prop(OFChild(ph), "name", NOALLOC));
+ VRDBG(VRDBG_TREE, vr_dump_config_node(node));
+ return(0);
+ }
+
+ switch (Component->Type) {
+
+ case DiskController:
+ if (strcmp(name, "disk") == 0) {
+ (void) add_new_child(node, "rdisk",
+ PeripheralClass, DiskPeripheral);
+ node->Child->Component.Flags.Input = 1;
+ node->Child->Component.Flags.Output = 1;
+ } else if (strcmp(name, "floppy") == 0) {
+ (void) add_new_child(node, "fdisk",
+ PeripheralClass, FloppyDiskPeripheral);
+ node->Child->Component.Flags.Input = 1;
+ node->Child->Component.Flags.Output = 1;
+ node->Child->Component.Flags.Removable = 1;
+ } else
+ warn("What is this disk controller '%s'?\n", name);
+ Component->Flags.Input = 1;
+ Component->Flags.Output = 1;
+ break;
+
+ case TapeController:
+ node->ComponentName = "tape";
+ (void) add_new_child(node, "tape",
+ PeripheralClass, TapePeripheral);
+ Component->Flags.Input = 1;
+ Component->Flags.Output = 1;
+ node->Child->Component.Flags.Input = 1;
+ node->Child->Component.Flags.Output = 1;
+ node->Child->Component.Flags.Removable = 1;
+ break;
+
+ case CdromController:
+ node->ComponentName = "cdrom";
+ (void) add_new_child(node, "fdisk",
+ PeripheralClass, FloppyDiskPeripheral);
+ Component->Flags.Input = 1;
+ Component->Flags.ReadOnly = 1;
+ Component->Flags.Removable = 1;
+ node->Child->Component.Flags.Input = 1;
+ node->Child->Component.Flags.ReadOnly = 1;
+ node->Child->Component.Flags.Removable = 1;
+ break;
+
+ case WormController:
+ node->ComponentName = "worm";
+ (void) add_new_child(node, "rdisk",
+ PeripheralClass, DiskPeripheral);
+ Component->Flags.Input = 1;
+ Component->Flags.Output = 1;
+ node->Child->Component.Flags.Input = 1;
+ node->Child->Component.Flags.Output = 1;
+ node->Child->Component.Flags.Removable = 1;
+ break;
+
+ case SerialController:
+ node->ComponentName = "serial";
+ (void) add_new_child(node, "line",
+ PeripheralClass, LinePeripheral);
+ Component->Flags.Input = 1;
+ Component->Flags.Output = 1;
+ Component->Flags.ConsoleIn = 1;
+ Component->Flags.ConsoleOut = 1;
+ node->Child->Component.Flags.Input = 1;
+ node->Child->Component.Flags.Output = 1;
+ node->Child->Component.Flags.ConsoleIn = 1;
+ node->Child->Component.Flags.ConsoleOut = 1;
+ break;
+
+ case NetworkController:
+ node->ComponentName = "net";
+ (void) add_new_child(node, "network",
+ PeripheralClass, NetworkPeripheral);
+ Component->Flags.Input = 1;
+ Component->Flags.Output = 1;
+ node->Child->Component.Flags.Input = 1;
+ node->Child->Component.Flags.Output = 1;
+ break;
+
+ case DisplayController:
+ node->ComponentName = "video";
+ (void) add_new_child(node, "monitor",
+ PeripheralClass, MonitorPeripheral);
+ Component->Flags.Output = 1;
+ Component->Flags.ConsoleOut = 1;
+ node->Child->Component.Identifier = "1024x768";
+ node->Child->Component.IdentifierLength = 9;
+ node->Child->Component.Flags.Output = 1;
+ node->Child->Component.Flags.ConsoleOut = 1;
+ break;
+
+ case ParallelController:
+ node->ComponentName = "par";
+ (void) add_new_child(node, "print",
+ PeripheralClass, PrinterPeripheral);
+ Component->Flags.Input = 1;
+ Component->Flags.Output = 1;
+ node->Child->Component.Flags.Input = 1;
+ node->Child->Component.Flags.Output = 1;
+ break;
+
+ case PointerController:
+ node->ComponentName = "point";
+ (void) add_new_child(node, "pointer",
+ PeripheralClass, PointerPeripheral);
+ Component->Flags.Input = 1;
+ node->Child->Component.Flags.Input = 1;
+ node->Child->Component.Identifier = MOUSE_IDENTIFIER;
+ node->Child->Component.IdentifierLength =
+ strlen(MOUSE_IDENTIFIER) + 1;
+ break;
+
+ case KeyboardController:
+ node->ComponentName = "key";
+ (void) add_new_child(node, "keyboard",
+ PeripheralClass, KeyboardPeripheral);
+ Component->Flags.Input = 1;
+ Component->Flags.ConsoleIn = 1;
+ node->Child->Component.Flags.Input = 1;
+ node->Child->Component.Flags.ConsoleIn = 1;
+ node->Child->Component.Identifier = KBD_IDENTIFIER;
+ node->Child->Component.IdentifierLength =
+ strlen(KBD_IDENTIFIER) + 1;
+ break;
+
+ case AudioController:
+ node->ComponentName = "other";
+ (void) add_new_child(node, "other",
+ PeripheralClass, OtherPeripheral);
+ Component->Flags.Input = 1;
+ Component->Flags.Output = 1;
+ node->Child->Component.Flags.Input = 1;
+ node->Child->Component.Flags.Output = 1;
+ break;
+
+ case OtherController:
+ node->ComponentName = "other";
+ (void) add_new_child(node, "other",
+ PeripheralClass, OtherPeripheral);
+ Component->Flags.Input = 1;
+ Component->Flags.Output = 1;
+ node->Child->Component.Flags.Input = 1;
+ node->Child->Component.Flags.Output = 1;
+ break;
+
+ default:
+ warn("Unknown controller class %d type %d\n",
+ Component->Class, Component->Type);
+ break;
+ }
+ //
+ // NOTE: the IdentifierLength *includes* the null terminator.
+ //
+ if (node->Component.Identifier) {
+ node->Component.IdentifierLength =
+ strlen(node->Component.Identifier) + 1;
+ }
+
+ debug(VRDBG_TREE, "convert_controller: node %x has parent %x of Type %s\n",
+ node, node->Parent, TypeNames[node->Parent->Component.Type]);
+
+ //
+ // Finally, check to see if this is a child of a ScsiAdapter.
+ // If it is, we may have to probe the bus.
+ //
+
+ if (node->Parent->Component.Type == ScsiAdapter) {
+ if (strcmp(node->Parent->Component.Identifier, "IDE") == 0) {
+ return (convert_IDE_device(node));
+ } else {
+ return (convert_SCSI_device(node));
+ }
+ }
+
+ return (node);
+}
+
+/*
+ * We found a leaf node. In classical OF this would be sufficient; i.e.
+ * this node would contain the methods to drive the device and the properties
+ * that describe the device. But in the ARC world, this node corresponds
+ * to a ControllerClass Component, which is expected to have a PeripheralClass
+ * Component that describes the actual device.
+ * In this function we take an existing "Controller" node and add a
+ * "Peripheral" node as a child.
+ */
+STATIC CONFIGURATION_NODE *
+add_new_child(
+ CONFIGURATION_NODE *parent,
+ char *name,
+ CONFIGURATION_CLASS class,
+ CONFIGURATION_TYPE type
+ )
+{
+ PCONFIGURATION_NODE child;
+ PCONFIGURATION_COMPONENT Component;
+
+ debug(VRDBG_TREE,
+ "add_new_child: parent %s(0x%x) will get child %s Type %s\n",
+ parent->ComponentName, parent, name, TypeNames[type]);
+ child = new(CONFIGURATION_NODE);
+ child->Parent = parent;
+ debug(VRDBG_TREE, "add_new_child: add child (0x%x) to node 0x%x\n",
+ child, child->Parent);
+ if (parent->Child != NULL) {
+ PCONFIGURATION_NODE node = parent->Child;
+ while (node->Peer) {
+ node = node->Peer;
+ }
+ node->Peer = child;
+ } else {
+ parent->Child = child;
+ }
+ child->ComponentName = name;
+ child->OfPhandle = parent->OfPhandle;
+ Component = &child->Component;
+ Component->Class = class;
+ Component->Type = type;
+ Component->Revision = ARC_REVISION;
+ Component->Version = ARC_VERSION;
+ Component->AffinityMask = default_affinity;
+ Component->Key = key_array[Component->Type]++;
+ VRDBG(VRDBG_TREE, vr_dump_config_node(child));
+
+ return (child);
+}
+
+/*
+ * A PCI device without an FCode ROM may yet have enough useful
+ * properties encoded in configuration space to make a reasonable
+ * guess about its device type, etc.
+ */
+STATIC int
+convert_PCI_device(PCONFIGURATION_NODE node)
+{
+ phandle ph = node->OfPhandle;
+ int class_code, base_class, sub_class, prog_class;
+
+ debug(VRDBG_TREE, "Converting PCI device '%s'\n", node->ComponentName);
+ class_code = get_int_prop(ph, "class-code");
+ debug(VRDBG_TREE, "PCI node class = %x\n", class_code);
+ if (class_code == -1) {
+ /* Hopeless */
+ return (0);
+ }
+ base_class = (class_code >> 16) & 0xff;
+ sub_class = (class_code >> 8) & 0xff;
+ prog_class = class_code & 0xff;
+
+ switch (base_class) {
+ case 0:
+ node->Component.Class = ControllerClass;
+ if (sub_class == 1 && prog_class == 0) {
+ node->Component.Type = DisplayController;
+ update_display_node(node);
+ } else {
+ node->Component.Type = OtherController;
+ }
+ goto ok;
+
+ case 1:
+ node->Component.Class = ControllerClass;
+ node->Component.Type = DiskController;
+ switch (sub_class) {
+ case 0: node->Component.Class = AdapterClass;
+ node->Component.Type = ScsiAdapter;
+ node->ComponentName = "scsi";
+ (void) add_new_child(node, "disk",
+ ControllerClass, DiskController);
+ (void) add_new_child(node, "tape",
+ ControllerClass, TapeController);
+ break;
+ case 1: node->ComponentName = "multi"; // IDE, actually
+ break;
+ case 2: node->ComponentName = "floppy";
+ break;
+ case 3: node->ComponentName = "ipi";
+ break;
+ default: node->ComponentName = "other";
+ break;
+ }
+ goto ok;
+
+ case 2:
+ node->Component.Class = ControllerClass;
+ node->Component.Type = NetworkController;
+ goto ok;
+
+ case 3:
+ node->Component.Class = ControllerClass;
+
+#ifdef rev1_30
+ node->Component.Type = DisplayController;
+#else
+ if (sub_class == 0 && prog_class == 0) {
+ node->Component.Type = DisplayController;
+ update_display_node(node);
+ } else {
+ node->Component.Type = OtherController;
+ }
+
+#endif
+ goto ok;
+
+ case 4:
+ node->Component.Class = ControllerClass;
+ switch (sub_class) {
+ case 0: node->Component.Type = DisplayController;
+ goto ok;
+ case 1: node->Component.Type = AudioController;
+ goto ok;
+ }
+ break;
+
+ case 5:
+ //
+ // What are we to do about memory cards?
+ //
+ break;
+
+ case 6:
+ node->Component.Class = AdapterClass;
+ if (sub_class == 2) {
+ node->Component.Type = EisaAdapter;
+ node->ComponentName = "eisa";
+ } else {
+ node->Component.Type = MultiFunctionAdapter;
+ node->ComponentName = "multi";
+ }
+ goto ok;
+
+ }
+
+ //
+ // What is this thing?
+ //
+ node->Component.Class = ControllerClass;
+ node->Component.Type = OtherController;
+ node->ComponentName = "other";
+ok:
+ if( VrDebug & VRDBG_TREE ) {
+ DisplayConfig(&node->Component);
+ }
+ return (1);
+}
+
+/*
+ * ScsiAdapter nodes have some special rules. The child controllers' Key
+ * values are the SCSI target ID, not the instance, and the child
+ * controllers' Identifiers are specified to be the concatenation of
+ * the vendor and product name fields as returned from INQUIRY.
+ *
+ * Worse news: SCSI devices may be wildcarded, so we've got to probe
+ * the whole bus here if we find a wildcard node.
+ *
+ * As an optimization, record the fact that we've probed the bus
+ * so we need probe only once. This eliminates duplicate probes as
+ * the firmware customarily reports both a disk and tape wildcard.
+ * The list of probed nodes is an array of "sufficient" size.
+ * Yes, I know.
+ */
+
+STATIC CONFIGURATION_NODE *
+convert_SCSI_device(PCONFIGURATION_NODE node)
+{
+ PCONFIGURATION_NODE newnode, parent=node->Parent;
+ CONFIGURATION_TYPE type = node->Component.Type, newtype;
+ phandle ph = node->OfPhandle;
+ phandle parentph = parent->OfPhandle;
+ static PCONFIGURATION_NODE done_list[32] = { 0 };
+ reg *regp;
+ char *path;
+ int i;
+ ihandle ih;
+ UCHAR inq[] = { 0x12, 0, 0, 0, 0xff, 0 };
+ ULONG res[2];
+ UCHAR *inq_data;
+ static int lock = 0;
+ int max_scsi_target = 8, scsi_host_id = 7;
+ int tmp_scsi_host_id = -1;
+
+
+
+ if (lock++) {
+ --lock;
+ return(0);
+ }
+
+ debug(VRDBG_ENTRY|VRDBG_TREE|VRDBG_SCSI,
+ "convert_SCSI_device: node 0x%x Begin.....\n", node);
+
+ if (OFGetproplen(ph, "reg") > 0) {
+ regp = get_reg_prop(ph, "reg", 0);
+ node->Component.Key = regp->hi;
+ node->Child->Component.Key = 0;
+ --lock;
+ return (node);
+ }
+
+ debug(VRDBG_SCSI|VRDBG_TREE,
+ "convert_SCSI_device: wildcard node (0x%x) parent (0x%x)\n",
+ node, parent);
+ VRDBG(VRDBG_SCSI, vr_dump_config_node(node));
+
+ //
+ // Discard the existing node: it's a wildcard and does
+ // us no good.
+ //
+ debug(VRDBG_SCSI, "convert_SCSI_device: parent child is(0x%x)\n",
+ parent->Child);
+ if (parent->Child == node) {
+ parent->Child = node->Peer;
+ debug(VRDBG_SCSI, "convert_SCSI_device: reset parent->Child \n");
+ VRDBG(VRDBG_SCSI, vr_dump_config_node(parent->Child));
+ }
+ for (newnode = parent->Child; newnode; newnode = newnode->Peer) {
+ debug(VRDBG_SCSI, "convert_SCSI_device: new node (0x%x)\n",newnode);
+ if (newnode->Peer == node) {
+ newnode->Peer = node->Peer;
+ node->Peer = 0;
+ }
+ }
+ if (node->Child) {
+ free((char *) node->Child);
+ }
+
+ //
+ // and finally, free the node...
+ //
+ free((char *) node);
+
+
+ //
+ // Have we already done this SCSI bus?
+ //
+ for (i = 0; i < 32; ++i) {
+ if (done_list[i] == 0) {
+ break;
+ }
+ if (done_list[i] == parent) {
+ debug(VRDBG_SCSI|VRDBG_TREE,
+ "already did node (0x%x)\n", parent);
+ --lock;
+ return (0);
+ }
+ }
+ if (i >= 32) {
+ fatal("Too many (>32) SCSI adapters!\n");
+ }
+ done_list[i] = parent;
+
+ if (get_bool_prop(parentph, "wide")) {
+ debug(VRDBG_TREE|VRDBG_SCSI, "SCSI controller is wide \n");
+
+ max_scsi_target = 16;
+
+ tmp_scsi_host_id = get_int_prop(parentph, "scsi-initiator-id");
+
+ debug(VRDBG_SCSI, "SCSI_Initiator_Id = %x\n", tmp_scsi_host_id);
+ if ( (tmp_scsi_host_id >= 0) && (tmp_scsi_host_id < 16) ) {
+ scsi_host_id = tmp_scsi_host_id;
+ }
+ }
+
+ //
+ // Build the parent adapter's path.
+ //
+ path = NodeToPath(parent);
+ ih = OFOpen(path);
+
+ //
+ // Loop through possible targets, and record each one
+ // which responds.
+ //
+ for (i = 0; i < max_scsi_target; ++i) {
+ if (i == scsi_host_id) {
+ continue; // don't want to probe the scsi host!
+ }
+
+ //
+ // This algorithm uses methods that are standard
+ // in the scsi node, but are not explicitly exported
+ // through the client interface--thus the "call-method."
+ //
+ OFCallMethod(0, 4, 0, "set-address", ih, i, 0);
+ OFCallMethod(2, 5, res, "short-data-command", ih, 6, inq, 0xff);
+ if (res[0] != 0) {
+ continue;
+ }
+
+ //
+ // The command succeeded.
+ //
+ inq_data = (UCHAR *) res[1];
+ if (inq_data[0] == 0x7f) {
+ continue;
+ }
+
+ //
+ // What kind of device are we looking for?
+ //
+ debug(VRDBG_TREE|VRDBG_SCSI,
+ "convert_SCSI_device: Device Found @ id %d\n",i);
+ newtype = ScsiNodeType[inq_data[0]];
+ debug(VRDBG_TREE|VRDBG_SCSI,
+ "convert_SCSI_device:\t\t '%s' of Type '%s'\n",
+ ScsiNodeName[inq_data[0]], TypeNames[newtype]);
+ //
+ // This target is for real. Add a new node to represent
+ // this device. Touch up the node as necessary
+ // for proper key, identifier, etc.
+ //
+ newnode = add_new_child(parent, ScsiNodeName[inq_data[0]],
+ ControllerClass, newtype);
+
+ newnode->OfPhandle = ph;
+ newnode->Component.Key = i;
+ newnode->Component.Identifier = (char *)zalloc(29);
+ bcopy(&inq_data[8], newnode->Component.Identifier, 28);
+ newnode->Component.IdentifierLength = 29;
+ newnode->Wildcard = 1;
+ newnode->WildcardAddrPath = (char *) zalloc(6);
+ strcpy(newnode->WildcardAddrPath, "@X,0");
+
+ //
+ // Convert scsi id to hex string value...
+ //
+ if (i < 10) {
+ newnode->WildcardAddrPath[1] = '0' + i;
+ } else {
+ newnode->WildcardAddrPath[1] = 'a' + (i-10);
+ }
+
+ if (!convert_controller(newnode)) {
+ debug(VRDBG_TEST|VRDBG_SCSI|VRDBG_TREE,
+ "Convert_SCSI_device: failed convert_controller\n");
+ }
+ newnode->Child->Component.Key = 0;
+ newnode->Child->Wildcard = 1;
+
+ } // end of for loop probing scsi bus
+ OFClose(ih);
+ free(path);
+ --lock;
+ return (0); // Zero because this was a wildcard node; don't convert.
+}
+
+/*
+ * Like SCSI, devices may be wildcarded, so we've got to probe
+ * the whole bus here if we find a wildcard node.
+ */
+STATIC CONFIGURATION_NODE *
+convert_IDE_device(PCONFIGURATION_NODE node)
+{
+ PCONFIGURATION_NODE newnode, parent=node->Parent;
+ CONFIGURATION_TYPE type = node->Component.Type, newtype;
+ phandle ph = node->OfPhandle;
+ static PCONFIGURATION_NODE done_list[32] = { 0 };
+ reg *regp;
+ char *path;
+ int i;
+ ihandle ih;
+ ULONG res[3];
+ static int lock = 0;
+
+ if (lock++) {
+ --lock;
+ return(0);
+ }
+ debug(VRDBG_TREE, "convert_IDE_device: node 0x%x\n", node);
+
+ if (OFGetproplen(ph, "reg") > 0) {
+ regp = get_reg_prop(ph, "reg", 0);
+ node->Component.Key = regp->hi;
+ node->Child->Component.Key = 0;
+ --lock;
+ return (node);
+ }
+
+ debug(VRDBG_IDE, "convert_IDE_device: wildcard node (0x%x)\n", node);
+ VRDBG(VRDBG_IDE, vr_dump_config_node(node));
+
+ //
+ // Discard the existing node: it's a wildcard and does
+ // us no good.
+ //
+
+ debug(VRDBG_IDE, "convert_IDE_device: parent child is(0x%x)\n",
+ parent->Child);
+ if (parent->Child == node) {
+ //
+ // remove this node from the parent's lineage...
+ //
+ parent->Child = node->Peer;
+ debug(VRDBG_IDE, "convert_IDE_device: reset parent->Child \n");
+ VRDBG(VRDBG_IDE, vr_dump_config_node(parent->Child));
+ }
+
+ //
+ // Run the list of peers and see who points to this wild card node.
+ // Once the wildcard's sibling is located, remove the wildcard
+ // from the "peer" list.
+ //
+ for (newnode = parent->Child; newnode; newnode = newnode->Peer) {
+ debug(VRDBG_IDE, "convert_IDE_device: new node (0x%x)\n",newnode);
+ if (newnode->Peer == node) {
+ //
+ // Now, remove this node from its peer(s)'s line
+ // of siblings....
+ //
+ newnode->Peer = node->Peer;
+ debug(VRDBG_IDE, "convert_IDE_device: reset newnode->Peer \n");
+ VRDBG(VRDBG_IDE, vr_dump_config_node(newnode));
+ node->Peer = 0;
+ }
+ }
+
+ //
+ // make sure this node's children are freed up since
+ // the children of a wild card node are wild themselves.
+ //
+ if (node->Child) {
+ debug(VRDBG_IDE, "convert_IDE_device: free child(0x%x)\n",
+ node->Child);
+ free((char *) node->Child);
+ }
+
+ //
+ // and finally, zero and free the node...
+ //
+ free((char *) node);
+
+ //
+ // Have we already done this IDE bus?
+ //
+ for (i = 0; i < 32; ++i) {
+ if (done_list[i] == 0) {
+ break;
+ }
+ if (done_list[i] == parent) {
+ debug(VRDBG_IDE|VRDBG_TREE,
+ "already did node (0x%x)\n", parent);
+ --lock;
+ return (0);
+ }
+ }
+
+ if (i >= 32){
+ fatal("Too many (>32) IDE adapters!\n");
+ }
+ done_list[i] = parent;
+
+ //
+ // Build the parent adapter's path.
+ //
+ path = NodeToPath(parent);
+ ih = OFOpen(path);
+ //
+ // Loop through possible targets, and record each one
+ // which responds.
+ //
+
+ for (i = 0; i < MAX_IDE_DEVICE; ++i) {
+ //
+ // This algorithm uses methods that are standard
+ // in the ide package, but are not explicitly exported
+ // through the client interface--thus the "call-method."
+ //
+
+ OFCallMethod(3, 3, res, "ide-drive-inquiry", ih, i);
+ //
+ // The command succeeded.
+ //
+
+ if (res[0] == 0) {
+ continue;
+ }
+
+ debug(VRDBG_TREE, "convert_IDE_device: Device Found @ id %d\n",i);
+ newtype = ScsiNodeType[res[1]];
+ debug(VRDBG_TREE, "convert_IDE_device:\t\t '%s' of Type '%s'\n",
+ ScsiNodeName[res[1]], TypeNames[newtype]);
+
+ //
+ // What kind of device are we looking for?
+ //
+ newnode = add_new_child(parent, ScsiNodeName[res[1]],
+ ControllerClass, newtype);
+ newnode->OfPhandle = ph;
+ newnode->Component.Key = i;
+ newnode->Component.Identifier = "disk";
+ newnode->Component.IdentifierLength = 5;
+ newnode->Wildcard = 1;
+ newnode->WildcardAddrPath = (char *) zalloc(6);
+ strcpy(newnode->WildcardAddrPath, "@X,0");
+ newnode->WildcardAddrPath[1] = '0' + i;
+
+ if (!convert_controller(newnode)) {
+ debug(VRDBG_TEST,
+ "Convert_IDE_device: failed convert_controller\n");
+ }
+ newnode->Child->Component.Key = 0;
+ newnode->Child->Wildcard = 1;
+
+ }
+ OFClose(ih);
+ free(path);
+ --lock;
+ return (0); // Zero because this was a wildcard node; don't convert.
+}
+
+#define prl_t CM_PARTIAL_RESOURCE_LIST
+#define prd_t CM_PARTIAL_RESOURCE_DESCRIPTOR
+
+STATIC prl_t *
+grow_prl(PCONFIGURATION_NODE node, int dev_specific)
+{
+ prl_t *prl;
+ int datalen;
+
+ if (node->ConfigurationData == (prl_t *) 0) {
+ node->ConfigurationData =
+ (PCM_PARTIAL_RESOURCE_LIST)
+ zalloc(sizeof(CM_PARTIAL_RESOURCE_LIST) + dev_specific);
+ prl = node->ConfigurationData;
+ prl->Version = 1;
+ prl->Revision = 2;
+ prl->Count = 0;
+ node->Component.ConfigurationDataLength =
+ sizeof(CM_PARTIAL_RESOURCE_LIST) + dev_specific;
+ return (prl);
+ }
+ datalen = node->Component.ConfigurationDataLength +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) + dev_specific;
+ node->Component.ConfigurationDataLength = datalen;
+ prl = (prl_t *) zalloc(datalen);
+ datalen -= sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) + dev_specific;
+ bcopy((char *) node->ConfigurationData, (char *) prl, datalen);
+ free((char *)node->ConfigurationData);
+ node->ConfigurationData = prl;
+ return(prl);
+}
+
+/*
+ * This extremely ad hoc routine is called when converting a floppy
+ * controller, and builds the appropriate device-specific data struct
+ * in the floppy peripheral (which is a child of the controller node).
+ */
+STATIC VOID
+convert_config_floppy(CONFIGURATION_NODE *node)
+{
+ PCM_FLOPPY_DEVICE_DATA fdd;
+ prl_t *prl;
+ prd_t *prd;
+
+ debug(VRDBG_TREE, "Convert_config_floppy: node 0x%x\n", *node);
+ node->ComponentName = "disk";
+ node->Component.Identifier = "I82077";
+ node->Component.IdentifierLength = 7;
+
+ node = node->Child;
+ //
+ // Add space for the floppy configuration data to the end of the
+ // configuration node:
+ //
+ prl = grow_prl(node, sizeof(CM_FLOPPY_DEVICE_DATA));
+
+ //
+ // set the partial resource descriptor pointer to the end of the
+ // configuration node before this new data area was added:
+ //
+ prd = &prl->PartialDescriptors[prl->Count];
+
+ //
+ // Tell the registry this data is device specific, and the resource
+ // is device exclusive. Basically, fill out a partial resource
+ // descriptor for the floppy:
+ //
+ prd->Type = CmResourceTypeDeviceSpecific;
+ prd->ShareDisposition = CmResourceShareDeviceExclusive;
+ prd->Flags = 0;
+ prd->u.DeviceSpecificData.DataSize = sizeof(CM_FLOPPY_DEVICE_DATA);
+
+ //
+ // finally, increment the count to match the increase in the data
+ // added to the partial resource list
+ //
+ prl->Count += 1;
+
+ //
+ // Device-specific data begins immediately after
+ // its descriptor.
+ //
+ fdd = (PCM_FLOPPY_DEVICE_DATA)
+ ((char *) prd + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
+ //
+ // These need to be version 1.2, else all the extended fields
+ // like "HeadSettleTime" are assumed to be valid and must be
+ // filled in, presumably by a scientist.
+ //
+ fdd->Version = 1;
+ fdd->Revision = 2;
+ strcpy(fdd->Size, "3.5");
+ fdd->MaxDensity = 1440;
+ /* All else is zero. */
+}
+
+/*
+ * This extremely ad hoc routine is called when converting a serial
+ * controller, and builds the appropriate device-specific data struct.
+ */
+STATIC VOID
+convert_config_serial(CONFIGURATION_NODE *node)
+{
+ PCM_SERIAL_DEVICE_DATA serd;
+ prl_t *prl;
+ prd_t *prd;
+
+ debug(VRDBG_TREE, "Convert_config_serial: node 0x%x\n", *node);
+ prl = grow_prl(node, sizeof(CM_SERIAL_DEVICE_DATA));
+ prd = &prl->PartialDescriptors[prl->Count];
+ prd->Type = CmResourceTypeDeviceSpecific;
+ prd->ShareDisposition = CmResourceShareDeviceExclusive;
+ prd->Flags = 0;
+ prd->u.DeviceSpecificData.DataSize = sizeof(CM_SERIAL_DEVICE_DATA);
+ prl->Count += 1;
+
+ //
+ // Device-specific data begins immediately after
+ // its descriptor.
+ //
+ serd = (PCM_SERIAL_DEVICE_DATA)
+ ((char *) prd + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
+ serd->Version = 1;
+ serd->Revision = 2;
+ if (VrDebug & SANDALFOOT) {
+ serd->BaudClock = 0x409980;
+ } else {
+ serd->BaudClock = 1843200;
+ }
+}
+
+/*
+ * This extremely ad hoc routine is called when converting the system
+ * node, and builds the appropriate device-specific data struct.
+ */
+STATIC VOID
+convert_system_node(CONFIGURATION_NODE *node)
+{
+ prl_t *prl;
+ prd_t *prd;
+ phandle ph;
+ PCHAR pData;
+ PCHAR pFirmwareVersion, pVeneerVersion;
+ PCHAR pVeneerVersionId = "Veneer";
+ PCHAR pFirmwareVersionId = "Firmware";
+#ifdef BUILTBY
+ PCHAR pBuiltById = "Built By";
+ PCHAR pBuiltBy;
+#endif
+ CHAR **srcPairs[] = {
+ &pFirmwareVersionId,
+ &pFirmwareVersion,
+ &pVeneerVersionId,
+ &pVeneerVersion,
+#ifdef BUILTBY
+ &pBuiltById,
+ &pBuiltBy,
+#endif
+ NULL
+ };
+ LONG dataSize;
+ LONG n;
+
+ debug(VRDBG_TREE, "Convert_system_node: node 0x%x\n", *node);
+
+ //
+ // The configuration data being built here will consist of
+ // multiple null terminated strings terminated by an empty
+ // string (ie. '\0'). The strings will consist of pairs
+ // of strings with the first string being the description
+ // of the second (paired) string.
+ //
+ // Example:
+ //
+ // "VeneerVersion" "FirmWorks,ENG,00.23,1995-04-27,14:42:21,GENERAL"
+ //
+
+ //
+ // grab the firmware and veneer versions
+ //
+
+ pVeneerVersion = VeneerVersion();
+ ph = OFFinddevice("/openprom");
+ pFirmwareVersion = get_str_prop(ph, "model", NOALLOC);
+ level_equals_vector = (OFGetproplen(ph,"arc-interrupt-level=vector") >= 0);
+ if (OFGetproplen(ph,"arc-interrupt-level") > 0) {
+ default_interrupt_level = get_int_prop(ph, "arc-interrupt-level");
+ }
+ if (OFGetproplen(ph,"arc-interrupt-affinity") > 0) {
+ default_interrupt_affinity = get_int_prop(ph, "arc-interrupt-affinity");
+ }
+
+#ifdef BUILTBY
+ //
+ // add the built by if defined
+ //
+ pBuiltBy = IQUOTE(BUILTBY);
+#endif
+
+ //
+ // the length of all strings + null terminaters + empty string
+ //
+
+ dataSize = 0;
+ for (n = 0; srcPairs[n]; n++) {
+ dataSize += strlen(*srcPairs[n]) + 1;
+ }
+ dataSize += 2*sizeof(CHAR); // an empty string (2* just for good measure)
+
+ prl = grow_prl(node, dataSize);
+ prd = &prl->PartialDescriptors[prl->Count];
+ prd->Type = CmResourceTypeDeviceSpecific;
+ prd->ShareDisposition = CmResourceShareDeviceExclusive;
+ prd->Flags = 0;
+ prd->u.DeviceSpecificData.DataSize = dataSize;
+ prl->Count += 1;
+ debug(VRDBG_TEST, "Count is now...%x\n", prl->Count);
+
+ //
+ // Device-specific data begins immediately after
+ // its descriptor.
+ //
+
+ pData = (char *) prd + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
+
+ {
+ //
+ // Now stuff the strings into the data buffer.
+ //
+
+ PCHAR dst = pData;
+ PCHAR src;
+
+ for (n = 0; srcPairs[n]; n++) {
+ src = *srcPairs[n];
+ strcpy(dst, src);
+ dst += strlen(src)+1;
+ }
+
+ *dst = '\0';
+ }
+
+ return;
+
+}
+
+//
+// 8042 subtrees compliant with the HRP binding define a new address
+// space for their children. Reg[0] in the child specifies the keyboard (0)
+// or aux (1) port of the 8042. All 8042 child nodes--keyboard and
+// mouse--are translated to ARC nodes--kbd and point--that have the same
+// PORT information in the registry. The reg information in the device
+// tree is suppressed, and the NT driver (i8042prt) sorts out who gets
+// what port on the 8042.
+// Although we shouldn't, we'll just "know" that an 8042 has two reg
+//
+STATIC VOID
+convert_config_i8042(CONFIGURATION_NODE *node)
+{
+ phandle parent;
+ prl_t *prl;
+ prd_t *prd;
+ int i;
+ reg *regp;
+
+ debug(VRDBG_TREE, "Convert_config_i8042: node 0x%x\n", *node);
+ parent = OFParent(node->OfPhandle);
+ for (i = 0; i < 2; ++i) {
+ regp = get_reg_prop(parent, "reg", i);
+ prl = grow_prl(node, 0);
+ prd = &prl->PartialDescriptors[prl->Count];
+ prd->Type = CmResourceTypePort;
+ prd->Flags = CM_RESOURCE_PORT_IO;
+ prd->u.Port.Start.LowPart = regp->lo;
+ prd->u.Port.Start.HighPart = 0;
+ prd->u.Port.Length = regp->size;
+ prd->ShareDisposition = CmResourceShareDeviceExclusive;
+ prl->Count += 1;
+ }
+}
+
+STATIC VOID
+replace_isa_name(CONFIGURATION_NODE *node, int port)
+{
+ struct pnp_info *pnp;
+
+ for (pnp = pnp_data; pnp->port != 0; ++pnp) {
+ if (pnp->port == (unsigned int) port) {
+ node->Component.Identifier = pnp->id;
+ node->Component.IdentifierLength = strlen(pnp->id) + 1;
+ break;
+ }
+ }
+}
+
+STATIC VOID
+convert_config(CONFIGURATION_NODE *node)
+{
+ phandle ph = node->OfPhandle;
+ prl_t *prl;
+ prd_t *prd=0;
+ reg *regp;
+ int prop;
+
+ debug(VRDBG_TREE, "convert_config: node 0x%x, name %s identifier %s\n",
+ node, node->ComponentName, node->Component.Identifier);
+ //
+ // The "arc-config-data" property totally overrides the conversion
+ // process, providing a complete verbatim ARC configuration data
+ // structure.
+ //
+ if ((prop = OFGetproplen(ph, "arc-config-data")) >= 0) {
+ char *buf;
+ debug(VRDBG_ARCDATA, "convert_config: arc data override: 0x%x\n", node);
+ buf = zalloc(prop);
+ (VOID) OFGetprop(ph, "arc-config-data", buf, prop);
+ node->ConfigurationData = (PCM_PARTIAL_RESOURCE_LIST) buf;
+ node->Component.ConfigurationDataLength = prop;
+
+ if (((prop = OFGetproplen(ph, "reg")) > 0)
+ && (strcmp(node->Parent->Component.Identifier, "ISA") == 0)) {
+ regp = get_reg_prop(ph, "reg", 0);
+ replace_isa_name(node, regp->lo);
+ }
+ return;
+ }
+
+ if ((prop = OFGetproplen(ph, "reg")) > 0) {
+ if (strcmp(node->ComponentName, "memory") == 0) {
+ regp = get_reg_prop(ph, "reg", 0);
+ ADD_MEM_RESOURCE(regp, node);
+ } else {
+ if (strcmp(node->Parent->Component.Identifier, "PCI") == 0) {
+ regp = get_reg_prop(ph, "reg", 1);
+ configure_pci_node(regp, node);
+ } else {
+ if (strcmp(node->Component.Identifier, "I8042PRT") == 0) {
+ convert_config_i8042(node);
+ } else {
+ regp = get_reg_prop(ph, "reg", 0);
+ ADD_IO_RESOURCE(regp, node);
+ replace_isa_name(node, prd->u.Port.Start.LowPart);
+ }
+ }
+ }
+ }
+
+ if ((prop = OFGetproplen(ph, "interrupts")) > 0) {
+ int level;
+ level = get_int_prop(ph, "interrupts");
+ ADD_INT_RESOURCE(level, node);
+ //
+ // Now check for deviations from the "NORM" in the form of
+ // arc-... properties that this particular system uses to
+ // override standard tree values.
+ //
+ if ((prop = OFGetproplen(ph, "arc-interrupt-flags")) > 0) {
+ prop = get_int_prop(ph, "arc-interrupt-flags");
+ prd->Flags = prop;
+ }
+ if ((prop = OFGetproplen(ph, "arc-interrupt-level")) > 0) {
+ prop = get_int_prop(ph, "arc-interrupt-level");
+ prd->u.Interrupt.Level = prop;
+ }
+
+ if ((prop = OFGetproplen(ph, "arc-interrupt-vector")) > 0) {
+ prop = get_int_prop(ph, "arc-interrupt-vector");
+ prd->u.Interrupt.Vector = prop;
+ }
+
+ if ((prop = OFGetproplen(ph, "arc-interrupt-affinity")) > 0) {
+ (int)(prd->u.Interrupt.Affinity) =
+ get_int_prop(ph, "arc-interrupt-affinity");
+ }
+
+ }
+
+ if ((prop = OFGetproplen(ph, "dma")) > 0) {
+ prop = get_int_prop(ph, "dma");
+ ADD_DMA_RESOURCE(prop, node);
+ if (prop != sizeof(int)) {
+ //
+ // Multiple cells are used to encode PNP data for
+ // AIX--just pick off the first cell.
+ //
+ char buf[sizeof(int)];
+ OFGetprop(ph, "dma", buf, sizeof(int));
+ prop = decode_int(buf);
+ prd->u.Dma.Channel = prop;
+ }
+ }
+
+ if ((prop = OFGetproplen(ph, "arc-device-specific")) > 0) {
+ ADD_DEVICE_SPECIFIC_RESOURCE(prop, node);
+ }
+
+ //
+ // Now check for special-case conversions.
+ //
+
+ debug(VRDBG_TREE, "\tCheck special case, Name '%s'\n",
+ node->ComponentName);
+
+ if (strcmp(node->ComponentName, "floppy") == 0) {
+ convert_config_floppy(node);
+ }
+
+ if (strcmp(node->ComponentName, "serial") == 0) {
+ convert_config_serial(node);
+ }
+
+#ifdef SANDALFOOT_YET_LIVES
+ //
+ // Empirically, Sandalfoot systems have this stuff (register
+ // init constants?) in their ARC trees. Ergo, we put it
+ // in our ARC trees too. Note that this stuff doesn't look
+ // like a normal node.
+ //
+ if (strcmp(node->ComponentName, "video") == 0) {
+ PULONG up;
+
+ node = node->Child;
+ prl = grow_prl(node, 0x1a);
+ prl->Version = 1;
+ prl->Revision = 0;
+
+ up = (PULONG) &prl->Count;
+ *up++ = 0x3e800400;
+ *up++ = 0x03e807d0;
+ *up++ = 0x030005dc;
+ *up++ = 0x00010027;
+ *up++ = 0x01570001;
+ *up++ = 0x00000112;
+
+ }
+#endif
+
+ if (node->Component.Type == ArcSystem) {
+ convert_system_node(node);
+ }
+}
+
+STATIC VOID
+convert_cache(CONFIGURATION_NODE *node)
+{
+ phandle ph = node->OfPhandle;
+ CONFIGURATION_NODE *newnode;
+ int block_size, cache_size;
+
+ debug(VRDBG_TREE, "Convert_cache: node 0x%x\n", node);
+ if (get_bool_prop(ph, "cache-unified")) {
+ cache_size = get_int_prop(ph, "i-cache-size");
+ if (cache_size == -1) {
+ fatal("Couldn't find 'i-cache-size': %s\n", node->ComponentName);
+ }
+ block_size = get_int_prop(ph, "i-cache-block-size");
+ if (block_size == -1) {
+ block_size = 8;
+ }
+
+ node->Component.Key = 0x01000000;
+ node->Component.Key |= log2(block_size) << 16;
+ node->Component.Key |= log2(cache_size >> PAGE_SHIFT);
+
+ return;
+ }
+
+ //
+ // Are we an I-cache?
+ //
+ if (get_int_prop(ph, "i-cache-size") != -1) {
+ cache_size = get_int_prop(ph, "i-cache-size");
+ block_size = get_int_prop(ph, "i-cache-block-size");
+ if (block_size == -1) {
+ fatal("Couldn't find 'i-cache-block-size': %s\n",
+ node->ComponentName);
+ }
+
+ node->Component.Key = 0x01000000;
+ node->Component.Key |= log2(block_size) << 16;
+ node->Component.Key |= log2(cache_size >> PAGE_SHIFT);
+
+ if (node->Parent->Component.Type == CentralProcessor) {
+ node->Component.Type = PrimaryIcache;
+ } else {
+ node->Component.Type = SecondaryIcache;
+ }
+
+ if (get_int_prop(ph, "d-cache-size") == -1) {
+ return;
+ }
+
+ //
+ // Uh-oh, there's a split cache here.
+ //
+ newnode = new(CONFIGURATION_NODE);
+ bcopy((char *) node, (char *) newnode, sizeof(CONFIGURATION_NODE));
+ newnode->Child = 0;
+ node->Peer = newnode;
+ node = newnode;
+ }
+
+ //
+ // Are we a D-cache?
+ //
+ if (get_int_prop(ph, "d-cache-size") != -1) {
+ cache_size = get_int_prop(ph, "d-cache-size");
+ block_size = get_int_prop(ph, "d-cache-block-size");
+ if (block_size == -1) {
+ fatal("Couldn't find 'd-cache-block-size': %s\n",
+ node->ComponentName);
+ }
+
+ node->Component.Key = 0x01000000;
+ node->Component.Key |= log2(block_size) << 16;
+ node->Component.Key |= log2(cache_size >> PAGE_SHIFT);
+
+ if (node->Parent->Component.Type == CentralProcessor) {
+ node->Component.Type = PrimaryDcache;
+ } else {
+ node->Component.Type = SecondaryDcache;
+ }
+ }
+}
+
+STATIC VOID
+update_display_node(PCONFIGURATION_NODE node)
+{
+ PCONFIGURATION_NODE n;
+
+ if (DisplayNode == 0) {
+ DisplayNode = node;
+ return;
+ }
+
+ if (DisplayNode->Child) {
+ free((char *) DisplayNode->Child);
+ }
+
+ n = DisplayNode->Parent;
+ if (n->Child == DisplayNode) {
+ n->Child = DisplayNode->Peer;
+ } else {
+ for (n = n->Child; n && n->Peer != DisplayNode; n = n->Peer) {
+ ;
+ }
+ if (n) {
+ n->Peer = DisplayNode->Peer;
+ }
+ }
+
+ free((char *) DisplayNode);
+ DisplayNode = node;
+}
+
+STATIC VOID
+configure_pci_node(reg *regp, PCONFIGURATION_NODE node)
+{
+ prl_t *prl;
+ prd_t *prd;
+ debug(VRDBG_TREE, "Convert_pci_node: node 0x%x\n", node);
+ if (regp != NULL) {
+ prl = grow_prl(node, 0);
+ prd = &prl->PartialDescriptors[prl->Count];
+ prd->ShareDisposition = CmResourceShareDeviceExclusive;
+
+ switch (regp->hi & 0x0f000000) {
+ case 0x01000000:
+ prd->Type = CmResourceTypePort;
+ prd->Flags = CM_RESOURCE_PORT_IO;
+ prd->u.Port.Start.LowPart = regp->lo;
+ prd->u.Port.Start.HighPart = 0;
+ break;
+ case 0x02000000:
+ case 0x03000000:
+ //
+ // XXX this is really quite bogus - we should probably
+ // look in the assigned-addresses property to find
+ // the actual assigned base address. However, we
+ // don't really know yet exactly what this property is
+ // supposed to contain for PCI devices.
+ //
+
+ prd->Type = CmResourceTypeMemory;
+ prd->Flags = 0;
+ prd->u.Memory.Start.LowPart = regp->lo;
+ prd->u.Memory.Start.HighPart = 0;
+ // XXX do something for 64-bit memory space
+ break;
+ }
+ prd->u.Port.Length = regp->size;
+ prl->Count += 1;
+ }
+
+}
+
+/*
+ * Routine: vr_dump_config_node(PCONFIGURATION_NODE)
+ *
+ * Description:
+ * To dump the open firmware info for the given node.
+ */
+
+VOID
+vr_dump_config_node(PCONFIGURATION_NODE node)
+{
+ CONFIGURATION_CLASS class;
+ CONFIGURATION_TYPE type;
+ PCHAR name="XXX";
+
+ if (!node) {
+ warn("vr_dump_config_node: NODE is invalid: 0x%x\n",node);
+ return;
+ }
+ class = node->Component.Class;
+ type = node->Component.Type;
+
+ if (class > MaximumClass ) {
+ warn("vr_dump_config: class value maxed out: previously 0x%x\n",class);
+ class = MaximumClass;
+ }
+
+ if (type > MaximumType) {
+ warn("vr_dump_config: type value maxed out: previously 0x%x\n",type);
+ type = MaximumType;
+ }
+
+ //
+ // Dump information to identify this node.
+ //
+ warn("\ndump_node:\tName\t%s\n", node->ComponentName);
+ warn("\t\tClass\t%s\t\t\tParent 0x%x\n",
+ ClassNames[class], node->Parent);
+ warn("\t\tType\t%s\t\t\t /\n", TypeNames[type]);
+ warn("\t\tKey\t%d\t\t\t Current 0x%x ----> Peer 0x%x\n",
+ node->Component.Key, node, node->Peer);
+ warn("\t\t\t\t\t\t/\n");
+ warn("\t\t\t\t\tChild 0x%x\n\n",node->Child);
+
+}
diff --git a/private/ntos/boot/veneer/vrtree.h b/private/ntos/boot/veneer/vrtree.h
new file mode 100644
index 000000000..42015fa9d
--- /dev/null
+++ b/private/ntos/boot/veneer/vrtree.h
@@ -0,0 +1,153 @@
+
+/*
+ *
+ * Copyright (c) 1995,1996 FirePower Systems, Inc.
+ * Copyright (c) 1994 FirmWorks, Mountain View CA USA. All rights reserved.
+ *
+ * $RCSfile: vrtree.h $
+ * $Revision: 1.3 $
+ * $Date: 1996/06/15 23:21:16 $
+ * $Locker: $
+ *
+ */
+
+#ifndef VRTREE_H
+#define VRTREE_H
+
+#define ADD_MEM_RESOURCE(regp, node) { \
+ prl = grow_prl(node, 0); \
+ prd = &prl->PartialDescriptors[prl->Count]; \
+ prd->Type = CmResourceTypeMemory; \
+ prd->u.Memory.Start.LowPart = regp->lo; \
+ prd->u.Memory.Start.HighPart = 0; \
+ prd->u.Port.Length = regp->size; \
+ prd->Flags = 0; \
+ prd->ShareDisposition = CmResourceShareDeviceExclusive;\
+ prl->Count += 1; \
+ }
+
+#define ADD_IO_RESOURCE(regp, node) { \
+ prl = grow_prl(node, 0); \
+ prd = &prl->PartialDescriptors[prl->Count];\
+ prd->ShareDisposition = CmResourceShareDeviceExclusive; \
+ \
+ prd->Type = CmResourceTypePort; \
+ prd->Flags = CM_RESOURCE_PORT_IO; \
+ prd->u.Port.Start.LowPart = regp->lo; \
+ prd->u.Port.Start.HighPart = 0; \
+ prd->u.Port.Length = regp->size; \
+ prl->Count += 1; \
+ }
+
+
+#define ADD_INT_RESOURCE(level, node) { \
+ prl = grow_prl(node, 0); \
+ prd = &prl->PartialDescriptors[prl->Count]; \
+ prd->u.Interrupt.Level = level; \
+ prd->Type = CmResourceTypeInterrupt; \
+ prd->ShareDisposition = CmResourceShareDeviceExclusive;\
+ prd->Flags = CM_RESOURCE_INTERRUPT_LATCHED; \
+ prd->u.Interrupt.Vector = \
+ level_equals_vector ? \
+ level : default_interrupt_level; \
+ (int)(prd->u.Interrupt.Affinity) = default_interrupt_affinity;\
+ prl->Count += 1; \
+ }
+
+#define ADD_DMA_RESOURCE(prop, node) { \
+ prl = grow_prl(node, 0); \
+ prd = &prl->PartialDescriptors[prl->Count]; \
+ prd->Type = CmResourceTypeDma; \
+ prd->ShareDisposition = CmResourceShareDeviceExclusive; \
+ prd->u.Dma.Channel = prop; \
+ prl->Count += 1; \
+ }
+
+#define ADD_DEVICE_SPECIFIC_RESOURCE(prop, node) { \
+ char *buf;\
+ prl = grow_prl(node, prop);\
+ prd = &prl->PartialDescriptors[prl->Count];\
+ prd->Type = CmResourceTypeDeviceSpecific;\
+ prd->ShareDisposition = CmResourceShareDeviceExclusive;\
+ prd->Flags = 0;\
+ prd->u.DeviceSpecificData.DataSize = prop;\
+ prl->Count += 1;\
+ buf = ((char *) prd + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));\
+ (VOID) OFGetprop(ph, "arc-device-specific", buf, prop);\
+ }
+
+
+PCHAR TypeNames[]={
+ "ArcSystem",
+ "CentralProcessor",
+ "FloatingPointProcessor",
+ "PrimaryIcache",
+ "PrimaryDcache",
+ "SecondaryIcache",
+ "SecondaryDcache",
+ "SecondaryCache",
+ "EisaAdapter",
+ "TcAdapter",
+ "ScsiAdapter",
+ "DtiAdapter",
+ "MultiFunctionAdapter",
+ "DiskController",
+ "TapeController",
+ "CdromController",
+ "WormController",
+ "SerialController",
+ "NetworkController",
+ "DisplayController",
+ "ParallelController",
+ "PointerController",
+ "KeyboardController",
+ "AudioController",
+ "OtherController",
+ "DiskPeripheral",
+ "FloppyDiskPeripheral",
+ "TapePeripheral",
+ "ModemPeripheral",
+ "MonitorPeripheral",
+ "PrinterPeripheral",
+ "PointerPeripheral",
+ "KeyboardPeripheral",
+ "TerminalPeripheral",
+ "OtherPeripheral",
+ "LinePeripheral",
+ "NetworkPeripheral",
+ "SystemMemory",
+ "MaximumType"
+};
+
+PCHAR ClassNames[]={
+ "SystemClass",
+ "ProcessorClass",
+ "CacheClass",
+ "AdapterClass",
+ "ControllerClass",
+ "PeripheralClass",
+ "MemoryClass",
+ "MaximumClass",
+ "XX 8 XX",
+ "XX 9 XX"
+};
+
+PCHAR ScsiNodeName[] ={
+ "disk",
+ "tape",
+ "nada",
+ "nada",
+ "worm",
+ "cdrom"
+};
+
+
+CONFIGURATION_TYPE ScsiNodeType[] ={
+ DiskController,
+ TapeController,
+ MaximumType,
+ MaximumType,
+ WormController,
+ CdromController
+};
+#endif // VRTREE_H