1/* $NetBSD: machdep.c,v 1.20 2024/03/05 14:15:29 thorpej Exp $ */ 2 3/* 4 * Copyright (c) 1988 University of Utah. 5 * Copyright (c) 1992, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by 9 * the Systems Programming Group of the University of Utah Computer 10 * Science Department, The Mach Operating System project at 11 * Carnegie-Mellon University and Ralph Campbell. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 3. Neither the name of the University nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 * 37 * @(#)machdep.c 8.3 (Berkeley) 1/12/94 38 * from: Utah Hdr: machdep.c 1.63 91/04/24 39 */ 40 41#include <sys/cdefs.h> 42__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.20 2024/03/05 14:15:29 thorpej Exp $"); 43 44#include "opt_ddb.h" 45 46#include <sys/param.h> 47#include <sys/systm.h> 48#include <sys/extent.h> 49#include <sys/kernel.h> 50#include <sys/buf.h> 51#include <sys/mbuf.h> 52#include <sys/reboot.h> 53#include <sys/mount.h> 54#include <sys/kcore.h> 55#include <sys/boot_flag.h> 56#include <sys/ksyms.h> 57#include <sys/proc.h> 58#include <sys/device.h> 59#include <sys/cpu.h> 60 61#include <uvm/uvm_extern.h> 62 63#include <dev/cons.h> 64 65#include <ufs/mfs/mfs_extern.h> /* mfs_initminiroot() */ 66 67#include <mips/cache.h> 68#include <machine/psl.h> 69#include <machine/autoconf.h> 70#include <emips/stand/common/prom_iface.h> 71#include <machine/sysconf.h> 72#include <machine/bootinfo.h> 73#include <machine/locore.h> 74#include <emips/emips/machdep.h> 75#include <machine/emipsreg.h> 76 77#define _EMIPS_BUS_DMA_PRIVATE 78#include <machine/bus.h> 79 80#if NKSYMS || defined(DDB) || defined(MODULAR) 81#include <machine/db_machdep.h> 82#include <ddb/db_extern.h> 83#endif 84 85vaddr_t iospace; 86vsize_t iospace_size = 64 * 1024; /* BUGBUG make it an option? */ 87 88#include "ksyms.h" 89 90/* 91 * Extent map to manage I/O register space. We allocate storage for 92 * 32 regions in the map. iomap_ex_malloc_safe will indicate that it's 93 * safe to use malloc() to dynamically allocate region descriptors in 94 * case we run out. 95 */ 96static long iomap_ex_storage[EXTENT_FIXED_STORAGE_SIZE(32) / sizeof(long)]; 97static struct extent *iomap_ex; 98static int iomap_ex_malloc_safe; 99 100/* maps for VM objects */ 101struct vm_map *phys_map = NULL; 102 103int systype; /* mother board type */ 104char *bootinfo = NULL; /* pointer to bootinfo structure */ 105int cpuspeed = 30; /* approx # instr per usec. */ 106intptr_t physmem_boardmax; /* {model,SIMM}-specific bound on physmem */ 107int mem_cluster_cnt; 108phys_ram_seg_t mem_clusters[VM_PHYSSEG_MAX]; 109 110void mach_init (int, char *[], int, intptr_t, u_int, char *); /* XXX */ 111 112/* Motherboard or system-specific initialization vector */ 113static void unimpl_bus_reset(void); 114static void unimpl_cons_init(void); 115static void unimpl_iointr(uint32_t, vaddr_t, uint32_t); 116static void unimpl_intr_establish(device_t, void *, int, 117 int (*)(void *, void *), void *); 118static int unimpl_memsize(void *); 119 120struct platform platform = { 121 "iobus not set", 122 unimpl_bus_reset, 123 unimpl_cons_init, 124 unimpl_iointr, 125 unimpl_intr_establish, 126 unimpl_memsize 127}; 128 129extern char *esym; /* XXX */ 130extern struct consdev promcd; /* XXX */ 131extern const struct callback *callv; 132extern const struct callback callvec; 133 134/* 135 * Do all the stuff that locore normally does before calling main(). 136 * The first 4 arguments are passed by PROM monitor, and remaining two 137 * are built on temporary stack by our boot loader. 138 */ 139void 140mach_init(int argc, char *argv[], int code, intptr_t cv, u_int bim, char *bip) 141{ 142 char *cp; 143 const char *bootinfo_msg; 144 u_long first, last; 145 int i, howtoboot; 146#if NKSYMS || defined(DDB) || defined(MODULAR) 147 void *ssym = 0; 148 struct btinfo_symtab *bi_syms; 149#endif 150 void *kernend; 151 extern char edata[], end[]; /* XXX */ 152 153 /* Set up bootinfo structure looking at stack. */ 154 if (bim == BOOTINFO_MAGIC) { 155 struct btinfo_magic *bi_magic; 156 157 bootinfo = bip; 158 bi_magic = lookup_bootinfo(BTINFO_MAGIC); 159 if (bi_magic == NULL || bi_magic->magic != BOOTINFO_MAGIC) 160 bootinfo_msg = 161 "invalid magic number in bootinfo structure.\n"; 162 else 163 bootinfo_msg = NULL; 164 } else 165 bootinfo_msg = "invalid bootinfo pointer (old bootblocks?)\n"; 166 167 /* 168 * Look at arguments passed to us and compute boothowto. 169 * Do it before we decide to keep symbols. 170 * NB: "boothowto" is in the BSS. 171 */ 172 howtoboot = 0; 173#ifdef KADB 174 howtoboot |= RB_KDB; 175#endif 176 for (i = 1; i < argc; i++) { 177 for (cp = argv[i]; *cp; cp++) { 178 switch (*cp) { 179 180#define RB_NOSYMBOLS 0x10000000 181 case 'e': /* empty the symtable */ 182 howtoboot |= RB_NOSYMBOLS; 183 break; 184 185 case 'n': /* ask for names */ 186 howtoboot |= RB_ASKNAME; 187 break; 188 189 case 'N': /* don't ask for names */ 190 howtoboot &= ~RB_ASKNAME; 191 break; 192 193 default: 194 BOOT_FLAG(*cp, howtoboot); /* see sys/boot_flag.h */ 195 break; 196 } 197 } 198 } 199 200 /* clear the BSS segment */ 201#if NKSYMS || defined(DDB) || defined(MODULAR) 202 bi_syms = lookup_bootinfo(BTINFO_SYMTAB); 203 204 /* Was it a valid bootinfo symtab info? */ 205 if ((bi_syms != NULL) && (!(howtoboot & RB_NOSYMBOLS))) { 206 ssym = (void *)(intptr_t)bi_syms->ssym; 207 esym = (void *)(intptr_t)bi_syms->esym; 208 kernend = (void *)mips_round_page(esym); 209 memset(edata, 0, end - edata); 210 } else 211#endif 212 { 213 kernend = (char *)mips_round_page(end); 214 /* should be done by bootloader? */ 215 memset(edata, 0, (char *)kernend - (char *)edata); 216 } 217 218 /* Initialize callv so we can do PROM output... */ 219 callv = (code == PROM_MAGIC) ? (void *)cv : &callvec; 220 221 /* Use PROM console output until we initialize a console driver. */ 222 cn_tab = &promcd; 223 224#if 1 225 if (bootinfo_msg != NULL) 226 printf(bootinfo_msg); 227#endif 228 uvm_md_init(); 229 230 /* 231 * Copy exception-dispatch code down to exception vector. 232 * Initialize locore-function vector. 233 * Clear out the I and D caches. 234 */ 235 mips_vector_init(NULL, false); 236 237 /* 238 * We know the CPU type now. Initialize our DMA tags (might 239 * need this early, for certain types of console devices!!). 240 */ 241 emips_bus_dma_init(); 242 243 /* Look at argv[0] and compute bootdev */ 244 makebootdev(argv[0]); 245 246 boothowto = howtoboot & ~RB_NOSYMBOLS; 247 248 /* 249 * Check to see if a mini-root was loaded into memory. It resides 250 * at the start of the next page just after the end of BSS. 251 */ 252 if (boothowto & RB_MINIROOT) 253 kernend = (char *)kernend 254 + round_page(mfs_initminiroot(kernend)); 255 256#if NKSYMS || defined(DDB) || defined(MODULAR) 257 /* init symbols if present */ 258 if (esym) { 259 ksyms_addsyms_elf((char *)esym - (char *)ssym, ssym, esym); 260 } 261#endif 262#ifdef DDB 263 if (boothowto & RB_KDB) 264 Debugger(); 265#endif 266 267 /* 268 * Initialize physmem_boardmax; assume no SIMM-bank limits. 269 * Adjust later in model-specific code if necessary. 270 */ 271 physmem_boardmax = MIPS_MAX_MEM_ADDR; 272 273 /* 274 * Determine what model of computer we are running on. 275 */ 276 systype = ((prom_systype() >> 16) & 0xff); 277 if (systype >= nsysinit) { 278 platform_not_supported(); 279 /* NOTREACHED */ 280 } 281 282 /* Machine specific initialization. */ 283 (*sysinit[systype].init)(); 284 285 /* Find out how much memory is available. */ 286 physmem = (*platform.memsize)(kernend); 287 288 /* 289 * Load the rest of the available pages into the VM system. 290 * NB: The kernel can span multiple segments. 291 */ 292 for (i = 0, physmem = 0; i < mem_cluster_cnt; ++i) { 293 first = mem_clusters[i].start; 294 if (first < round_page(MIPS_KSEG0_TO_PHYS(kernend))) 295 first = round_page(MIPS_KSEG0_TO_PHYS(kernend)); 296 last = mem_clusters[i].start + mem_clusters[i].size; 297 physmem += atop(mem_clusters[i].size); 298 299 /* if the kernel spans multiple segments (does on ML40x) */ 300 if (last <= first) 301 continue; 302 303 uvm_page_physload(atop(first), atop(last), atop(first), 304 atop(last), VM_FREELIST_DEFAULT); 305 } 306 307 /* 308 * Initialize error message buffer (at end of core). 309 */ 310 mips_init_msgbuf(); 311 312 /* 313 * Initialize the virtual memory system. 314 */ 315 iospace = pmap_limits.virtual_start; 316 pmap_limits.virtual_start += iospace_size; 317 pmap_bootstrap(); 318 319 mips_init_lwp0_uarea(); 320} 321 322void 323mips_machdep_cache_config(void) 324{ 325} 326 327void 328consinit(void) 329{ 330 /* 331 * Init I/O memory extent map. Must be done before cninit() 332 * is called; we may want to use iospace in the console routines. 333 */ 334 KASSERT(iospace != 0); 335 iomap_ex = extent_create("iomap", iospace, 336 iospace + iospace_size - 1, 337 (void *) iomap_ex_storage, sizeof(iomap_ex_storage), 338 EX_NOCOALESCE|EX_NOWAIT); 339 340 /* 341 * Up until now we have kept the TLB disabled, 342 * and that allowed the "PROM" to work. 343 * Specifically, romputc() and the debugger's getc() functions worked. 344 * Now is the last chance we get to turn it on. 345 * That means no more console I/O until autoconf() [sigh!], or.. 346 * The platform-specific code will have to map [1:1 probably] 347 * the I/O registers. 348 */ 349 register_t s = mips_cp0_status_read(); 350 s &= ~MIPS_SR_TS; 351 mips_cp0_status_write(s); 352 353 (*platform.cons_init)(); 354 355 /* 356 * Do NOT call cninit(); It will clobber cn_tab using constab[] 357 * which we do not use 358 */ 359} 360 361/* 362 * Allocates a virtual range suitable for mapping in physical memory. 363 * Uses resource maps when allocating space, which is allocated from 364 * the IOMAP submap. SIZE is a linear range (NOT vax-pages like the VAX). 365 * If the page requested is bigger than a logical page, space is 366 * allocated from the kernel map instead. 367 */ 368vaddr_t 369mips_map_physmem(paddr_t phys, vsize_t size) 370{ 371 vaddr_t addr; 372 int error; 373 static int warned = 0; 374 375 size += phys & PAGE_MASK; 376 if (size >= PAGE_SIZE) { 377 addr = uvm_km_alloc(kernel_map, size, 0, UVM_KMF_VAONLY); 378 if (addr == 0) 379 panic("mips_map_physmem: kernel map full"); 380 } else { 381 error = extent_alloc(iomap_ex, size, PAGE_SIZE, 0, 382 EX_FAST | EX_NOWAIT | 383 (iomap_ex_malloc_safe ? EX_MALLOCOK : 0), (u_long *)&addr); 384 if (error) { 385 if (warned++ == 0) /* Warn only once */ 386 printf("mips_map_physmem: iomap too small"); 387 return 0; 388 } 389 } 390 ioaccess(addr, phys, size); 391#ifdef PHYSMEMDEBUG 392 printf("mips_map_physmem: alloc'ed %x bytes for paddr %x, at %x\n", 393 size, phys, addr); 394#endif 395 return addr | (phys & PAGE_MASK); 396} 397 398/* 399 * Unmaps the previous mapped (addr, size) pair. 400 */ 401void 402mips_unmap_physmem(vaddr_t addr, vsize_t size) 403{ 404#ifdef PHYSMEMDEBUG 405 printf("mips_unmap_physmem: unmapping %x bytes at addr %x\n", 406 size, addr); 407#endif 408 size += addr & PAGE_MASK; 409 addr &= ~PAGE_MASK; 410 411 iounaccess(addr, size); 412 if (size >= PAGE_SIZE) 413 uvm_km_free(kernel_map, addr, size, UVM_KMF_VAONLY); 414 else if (extent_free(iomap_ex, addr, size, 415 EX_NOWAIT | (iomap_ex_malloc_safe ? EX_MALLOCOK : 0))) 416 printf("mips_unmap_physmem: addr 0x%llx size %llx: " 417 "can't free region\n", (long long)addr, (long long)size); 418} 419 420/* 421 * Machine-dependent startup code: allocate memory for variable-sized 422 * tables. 423 */ 424void 425cpu_startup(void) 426{ 427 vaddr_t minaddr, maxaddr; 428 char pbuf[9]; 429#ifdef DEBUG 430 extern int pmapdebug; /* XXX */ 431 int opmapdebug = pmapdebug; 432 433 pmapdebug = 0; 434#endif 435 436 /* 437 * Good {morning,afternoon,evening,night}. 438 */ 439 printf("%s%s", copyright, version); 440 printf("%s\n", cpu_getmodel()); 441 format_bytes(pbuf, sizeof(pbuf), ctob(physmem)); 442 printf("total memory = %s\n", pbuf); 443 444 minaddr = 0; 445 446 /* 447 * Allocate a submap for physio 448 */ 449 phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr, 450 VM_PHYS_SIZE, 0, false, NULL); 451 452 /* 453 * No need to allocate an mbuf cluster submap. Mbuf clusters 454 * are allocated via the pool allocator, and we use KSEG to 455 * map those pages. 456 */ 457 458 iomap_ex_malloc_safe = 1; 459 460#ifdef DEBUG 461 pmapdebug = opmapdebug; 462#endif 463 format_bytes(pbuf, sizeof(pbuf), ptoa(uvm_availmem(false))); 464 printf("avail memory = %s\n", pbuf); 465} 466 467/* 468 * Look up information in bootinfo of boot loader. 469 */ 470void * 471lookup_bootinfo(int type) 472{ 473 struct btinfo_common *bt; 474 char *help = bootinfo; 475 476 /* Check for a bootinfo record first. */ 477 if (help == NULL) 478 return (NULL); 479 480 do { 481 bt = (struct btinfo_common *)help; 482 if (bt->type == type) 483 return ((void *)help); 484 help += bt->next; 485 } while (bt->next != 0 && 486 (size_t)help < (size_t)bootinfo + BOOTINFO_SIZE); 487 488 return (NULL); 489} 490 491void 492cpu_reboot(volatile int howto, /* XXX volatile to keep gcc happy */ 493 char *bootstr) 494{ 495 496 /* take a snap shot before clobbering any registers */ 497 if (curlwp) 498 savectx(curpcb); 499 500#ifdef DEBUG 501 if (panicstr) 502 stacktrace(); 503#endif 504 505 /* If system is cold, just halt. */ 506 if (cold) { 507 howto |= RB_HALT; 508 goto haltsys; 509 } 510 511 /* If "always halt" was specified as a boot flag, obey. */ 512 if ((boothowto & RB_HALT) != 0) 513 howto |= RB_HALT; 514 515 boothowto = howto; 516 if ((howto & RB_NOSYNC) == 0) { 517 /* 518 * Synchronize the disks.... 519 */ 520 vfs_shutdown(); 521 } 522 523 /* Disable interrupts. */ 524 splhigh(); 525 526 /* If rebooting and a dump is requested do it. */ 527 if ((howto & (RB_DUMP | RB_HALT)) == RB_DUMP) 528 dumpsys(); 529 530haltsys: 531 /* run any shutdown hooks */ 532 doshutdownhooks(); 533 534 pmf_system_shutdown(boothowto); 535 536 /* Finally, halt/reboot the system. */ 537 printf("%s\n\n", ((howto & RB_HALT) != 0) ? "halted." : "rebooting..."); 538 539 prom_halt(howto); 540 for (;;) ; 541 /*NOTREACHED*/ 542} 543 544#if defined(MIPS_4GB_PHYSICAL_MEMORY) 545#define trim_memory(n) n 546#else 547#if 0 548#define TOO_MUCH (MIPS_PHYS_MASK+1) 549#else 550#define TOO_MUCH (2*64*1024*1024) 551#endif 552u_long trim_memory(uint32_t nbytes);/*cheat*/ 553u_long trim_memory(uint32_t nbytes) 554{ 555 int i; 556 u_long first, last; 557 558 nbytes *= 4096; 559 if (nbytes <= TOO_MUCH) 560 return nbytes; 561 562 /* We have more memory than we can handle */ 563 564 mem_clusters[mem_cluster_cnt].start = 0;/* sentinel record */ 565 mem_clusters[mem_cluster_cnt].size = 0; 566 for (i = 0; i < mem_cluster_cnt;) { 567 first = mem_clusters[i].start; 568 last = mem_clusters[i].start + mem_clusters[i].size; 569 570 if (first > TOO_MUCH) { 571 printf("Too much memory, ignoring memory " 572 "range %08lx..%08lx\n", first, last); 573 memcpy(mem_clusters+i,mem_clusters+i+1, 574 (sizeof(mem_clusters[0])*(mem_cluster_cnt-i))); 575 mem_cluster_cnt--; 576 continue; 577 } 578 579 if (last > TOO_MUCH) { 580 last = TOO_MUCH; 581 printf("Too much memory in cluster %d, trimming " 582 "memory to range %08lx..%08lx\n", 583 i, first, last); 584 mem_clusters[i].size = last - mem_clusters[i].start; 585 } 586 i++; 587 } 588 return TOO_MUCH; 589} 590#endif 591 592/* 593 * Find out how much memory is available by testing memory. 594 */ 595int 596memsize_scan(void *first) 597{ 598 int i, mem; 599 char *cp; 600 601 mem = btoc((paddr_t)first - MIPS_KSEG0_START); 602 cp = (char *)MIPS_PHYS_TO_KSEG1(mem << PGSHIFT); 603 while (cp < (char *)physmem_boardmax) { 604 int j; 605 if (badaddr(cp, 4)) 606 break; 607 i = *(int *)cp; 608 j = ((int *)cp)[4]; 609 *(int *)cp = 0xa5a5a5a5; 610 /* 611 * Data will persist on the bus if we read it right away. 612 * Have to be tricky here. 613 */ 614 ((int *)cp)[4] = 0x5a5a5a5a; 615 wbflush(); 616 if (*(int *)cp != 0xa5a5a5a5) 617 break; 618 *(int *)cp = i; 619 ((int *)cp)[4] = j; 620 cp += PAGE_SIZE; 621 mem++; 622 } 623 624 /* 625 * Now that we know how much memory we have, initialize the 626 * mem cluster array. 627 */ 628 mem_clusters[0].start = 0; /* XXX is this correct? */ 629 mem_clusters[0].size = ctob(mem); 630 mem_cluster_cnt = 1; 631 632 /* clear any memory error conditions possibly caused by probe */ 633 (*platform.bus_reset)(); 634 return (mem); 635} 636 637/* 638 * Find out how much memory is available by testing memory, starting at first. 639 * Returns the total number of pages. 640 */ 641int 642memsize_pmt(void * first) 643{ 644 int i, mem; 645 struct _Pmt *Pmt = ThePmt; 646 struct _Sram *ram; 647 uint32_t addr, len; 648 649 /* 650 * Build the RAM memory map from the PMT. 651 */ 652 mem = 0; 653 for (i = 0; i < VM_PHYSSEG_MAX; Pmt--) { 654 uint16_t tag = Pmt->Tag; 655 656 if (tag == PMTTAG_END_OF_TABLE) 657 break; 658 659 if ((tag != PMTTAG_SRAM) && (tag != PMTTAG_DDRAM)) 660 continue; 661 662 /* 663 * Got a memory controller segment, 664 * scan all the controllers in it 665 */ 666 ram = (struct _Sram *)(Pmt->TopOfPhysicalAddress << 16); 667 668 for (;(ram->BaseAddressAndTag & SRAMBT_TAG) == tag;) { 669 addr = ram->BaseAddressAndTag & SRAMBT_BASE; 670 len = ram->Control & SRAMST_SIZE; 671 672 mem_clusters[i].start = addr; 673 mem_clusters[i].size = len; 674 printf("memory segment %2d start %08lx size %08lx\n", i, 675 (long)mem_clusters[i].start, 676 (long)mem_clusters[i].size); 677 i++; 678 mem += len; 679 680 /* SRAM and DDRAM have different sizes */ 681 ram = (tag == PMTTAG_SRAM) ? ram+1 : ram+2; 682 } 683 } 684 mem_cluster_cnt = i; 685 686 return trim_memory(btoc(mem)); 687} 688/* 689 * Ensure all platform vectors are always initialized. 690 */ 691static void 692unimpl_bus_reset(void) 693{ 694 695 panic("sysconf.init didn't set bus_reset"); 696} 697 698static void 699unimpl_cons_init(void) 700{ 701 702 panic("sysconf.init didn't set cons_init"); 703} 704 705static void 706unimpl_iointr(uint32_t status, vaddr_t pc, uint32_t ipending) 707{ 708 709 panic("sysconf.init didn't set intr"); 710} 711 712static void 713unimpl_intr_establish(device_t dev, void *cookie, int level, 714 int (*handler) (void *,void *), void *arg) 715{ 716 717 panic("sysconf.init didn't set intr_establish"); 718} 719 720static int 721unimpl_memsize(void * first) 722{ 723 724 panic("sysconf.init didn't set memsize"); 725} 726 727/* 728 * Wait "n" microseconds. 729 */ 730void 731delay(int n) 732{ 733 734 DELAY(n); 735} 736