From 208a651c13a643919346ce52b3eacd948de28db1 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 25 Jan 2011 00:01:25 +0000 Subject: [import] Import version 4.20 http://www.memtest.org/download/4.20/memtest86+-4.20.tar.gz --- README | 2 +- changelog | 16 ++--- config.h | 3 + controller.c | 201 +++++++++++++++++++++++++++++++++++++++++++++++++++-- init.c | 77 +++++++++++++++++--- jedec_id.h | 2 +- linuxbios.c | 11 +++ linuxbios_tables.h | 7 ++ makeiso.sh | 6 +- mt86+_loader | Bin 784 -> 784 bytes mt86+_loader.asm | 4 +- precomp.bin | Bin 165080 -> 164504 bytes spd.c | 115 ++++-------------------------- 13 files changed, 313 insertions(+), 131 deletions(-) diff --git a/README b/README index cbdb42e..963cfc4 100644 --- a/README +++ b/README @@ -1,4 +1,4 @@ -Memtest86++ v4.10 +Memtest86++ v4.20 ==================== Table of Contents diff --git a/changelog b/changelog index 5ca01c5..d6e49d2 100644 --- a/changelog +++ b/changelog @@ -1,11 +1,9 @@ -Memtest86+ V4.10 changelog +Memtest86+ V4.20 changelog -------------------------- - - Added support for Core i7 Extreme CPU (32nm) - - Added support for Core i5/i3 (32 nm) - - Added support for Pentium Gxxxx (32 mn) - - Added support for Westmere-based Xeon - - Added preliminary support for Intel Sandy Bridge - - Added support for AMD 6-cores CPU - - Added detection for Intel 3200/3210 - - Many bug fixes + - Added failsafe mode (F1 at startup) + - Added support for Intel "Sandy Bridge" CPU + - Added support for AMD "fusion" CPU + - Added Coreboot "table forward" support + - Corrected some memory brand not detected + - Various bug fixes \ No newline at end of file diff --git a/config.h b/config.h index 8e68985..e32eef4 100644 --- a/config.h +++ b/config.h @@ -21,6 +21,9 @@ /* SERIAL_BAUD_RATE - Baud rate for the serial console */ #define SERIAL_BAUD_RATE 9600 +/* START_FAIL_SAFE - Default 0 = normal. Change to 1 to always start in fail safe mode */ +#define START_FAIL_SAFE 0 + /* BEEP_MODE - Beep on error. Default off, Change to 1 to enable */ #define BEEP_MODE 0 diff --git a/controller.c b/controller.c index 89589ab..9009996 100644 --- a/controller.c +++ b/controller.c @@ -3,7 +3,7 @@ * Released under version 2 of the Gnu Public License. * By Chris Brady, cbrady@sgi.com * ---------------------------------------------------- - * MemTest86+ V4.00 Specific code (GPL V2.0) + * MemTest86+ V4.20 Specific code (GPL V2.0) * By Samuel DEMEULEMEESTER, sdemeule@memtest.org * http://www.canardpc.com - http://www.memtest.org */ @@ -23,6 +23,7 @@ int nhm_bus = 0x3F; extern ulong extclock; extern unsigned long imc_type; extern struct cpu_ident cpu_id; +extern int fail_safe; #define rdmsr(msr,val1,val2) \ __asm__ __volatile__("rdmsr" \ @@ -175,7 +176,13 @@ static void poll_timings_nothing(void) return; } - +static void poll_fsb_failsafe(void) +{ +/* Code to run for no specific fsb detection */ + cprint(LINE_CPU+5, 0, "Chipset/IMC : ***FAIL SAFE***FAIL SAFE***FAIL SAFE***FAIL SAFE***FAIL SAFE***"); + cprint(LINE_CPU+6, 0, "*** Memtest86+ is running in fail safe mode. Same reliability, less details ***"); + return; +} static void setup_nothing(void) { ctrl.cap = ECC_NONE; @@ -1230,6 +1237,24 @@ static float getNHMmultiplier(void) return coef; } +static float getSNBmultiplier(void) +{ + unsigned int msr_lo, msr_hi; + float coef; + + rdmsr(0x198, msr_lo, msr_hi); + coef = (msr_lo >> 8) & 0xFF; + if(coef < 4) + { + rdmsr(0xCE, msr_lo, msr_hi); + coef = (msr_lo >> 16) & 0xFF; + } + + + + return coef; +} + void getIntelPNS(void) { @@ -1456,6 +1481,58 @@ static void poll_fsb_k10(void) { } +static void poll_fsb_k14(void) { + + unsigned long temp2; + unsigned long dramchr; + double dramclock; + unsigned long pns_low; + unsigned long pns_high; + unsigned long msr_psn; + + + /* If ECC not enabled : display CPU name as IMC */ + if(ctrl.mode == ECC_NONE) + { + cprint(LINE_CPU+5, 0, "IMC : "); + for(msr_psn = 0; msr_psn < 5; msr_psn++) + { + rdmsr(0xC0010030+msr_psn, pns_low, pns_high); + cprint(LINE_CPU+5, 6+(msr_psn*8), convert_hex_to_char(pns_low & 0xff)); + cprint(LINE_CPU+5, 7+(msr_psn*8), convert_hex_to_char((pns_low >> 8) & 0xff)); + cprint(LINE_CPU+5, 8+(msr_psn*8), convert_hex_to_char((pns_low >> 16) & 0xff)); + cprint(LINE_CPU+5, 9+(msr_psn*8), convert_hex_to_char((pns_low >> 24) & 0xff)); + cprint(LINE_CPU+5, 10+(msr_psn*8), convert_hex_to_char(pns_high & 0xff)); + cprint(LINE_CPU+5, 11+(msr_psn*8), convert_hex_to_char((pns_high >> 8) & 0xff)); + cprint(LINE_CPU+5, 12+(msr_psn*8), convert_hex_to_char((pns_high >> 16) & 0xff)); + cprint(LINE_CPU+5, 13+(msr_psn*8), convert_hex_to_char((pns_high >> 24) & 0xff)); + } + cprint(LINE_CPU+5, 41, "(ECC : Disabled)"); + } + + /* First, we need the clock ratio */ + pci_conf_read(0, 24, 2, 0x94, 4, &dramchr); + temp2 = (dramchr & 0x1F); + + switch (temp2) { + default: + case 6: + dramclock = 400; + break; + case 10: + dramclock = 533; + break; + case 14: + dramclock = 667; + break; + } + + + /* print */ + print_fsb_info(dramclock, "RAM : ", "DDR-"); + +} + static void poll_fsb_i925(void) { double dramclock, dramratio, fsb; @@ -2291,6 +2368,50 @@ static void poll_fsb_wmr(void) { } +static void poll_fsb_snb(void) { + + double dramclock, dramratio, fsb; + unsigned long dev0, mchcfg; + float coef = getSNBmultiplier(); + long *ptr; + + fsb = ((extclock / 1000) / coef); + + if(ctrl.mode == ECC_NONE) + { + col = 0; + cprint(LINE_CPU+5, col, "IMC : "); col += 6; + getIntelPNS(); + //cprint(LINE_CPU+5, col, "(ECC : Disabled)"); + //col += 16; + } + + /* Print FSB */ + cprint(LINE_CPU+5, col +1, "/ BCLK : "); + col += 10; + dprint(LINE_CPU+5, col, fsb, 3,0); + col += 3; + cprint(LINE_CPU+5, col +1, "MHz"); + col += 4; + + /* Find dramratio */ + pci_conf_read( 0, 0, 0, 0x48, 4, &dev0); + dev0 &= 0xFFFFC000; + ptr=(long*)(dev0+0x5E04); + mchcfg = *ptr & 0xFFFF; + dramratio = 1; + + /* Get the clock ratio */ + dramratio = (float)(*ptr & 0x1F) * (133.34f / 100.0f); + + // Compute RAM Frequency + dramclock = fsb * dramratio; + + // Print DRAM Freq + print_fsb_info(dramclock, "RAM : ", "DDR3-"); + +} + /* ------------------ Here the code for Timings detection ------------------ */ /* ------------------------------------------------------------------------- */ @@ -2747,6 +2868,52 @@ static void poll_timings_wmr(void) { } +static void poll_timings_snb(void) { + + float cas; + int rcd, rp, ras; + ulong dev0, offset; + ulong IMC_Register, MCMain0_Register, MCMain1_Register; + long *ptr; + + //Now, read MMR Base Address + pci_conf_read( 0, 0, 0, 0x48, 4, &dev0); + dev0 &= 0xFFFFC000; + + offset = 0x0000; + + ptr = (long*)(dev0+offset+0x4000); + IMC_Register = *ptr & 0xFFFFFFFF; + + // CAS Latency (tCAS) + cas = (float)((IMC_Register >> 8) & 0x0F); + + // RAS-To-CAS (tRCD) + rcd = IMC_Register & 0x0F; + + // RAS Precharge (tRP) + rp = (IMC_Register >> 4) & 0x0F; + + // RAS Active to precharge (tRAS) + ras = (IMC_Register >> 16) & 0xFF; + + print_timings_info(cas, rcd, rp, ras); + + cprint(LINE_CPU+6, col2+1, "/"); col2 +=2; + + // Channels + ptr = (long*)(dev0+offset+0x5004); + MCMain0_Register = *ptr & 0xFFFF; + ptr = (long*)(dev0+offset+0x5008); + MCMain1_Register = *ptr & 0xFFFF; + + if(MCMain0_Register == 0 || MCMain1_Register == 0) { + cprint(LINE_CPU+6, col2+1, "Single Channel"); + } else { + cprint(LINE_CPU+6, col2+1, "Dual Channel"); + } + +} static void poll_timings_5400(void) { @@ -3083,6 +3250,27 @@ static void poll_timings_k10(void) { } +static void poll_timings_k14(void) { + + ulong dramt0, dramlow; + int cas, rcd, rp, rc, ras; + + pci_conf_read(0, 24, 2, 0x88, 4, &dramlow); + pci_conf_write(0, 24, 2, 0xF0, 4, 0x00000040); + pci_conf_read(0, 24, 2, 0xF4, 4, &dramt0); + + cas = (dramlow & 0xF) + 4; + rcd = (dramt0 & 0xF) + 5; + rp = ((dramt0 >> 8) & 0xF) + 5; + ras = ((dramt0 >> 16) & 0x1F) + 15; + rc = ((dramt0 >> 24) & 0x3F) + 16; + + print_timings_info(cas, rcd, rp, ras); + + cprint(LINE_CPU+6, col2, "/ DDR3 (64 bits)"); + +} + static void poll_timings_EP80579(void) { ulong drt1, drt2; @@ -3380,9 +3568,13 @@ static struct pci_memory_controller controllers[] = { { 0xFFFF, 0x0001, "Core IMC", 0, poll_fsb_nhm, poll_timings_nhm, setup_nhm, poll_nothing}, { 0xFFFF, 0x0002, "Core IMC 32nm", 0, poll_fsb_nhm32, poll_timings_nhm, setup_nhm32, poll_nothing}, { 0xFFFF, 0x0003, "Core IMC 32nm", 0, poll_fsb_wmr, poll_timings_wmr, setup_wmr, poll_nothing}, + { 0xFFFF, 0x0004, "SNB IMC 32nm", 0, poll_fsb_snb, poll_timings_snb, setup_wmr, poll_nothing}, { 0xFFFF, 0x0100, "AMD K8 IMC", 0, poll_fsb_amd64, poll_timings_amd64, setup_amd64, poll_amd64 }, - { 0xFFFF, 0x0101, "AMD K10 IMC", 0, poll_fsb_k10, poll_timings_k10, setup_k10, poll_nothing } - + { 0xFFFF, 0x0101, "AMD K10 IMC", 0, poll_fsb_k10, poll_timings_k10, setup_k10, poll_nothing }, + { 0xFFFF, 0x0102, "AMD APU IMC", 0, poll_fsb_k14, poll_timings_k14, setup_nothing, poll_nothing }, + + /* Fail Safe */ + { 0xFFFF, 0xFFFF, "", 0, poll_fsb_failsafe, poll_timings_nothing, setup_nothing, poll_nothing } }; static void print_memory_controller(void) @@ -3474,6 +3666,7 @@ void find_controller(void) // Detect IMC by CPUID if(imc_type) { vendor = 0xFFFF; device = imc_type; } + if(fail_safe) { vendor = 0xFFFF; device = 0xFFFF; } ctrl.index = 0; if (result == 0) { diff --git a/init.c b/init.c index d965ec3..f7f43c1 100644 --- a/init.c +++ b/init.c @@ -3,7 +3,7 @@ * Released under version 2 of the Gnu Public License. * By Chris Brady, cbrady@sgi.com * ---------------------------------------------------- - * MemTest86+ V4.10 Specific code (GPL V2.0) + * MemTest86+ V4.20 Specific code (GPL V2.0) * By Samuel DEMEULEMEESTER, sdemeule@memtest.org * http://www.canardpc.com - http://www.memtest.org */ @@ -41,7 +41,54 @@ ulong memspeed(ulong src, ulong len, int iter, int type); static void cpu_type(void); static void cacheable(void); static int cpuspeed(void); -int beepmode; +int beepmode, fail_safe; + +/* Failsafe function */ +/* msec: number of ms to wait - scs: scancode expected to stop */ +void failsafe(int msec, int scs) +{ + int ip; + ulong sh, sl, l, h, t; + unsigned char c; + + cprint(18, 22, "Press *F1* to enter Fail-Safe Mode"); + + ip = 0; + /* save the starting time */ + asm __volatile__( + "rdtsc":"=a" (sl),"=d" (sh)); + + /* loop for n seconds */ + while (1) { + asm __volatile__( + "rdtsc":"=a" (l),"=d" (h)); + asm __volatile__ ( + "subl %2,%0\n\t" + "sbbl %3,%1" + :"=a" (l), "=d" (h) + :"g" (sl), "g" (sh), + "0" (l), "1" (h)); + + t = h * ((unsigned)0xffffffff / v->clks_msec); + t += (l / v->clks_msec); + + /* Is the time up? */ + if (t >= msec) { + cprint(18, 22, " "); + break; + } + + /* Is expected Scan code pressed? */ + c = get_key(); + c &= 0x7f; + + if(c == scs) { + fail_safe = 1; + cprint(18, 22, " "); + break; + } + } +} static void display_init(void) { @@ -65,7 +112,7 @@ static void display_init(void) for(i=0, pp=(char *)(SCREEN_ADR+1); irdtsc) { cacheable(); @@ -576,18 +627,25 @@ void cpu_type(void) l3_cache = (cpu_id.cache_info[15] << 8); l3_cache += (cpu_id.cache_info[14] >> 2); l3_cache *= 512; - imc_type = 0x0101; switch(cpu_id.model) { + case 1: + imc_type = 0x0102; + cprint(LINE_CPU, 0, "AMD Fusion @"); + off = 12; + break; default: case 2: + imc_type = 0x0101; cprint(LINE_CPU, 0, "AMD K10 (65nm) @"); off = 16; break; case 4: + imc_type = 0x0101; cprint(LINE_CPU, 0, "AMD K10 (45nm) @"); off = 16; break; case 9: + imc_type = 0x0101; cprint(LINE_CPU, 0, "AMD Magny-Cours"); off = 15; break; @@ -913,9 +971,9 @@ void cpu_type(void) if (((cpu_id.ext >> 16) & 0xF) != 0) { tsc_invariable = 1; if(((cpu_id.ext >> 16) & 0xF) > 1) { - cprint(LINE_CPU, 0, "Intel SNB"); - imc_type = 0x0003; - off = 9; + cprint(LINE_CPU, 0, "Intel Core Gen2"); + imc_type = 0x0004; + off = 15; } else { imc_type = 0x0001; cprint(LINE_CPU, 0, "Intel Core i7"); @@ -1491,3 +1549,4 @@ ulong correct_tsc(ulong el_org) return el_org; } + diff --git a/jedec_id.h b/jedec_id.h index 6694c17..e62b343 100644 --- a/jedec_id.h +++ b/jedec_id.h @@ -621,7 +621,7 @@ struct spd_jedec_manufacturer jep106[] = { { 4, 0xe9, "Century Micro"}, { 4, 0xea, "Icera Semiconductor"}, { 4, 0x6b, "Mediaworks Integrated Systems"}, - { 4, 0xec, "O?Neil Product Development"}, + { 4, 0xec, "O'Neil Product Development"}, { 4, 0x6d, "Supreme Top Technology"}, { 4, 0x6e, "MicroDisplay"}, { 4, 0xef, "Team Group"}, diff --git a/linuxbios.c b/linuxbios.c index fa34c6a..75d9181 100644 --- a/linuxbios.c +++ b/linuxbios.c @@ -115,11 +115,22 @@ int query_linuxbios(void) struct lb_header *head; struct lb_record *rec; struct lb_memory *mem; + struct lb_forward *forward; int i, entries; + head = find_lb_table(); if (!head) { return 0; } + + /* coreboot also can forward the table to the high tables area. */ + rec = (struct lb_record *)(((char *)head) + sizeof(*head)); + if (rec->tag == LB_TAG_FORWARD) { + forward = (struct lb_forward *)rec; + head = (struct lb_header *)(unsigned long)(forward->forward); + if (!head) { return 0; } + } + mem = 0; for_each_lbrec(head, rec) { if (rec->tag == LB_TAG_MEMORY) { diff --git a/linuxbios_tables.h b/linuxbios_tables.h index d312173..38f2038 100644 --- a/linuxbios_tables.h +++ b/linuxbios_tables.h @@ -56,6 +56,7 @@ struct lb_record { #define LB_TAG_UNUSED 0x0000 #define LB_TAG_MEMORY 0x0001 +#define LB_TAG_FORWARD 0x0011 struct lb_memory_range { uint64_t start; @@ -79,4 +80,10 @@ struct lb_hwrpb { uint64_t hwrpb; }; +struct lb_forward { + uint32_t tag; + uint32_t size; + uint64_t forward; +}; + #endif /* LINUXBIOS_TABLES_H */ diff --git a/makeiso.sh b/makeiso.sh index bc1c137..0ed373e 100755 --- a/makeiso.sh +++ b/makeiso.sh @@ -37,9 +37,9 @@ cd cd echo -e "There is nothing to do here\r\r\nMemtest86+ is located on the bootsector of this CD\r\r\n" > README.TXT echo -e "Just boot from this CD and Memtest86+ will launch" >> README.TXT -mkisofs -A "MKISOFS 1.1.2" -p "Memtest86+ 4.10" -publisher "Samuel D. " -b boot/memtest.img -c boot/boot.catalog -V "MT410" -o memtest.iso . -mv memtest.iso ../mt410.iso +mkisofs -A "MKISOFS 1.1.2" -p "Memtest86+ 4.20" -publisher "Samuel D. " -b boot/memtest.img -c boot/boot.catalog -V "MT410" -o memtest.iso . +mv memtest.iso ../mt420.iso cd .. rm -rf cd -echo "Done! Memtest86+ 4.10 ISO is mt410.iso" +echo "Done! Memtest86+ 4.20 ISO is mt420.iso" diff --git a/mt86+_loader b/mt86+_loader index df62b62..6c77a6f 100644 Binary files a/mt86+_loader and b/mt86+_loader differ diff --git a/mt86+_loader.asm b/mt86+_loader.asm index a305400..600ebfa 100644 --- a/mt86+_loader.asm +++ b/mt86+_loader.asm @@ -12,8 +12,8 @@ ; The good thing is that you get a single file which can be ; compressed, for example with http://upx.sf.net/ (UPX). -%define fullsize (165080 + buffer - exeh) - ; 165080 is the size of memtest86+ V4.00, adjust as needed! +%define fullsize (164504 + buffer - exeh) + ; 164504 is the size of memtest86+ V4.20, adjust as needed! %define stacksize 2048 %define stackpara ((stacksize + 15) / 16) diff --git a/precomp.bin b/precomp.bin index e54513b..293e15d 100755 Binary files a/precomp.bin and b/precomp.bin differ diff --git a/spd.c b/spd.c index 0cdfe1e..cef93f0 100644 --- a/spd.c +++ b/spd.c @@ -3,7 +3,7 @@ * * Released under version 2 of the Gnu Puclic License * ---------------------------------------------------- - * MemTest86+ V4.00 Specific code (GPL V2.0) + * MemTest86+ V4.20 Specific code (GPL V2.0) * By Samuel DEMEULEMEESTER, sdemeule@memtest.org * http://www.canardpc.com - http://www.memtest.org */ @@ -123,6 +123,7 @@ struct pci_smbus_controller { }; static struct pci_smbus_controller smbcontrollers[] = { +{0x8086, 0x1C22, "Intel P67", ich5_get_smb, ich5_read_spd}, {0x8086, 0x3B30, "Intel P55", ich5_get_smb, ich5_read_spd}, {0x8086, 0x3A60, "Intel ICH10B", ich5_get_smb, ich5_read_spd}, {0x8086, 0x3A30, "Intel ICH10R", ich5_get_smb, ich5_read_spd}, @@ -233,6 +234,7 @@ void get_spd_spec(void) curcol++; // Then print module infos (manufacturer & part number) + spd[117] &= 0x0F; // Parity odd or even for (i = 0; jep106[i].cont_code < 9; i++) { if (spd[117] == jep106[i].cont_code && spd[118] == jep106[i].hex_byte) { // We are here if a Jedec manufacturer is detected @@ -459,106 +461,15 @@ struct ascii_map { char *name; }; -struct ascii_map amap[] = { -{ 0x20, " "}, -{ 0x21, "!"}, -{ 0x22, "'"}, -{ 0x23, "#"}, -{ 0x24, "$"}, -{ 0x25, "%"}, -{ 0x26, "&"}, -{ 0x28, "("}, -{ 0x29, ")"}, -{ 0x2A, "*"}, -{ 0x2B, "+"}, -{ 0x2C, ","}, -{ 0x2D, "-"}, -{ 0x2E, "."}, -{ 0x30, "0"}, -{ 0x31, "1"}, -{ 0x32, "2"}, -{ 0x33, "3"}, -{ 0x34, "4"}, -{ 0x35, "5"}, -{ 0x36, "6"}, -{ 0x38, "8"}, -{ 0x39, "9"}, -{ 0x3A, ":"}, -{ 0x3B, ";"}, -{ 0x3C, "<"}, -{ 0x3D, "="}, -{ 0x3E, ">"}, -{ 0x40, "@"}, -{ 0x41, "A"}, -{ 0x42, "B"}, -{ 0x43, "C"}, -{ 0x44, "D"}, -{ 0x45, "E"}, -{ 0x46, "F"}, -{ 0x47, "G"}, -{ 0x48, "H"}, -{ 0x49, "I"}, -{ 0x4A, "J"}, -{ 0x4B, "K"}, -{ 0x4C, "L"}, -{ 0x4D, "M"}, -{ 0x4E, "N"}, -{ 0x4F, "O"}, -{ 0x50, "P"}, -{ 0x51, "Q"}, -{ 0x52, "R"}, -{ 0x53, "S"}, -{ 0x54, "T"}, -{ 0x55, "U"}, -{ 0x56, "V"}, -{ 0x57, "W"}, -{ 0x58, "X"}, -{ 0x59, "Y"}, -{ 0x5A, "Z"}, -{ 0x5B, "["}, -{ 0x5C, "-"}, -{ 0x5D, "]"}, -{ 0x5E, "^"}, -{ 0x60, "`"}, -{ 0x61, "a"}, -{ 0x62, "b"}, -{ 0x63, "c"}, -{ 0x64, "d"}, -{ 0x65, "e"}, -{ 0x66, "f"}, -{ 0x68, "h"}, -{ 0x69, "i"}, -{ 0x6A, "j"}, -{ 0x6B, "k"}, -{ 0x6C, "l"}, -{ 0x6D, "m"}, -{ 0x6E, "n"}, -{ 0x6F, "o"}, -{ 0x70, "p"}, -{ 0x71, "q"}, -{ 0x72, "r"}, -{ 0x73, "s"}, -{ 0x74, "t"}, -{ 0x75, "u"}, -{ 0x76, "v"}, -{ 0x78, "x"}, -{ 0x79, "y"}, -{ 0x7A, "z"}, -{ 0x7B, "{"}, -{ 0x7C, "|"}, -{ 0x7D, "}"}, -{ 0x7E, "~"}, -{ 0, ""} -}; -char* convert_hex_to_char(unsigned hex_org){ - int i; - - for (i = 0; amap[i].hex_code > 0; i++) { - if (hex_org == amap[i].hex_code) { - return amap[i].name; - } - } - return ""; -} +char* convert_hex_to_char(unsigned hex_org) { + static char buf[2] = " "; + if (hex_org >= 0x20 && hex_org < 0x80) { + buf[0] = hex_org; + } else { + //buf[0] = '\0'; + buf[0] = ' '; + } + return buf; +} \ No newline at end of file -- cgit v1.2.3-55-g7522